mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
Merge pull request #5393 from knst/bc-bp-v20-missing-7
backport: bitcoin#16902, #17720, #18107, #18278, #18360, #18397, #18402, #18420, #18447, #18481, #18494, #18496, #18503, #18515
This commit is contained in:
commit
2c0cb13f09
@ -1,7 +1,7 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[dash.qt-translation-018x]
|
||||
[dash.qt-translation-020x]
|
||||
file_filter = src/qt/locale/dash_<lang>.ts
|
||||
source_file = src/qt/locale/dash_en.xlf
|
||||
source_lang = en
|
||||
|
22
Makefile.am
22
Makefile.am
@ -73,7 +73,7 @@ OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \
|
||||
COVERAGE_INFO = baseline.info \
|
||||
test_dash_filtered.info total_coverage.info \
|
||||
baseline_filtered.info functional_test.info functional_test_filtered.info \
|
||||
test_dash_coverage.info test_dash.info
|
||||
test_dash_coverage.info test_dash.info fuzz.info fuzz_coverage.info
|
||||
|
||||
dist-hook:
|
||||
-$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf -
|
||||
@ -211,6 +211,15 @@ baseline_filtered.info: baseline.info
|
||||
$(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@
|
||||
$(LCOV) -a $@ $(LCOV_OPTS) -o $@
|
||||
|
||||
fuzz.info: baseline_filtered.info
|
||||
@TIMEOUT=15 test/fuzz/test_runner.py qa-assets/fuzz_seed_corpus -l DEBUG
|
||||
$(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src --t fuzz-tests -o $@
|
||||
$(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src
|
||||
|
||||
fuzz_filtered.info: fuzz.info
|
||||
$(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@
|
||||
$(LCOV) -a $@ $(LCOV_OPTS) -o $@
|
||||
|
||||
test_dash.info: baseline_filtered.info
|
||||
$(MAKE) -C src/ check
|
||||
$(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src -t test_dash -o $@
|
||||
@ -229,12 +238,19 @@ functional_test_filtered.info: functional_test.info
|
||||
$(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@
|
||||
$(LCOV) -a $@ $(LCOV_OPTS) -o $@
|
||||
|
||||
fuzz_coverage.info: fuzz_filtered.info
|
||||
$(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a fuzz_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
|
||||
|
||||
test_dash_coverage.info: baseline_filtered.info test_dash_filtered.info
|
||||
$(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_dash_filtered.info -o $@
|
||||
|
||||
total_coverage.info: test_dash_filtered.info functional_test_filtered.info
|
||||
$(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_dash_filtered.info -a functional_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
|
||||
|
||||
fuzz.coverage/.dirstamp: fuzz_coverage.info
|
||||
$(GENHTML) -s $(LCOV_OPTS) $< -o $(@D)
|
||||
@touch $@
|
||||
|
||||
test_dash.coverage/.dirstamp: test_dash_coverage.info
|
||||
$(GENHTML) -s $(LCOV_OPTS) $< -o $(@D)
|
||||
@touch $@
|
||||
@ -243,6 +259,8 @@ total.coverage/.dirstamp: total_coverage.info
|
||||
$(GENHTML) -s $(LCOV_OPTS) $< -o $(@D)
|
||||
@touch $@
|
||||
|
||||
cov_fuzz: fuzz.coverage/.dirstamp
|
||||
|
||||
cov: test_dash.coverage/.dirstamp total.coverage/.dirstamp
|
||||
|
||||
endif
|
||||
@ -318,7 +336,7 @@ clean-docs:
|
||||
rm -rf doc/doxygen
|
||||
|
||||
clean-local: clean-docs
|
||||
rm -rf coverage_percent.txt test_dash.coverage/ total.coverage/ test/tmp/ cache/ $(OSX_APP)
|
||||
rm -rf coverage_percent.txt test_dash.coverage/ total.coverage/ fuzz.coverage/ test/tmp/ cache/ $(OSX_APP)
|
||||
rm -rf test/functional/__pycache__ test/functional/test_framework/__pycache__ test/cache share/rpcauth/__pycache__
|
||||
rm -rf osx_volname dist/ dpi36.background.tiff dpi72.background.tiff
|
||||
|
||||
|
@ -829,7 +829,6 @@ if test x$use_lcov = xyes; then
|
||||
[AC_MSG_ERROR("lcov testing requested but --coverage linker flag does not work")])
|
||||
AX_CHECK_COMPILE_FLAG([--coverage],[CXXFLAGS="$CXXFLAGS --coverage"],
|
||||
[AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")])
|
||||
AC_DEFINE(USE_COVERAGE, 1, [Define this symbol if coverage is enabled])
|
||||
CXXFLAGS="$CXXFLAGS -Og"
|
||||
fi
|
||||
|
||||
@ -1473,7 +1472,7 @@ if test x$use_pkgconfig = xyes; then
|
||||
if test x$use_qr != xno; then
|
||||
BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])])
|
||||
fi
|
||||
if test x$build_bitcoin_cli$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then
|
||||
if test x$build_bitcoin_cli$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench != xnononono; then
|
||||
PKG_CHECK_MODULES([EVENT], [libevent >= 2.0.21], [use_libevent=yes], [AC_MSG_ERROR(libevent version 2.0.21 or greater not found.)])
|
||||
if test x$TARGET_OS != xwindows; then
|
||||
PKG_CHECK_MODULES([EVENT_PTHREADS], [libevent_pthreads >= 2.0.21],, [AC_MSG_ERROR(libevent_pthreads version 2.0.21 or greater not found.)])
|
||||
@ -1493,7 +1492,7 @@ if test x$use_pkgconfig = xyes; then
|
||||
)
|
||||
else
|
||||
|
||||
if test x$build_bitcoin_cli$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then
|
||||
if test x$build_bitcoin_cli$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench != xnonononono; then
|
||||
AC_CHECK_HEADER([event2/event.h],, AC_MSG_ERROR(libevent headers missing),)
|
||||
AC_CHECK_LIB([event],[main],EVENT_LIBS=-levent,AC_MSG_ERROR(libevent missing))
|
||||
if test x$TARGET_OS != xwindows; then
|
||||
@ -1828,6 +1827,7 @@ AC_CONFIG_LINKS([contrib/devtools/symbol-check.py:contrib/devtools/symbol-check.
|
||||
AC_CONFIG_LINKS([contrib/devtools/test-symbol-check.py:contrib/devtools/test-symbol-check.py])
|
||||
AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py])
|
||||
AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py])
|
||||
AC_CONFIG_LINKS([test/fuzz/test_runner.py:test/fuzz/test_runner.py])
|
||||
AC_CONFIG_LINKS([test/util/bitcoin-util-test.py:test/util/bitcoin-util-test.py])
|
||||
AC_CONFIG_LINKS([test/util/rpcauth-test.py:test/util/rpcauth-test.py])
|
||||
|
||||
|
@ -44,6 +44,7 @@ Developer Notes
|
||||
- [Suggestions and examples](#suggestions-and-examples)
|
||||
- [Release notes](#release-notes)
|
||||
- [RPC interface guidelines](#rpc-interface-guidelines)
|
||||
- [Internal interface guidelines](#internal-interface-guidelines)
|
||||
|
||||
<!-- markdown-toc end -->
|
||||
|
||||
@ -1189,3 +1190,124 @@ A few guidelines for introducing and reviewing new RPC interfaces:
|
||||
timestamps in the documentation.
|
||||
|
||||
- *Rationale*: User-facing consistency.
|
||||
|
||||
Internal interface guidelines
|
||||
-----------------------------
|
||||
|
||||
Internal interfaces between parts of the codebase that are meant to be
|
||||
independent (node, wallet, GUI), are defined in
|
||||
[`src/interfaces/`](../src/interfaces/). The main interface classes defined
|
||||
there are [`interfaces::Chain`](../src/interfaces/chain.h), used by wallet to
|
||||
access the node's latest chain state,
|
||||
[`interfaces::Node`](../src/interfaces/node.h), used by the GUI to control the
|
||||
node, and [`interfaces::Wallet`](../src/interfaces/wallet.h), used by the GUI
|
||||
to control an individual wallet. There are also more specialized interface
|
||||
types like [`interfaces::Handler`](../src/interfaces/handler.h)
|
||||
[`interfaces::ChainClient`](../src/interfaces/chain.h) passed to and from
|
||||
various interface methods.
|
||||
|
||||
Interface classes are written in a particular style so node, wallet, and GUI
|
||||
code doesn't need to run in the same process, and so the class declarations
|
||||
work more easily with tools and libraries supporting interprocess
|
||||
communication:
|
||||
|
||||
- Interface classes should be abstract and have methods that are [pure
|
||||
virtual](https://en.cppreference.com/w/cpp/language/abstract_class). This
|
||||
allows multiple implementations to inherit from the same interface class,
|
||||
particularly so one implementation can execute functionality in the local
|
||||
process, and other implementations can forward calls to remote processes.
|
||||
|
||||
- Interface method definitions should wrap existing functionality instead of
|
||||
implementing new functionality. Any substantial new node or wallet
|
||||
functionality should be implemented in [`src/node/`](../src/node/) or
|
||||
[`src/wallet/`](../src/wallet/) and just exposed in
|
||||
[`src/interfaces/`](../src/interfaces/) instead of being implemented there,
|
||||
so it can be more modular and accessible to unit tests.
|
||||
|
||||
- Interface method parameter and return types should either be serializable or
|
||||
be other interface classes. Interface methods shouldn't pass references to
|
||||
objects that can't be serialized or accessed from another process.
|
||||
|
||||
Examples:
|
||||
|
||||
```c++
|
||||
// Good: takes string argument and returns interface class pointer
|
||||
virtual unique_ptr<interfaces::Wallet> loadWallet(std::string filename) = 0;
|
||||
|
||||
// Bad: returns CWallet reference that can't be used from another process
|
||||
virtual CWallet& loadWallet(std::string filename) = 0;
|
||||
```
|
||||
|
||||
```c++
|
||||
// Good: accepts and returns primitive types
|
||||
virtual bool findBlock(const uint256& hash, int& out_height, int64_t& out_time) = 0;
|
||||
|
||||
// Bad: returns pointer to internal node in a linked list inaccessible to
|
||||
// other processes
|
||||
virtual const CBlockIndex* findBlock(const uint256& hash) = 0;
|
||||
```
|
||||
|
||||
```c++
|
||||
// Good: takes plain callback type and returns interface pointer
|
||||
using TipChangedFn = std::function<void(int block_height, int64_t block_time)>;
|
||||
virtual std::unique_ptr<interfaces::Handler> handleTipChanged(TipChangedFn fn) = 0;
|
||||
|
||||
// Bad: returns boost connection specific to local process
|
||||
using TipChangedFn = std::function<void(int block_height, int64_t block_time)>;
|
||||
virtual boost::signals2::scoped_connection connectTipChanged(TipChangedFn fn) = 0;
|
||||
```
|
||||
|
||||
- For consistency and friendliness to code generation tools, interface method
|
||||
input and inout parameters should be ordered first and output parameters
|
||||
should come last.
|
||||
|
||||
Example:
|
||||
|
||||
```c++
|
||||
// Good: error output param is last
|
||||
virtual bool broadcastTransaction(const CTransactionRef& tx, CAmount max_fee, std::string& error) = 0;
|
||||
|
||||
// Bad: error output param is between input params
|
||||
virtual bool broadcastTransaction(const CTransactionRef& tx, std::string& error, CAmount max_fee) = 0;
|
||||
```
|
||||
|
||||
- For friendliness to code generation tools, interface methods should not be
|
||||
overloaded:
|
||||
|
||||
Example:
|
||||
|
||||
```c++
|
||||
// Good: method names are unique
|
||||
virtual bool disconnectByAddress(const CNetAddr& net_addr) = 0;
|
||||
virtual bool disconnectById(NodeId id) = 0;
|
||||
|
||||
// Bad: methods are overloaded by type
|
||||
virtual bool disconnect(const CNetAddr& net_addr) = 0;
|
||||
virtual bool disconnect(NodeId id) = 0;
|
||||
```
|
||||
|
||||
- For consistency and friendliness to code generation tools, interface method
|
||||
names should be `lowerCamelCase` and standalone function names should be
|
||||
`UpperCamelCase`.
|
||||
|
||||
Examples:
|
||||
|
||||
```c++
|
||||
// Good: lowerCamelCase method name
|
||||
virtual void blockConnected(const CBlock& block, int height) = 0;
|
||||
|
||||
// Bad: uppercase class method
|
||||
virtual void BlockConnected(const CBlock& block, int height) = 0;
|
||||
```
|
||||
|
||||
```c++
|
||||
// Good: UpperCamelCase standalone function name
|
||||
std::unique_ptr<Node> MakeNode(LocalInit& init);
|
||||
|
||||
// Bad: lowercase standalone function
|
||||
std::unique_ptr<Node> makeNode(LocalInit& init);
|
||||
```
|
||||
|
||||
Note: This last convention isn't generally followed outside of
|
||||
[`src/interfaces/`](../src/interfaces/), though it did come up for discussion
|
||||
before in [#14635](https://github.com/bitcoin/bitcoin/pull/14635).
|
||||
|
@ -47,11 +47,12 @@ bench_bench_dash_SOURCES = \
|
||||
bench/lockedpool.cpp \
|
||||
bench/poly1305.cpp \
|
||||
bench/prevector.cpp \
|
||||
bench/string_cast.cpp
|
||||
bench/string_cast.cpp \
|
||||
bench/verify_script.cpp
|
||||
|
||||
nodist_bench_bench_dash_SOURCES = $(GENERATED_BENCH_FILES)
|
||||
|
||||
bench_bench_dash_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
|
||||
bench_bench_dash_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
|
||||
bench_bench_dash_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
bench_bench_dash_LDADD = \
|
||||
$(LIBBITCOIN_SERVER) \
|
||||
|
33
src/bench/verify_script.cpp
Normal file
33
src/bench/verify_script.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2016-2019 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <script/script.h>
|
||||
#include <script/standard.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
|
||||
static void VerifyNestedIfScript(benchmark::Bench& bench) {
|
||||
std::vector<std::vector<unsigned char>> stack;
|
||||
CScript script;
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
script << OP_1 << OP_IF;
|
||||
}
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
script << OP_1;
|
||||
}
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
script << OP_ENDIF;
|
||||
}
|
||||
bench.run([&] {
|
||||
auto stack_copy = stack;
|
||||
ScriptError error;
|
||||
bool ret = EvalScript(stack_copy, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
|
||||
assert(ret);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK(VerifyNestedIfScript);
|
@ -799,13 +799,12 @@ void SetupServerArgs(NodeContext& node)
|
||||
std::string LicenseInfo()
|
||||
{
|
||||
const std::string URL_SOURCE_CODE = "<https://github.com/dashpay/dash>";
|
||||
const std::string URL_WEBSITE = "<https://dash.org>";
|
||||
|
||||
return CopyrightHolders(_("Copyright (C)").translated, 2014, COPYRIGHT_YEAR) + "\n" +
|
||||
"\n" +
|
||||
strprintf(_("Please contribute if you find %s useful. "
|
||||
"Visit %s for further information about the software.").translated,
|
||||
PACKAGE_NAME, URL_WEBSITE) +
|
||||
PACKAGE_NAME, "<" PACKAGE_URL ">") +
|
||||
"\n" +
|
||||
strprintf(_("The source code is available from %s.").translated,
|
||||
URL_SOURCE_CODE) +
|
||||
|
@ -183,7 +183,10 @@ public:
|
||||
//! Transaction is added to memory pool, if the transaction fee is below the
|
||||
//! amount specified by max_tx_fee, and broadcast to all peers if relay is set to true.
|
||||
//! Return false if the transaction could not be added due to the fee or for another reason.
|
||||
virtual bool broadcastTransaction(const CTransactionRef& tx, std::string& err_string, const CAmount& max_tx_fee, bool relay) = 0;
|
||||
virtual bool broadcastTransaction(const CTransactionRef& tx,
|
||||
const CAmount& max_tx_fee,
|
||||
bool relay,
|
||||
std::string& err_string) = 0;
|
||||
|
||||
//! Calculate mempool ancestor and descendant counts for the given transaction.
|
||||
virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) = 0;
|
||||
@ -243,14 +246,14 @@ public:
|
||||
{
|
||||
public:
|
||||
virtual ~Notifications() {}
|
||||
virtual void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) {}
|
||||
virtual void TransactionRemovedFromMempool(const CTransactionRef& ptx, MemPoolRemovalReason reason) {}
|
||||
virtual void BlockConnected(const CBlock& block, int height) {}
|
||||
virtual void BlockDisconnected(const CBlock& block, int height) {}
|
||||
virtual void UpdatedBlockTip() {}
|
||||
virtual void ChainStateFlushed(const CBlockLocator& locator) {}
|
||||
virtual void NotifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const llmq::CChainLockSig>& clsig) {}
|
||||
virtual void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock) {}
|
||||
virtual void transactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) {}
|
||||
virtual void transactionRemovedFromMempool(const CTransactionRef& ptx, MemPoolRemovalReason reason) {}
|
||||
virtual void blockConnected(const CBlock& block, int height) {}
|
||||
virtual void blockDisconnected(const CBlock& block, int height) {}
|
||||
virtual void updatedBlockTip() {}
|
||||
virtual void chainStateFlushed(const CBlockLocator& locator) {}
|
||||
virtual void notifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const llmq::CChainLockSig>& clsig) {}
|
||||
virtual void notifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock) {}
|
||||
};
|
||||
|
||||
//! Register handler for notifications.
|
||||
@ -276,7 +279,7 @@ public:
|
||||
//! Write a setting to <datadir>/settings.json.
|
||||
virtual bool updateRwSetting(const std::string& name, const util::SettingsValue& value) = 0;
|
||||
|
||||
//! Synchronously send TransactionAddedToMempool notifications about all
|
||||
//! Synchronously send transactionAddedToMempool notifications about all
|
||||
//! current mempool transactions to the specified handler and return after
|
||||
//! the last one is sent. These notifications aren't coordinated with async
|
||||
//! notifications sent by handleNotifications, so out of date async
|
||||
|
@ -210,10 +210,10 @@ public:
|
||||
virtual bool unban(const CSubNet& ip) = 0;
|
||||
|
||||
//! Disconnect node by address.
|
||||
virtual bool disconnect(const CNetAddr& net_addr) = 0;
|
||||
virtual bool disconnectByAddress(const CNetAddr& net_addr) = 0;
|
||||
|
||||
//! Disconnect node by id.
|
||||
virtual bool disconnect(NodeId id) = 0;
|
||||
virtual bool disconnectById(NodeId id) = 0;
|
||||
|
||||
//! Get total bytes recv.
|
||||
virtual int64_t getTotalBytesRecv() = 0;
|
||||
|
@ -220,11 +220,11 @@ public:
|
||||
virtual bool isFullyMixed(const COutPoint& outpoint) = 0;
|
||||
|
||||
//! Fill PSBT.
|
||||
virtual TransactionError fillPSBT(PartiallySignedTransaction& psbtx,
|
||||
bool& complete,
|
||||
int sighash_type = 1 /* SIGHASH_ALL */,
|
||||
bool sign = true,
|
||||
bool bip32derivs = false) const = 0;
|
||||
virtual TransactionError fillPSBT(int sighash_type,
|
||||
bool sign,
|
||||
bool bip32derivs,
|
||||
PartiallySignedTransaction& psbtx,
|
||||
bool& complete) = 0;
|
||||
|
||||
//! Get balances.
|
||||
virtual WalletBalances getBalances() = 0;
|
||||
@ -289,10 +289,10 @@ public:
|
||||
virtual bool hdEnabled() = 0;
|
||||
|
||||
// Return whether the wallet is blank.
|
||||
virtual bool canGetAddresses() const = 0;
|
||||
virtual bool canGetAddresses() = 0;
|
||||
|
||||
// check if a certain wallet flag is set.
|
||||
virtual bool IsWalletFlagSet(uint64_t flag) = 0;
|
||||
// Return whether private keys enabled.
|
||||
virtual bool privateKeysDisabled() = 0;
|
||||
|
||||
virtual CoinJoin::Client& coinJoin() = 0;
|
||||
|
||||
|
@ -290,14 +290,14 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool disconnect(const CNetAddr& net_addr) override
|
||||
bool disconnectByAddress(const CNetAddr& net_addr) override
|
||||
{
|
||||
if (m_context->connman) {
|
||||
return m_context->connman->DisconnectNode(net_addr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool disconnect(NodeId id) override
|
||||
bool disconnectById(NodeId id) override
|
||||
{
|
||||
if (m_context->connman) {
|
||||
return m_context->connman->DisconnectNode(id);
|
||||
@ -498,32 +498,32 @@ public:
|
||||
virtual ~NotificationsProxy() = default;
|
||||
void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) override
|
||||
{
|
||||
m_notifications->TransactionAddedToMempool(tx, nAcceptTime);
|
||||
m_notifications->transactionAddedToMempool(tx, nAcceptTime);
|
||||
}
|
||||
void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) override
|
||||
{
|
||||
m_notifications->TransactionRemovedFromMempool(tx, reason);
|
||||
m_notifications->transactionRemovedFromMempool(tx, reason);
|
||||
}
|
||||
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
|
||||
{
|
||||
m_notifications->BlockConnected(*block, index->nHeight);
|
||||
m_notifications->blockConnected(*block, index->nHeight);
|
||||
}
|
||||
void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
|
||||
{
|
||||
m_notifications->BlockDisconnected(*block, index->nHeight);
|
||||
m_notifications->blockDisconnected(*block, index->nHeight);
|
||||
}
|
||||
void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
|
||||
{
|
||||
m_notifications->UpdatedBlockTip();
|
||||
m_notifications->updatedBlockTip();
|
||||
}
|
||||
void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->ChainStateFlushed(locator); }
|
||||
void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->chainStateFlushed(locator); }
|
||||
void NotifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const llmq::CChainLockSig>& clsig) override
|
||||
{
|
||||
m_notifications->NotifyChainLock(pindexChainLock, clsig);
|
||||
m_notifications->notifyChainLock(pindexChainLock, clsig);
|
||||
}
|
||||
void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock) override
|
||||
{
|
||||
m_notifications->NotifyTransactionLock(tx, islock);
|
||||
m_notifications->notifyTransactionLock(tx, islock);
|
||||
}
|
||||
std::shared_ptr<Chain::Notifications> m_notifications;
|
||||
};
|
||||
@ -727,7 +727,7 @@ public:
|
||||
auto it = m_node.mempool->GetIter(txid);
|
||||
return it && (*it)->GetCountWithDescendants() > 1;
|
||||
}
|
||||
bool broadcastTransaction(const CTransactionRef& tx, std::string& err_string, const CAmount& max_tx_fee, bool relay) override
|
||||
bool broadcastTransaction(const CTransactionRef& tx, const CAmount& max_tx_fee, bool relay, std::string& err_string) override
|
||||
{
|
||||
const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, relay, /*wait_callback*/ false);
|
||||
// Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.
|
||||
@ -843,7 +843,7 @@ public:
|
||||
if (!m_node.mempool) return;
|
||||
LOCK2(::cs_main, m_node.mempool->cs);
|
||||
for (const CTxMemPoolEntry& entry : m_node.mempool->mapTx) {
|
||||
notifications.TransactionAddedToMempool(entry.GetSharedTx(), 0);
|
||||
notifications.transactionAddedToMempool(entry.GetSharedTx(), 0);
|
||||
}
|
||||
}
|
||||
NodeContext& m_node;
|
||||
|
@ -693,12 +693,12 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -1403,6 +1403,32 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="20" column="0">
|
||||
<widget class="QLabel" name="peerMappedASLabel">
|
||||
<property name="toolTip">
|
||||
<string>The mapped Autonomous System used for diversifying peer selection.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Mapped AS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="20" column="2">
|
||||
<widget class="QLabel" name="peerMappedAS">
|
||||
<property name="cursor">
|
||||
<cursorShape>IBeamCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>N/A</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="21" column="0">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
@ -189,7 +189,7 @@ void OverviewPage::setBalance(const interfaces::WalletBalances& balances)
|
||||
{
|
||||
int unit = walletModel->getOptionsModel()->getDisplayUnit();
|
||||
m_balances = balances;
|
||||
if (walletModel->privateKeysDisabled()) {
|
||||
if (walletModel->wallet().privateKeysDisabled()) {
|
||||
ui->labelBalance->setText(BitcoinUnits::floorHtmlWithUnit(unit, balances.watch_only_balance, false, BitcoinUnits::separatorAlways));
|
||||
ui->labelUnconfirmed->setText(BitcoinUnits::floorHtmlWithUnit(unit, balances.unconfirmed_watch_only_balance, false, BitcoinUnits::separatorAlways));
|
||||
ui->labelImmature->setText(BitcoinUnits::floorHtmlWithUnit(unit, balances.immature_watch_only_balance, false, BitcoinUnits::separatorAlways));
|
||||
@ -214,7 +214,7 @@ void OverviewPage::setBalance(const interfaces::WalletBalances& balances)
|
||||
// for symmetry reasons also show immature label when the watch-only one is shown
|
||||
ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
|
||||
ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature);
|
||||
ui->labelWatchImmature->setVisible(!walletModel->privateKeysDisabled() && showWatchOnlyImmature); // show watch-only immature balance
|
||||
ui->labelWatchImmature->setVisible(!walletModel->wallet().privateKeysDisabled() && showWatchOnlyImmature); // show watch-only immature balance
|
||||
|
||||
updateCoinJoinProgress();
|
||||
|
||||
@ -273,9 +273,9 @@ void OverviewPage::setWalletModel(WalletModel *model)
|
||||
|
||||
connect(model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &OverviewPage::updateDisplayUnit);
|
||||
|
||||
updateWatchOnlyLabels((wallet.haveWatchOnly() && !model->privateKeysDisabled()) || gArgs.GetBoolArg("-debug-ui", false));
|
||||
updateWatchOnlyLabels((wallet.haveWatchOnly() && !model->wallet().privateKeysDisabled()) || gArgs.GetBoolArg("-debug-ui", false));
|
||||
connect(model, &WalletModel::notifyWatchonlyChanged, [this](bool showWatchOnly) {
|
||||
updateWatchOnlyLabels(showWatchOnly && !walletModel->privateKeysDisabled());
|
||||
updateWatchOnlyLabels(showWatchOnly && !walletModel->wallet().privateKeysDisabled());
|
||||
});
|
||||
|
||||
// explicitly update PS frame and transaction list to reflect actual settings
|
||||
|
@ -86,11 +86,11 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model)
|
||||
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);
|
||||
|
||||
// Set the button to be enabled or disabled based on whether the wallet can give out new addresses.
|
||||
ui->receiveButton->setEnabled(model->canGetAddresses());
|
||||
ui->receiveButton->setEnabled(model->wallet().canGetAddresses());
|
||||
|
||||
// Enable/disable the receive button if the wallet is now able/unable to give out new addresses.
|
||||
connect(model, &WalletModel::canGetAddressesChanged, [this] {
|
||||
ui->receiveButton->setEnabled(model->canGetAddresses());
|
||||
ui->receiveButton->setEnabled(model->wallet().canGetAddresses());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1238,15 +1238,16 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
|
||||
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.m_ping_wait_usec));
|
||||
ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.m_min_ping_usec));
|
||||
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
|
||||
ui->peerVersion->setText(QString("%1").arg(QString::number(stats->nodeStats.nVersion)));
|
||||
ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
|
||||
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
|
||||
ui->peerDirection->setText(stats->nodeStats.fInbound
|
||||
? tr("Inbound")
|
||||
: stats->nodeStats.fRelayTxes
|
||||
? tr("Outbound")
|
||||
: tr("Outbound block-relay"));
|
||||
ui->peerHeight->setText(QString("%1").arg(QString::number(stats->nodeStats.nStartingHeight)));
|
||||
ui->peerHeight->setText(QString::number(stats->nodeStats.nStartingHeight));
|
||||
ui->peerWhitelisted->setText(stats->nodeStats.m_legacyWhitelisted ? tr("Yes") : tr("No"));
|
||||
ui->peerMappedAS->setText(stats->nodeStats.m_mapped_as != 0 ? QString::number(stats->nodeStats.m_mapped_as) : tr("N/A"));
|
||||
auto dmn = clientModel->getMasternodeList().GetMNByService(stats->nodeStats.addr);
|
||||
if (dmn == nullptr) {
|
||||
ui->peerNodeType->setText(tr("Regular"));
|
||||
@ -1359,7 +1360,7 @@ void RPCConsole::disconnectSelectedNode()
|
||||
// Get currently selected peer address
|
||||
NodeId id = nodes.at(i).data().toLongLong();
|
||||
// Find the node, disconnect it and clear the selected node
|
||||
if(m_node.disconnect(id))
|
||||
if(m_node.disconnectById(id))
|
||||
clearSelectedNode();
|
||||
}
|
||||
}
|
||||
@ -1384,7 +1385,7 @@ void RPCConsole::banSelectedNode(int bantime)
|
||||
const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
|
||||
if (stats) {
|
||||
m_node.ban(stats->nodeStats.addr, bantime);
|
||||
m_node.disconnect(stats->nodeStats.addr);
|
||||
m_node.disconnectByAddress(stats->nodeStats.addr);
|
||||
}
|
||||
}
|
||||
clearSelectedNode();
|
||||
|
@ -215,7 +215,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
|
||||
updateFeeSectionControls();
|
||||
updateSmartFeeLabel();
|
||||
|
||||
if (model->privateKeysDisabled()) {
|
||||
if (model->wallet().privateKeysDisabled()) {
|
||||
ui->sendButton->setText(tr("Cr&eate Unsigned"));
|
||||
ui->sendButton->setToolTip(tr("Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.").arg(PACKAGE_NAME));
|
||||
}
|
||||
@ -356,12 +356,12 @@ void SendCoinsDialog::send(QList<SendCoinsRecipient> recipients)
|
||||
}
|
||||
|
||||
QString questionString;
|
||||
if (model->privateKeysDisabled()) {
|
||||
if (model->wallet().privateKeysDisabled()) {
|
||||
questionString.append(tr("Do you want to draft this transaction?"));
|
||||
} else {
|
||||
questionString.append(tr("Are you sure you want to send?"));
|
||||
}
|
||||
if (model->privateKeysDisabled()) {
|
||||
if (model->wallet().privateKeysDisabled()) {
|
||||
questionString.append("<br /><span style='font-size:10pt;'>");
|
||||
questionString.append(tr("This will produce a Partially Signed Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.").arg(PACKAGE_NAME));
|
||||
questionString.append("</span>");
|
||||
@ -452,8 +452,8 @@ void SendCoinsDialog::send(QList<SendCoinsRecipient> recipients)
|
||||
informative_text = tr("To review recipient list click \"Show Details...\"");
|
||||
detailed_text = formatted.join("\n\n");
|
||||
}
|
||||
const QString confirmation = model->privateKeysDisabled() ? tr("Confirm transaction proposal") : tr("Confirm send coins");
|
||||
const QString confirmButtonText = model->privateKeysDisabled() ? tr("Copy PSBT to clipboard") : tr("Send");
|
||||
const QString confirmation = model->wallet().privateKeysDisabled() ? tr("Confirm transaction proposal") : tr("Confirm send coins");
|
||||
const QString confirmButtonText = model->wallet().privateKeysDisabled() ? tr("Copy PSBT to clipboard") : tr("Send");
|
||||
SendConfirmationDialog confirmationDialog(confirmation, questionString, informative_text, detailed_text, SEND_CONFIRM_DELAY, confirmButtonText, this);
|
||||
confirmationDialog.exec();
|
||||
QMessageBox::StandardButton retval = static_cast<QMessageBox::StandardButton>(confirmationDialog.result());
|
||||
@ -465,11 +465,11 @@ void SendCoinsDialog::send(QList<SendCoinsRecipient> recipients)
|
||||
}
|
||||
|
||||
bool send_failure = false;
|
||||
if (model->privateKeysDisabled()) {
|
||||
if (model->wallet().privateKeysDisabled()) {
|
||||
CMutableTransaction mtx = CMutableTransaction{*(currentTransaction.getWtx())};
|
||||
PartiallySignedTransaction psbtx(mtx);
|
||||
bool complete = false;
|
||||
const TransactionError err = model->wallet().fillPSBT(psbtx, complete, SIGHASH_ALL, false /* sign */, true /* bip32derivs */);
|
||||
const TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, psbtx, complete);
|
||||
assert(!complete);
|
||||
assert(err == TransactionError::OK);
|
||||
// Serialize the PSBT
|
||||
@ -642,7 +642,7 @@ void SendCoinsDialog::setBalance(const interfaces::WalletBalances& balances)
|
||||
if(model && model->getOptionsModel())
|
||||
{
|
||||
CAmount balance = 0;
|
||||
if (model->privateKeysDisabled()) {
|
||||
if (model->wallet().privateKeysDisabled()) {
|
||||
balance = balances.watch_only_balance;
|
||||
ui->labelBalanceName->setText(tr("Watch-only balance:"));
|
||||
} else if (m_coin_control->IsUsingCoinJoin()) {
|
||||
@ -732,7 +732,7 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked()
|
||||
void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
|
||||
{
|
||||
// Include watch-only for wallets without private key
|
||||
m_coin_control->fAllowWatchOnly = model->privateKeysDisabled();
|
||||
m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled();
|
||||
|
||||
// Calculate available amount to send.
|
||||
CAmount amount = model->wallet().getAvailableBalance(*m_coin_control);
|
||||
@ -786,7 +786,7 @@ void SendCoinsDialog::updateCoinControlState(CCoinControl& ctrl)
|
||||
// Either custom fee will be used or if not selected, the confirmation target from dropdown box
|
||||
ctrl.m_confirm_target = getConfTargetForIndex(ui->confTargetSelector->currentIndex());
|
||||
// Include watch-only for wallets without private key
|
||||
ctrl.fAllowWatchOnly = model->privateKeysDisabled();
|
||||
ctrl.fAllowWatchOnly = model->wallet().privateKeysDisabled();
|
||||
}
|
||||
|
||||
void SendCoinsDialog::updateSmartFeeLabel()
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <util/system.h> // for GetBoolArg
|
||||
#include <util/translation.h>
|
||||
#include <wallet/coincontrol.h>
|
||||
#include <wallet/wallet.h>
|
||||
#include <wallet/wallet.h> // for CRecipient
|
||||
|
||||
#include <spork.h>
|
||||
|
||||
@ -240,7 +240,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
|
||||
int nChangePosRet = -1;
|
||||
|
||||
auto& newTx = transaction.getWtx();
|
||||
newTx = m_wallet->createTransaction(vecSend, coinControl, !privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, error);
|
||||
newTx = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired, error);
|
||||
transaction.setTransactionFee(nFeeRequired);
|
||||
if (fSubtractFeeFromAmount && newTx)
|
||||
transaction.reassignAmounts(nChangePosRet);
|
||||
@ -593,16 +593,6 @@ bool WalletModel::isWalletEnabled()
|
||||
return !gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
|
||||
}
|
||||
|
||||
bool WalletModel::privateKeysDisabled() const
|
||||
{
|
||||
return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
|
||||
}
|
||||
|
||||
bool WalletModel::canGetAddresses() const
|
||||
{
|
||||
return m_wallet->canGetAddresses();
|
||||
}
|
||||
|
||||
QString WalletModel::getWalletName() const
|
||||
{
|
||||
return QString::fromStdString(m_wallet->getWalletName());
|
||||
|
@ -142,8 +142,6 @@ public:
|
||||
bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest);
|
||||
|
||||
static bool isWalletEnabled();
|
||||
bool privateKeysDisabled() const;
|
||||
bool canGetAddresses() const;
|
||||
|
||||
int getNumISLocks() const;
|
||||
|
||||
|
@ -274,6 +274,70 @@ int FindAndDelete(CScript& script, const CScript& b)
|
||||
return nFound;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/** A data type to abstract out the condition stack during script execution.
|
||||
*
|
||||
* Conceptually it acts like a vector of booleans, one for each level of nested
|
||||
* IF/THEN/ELSE, indicating whether we're in the active or inactive branch of
|
||||
* each.
|
||||
*
|
||||
* The elements on the stack cannot be observed individually; we only need to
|
||||
* expose whether the stack is empty and whether or not any false values are
|
||||
* present at all. To implement OP_ELSE, a toggle_top modifier is added, which
|
||||
* flips the last value without returning it.
|
||||
*
|
||||
* This uses an optimized implementation that does not materialize the
|
||||
* actual stack. Instead, it just stores the size of the would-be stack,
|
||||
* and the position of the first false value in it.
|
||||
*/
|
||||
class ConditionStack {
|
||||
private:
|
||||
//! A constant for m_first_false_pos to indicate there are no falses.
|
||||
static constexpr uint32_t NO_FALSE = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
//! The size of the implied stack.
|
||||
uint32_t m_stack_size = 0;
|
||||
//! The position of the first false value on the implied stack, or NO_FALSE if all true.
|
||||
uint32_t m_first_false_pos = NO_FALSE;
|
||||
|
||||
public:
|
||||
bool empty() { return m_stack_size == 0; }
|
||||
bool all_true() { return m_first_false_pos == NO_FALSE; }
|
||||
void push_back(bool f)
|
||||
{
|
||||
if (m_first_false_pos == NO_FALSE && !f) {
|
||||
// The stack consists of all true values, and a false is added.
|
||||
// The first false value will appear at the current size.
|
||||
m_first_false_pos = m_stack_size;
|
||||
}
|
||||
++m_stack_size;
|
||||
}
|
||||
void pop_back()
|
||||
{
|
||||
assert(m_stack_size > 0);
|
||||
--m_stack_size;
|
||||
if (m_first_false_pos == m_stack_size) {
|
||||
// When popping off the first false value, everything becomes true.
|
||||
m_first_false_pos = NO_FALSE;
|
||||
}
|
||||
}
|
||||
void toggle_top()
|
||||
{
|
||||
assert(m_stack_size > 0);
|
||||
if (m_first_false_pos == NO_FALSE) {
|
||||
// The current stack is all true values; the first false will be the top.
|
||||
m_first_false_pos = m_stack_size - 1;
|
||||
} else if (m_first_false_pos == m_stack_size - 1) {
|
||||
// The top is the first false value; toggling it will make everything true.
|
||||
m_first_false_pos = NO_FALSE;
|
||||
} else {
|
||||
// There is a false value, but not on top. No action is needed as toggling
|
||||
// anything but the first false value is unobservable.
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Helper for OP_CHECKSIG and OP_CHECKSIGVERIFY
|
||||
*
|
||||
* A return value of false means the script fails entirely. When true is returned, the
|
||||
@ -303,6 +367,7 @@ static bool EvalChecksig(const valtype& vchSig, const valtype& vchPubKey, CScrip
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
|
||||
{
|
||||
static const CScriptNum bnZero(0);
|
||||
@ -318,7 +383,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
CScript::const_iterator pbegincodehash = script.begin();
|
||||
opcodetype opcode;
|
||||
valtype vchPushValue;
|
||||
std::vector<bool> vfExec;
|
||||
ConditionStack vfExec;
|
||||
std::vector<valtype> altstack;
|
||||
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
|
||||
if (script.size() > MAX_SCRIPT_SIZE)
|
||||
@ -330,7 +395,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
{
|
||||
while (pc < pend)
|
||||
{
|
||||
bool fExec = !count(vfExec.begin(), vfExec.end(), false);
|
||||
bool fExec = vfExec.all_true();
|
||||
|
||||
//
|
||||
// Read instruction
|
||||
@ -521,7 +586,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
{
|
||||
if (vfExec.empty())
|
||||
return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
|
||||
vfExec.back() = !vfExec.back();
|
||||
vfExec.toggle_top();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -426,6 +426,40 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
|
||||
BOOST_CHECK_EQUAL(reason, "scriptsig-size");
|
||||
|
||||
// Check scriptSig format (non-standard if there are any other ops than just PUSHs)
|
||||
t.vin[0].scriptSig = CScript()
|
||||
<< OP_TRUE << OP_0 << OP_1NEGATE << OP_16 // OP_n (single byte pushes: n = 1, 0, -1, 16)
|
||||
<< std::vector<unsigned char>(75, 0) // OP_PUSHx [...x bytes...]
|
||||
<< std::vector<unsigned char>(235, 0) // OP_PUSHDATA1 x [...x bytes...]
|
||||
<< std::vector<unsigned char>(1234, 0) // OP_PUSHDATA2 x [...x bytes...]
|
||||
<< OP_9;
|
||||
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
|
||||
|
||||
const std::vector<unsigned char> non_push_ops = { // arbitrary set of non-push operations
|
||||
OP_NOP, OP_VERIFY, OP_IF, OP_ROT, OP_3DUP, OP_SIZE, OP_EQUAL, OP_ADD, OP_SUB,
|
||||
OP_HASH256, OP_CODESEPARATOR, OP_CHECKSIG, OP_CHECKLOCKTIMEVERIFY };
|
||||
|
||||
CScript::const_iterator pc = t.vin[0].scriptSig.begin();
|
||||
while (pc < t.vin[0].scriptSig.end()) {
|
||||
opcodetype opcode;
|
||||
CScript::const_iterator prev_pc = pc;
|
||||
t.vin[0].scriptSig.GetOp(pc, opcode); // advance to next op
|
||||
// for the sake of simplicity, we only replace single-byte push operations
|
||||
if (opcode >= 1 && opcode <= OP_PUSHDATA4)
|
||||
continue;
|
||||
|
||||
int index = prev_pc - t.vin[0].scriptSig.begin();
|
||||
unsigned char orig_op = *prev_pc; // save op
|
||||
// replace current push-op with each non-push-op
|
||||
for (auto op : non_push_ops) {
|
||||
t.vin[0].scriptSig[index] = op;
|
||||
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
|
||||
BOOST_CHECK_EQUAL(reason, "scriptsig-not-pushonly");
|
||||
}
|
||||
t.vin[0].scriptSig[index] = orig_op; // restore op
|
||||
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
|
||||
}
|
||||
|
||||
// Check bare multisig (standard if policy flag fIsBareMultisigStd is set)
|
||||
fIsBareMultisigStd = true;
|
||||
t.vout[0].scriptPubKey = GetScriptForMultisig(1, {key.GetPubKey()}); // simple 1-of-1
|
||||
|
@ -409,11 +409,11 @@ public:
|
||||
int getRealOutpointCoinJoinRounds(const COutPoint& outpoint) override { return m_wallet->GetRealOutpointCoinJoinRounds(outpoint); }
|
||||
bool isFullyMixed(const COutPoint& outpoint) override { return m_wallet->IsFullyMixed(outpoint); }
|
||||
|
||||
TransactionError fillPSBT(PartiallySignedTransaction& psbtx,
|
||||
bool& complete,
|
||||
int sighash_type = 1 /* SIGHASH_ALL */,
|
||||
bool sign = true,
|
||||
bool bip32derivs = false) const override
|
||||
TransactionError fillPSBT(int sighash_type,
|
||||
bool sign,
|
||||
bool bip32derivs,
|
||||
PartiallySignedTransaction& psbtx,
|
||||
bool& complete) override
|
||||
{
|
||||
return m_wallet->FillPSBT(psbtx, complete, sighash_type, sign, bip32derivs);
|
||||
}
|
||||
@ -545,8 +545,8 @@ public:
|
||||
}
|
||||
unsigned int getConfirmTarget() override { return m_wallet->m_confirm_target; }
|
||||
bool hdEnabled() override { return m_wallet->IsHDEnabled(); }
|
||||
bool canGetAddresses() const override { return m_wallet->CanGetAddresses(); }
|
||||
bool IsWalletFlagSet(uint64_t flag) override { return m_wallet->IsWalletFlagSet(flag); }
|
||||
bool canGetAddresses() override { return m_wallet->CanGetAddresses(); }
|
||||
bool privateKeysDisabled() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); }
|
||||
CoinJoin::Client& coinJoin() override { return m_coinjoin; }
|
||||
CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; }
|
||||
void remove() override
|
||||
|
@ -1258,7 +1258,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup)
|
||||
auto block_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
|
||||
m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
|
||||
auto mempool_tx = TestSimpleSpend(*m_coinbase_txns[1], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
|
||||
BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), error, DEFAULT_TRANSACTION_MAXFEE, false));
|
||||
BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error));
|
||||
|
||||
|
||||
// Reload wallet and make sure new transactions are detected despite events
|
||||
@ -1295,7 +1295,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup)
|
||||
block_tx = TestSimpleSpend(*m_coinbase_txns[2], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
|
||||
m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
|
||||
mempool_tx = TestSimpleSpend(*m_coinbase_txns[3], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
|
||||
BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), error, DEFAULT_TRANSACTION_MAXFEE, false));
|
||||
BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error));
|
||||
LEAVE_CRITICAL_SECTION(cs_wallets);
|
||||
LEAVE_CRITICAL_SECTION(wallet->wallet()->cs_wallet);
|
||||
SyncWithValidationInterfaceQueue();
|
||||
|
@ -436,7 +436,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
|
||||
return false;
|
||||
}
|
||||
|
||||
void CWallet::ChainStateFlushed(const CBlockLocator& loc)
|
||||
void CWallet::chainStateFlushed(const CBlockLocator& loc)
|
||||
{
|
||||
WalletBatch batch(*database);
|
||||
batch.WriteBestBlock(loc);
|
||||
@ -1218,7 +1218,7 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::Confirmatio
|
||||
fAnonymizableTallyCachedNonDenom = false;
|
||||
}
|
||||
|
||||
void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx, int64_t nAcceptTime) {
|
||||
void CWallet::transactionAddedToMempool(const CTransactionRef& ptx, int64_t nAcceptTime) {
|
||||
LOCK(cs_wallet);
|
||||
CWalletTx::Confirmation confirm(CWalletTx::Status::UNCONFIRMED, /* block_height */ 0, {}, /* nIndex */ 0);
|
||||
SyncTransaction(ptx, confirm);
|
||||
@ -1229,7 +1229,7 @@ void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx, int64_t nAcc
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolRemovalReason reason) {
|
||||
void CWallet::transactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolRemovalReason reason) {
|
||||
if (reason != MemPoolRemovalReason::CONFLICT) {
|
||||
LOCK(cs_wallet);
|
||||
auto it = mapWallet.find(ptx->GetHash());
|
||||
@ -1239,7 +1239,7 @@ void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolR
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::BlockConnected(const CBlock& block, int height)
|
||||
void CWallet::blockConnected(const CBlock& block, int height)
|
||||
{
|
||||
const uint256& block_hash = block.GetHash();
|
||||
LOCK(cs_wallet);
|
||||
@ -1249,7 +1249,7 @@ void CWallet::BlockConnected(const CBlock& block, int height)
|
||||
for (size_t index = 0; index < block.vtx.size(); index++) {
|
||||
CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, block_hash, index);
|
||||
SyncTransaction(block.vtx[index], confirm);
|
||||
TransactionRemovedFromMempool(block.vtx[index], MemPoolRemovalReason::MANUAL);
|
||||
transactionRemovedFromMempool(block.vtx[index], MemPoolRemovalReason::MANUAL);
|
||||
}
|
||||
|
||||
// reset cache to make sure no longer immature coins are included
|
||||
@ -1257,7 +1257,7 @@ void CWallet::BlockConnected(const CBlock& block, int height)
|
||||
fAnonymizableTallyCachedNonDenom = false;
|
||||
}
|
||||
|
||||
void CWallet::BlockDisconnected(const CBlock& block, int height)
|
||||
void CWallet::blockDisconnected(const CBlock& block, int height)
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
|
||||
@ -1277,7 +1277,7 @@ void CWallet::BlockDisconnected(const CBlock& block, int height)
|
||||
fAnonymizableTallyCachedNonDenom = false;
|
||||
}
|
||||
|
||||
void CWallet::UpdatedBlockTip()
|
||||
void CWallet::updatedBlockTip()
|
||||
{
|
||||
m_best_block_time = GetTime();
|
||||
}
|
||||
@ -2067,7 +2067,7 @@ bool CWalletTx::SubmitMemoryPoolAndRelay(std::string& err_string, bool relay)
|
||||
// Irrespective of the failure reason, un-marking fInMempool
|
||||
// out-of-order is incorrect - it should be unmarked when
|
||||
// TransactionRemovedFromMempool fires.
|
||||
bool ret = pwallet->chain().broadcastTransaction(tx, err_string, pwallet->m_default_max_tx_fee, relay);
|
||||
bool ret = pwallet->chain().broadcastTransaction(tx, pwallet->m_default_max_tx_fee, relay, err_string);
|
||||
fInMempool |= ret;
|
||||
return ret;
|
||||
}
|
||||
@ -4582,7 +4582,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
|
||||
}
|
||||
}
|
||||
|
||||
walletInstance->ChainStateFlushed(chain.getTipLocator());
|
||||
walletInstance->chainStateFlushed(chain.getTipLocator());
|
||||
|
||||
// Try to create wallet backup right after new wallet was created
|
||||
bilingual_str strBackupError;
|
||||
@ -4782,7 +4782,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
walletInstance->ChainStateFlushed(chain.getTipLocator());
|
||||
walletInstance->chainStateFlushed(chain.getTipLocator());
|
||||
walletInstance->database->IncrementUpdateCounter();
|
||||
}
|
||||
|
||||
@ -5013,7 +5013,7 @@ bool CWallet::AutoBackupWallet(const fs::path& wallet_path, bilingual_str& error
|
||||
}
|
||||
#endif // USE_BDB
|
||||
|
||||
void CWallet::NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock)
|
||||
void CWallet::notifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock)
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
// Only notify UI if this transaction is in this wallet
|
||||
@ -5034,7 +5034,7 @@ void CWallet::NotifyTransactionLock(const CTransactionRef &tx, const std::shared
|
||||
}
|
||||
}
|
||||
|
||||
void CWallet::NotifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const llmq::CChainLockSig>& clsig)
|
||||
void CWallet::notifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const llmq::CChainLockSig>& clsig)
|
||||
{
|
||||
NotifyChainLockReceived(pindexChainLock->nHeight);
|
||||
}
|
||||
|
@ -964,10 +964,10 @@ public:
|
||||
void MarkDirty();
|
||||
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
|
||||
void LoadToWallet(CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
void TransactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) override;
|
||||
void BlockConnected(const CBlock& block, int height) override;
|
||||
void BlockDisconnected(const CBlock& block, int height) override;
|
||||
void UpdatedBlockTip() override;
|
||||
void transactionAddedToMempool(const CTransactionRef& tx, int64_t nAcceptTime) override;
|
||||
void blockConnected(const CBlock& block, int height) override;
|
||||
void blockDisconnected(const CBlock& block, int height) override;
|
||||
void updatedBlockTip() override;
|
||||
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
|
||||
|
||||
struct ScanResult {
|
||||
@ -986,7 +986,7 @@ public:
|
||||
uint256 last_failed_block;
|
||||
};
|
||||
ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate);
|
||||
void TransactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolRemovalReason reason) override;
|
||||
void transactionRemovedFromMempool(const CTransactionRef &ptx, MemPoolRemovalReason reason) override;
|
||||
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
void ResendWalletTransactions();
|
||||
struct Balance {
|
||||
@ -1126,7 +1126,7 @@ public:
|
||||
bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;
|
||||
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
||||
CAmount GetChange(const CTransaction& tx) const;
|
||||
void ChainStateFlushed(const CBlockLocator& loc) override;
|
||||
void chainStateFlushed(const CBlockLocator& loc) override;
|
||||
|
||||
DBErrors LoadWallet(bool& fFirstRunRet);
|
||||
void AutoLockMasternodeCollaterals();
|
||||
@ -1241,8 +1241,8 @@ public:
|
||||
/* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */
|
||||
bool CanGetAddresses(bool internal = false) const;
|
||||
|
||||
void NotifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock) override;
|
||||
void NotifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const llmq::CChainLockSig>& clsig) override;
|
||||
void notifyTransactionLock(const CTransactionRef &tx, const std::shared_ptr<const llmq::CInstantSendLock>& islock) override;
|
||||
void notifyChainLock(const CBlockIndex* pindexChainLock, const std::shared_ptr<const llmq::CChainLockSig>& clsig) override;
|
||||
|
||||
/** Load a CGovernanceObject into m_gobjects. */
|
||||
bool LoadGovernanceObject(const CGovernanceObject& obj);
|
||||
|
@ -99,8 +99,7 @@ class MaxUploadTest(BitcoinTestFramework):
|
||||
# 144MB will be reserved for relaying new blocks, so expect this to
|
||||
# succeed for ~70 tries.
|
||||
for i in range(success_count):
|
||||
p2p_conns[0].send_message(getdata_request)
|
||||
p2p_conns[0].sync_with_ping()
|
||||
p2p_conns[0].send_and_ping(getdata_request)
|
||||
assert_equal(p2p_conns[0].block_receive_map[big_old_block], i+1)
|
||||
|
||||
assert_equal(len(self.nodes[0].getpeerinfo()), 3)
|
||||
@ -117,7 +116,7 @@ class MaxUploadTest(BitcoinTestFramework):
|
||||
# We'll try 200 times
|
||||
getdata_request.inv = [CInv(MSG_BLOCK, big_new_block)]
|
||||
for i in range(200):
|
||||
p2p_conns[1].send_message(getdata_request)
|
||||
p2p_conns[1].send_and_ping(getdata_request)
|
||||
p2p_conns[1].sync_with_ping()
|
||||
assert_equal(p2p_conns[1].block_receive_map[big_new_block], i+1)
|
||||
|
||||
@ -137,8 +136,7 @@ class MaxUploadTest(BitcoinTestFramework):
|
||||
# and p2p_conns[2] should be able to retrieve the old block.
|
||||
self.nodes[0].setmocktime(current_mocktime)
|
||||
p2p_conns[2].sync_with_ping()
|
||||
p2p_conns[2].send_message(getdata_request)
|
||||
p2p_conns[2].sync_with_ping()
|
||||
p2p_conns[2].send_and_ping(getdata_request)
|
||||
assert_equal(p2p_conns[2].block_receive_map[big_old_block], 1)
|
||||
|
||||
self.log.info("Peer 2 able to download old block")
|
||||
@ -155,8 +153,7 @@ class MaxUploadTest(BitcoinTestFramework):
|
||||
#retrieve 20 blocks which should be enough to break the 1MB limit
|
||||
getdata_request.inv = [CInv(MSG_BLOCK, big_new_block)]
|
||||
for i in range(20):
|
||||
self.nodes[0].p2p.send_message(getdata_request)
|
||||
self.nodes[0].p2p.sync_with_ping()
|
||||
self.nodes[0].p2p.send_and_ping(getdata_request)
|
||||
assert_equal(self.nodes[0].p2p.block_receive_map[big_new_block], i+1)
|
||||
|
||||
getdata_request.inv = [CInv(MSG_BLOCK, big_old_block)]
|
||||
|
@ -164,8 +164,7 @@ class CompactFiltersTest(BitcoinTestFramework):
|
||||
start_height=1,
|
||||
stop_hash=int(stop_hash, 16)
|
||||
)
|
||||
node0.send_message(request)
|
||||
node0.sync_with_ping()
|
||||
node0.send_and_ping(request)
|
||||
response = node0.pop_cfilters()
|
||||
assert_equal(len(response), 10)
|
||||
|
||||
@ -183,8 +182,7 @@ class CompactFiltersTest(BitcoinTestFramework):
|
||||
start_height=1000,
|
||||
stop_hash=int(stale_block_hash, 16)
|
||||
)
|
||||
node0.send_message(request)
|
||||
node0.sync_with_ping()
|
||||
node0.send_and_ping(request)
|
||||
response = node0.pop_cfilters()
|
||||
assert_equal(len(response), 1)
|
||||
|
||||
|
@ -11,6 +11,8 @@ from test_framework.messages import (
|
||||
MSG_FILTERED_BLOCK,
|
||||
msg_getdata,
|
||||
msg_filterload,
|
||||
msg_filteradd,
|
||||
msg_filterclear,
|
||||
)
|
||||
from test_framework.mininode import P2PInterface
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
@ -60,8 +62,7 @@ class FilterTest(BitcoinTestFramework):
|
||||
def run_test(self):
|
||||
self.log.info('Add filtered P2P connection to the node')
|
||||
filter_node = self.nodes[0].add_p2p_connection(FilterNode())
|
||||
filter_node.send_message(filter_node.watch_filter_init)
|
||||
filter_node.sync_with_ping()
|
||||
filter_node.send_and_ping(filter_node.watch_filter_init)
|
||||
filter_address = self.nodes[0].decodescript(filter_node.watch_script_pubkey)['addresses'][0]
|
||||
|
||||
self.log.info('Check that we receive merkleblock and tx if the filter matches a tx in a block')
|
||||
@ -91,6 +92,16 @@ class FilterTest(BitcoinTestFramework):
|
||||
filter_node.wait_for_tx(txid)
|
||||
assert not filter_node.merkleblock_received
|
||||
|
||||
self.log.info('Check that after deleting filter all txs get relayed again')
|
||||
filter_node.send_and_ping(msg_filterclear())
|
||||
for _ in range(5):
|
||||
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 7)
|
||||
filter_node.wait_for_tx(txid)
|
||||
|
||||
self.log.info("Check that division-by-zero remote crash bug [CVE-2013-5700] is fixed")
|
||||
filter_node.send_and_ping(msg_filterload(data=b'', nHashFuncs=1))
|
||||
filter_node.send_and_ping(msg_filteradd(data=b'letstrytocrashthisnode'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
FilterTest().main()
|
||||
|
@ -39,8 +39,7 @@ class P2PLeakTxTest(BitcoinTestFramework):
|
||||
want_tx = msg_getdata()
|
||||
want_tx.inv.append(CInv(t=MSG_TX, h=int(txid, 16)))
|
||||
inbound_peer.last_message.pop('notfound', None)
|
||||
inbound_peer.send_message(want_tx)
|
||||
inbound_peer.sync_with_ping()
|
||||
inbound_peer.send_and_ping(want_tx)
|
||||
|
||||
if inbound_peer.last_message.get('notfound'):
|
||||
self.log.debug('tx {} was not yet announced to us.'.format(txid))
|
||||
|
@ -236,10 +236,6 @@ class SendHeadersTest(BitcoinTestFramework):
|
||||
# will occur outside of direct fetching
|
||||
test_node = self.nodes[0].add_p2p_connection(BaseNode(), services=NODE_HEADERS_COMPRESSED)
|
||||
|
||||
# Ensure verack's have been processed by our peer
|
||||
inv_node.sync_with_ping()
|
||||
test_node.sync_with_ping()
|
||||
|
||||
self.test_null_locators(test_node, inv_node)
|
||||
self.test_nonnull_locators(test_node, inv_node)
|
||||
|
||||
@ -300,8 +296,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
||||
new_block.solve()
|
||||
test_node.send_header_for_blocks([new_block])
|
||||
test_node.wait_for_getdata([new_block.sha256])
|
||||
test_node.send_message(msg_block(new_block))
|
||||
test_node.sync_with_ping() # make sure this block is processed
|
||||
test_node.send_and_ping(msg_block(new_block)) # make sure this block is processed
|
||||
wait_until(lambda: inv_node.block_announced, timeout=60, lock=mininode_lock)
|
||||
inv_node.clear_block_announcements()
|
||||
test_node.clear_block_announcements()
|
||||
|
@ -303,8 +303,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
||||
new_block.solve()
|
||||
test_node.send_header_for_blocks([new_block])
|
||||
test_node.wait_for_getdata([new_block.sha256])
|
||||
test_node.send_message(msg_block(new_block))
|
||||
test_node.sync_with_ping() # make sure this block is processed
|
||||
test_node.send_and_ping(msg_block(new_block)) # make sure this block is processed
|
||||
wait_until(lambda: inv_node.block_announced, timeout=60, lock=mininode_lock)
|
||||
inv_node.clear_block_announcements()
|
||||
test_node.clear_block_announcements()
|
||||
|
@ -63,8 +63,7 @@ class TxDownloadTest(BitcoinTestFramework):
|
||||
self.log.info("Announce the txid from each incoming peer to node 0")
|
||||
msg = msg_inv([CInv(t=1, h=txid)])
|
||||
for p in self.nodes[0].p2ps:
|
||||
p.send_message(msg)
|
||||
p.sync_with_ping()
|
||||
p.send_and_ping(msg)
|
||||
|
||||
outstanding_peer_index = [i for i in range(len(self.nodes[0].p2ps))]
|
||||
|
||||
@ -102,7 +101,7 @@ class TxDownloadTest(BitcoinTestFramework):
|
||||
"Announce the transaction to all nodes from all {} incoming peers, but never send it".format(NUM_INBOUND))
|
||||
msg = msg_inv([CInv(t=1, h=txid)])
|
||||
for p in self.peers:
|
||||
p.send_message(msg)
|
||||
p.send_and_ping(msg)
|
||||
p.sync_with_ping()
|
||||
self.bump_mocktime(1)
|
||||
|
||||
|
@ -84,11 +84,9 @@ class AcceptBlockTest(BitcoinTestFramework):
|
||||
blocks_h2.append(create_block(tips[i], create_coinbase(2), block_time + 1))
|
||||
blocks_h2[i].solve()
|
||||
block_time += 1
|
||||
test_node.send_message(msg_block(blocks_h2[0]))
|
||||
min_work_node.send_message(msg_block(blocks_h2[1]))
|
||||
test_node.send_and_ping(msg_block(blocks_h2[0]))
|
||||
min_work_node.send_and_ping(msg_block(blocks_h2[1]))
|
||||
|
||||
for x in [test_node, min_work_node]:
|
||||
x.sync_with_ping()
|
||||
assert_equal(self.nodes[0].getblockcount(), 2)
|
||||
assert_equal(self.nodes[1].getblockcount(), 1)
|
||||
self.log.info("First height 2 block accepted by node0; correctly rejected by node1")
|
||||
@ -97,9 +95,8 @@ class AcceptBlockTest(BitcoinTestFramework):
|
||||
block_h1f = create_block(int("0x" + self.nodes[0].getblockhash(0), 0), create_coinbase(1), block_time)
|
||||
block_time += 1
|
||||
block_h1f.solve()
|
||||
test_node.send_message(msg_block(block_h1f))
|
||||
test_node.send_and_ping(msg_block(block_h1f))
|
||||
|
||||
test_node.sync_with_ping()
|
||||
tip_entry_found = False
|
||||
for x in self.nodes[0].getchaintips():
|
||||
if x['hash'] == block_h1f.hash:
|
||||
@ -112,9 +109,8 @@ class AcceptBlockTest(BitcoinTestFramework):
|
||||
block_h2f = create_block(block_h1f.sha256, create_coinbase(2), block_time)
|
||||
block_time += 1
|
||||
block_h2f.solve()
|
||||
test_node.send_message(msg_block(block_h2f))
|
||||
test_node.send_and_ping(msg_block(block_h2f))
|
||||
|
||||
test_node.sync_with_ping()
|
||||
# Since the earlier block was not processed by node, the new block
|
||||
# can't be fully validated.
|
||||
tip_entry_found = False
|
||||
@ -131,9 +127,8 @@ class AcceptBlockTest(BitcoinTestFramework):
|
||||
# 4b. Now send another block that builds on the forking chain.
|
||||
block_h3 = create_block(block_h2f.sha256, create_coinbase(3), block_h2f.nTime+1)
|
||||
block_h3.solve()
|
||||
test_node.send_message(msg_block(block_h3))
|
||||
test_node.send_and_ping(msg_block(block_h3))
|
||||
|
||||
test_node.sync_with_ping()
|
||||
# Since the earlier block was not processed by node, the new block
|
||||
# can't be fully validated.
|
||||
tip_entry_found = False
|
||||
@ -159,8 +154,7 @@ class AcceptBlockTest(BitcoinTestFramework):
|
||||
tip = next_block
|
||||
|
||||
# Now send the block at height 5 and check that it wasn't accepted (missing header)
|
||||
test_node.send_message(msg_block(all_blocks[1]))
|
||||
test_node.sync_with_ping()
|
||||
test_node.send_and_ping(msg_block(all_blocks[1]))
|
||||
assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblock, all_blocks[1].hash)
|
||||
assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblockheader, all_blocks[1].hash)
|
||||
|
||||
@ -168,8 +162,7 @@ class AcceptBlockTest(BitcoinTestFramework):
|
||||
headers_message = msg_headers()
|
||||
headers_message.headers.append(CBlockHeader(all_blocks[0]))
|
||||
test_node.send_message(headers_message)
|
||||
test_node.send_message(msg_block(all_blocks[1]))
|
||||
test_node.sync_with_ping()
|
||||
test_node.send_and_ping(msg_block(all_blocks[1]))
|
||||
self.nodes[0].getblock(all_blocks[1].hash)
|
||||
|
||||
# Now send the blocks in all_blocks
|
||||
@ -194,9 +187,7 @@ class AcceptBlockTest(BitcoinTestFramework):
|
||||
|
||||
test_node = self.nodes[0].add_p2p_connection(P2PInterface())
|
||||
|
||||
test_node.send_message(msg_block(block_h1f))
|
||||
|
||||
test_node.sync_with_ping()
|
||||
test_node.send_and_ping(msg_block(block_h1f))
|
||||
assert_equal(self.nodes[0].getblockcount(), 2)
|
||||
self.log.info("Unrequested block that would complete more-work chain was ignored")
|
||||
|
||||
@ -217,9 +208,7 @@ class AcceptBlockTest(BitcoinTestFramework):
|
||||
self.log.info("Inv at tip triggered getdata for unprocessed block")
|
||||
|
||||
# 7. Send the missing block for the third time (now it is requested)
|
||||
test_node.send_message(msg_block(block_h1f))
|
||||
|
||||
test_node.sync_with_ping()
|
||||
test_node.send_and_ping(msg_block(block_h1f))
|
||||
assert_equal(self.nodes[0].getblockcount(), 290)
|
||||
self.nodes[0].getblock(all_blocks[286].hash)
|
||||
assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash)
|
||||
@ -246,9 +235,8 @@ class AcceptBlockTest(BitcoinTestFramework):
|
||||
headers_message.headers.append(CBlockHeader(block_290f))
|
||||
headers_message.headers.append(CBlockHeader(block_291))
|
||||
headers_message.headers.append(CBlockHeader(block_292))
|
||||
test_node.send_message(headers_message)
|
||||
test_node.send_and_ping(headers_message)
|
||||
|
||||
test_node.sync_with_ping()
|
||||
tip_entry_found = False
|
||||
for x in self.nodes[0].getchaintips():
|
||||
if x['hash'] == block_292.hash:
|
||||
@ -258,9 +246,8 @@ class AcceptBlockTest(BitcoinTestFramework):
|
||||
assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_292.hash)
|
||||
|
||||
test_node.send_message(msg_block(block_289f))
|
||||
test_node.send_message(msg_block(block_290f))
|
||||
test_node.send_and_ping(msg_block(block_290f))
|
||||
|
||||
test_node.sync_with_ping()
|
||||
self.nodes[0].getblock(block_289f.hash)
|
||||
self.nodes[0].getblock(block_290f.hash)
|
||||
|
||||
|
@ -390,8 +390,7 @@ class BlockchainTest(BitcoinTestFramework):
|
||||
def solve_and_send_block(prevhash, height, time):
|
||||
b = create_block(prevhash, create_coinbase(height), time)
|
||||
b.solve()
|
||||
node.p2p.send_message(msg_block(b))
|
||||
node.p2p.sync_with_ping()
|
||||
node.p2p.send_and_ping(msg_block(b))
|
||||
return b
|
||||
|
||||
b21f = solve_and_send_block(int(b20hash, 16), 21, b20['time'] + 1)
|
||||
|
@ -1880,6 +1880,42 @@ class msg_filterload:
|
||||
self.data, self.nHashFuncs, self.nTweak, self.nFlags)
|
||||
|
||||
|
||||
class msg_filteradd:
|
||||
__slots__ = ("data")
|
||||
command = b"filteradd"
|
||||
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
||||
def deserialize(self, f):
|
||||
self.data = deser_string(f)
|
||||
|
||||
def serialize(self):
|
||||
r = b""
|
||||
r += ser_string(self.data)
|
||||
return r
|
||||
|
||||
def __repr__(self):
|
||||
return "msg_filteradd(data={})".format(self.data)
|
||||
|
||||
|
||||
class msg_filterclear:
|
||||
__slots__ = ()
|
||||
command = b"filterclear"
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def deserialize(self, f):
|
||||
pass
|
||||
|
||||
def serialize(self):
|
||||
return b""
|
||||
|
||||
def __repr__(self):
|
||||
return "msg_filterclear()"
|
||||
|
||||
|
||||
class msg_sendcmpct:
|
||||
__slots__ = ("announce", "version")
|
||||
command = b"sendcmpct"
|
||||
|
@ -38,6 +38,8 @@ from test_framework.messages import (
|
||||
msg_cfilter,
|
||||
msg_clsig,
|
||||
msg_cmpctblock,
|
||||
msg_filteradd,
|
||||
msg_filterclear,
|
||||
msg_filterload,
|
||||
msg_getaddr,
|
||||
msg_getblocks,
|
||||
@ -86,6 +88,8 @@ MESSAGEMAP = {
|
||||
b"cfheaders": msg_cfheaders,
|
||||
b"cfilter": msg_cfilter,
|
||||
b"cmpctblock": msg_cmpctblock,
|
||||
b"filteradd": msg_filteradd,
|
||||
b"filterclear": msg_filterclear,
|
||||
b"filterload": msg_filterload,
|
||||
b"getaddr": msg_getaddr,
|
||||
b"getblocks": msg_getblocks,
|
||||
@ -392,6 +396,8 @@ class P2PInterface(P2PConnection):
|
||||
def on_cfilter(self, message): pass
|
||||
def on_cmpctblock(self, message): pass
|
||||
def on_feefilter(self, message): pass
|
||||
def on_filteradd(self, message): pass
|
||||
def on_filterclear(self, message): pass
|
||||
def on_filterload(self, message): pass
|
||||
def on_getaddr(self, message): pass
|
||||
def on_getblocks(self, message): pass
|
||||
|
@ -110,23 +110,21 @@ class ListSinceBlockTest(BitcoinTestFramework):
|
||||
senttx = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1)
|
||||
|
||||
# generate on both sides
|
||||
lastblockhash = self.nodes[1].generate(6)[5]
|
||||
self.nodes[2].generate(7)
|
||||
self.log.debug('lastblockhash={}'.format(lastblockhash))
|
||||
nodes1_last_blockhash = self.nodes[1].generate(6)[-1]
|
||||
nodes2_first_blockhash = self.nodes[2].generate(7)[0]
|
||||
self.log.debug("nodes[1] last blockhash = {}".format(nodes1_last_blockhash))
|
||||
self.log.debug("nodes[2] first blockhash = {}".format(nodes2_first_blockhash))
|
||||
|
||||
self.sync_all(self.nodes[:2])
|
||||
self.sync_all(self.nodes[2:])
|
||||
|
||||
self.join_network()
|
||||
|
||||
# listsinceblock(lastblockhash) should now include tx, as seen from nodes[0]
|
||||
lsbres = self.nodes[0].listsinceblock(lastblockhash)
|
||||
found = False
|
||||
for tx in lsbres['transactions']:
|
||||
if tx['txid'] == senttx:
|
||||
found = True
|
||||
break
|
||||
assert found
|
||||
# listsinceblock(nodes1_last_blockhash) should now include tx as seen from nodes[0]
|
||||
# and return the block height which listsinceblock now exposes since a5e7795.
|
||||
transactions = self.nodes[0].listsinceblock(nodes1_last_blockhash)['transactions']
|
||||
found = next(tx for tx in transactions if tx['txid'] == senttx)
|
||||
assert_equal(found['blockheight'], self.nodes[0].getblockheader(nodes2_first_blockhash)['height'])
|
||||
|
||||
def test_double_spend(self):
|
||||
'''
|
||||
|
@ -199,6 +199,12 @@
|
||||
"output_cmp": "txcreate2.json",
|
||||
"description": "Creates a new transaction with a single empty output script (output in json)"
|
||||
},
|
||||
{ "exec": "./dash-tx",
|
||||
"args": ["-create", "outscript=0:123badscript"],
|
||||
"return_code": 1,
|
||||
"error_txt": "error: script parse error",
|
||||
"description": "Create a new transaction with an invalid output script"
|
||||
},
|
||||
{ "exec": "./dash-tx",
|
||||
"args": ["-create", "outscript=0:OP_DROP", "nversion=1"],
|
||||
"output_cmp": "txcreatescript1.hex",
|
||||
|
Loading…
Reference in New Issue
Block a user