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:
PastaPastaPasta 2023-05-31 12:19:27 -05:00 committed by GitHub
commit 2c0cb13f09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 494 additions and 174 deletions

View File

@ -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

View File

@ -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

View File

@ -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])

View File

@ -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).

View File

@ -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) \

View 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);

View File

@ -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) +

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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>

View File

@ -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

View File

@ -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());
});
}
}

View File

@ -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();

View File

@ -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()

View File

@ -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());

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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);
}

View File

@ -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);

View File

@ -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)]

View File

@ -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)

View File

@ -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()

View File

@ -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))

View File

@ -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()

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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

View File

@ -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):
'''

View File

@ -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",