aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.bench.include7
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/Makefile.test.include4
-rw-r--r--src/addrdb.cpp20
-rw-r--r--src/addrman.cpp1
-rw-r--r--src/arith_uint256.cpp1
-rw-r--r--src/bench/base58.cpp1
-rw-r--r--src/bench/bech32.cpp1
-rw-r--r--src/bench/bench_bitcoin.cpp6
-rw-r--r--src/bench/chacha20.cpp1
-rw-r--r--src/bench/checkblock.cpp17
-rw-r--r--src/bench/checkqueue.cpp1
-rw-r--r--src/bench/crypto_hash.cpp2
-rw-r--r--src/bench/data.cpp14
-rw-r--r--src/bench/data.h19
-rw-r--r--src/bench/duplicate_inputs.cpp4
-rw-r--r--src/bench/examples.cpp1
-rw-r--r--src/bench/rpc_blockchain.cpp33
-rw-r--r--src/bench/rpc_mempool.cpp1
-rw-r--r--src/bench/verify_script.cpp1
-rw-r--r--src/bench/wallet_balance.cpp1
-rw-r--r--src/bitcoin-cli.cpp16
-rw-r--r--src/bitcoin-tx.cpp16
-rw-r--r--src/bitcoin-wallet.cpp13
-rw-r--r--src/bitcoind.cpp22
-rw-r--r--src/consensus/merkle.cpp1
-rw-r--r--src/core_read.cpp1
-rw-r--r--src/core_write.cpp1
-rw-r--r--src/crypto/aes.cpp1
-rw-r--r--src/crypto/sha256_avx2.cpp1
-rw-r--r--src/crypto/sha256_sse41.cpp1
-rw-r--r--src/httprpc.cpp1
-rw-r--r--src/index/blockfilterindex.cpp4
-rw-r--r--src/init.cpp46
-rw-r--r--src/interfaces/chain.cpp6
-rw-r--r--src/interfaces/node.cpp3
-rw-r--r--src/interfaces/wallet.cpp10
-rw-r--r--src/interfaces/wallet.h4
-rw-r--r--src/key.cpp1
-rw-r--r--src/logging.cpp76
-rw-r--r--src/logging.h21
-rw-r--r--src/merkleblock.cpp1
-rw-r--r--src/miner.cpp3
-rw-r--r--src/net.cpp6
-rw-r--r--src/net_processing.cpp152
-rw-r--r--src/netaddress.cpp11
-rw-r--r--src/netaddress.h3
-rw-r--r--src/netbase.cpp3
-rw-r--r--src/noui.cpp36
-rw-r--r--src/policy/fees.cpp3
-rw-r--r--src/policy/fees.h1
-rw-r--r--src/policy/policy.cpp4
-rw-r--r--src/prevector.h15
-rw-r--r--src/primitives/block.cpp1
-rw-r--r--src/psbt.cpp22
-rw-r--r--src/psbt.h6
-rw-r--r--src/qt/addressbookpage.cpp1
-rw-r--r--src/qt/addresstablemodel.cpp1
-rw-r--r--src/qt/bantablemodel.cpp2
-rw-r--r--src/qt/bitcoin.cpp23
-rw-r--r--src/qt/bitcoingui.cpp68
-rw-r--r--src/qt/bitcoingui.h3
-rw-r--r--src/qt/bitcoinstrings.cpp17
-rw-r--r--src/qt/bitcoinunits.cpp2
-rw-r--r--src/qt/clientmodel.cpp6
-rw-r--r--src/qt/coincontroldialog.cpp4
-rw-r--r--src/qt/forms/debugwindow.ui16
-rw-r--r--src/qt/guiutil.cpp11
-rw-r--r--src/qt/intro.cpp12
-rw-r--r--src/qt/locale/bitcoin_en.ts455
-rw-r--r--src/qt/optionsdialog.cpp8
-rw-r--r--src/qt/optionsmodel.cpp2
-rw-r--r--src/qt/paymentserver.cpp2
-rw-r--r--src/qt/peertablemodel.cpp1
-rw-r--r--src/qt/platformstyle.cpp2
-rw-r--r--src/qt/receivecoinsdialog.cpp2
-rw-r--r--src/qt/receiverequestdialog.cpp1
-rwxr-xr-xsrc/qt/res/movies/makespinner.sh2
-rw-r--r--src/qt/rpcconsole.cpp7
-rw-r--r--src/qt/sendcoinsdialog.cpp44
-rw-r--r--src/qt/sendcoinsdialog.h2
-rw-r--r--src/qt/splashscreen.cpp2
-rw-r--r--src/qt/test/addressbooktests.cpp3
-rw-r--r--src/qt/test/apptests.cpp14
-rw-r--r--src/qt/test/paymentservertests.cpp4
-rw-r--r--src/qt/test/rpcnestedtests.cpp5
-rw-r--r--src/qt/test/rpcnestedtests.h3
-rw-r--r--src/qt/test/test_main.cpp25
-rw-r--r--src/qt/test/wallettests.cpp2
-rw-r--r--src/qt/trafficgraphwidget.cpp1
-rw-r--r--src/qt/transactiondesc.cpp3
-rw-r--r--src/qt/transactionrecord.cpp4
-rw-r--r--src/qt/transactiontablemodel.cpp4
-rw-r--r--src/qt/transactionview.cpp1
-rw-r--r--src/qt/utilitydialog.cpp13
-rw-r--r--src/qt/walletcontroller.cpp13
-rw-r--r--src/qt/walletcontroller.h10
-rw-r--r--src/qt/walletmodel.cpp4
-rw-r--r--src/qt/walletmodeltransaction.cpp1
-rw-r--r--src/qt/walletview.cpp1
-rw-r--r--src/qt/winshutdownmonitor.cpp2
-rw-r--r--src/rpc/blockchain.cpp64
-rw-r--r--src/rpc/client.cpp5
-rw-r--r--src/rpc/mining.cpp12
-rw-r--r--src/rpc/misc.cpp12
-rw-r--r--src/rpc/net.cpp2
-rw-r--r--src/rpc/protocol.cpp1
-rw-r--r--src/rpc/rawtransaction.cpp99
-rw-r--r--src/rpc/rawtransaction_util.cpp4
-rw-r--r--src/rpc/server.cpp9
-rw-r--r--src/rpc/util.cpp62
-rw-r--r--src/rpc/util.h10
-rw-r--r--src/script/descriptor.cpp48
-rw-r--r--src/script/descriptor.h8
-rw-r--r--src/script/script.cpp1
-rw-r--r--src/script/sigcache.cpp1
-rw-r--r--src/script/sign.cpp16
-rw-r--r--src/script/sign.h3
-rw-r--r--src/script/standard.cpp2
-rw-r--r--src/serialize.h6
-rw-r--r--src/support/cleanse.cpp36
-rw-r--r--src/support/cleanse.h3
-rw-r--r--src/sync.cpp8
-rw-r--r--src/test/allocator_tests.cpp2
-rw-r--r--src/test/arith_uint256_tests.cpp1
-rw-r--r--src/test/bip32_tests.cpp3
-rw-r--r--src/test/blockchain_tests.cpp1
-rw-r--r--src/test/blockencodings_tests.cpp2
-rw-r--r--src/test/blockfilter_index_tests.cpp3
-rw-r--r--src/test/checkqueue_tests.cpp3
-rw-r--r--src/test/coins_tests.cpp7
-rw-r--r--src/test/compilerbug_tests.cpp43
-rw-r--r--src/test/crypto_tests.cpp2
-rw-r--r--src/test/dbwrapper_tests.cpp16
-rw-r--r--src/test/denialofservice_tests.cpp3
-rw-r--r--src/test/flatfile_tests.cpp11
-rw-r--r--src/test/fs_tests.cpp3
-rw-r--r--src/test/fuzz/deserialize.cpp5
-rw-r--r--src/test/fuzz/fuzz.h1
-rw-r--r--src/test/fuzz/script_flags.cpp1
-rw-r--r--src/test/hash_tests.cpp3
-rw-r--r--src/test/key_properties.cpp4
-rw-r--r--src/test/key_tests.cpp1
-rw-r--r--src/test/mempool_tests.cpp2
-rw-r--r--src/test/miner_tests.cpp3
-rw-r--r--src/test/multisig_tests.cpp2
-rw-r--r--src/test/net_tests.cpp7
-rw-r--r--src/test/netbase_tests.cpp1
-rw-r--r--src/test/policyestimator_tests.cpp1
-rw-r--r--src/test/pow_tests.cpp1
-rw-r--r--src/test/prevector_tests.cpp28
-rw-r--r--src/test/raii_event_tests.cpp2
-rw-r--r--src/test/rpc_tests.cpp4
-rw-r--r--src/test/script_p2sh_tests.cpp4
-rw-r--r--src/test/script_standard_tests.cpp362
-rw-r--r--src/test/script_tests.cpp2
-rw-r--r--src/test/scriptnum10.h1
-rw-r--r--src/test/serialize_tests.cpp1
-rw-r--r--src/test/setup_common.cpp29
-rw-r--r--src/test/setup_common.h9
-rw-r--r--src/test/sigopcount_tests.cpp2
-rw-r--r--src/test/streams_tests.cpp1
-rw-r--r--src/test/torcontrol_tests.cpp1
-rw-r--r--src/test/transaction_tests.cpp1
-rw-r--r--src/test/txindex_tests.cpp1
-rw-r--r--src/test/txvalidation_tests.cpp2
-rw-r--r--src/test/txvalidationcache_tests.cpp6
-rw-r--r--src/test/uint256_tests.cpp6
-rw-r--r--src/test/util.cpp5
-rw-r--r--src/test/util_tests.cpp7
-rw-r--r--src/test/validation_block_tests.cpp155
-rw-r--r--src/timedata.cpp3
-rw-r--r--src/tinyformat.h1
-rw-r--r--src/torcontrol.cpp10
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txmempool.cpp22
-rw-r--r--src/txmempool.h36
-rw-r--r--src/ui_interface.cpp4
-rw-r--r--src/ui_interface.h3
-rw-r--r--src/uint256.cpp15
-rw-r--r--src/util/error.cpp2
-rw-r--r--src/util/error.h1
-rw-r--r--src/util/fees.cpp1
-rw-r--r--src/util/system.cpp37
-rw-r--r--src/util/system.h9
-rw-r--r--src/validation.cpp337
-rw-r--r--src/validation.h195
-rw-r--r--src/validationinterface.cpp2
-rw-r--r--src/validationinterface.h1
-rw-r--r--src/wallet/coincontrol.cpp1
-rw-r--r--src/wallet/coincontrol.h2
-rw-r--r--src/wallet/db.cpp4
-rw-r--r--src/wallet/feebumper.cpp4
-rw-r--r--src/wallet/fees.cpp11
-rw-r--r--src/wallet/init.cpp9
-rw-r--r--src/wallet/ismine.cpp (renamed from src/script/ismine.cpp)13
-rw-r--r--src/wallet/ismine.h (renamed from src/script/ismine.h)16
-rw-r--r--src/wallet/psbtwallet.cpp11
-rw-r--r--src/wallet/rpcdump.cpp7
-rw-r--r--src/wallet/rpcwallet.cpp171
-rw-r--r--src/wallet/test/db_tests.cpp12
-rw-r--r--src/wallet/test/init_test_fixture.cpp5
-rw-r--r--src/wallet/test/init_tests.cpp6
-rw-r--r--src/wallet/test/ismine_tests.cpp398
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp3
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp4
-rw-r--r--src/wallet/test/wallet_tests.cpp4
-rw-r--r--src/wallet/wallet.cpp97
-rw-r--r--src/wallet/wallet.h34
-rw-r--r--src/wallet/wallettool.cpp39
-rw-r--r--src/wallet/wallettool.h2
-rw-r--r--src/warnings.cpp1
-rw-r--r--src/zmq/zmqabstractnotifier.cpp1
-rw-r--r--src/zmq/zmqnotificationinterface.cpp1
215 files changed, 2447 insertions, 1726 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index ec3d81b76f..39e8d3d689 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -181,7 +181,6 @@ BITCOIN_CORE_H = \
rpc/util.h \
scheduler.h \
script/descriptor.h \
- script/ismine.h \
script/sigcache.h \
script/sign.h \
script/standard.h \
@@ -223,6 +222,7 @@ BITCOIN_CORE_H = \
wallet/db.h \
wallet/feebumper.h \
wallet/fees.h \
+ wallet/ismine.h \
wallet/load.h \
wallet/psbtwallet.h \
wallet/rpcwallet.h \
@@ -328,6 +328,7 @@ libbitcoin_wallet_a_SOURCES = \
wallet/db.cpp \
wallet/feebumper.cpp \
wallet/fees.cpp \
+ wallet/ismine.cpp \
wallet/load.cpp \
wallet/psbtwallet.cpp \
wallet/rpcdump.cpp \
@@ -458,7 +459,6 @@ libbitcoin_common_a_SOURCES = \
rpc/util.cpp \
scheduler.cpp \
script/descriptor.cpp \
- script/ismine.cpp \
script/sign.cpp \
script/standard.cpp \
versionbitsinfo.cpp \
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index c6162b5caa..c1d9bf281c 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -18,6 +18,8 @@ bench_bench_bitcoin_SOURCES = \
bench/block_assemble.cpp \
bench/checkblock.cpp \
bench/checkqueue.cpp \
+ bench/data.h \
+ bench/data.cpp \
bench/duplicate_inputs.cpp \
bench/examples.cpp \
bench/rollingbloom.cpp \
@@ -27,6 +29,7 @@ bench_bench_bitcoin_SOURCES = \
bench/gcs_filter.cpp \
bench/merkle_root.cpp \
bench/mempool_eviction.cpp \
+ bench/rpc_blockchain.cpp \
bench/rpc_mempool.cpp \
bench/util_time.cpp \
bench/verify_script.cpp \
@@ -76,7 +79,7 @@ CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)
CLEANFILES += $(CLEAN_BITCOIN_BENCH)
-bench/checkblock.cpp: bench/data/block413567.raw.h
+bench/data.cpp: bench/data/block413567.raw.h
bitcoin_bench: $(BENCH_BINARY)
@@ -89,7 +92,7 @@ bitcoin_bench_clean : FORCE
%.raw.h: %.raw
@$(MKDIR_P) $(@D)
@{ \
- echo "static unsigned const char $(*F)[] = {" && \
+ echo "static unsigned const char $(*F)_raw[] = {" && \
$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
echo "};"; \
} > "$@.new" && mv -f "$@.new" "$@"
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index c4c08487f3..3ae8498a87 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -447,7 +447,7 @@ SECONDARY: $(QT_QM)
$(srcdir)/qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_zmq_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) $(libbitcoin_util_a_SOURCES)
@test -n $(XGETTEXT) || echo "xgettext is required for updating translations"
- $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" COPYRIGHT_HOLDERS_SUBSTITUTION="$(COPYRIGHT_HOLDERS_SUBSTITUTION)" $(PYTHON) ../share/qt/extract_strings_qt.py $^
+ $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" $(PYTHON) ../share/qt/extract_strings_qt.py $^
translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) qt/bitcoin.cpp $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM)
@test -n $(LUPDATE) || echo "lupdate is required for updating translations"
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 1144ca8a78..d3fe138133 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -97,6 +97,7 @@ BITCOIN_TESTS =\
test/bswap_tests.cpp \
test/checkqueue_tests.cpp \
test/coins_tests.cpp \
+ test/compilerbug_tests.cpp \
test/compress_tests.cpp \
test/crypto_tests.cpp \
test/cuckoocache_tests.cpp \
@@ -166,7 +167,8 @@ BITCOIN_TESTS += \
wallet/test/wallet_tests.cpp \
wallet/test/wallet_crypto_tests.cpp \
wallet/test/coinselector_tests.cpp \
- wallet/test/init_tests.cpp
+ wallet/test/init_tests.cpp \
+ wallet/test/ismine_tests.cpp
BITCOIN_TEST_SUITE += \
wallet/test/wallet_test_fixture.cpp \
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index c6083f5554..db936486b6 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -44,18 +44,30 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
fs::path pathTmp = GetDataDir() / tmpfn;
FILE *file = fsbridge::fopen(pathTmp, "wb");
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
- if (fileout.IsNull())
+ if (fileout.IsNull()) {
+ fileout.fclose();
+ remove(pathTmp);
return error("%s: Failed to open file %s", __func__, pathTmp.string());
+ }
// Serialize
- if (!SerializeDB(fileout, data)) return false;
- if (!FileCommit(fileout.Get()))
+ if (!SerializeDB(fileout, data)) {
+ fileout.fclose();
+ remove(pathTmp);
+ return false;
+ }
+ if (!FileCommit(fileout.Get())) {
+ fileout.fclose();
+ remove(pathTmp);
return error("%s: Failed to flush file %s", __func__, pathTmp.string());
+ }
fileout.fclose();
// replace existing file, if any, with new file
- if (!RenameOver(pathTmp, path))
+ if (!RenameOver(pathTmp, path)) {
+ remove(pathTmp);
return error("%s: Rename-into-place failed", __func__);
+ }
return true;
}
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 8a5f78d1c5..32676f8fa5 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -7,7 +7,6 @@
#include <hash.h>
#include <serialize.h>
-#include <streams.h>
int CAddrInfo::GetTriedBucket(const uint256& nKey) const
{
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index aa66d13102..be145a0e63 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -6,7 +6,6 @@
#include <arith_uint256.h>
#include <uint256.h>
-#include <util/strencodings.h>
#include <crypto/common.h>
#include <stdio.h>
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index e7702ec461..0f4b52cf79 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -4,7 +4,6 @@
#include <bench/bench.h>
-#include <validation.h>
#include <base58.h>
#include <array>
diff --git a/src/bench/bech32.cpp b/src/bench/bech32.cpp
index 3c4b453a23..80f13eeb3b 100644
--- a/src/bench/bech32.cpp
+++ b/src/bench/bech32.cpp
@@ -4,7 +4,6 @@
#include <bench/bench.h>
-#include <validation.h>
#include <bech32.h>
#include <util/strencodings.h>
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 3cf0bf9530..8eea96d930 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -4,8 +4,6 @@
#include <bench/bench.h>
-#include <crypto/sha256.h>
-#include <key.h>
#include <util/strencodings.h>
#include <util/system.h>
@@ -38,7 +36,7 @@ int main(int argc, char** argv)
SetupBenchArgs();
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
- fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str());
return EXIT_FAILURE;
}
@@ -55,7 +53,7 @@ int main(int argc, char** argv)
double scaling_factor;
if (!ParseDouble(scaling_str, &scaling_factor)) {
- fprintf(stderr, "Error parsing scaling factor as double: %s\n", scaling_str.c_str());
+ tfm::format(std::cerr, "Error parsing scaling factor as double: %s\n", scaling_str.c_str());
return EXIT_FAILURE;
}
diff --git a/src/bench/chacha20.cpp b/src/bench/chacha20.cpp
index 69d8c96ec0..030067aca5 100644
--- a/src/bench/chacha20.cpp
+++ b/src/bench/chacha20.cpp
@@ -5,7 +5,6 @@
#include <iostream>
#include <bench/bench.h>
-#include <hash.h>
#include <crypto/chacha20.h>
/* Number of bytes to process per iteration */
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index e325333c01..4b13381e16 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -3,41 +3,34 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
+#include <bench/data.h>
#include <chainparams.h>
#include <validation.h>
#include <streams.h>
#include <consensus/validation.h>
-namespace block_bench {
-#include <bench/data/block413567.raw.h>
-} // namespace block_bench
-
// These are the two major time-sinks which happen after we have fully received
// a block off the wire, but before we can relay the block on to peers using
// compact block relay.
static void DeserializeBlockTest(benchmark::State& state)
{
- CDataStream stream((const char*)block_bench::block413567,
- (const char*)block_bench::block413567 + sizeof(block_bench::block413567),
- SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
char a = '\0';
stream.write(&a, 1); // Prevent compaction
while (state.KeepRunning()) {
CBlock block;
stream >> block;
- bool rewound = stream.Rewind(sizeof(block_bench::block413567));
+ bool rewound = stream.Rewind(benchmark::data::block413567.size());
assert(rewound);
}
}
static void DeserializeAndCheckBlockTest(benchmark::State& state)
{
- CDataStream stream((const char*)block_bench::block413567,
- (const char*)block_bench::block413567 + sizeof(block_bench::block413567),
- SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
char a = '\0';
stream.write(&a, 1); // Prevent compaction
@@ -46,7 +39,7 @@ static void DeserializeAndCheckBlockTest(benchmark::State& state)
while (state.KeepRunning()) {
CBlock block; // Note that CBlock caches its checked state, so we need to recreate it here
stream >> block;
- bool rewound = stream.Rewind(sizeof(block_bench::block413567));
+ bool rewound = stream.Rewind(benchmark::data::block413567.size());
assert(rewound);
CValidationState validationState;
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index 6ab542067a..000a0259bb 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -4,7 +4,6 @@
#include <bench/bench.h>
#include <util/system.h>
-#include <validation.h>
#include <checkqueue.h>
#include <prevector.h>
#include <vector>
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index dc0b054420..fb2bab9dee 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -5,11 +5,9 @@
#include <iostream>
#include <bench/bench.h>
-#include <bloom.h>
#include <hash.h>
#include <random.h>
#include <uint256.h>
-#include <util/time.h>
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
diff --git a/src/bench/data.cpp b/src/bench/data.cpp
new file mode 100644
index 0000000000..0ae4c7cad4
--- /dev/null
+++ b/src/bench/data.cpp
@@ -0,0 +1,14 @@
+// Copyright (c) 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/data.h>
+
+namespace benchmark {
+namespace data {
+
+#include <bench/data/block413567.raw.h>
+const std::vector<uint8_t> block413567{block413567_raw, block413567_raw + sizeof(block413567_raw) / sizeof(block413567_raw[0])};
+
+} // namespace data
+} // namespace benchmark
diff --git a/src/bench/data.h b/src/bench/data.h
new file mode 100644
index 0000000000..5f13d766ea
--- /dev/null
+++ b/src/bench/data.h
@@ -0,0 +1,19 @@
+// Copyright (c) 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.
+
+#ifndef BITCOIN_BENCH_DATA_H
+#define BITCOIN_BENCH_DATA_H
+
+#include <cstdint>
+#include <vector>
+
+namespace benchmark {
+namespace data {
+
+extern const std::vector<uint8_t> block413567;
+
+} // namespace data
+} // namespace benchmark
+
+#endif // BITCOIN_BENCH_DATA_H
diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp
index 80ff13612c..2440341287 100644
--- a/src/bench/duplicate_inputs.cpp
+++ b/src/bench/duplicate_inputs.cpp
@@ -7,13 +7,9 @@
#include <coins.h>
#include <consensus/merkle.h>
#include <consensus/validation.h>
-#include <miner.h>
-#include <policy/policy.h>
#include <pow.h>
-#include <test/util.h>
#include <txmempool.h>
#include <validation.h>
-#include <validationinterface.h>
#include <list>
#include <vector>
diff --git a/src/bench/examples.cpp b/src/bench/examples.cpp
index e7ddd5a938..3595249559 100644
--- a/src/bench/examples.cpp
+++ b/src/bench/examples.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
-#include <validation.h>
#include <util/time.h>
// Sanity test: this should loop ten times, and
diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp
new file mode 100644
index 0000000000..29e448fc43
--- /dev/null
+++ b/src/bench/rpc_blockchain.cpp
@@ -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 <bench/data.h>
+
+#include <validation.h>
+#include <streams.h>
+#include <consensus/validation.h>
+#include <rpc/blockchain.h>
+
+#include <univalue.h>
+
+static void BlockToJsonVerbose(benchmark::State& state) {
+ CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
+ char a = '\0';
+ stream.write(&a, 1); // Prevent compaction
+
+ CBlock block;
+ stream >> block;
+
+ CBlockIndex blockindex;
+ const uint256 blockHash = block.GetHash();
+ blockindex.phashBlock = &blockHash;
+ blockindex.nBits = 403014710;
+
+ while (state.KeepRunning()) {
+ (void)blockToJSON(block, &blockindex, &blockindex, /*verbose*/ true);
+ }
+}
+
+BENCHMARK(BlockToJsonVerbose, 10);
diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp
index 67d8a25564..b35a744055 100644
--- a/src/bench/rpc_mempool.cpp
+++ b/src/bench/rpc_mempool.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
-#include <policy/policy.h>
#include <rpc/blockchain.h>
#include <txmempool.h>
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index 312b66e38a..4891c57b3a 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -8,7 +8,6 @@
#include <script/bitcoinconsensus.h>
#endif
#include <script/script.h>
-#include <script/sign.h>
#include <script/standard.h>
#include <streams.h>
diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp
index 46ca12826b..313b5a3ba0 100644
--- a/src/bench/wallet_balance.cpp
+++ b/src/bench/wallet_balance.cpp
@@ -4,7 +4,6 @@
#include <bench/bench.h>
#include <interfaces/chain.h>
-#include <key_io.h>
#include <optional.h>
#include <test/util.h>
#include <validationinterface.h>
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 1009a771f8..38010c461e 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -101,7 +101,7 @@ static int AppInitRPC(int argc, char* argv[])
SetupCliArgs();
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
- fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str());
return EXIT_FAILURE;
}
if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
@@ -115,26 +115,26 @@ static int AppInitRPC(int argc, char* argv[])
strUsage += "\n" + gArgs.GetHelpMessage();
}
- fprintf(stdout, "%s", strUsage.c_str());
+ tfm::format(std::cout, "%s", strUsage.c_str());
if (argc < 2) {
- fprintf(stderr, "Error: too few parameters\n");
+ tfm::format(std::cerr, "Error: too few parameters\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
if (!fs::is_directory(GetDataDir(false))) {
- fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
+ tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return EXIT_FAILURE;
}
if (!gArgs.ReadConfigFiles(error, true)) {
- fprintf(stderr, "Error reading configuration file: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error reading configuration file: %s\n", error.c_str());
return EXIT_FAILURE;
}
// Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
try {
SelectBaseParams(gArgs.GetChainName());
} catch (const std::exception& e) {
- fprintf(stderr, "Error: %s\n", e.what());
+ tfm::format(std::cerr, "Error: %s\n", e.what());
return EXIT_FAILURE;
}
return CONTINUE_EXECUTION;
@@ -495,7 +495,7 @@ static int CommandLineRPC(int argc, char *argv[])
}
if (strPrint != "") {
- fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
+ tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint.c_str());
}
return nRet;
}
@@ -508,7 +508,7 @@ int main(int argc, char* argv[])
#endif
SetupEnvironment();
if (!SetupNetworking()) {
- fprintf(stderr, "Error: Initializing networking failed\n");
+ tfm::format(std::cerr, "Error: Initializing networking failed\n");
return EXIT_FAILURE;
}
event_set_log_callback(&libevent_log_cb);
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index ac1d62a8f4..933b34744d 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -82,7 +82,7 @@ static int AppInitRawTx(int argc, char* argv[])
SetupBitcoinTxArgs();
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
- fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str());
return EXIT_FAILURE;
}
@@ -90,7 +90,7 @@ static int AppInitRawTx(int argc, char* argv[])
try {
SelectParams(gArgs.GetChainName());
} catch (const std::exception& e) {
- fprintf(stderr, "Error: %s\n", e.what());
+ tfm::format(std::cerr, "Error: %s\n", e.what());
return EXIT_FAILURE;
}
@@ -104,10 +104,10 @@ static int AppInitRawTx(int argc, char* argv[])
"\n";
strUsage += gArgs.GetHelpMessage();
- fprintf(stdout, "%s", strUsage.c_str());
+ tfm::format(std::cout, "%s", strUsage.c_str());
if (argc < 2) {
- fprintf(stderr, "Error: too few parameters\n");
+ tfm::format(std::cerr, "Error: too few parameters\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
@@ -723,21 +723,21 @@ static void OutputTxJSON(const CTransaction& tx)
TxToUniv(tx, uint256(), entry);
std::string jsonOutput = entry.write(4);
- fprintf(stdout, "%s\n", jsonOutput.c_str());
+ tfm::format(std::cout, "%s\n", jsonOutput.c_str());
}
static void OutputTxHash(const CTransaction& tx)
{
std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
- fprintf(stdout, "%s\n", strHexHash.c_str());
+ tfm::format(std::cout, "%s\n", strHexHash.c_str());
}
static void OutputTxHex(const CTransaction& tx)
{
std::string strHex = EncodeHexTx(tx);
- fprintf(stdout, "%s\n", strHex.c_str());
+ tfm::format(std::cout, "%s\n", strHex.c_str());
}
static void OutputTx(const CTransaction& tx)
@@ -828,7 +828,7 @@ static int CommandLineRawTx(int argc, char* argv[])
}
if (strPrint != "") {
- fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
+ tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint.c_str());
}
return nRet;
}
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index 32a539aac6..cbb4ea750c 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -8,7 +8,6 @@
#include <chainparams.h>
#include <chainparamsbase.h>
-#include <consensus/consensus.h>
#include <logging.h>
#include <util/system.h>
#include <util/strencodings.h>
@@ -37,7 +36,7 @@ static bool WalletAppInit(int argc, char* argv[])
SetupWalletToolArgs();
std::string error_message;
if (!gArgs.ParseParameters(argc, argv, error_message)) {
- fprintf(stderr, "Error parsing command line arguments: %s\n", error_message.c_str());
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error_message.c_str());
return false;
}
if (argc < 2 || HelpRequested(gArgs)) {
@@ -49,7 +48,7 @@ static bool WalletAppInit(int argc, char* argv[])
" bitcoin-wallet [options] <command>\n\n" +
gArgs.GetHelpMessage();
- fprintf(stdout, "%s", usage.c_str());
+ tfm::format(std::cout, "%s", usage.c_str());
return false;
}
@@ -57,7 +56,7 @@ static bool WalletAppInit(int argc, char* argv[])
LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", gArgs.GetBoolArg("-debug", false));
if (!fs::is_directory(GetDataDir(false))) {
- fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
+ tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return false;
}
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
@@ -88,7 +87,7 @@ int main(int argc, char* argv[])
for(int i = 1; i < argc; ++i) {
if (!IsSwitchChar(argv[i][0])) {
if (!method.empty()) {
- fprintf(stderr, "Error: two methods provided (%s and %s). Only one method should be provided.\n", method.c_str(), argv[i]);
+ tfm::format(std::cerr, "Error: two methods provided (%s and %s). Only one method should be provided.\n", method.c_str(), argv[i]);
return EXIT_FAILURE;
}
method = argv[i];
@@ -96,13 +95,13 @@ int main(int argc, char* argv[])
}
if (method.empty()) {
- fprintf(stderr, "No method provided. Run `bitcoin-wallet -help` for valid methods.\n");
+ tfm::format(std::cerr, "No method provided. Run `bitcoin-wallet -help` for valid methods.\n");
return EXIT_FAILURE;
}
// A name must be provided when creating a file
if (method == "create" && !gArgs.IsArgSet("-wallet")) {
- fprintf(stderr, "Wallet name must be provided when creating a new wallet.\n");
+ tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
return EXIT_FAILURE;
}
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index b31f86cdd9..ba6de702e0 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -12,16 +12,12 @@
#include <compat.h>
#include <fs.h>
#include <interfaces/chain.h>
-#include <rpc/server.h>
#include <init.h>
#include <noui.h>
#include <shutdown.h>
#include <util/system.h>
-#include <httpserver.h>
-#include <httprpc.h>
#include <util/threadnames.h>
#include <util/strencodings.h>
-#include <walletinitinterface.h>
#include <stdio.h>
@@ -74,7 +70,7 @@ static bool AppInit(int argc, char* argv[])
SetupServerArgs();
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
- fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str());
return false;
}
@@ -92,7 +88,7 @@ static bool AppInit(int argc, char* argv[])
strUsage += "\n" + gArgs.GetHelpMessage();
}
- fprintf(stdout, "%s", strUsage.c_str());
+ tfm::format(std::cout, "%s", strUsage.c_str());
return true;
}
@@ -100,25 +96,25 @@ static bool AppInit(int argc, char* argv[])
{
if (!fs::is_directory(GetDataDir(false)))
{
- fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
+ tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return false;
}
if (!gArgs.ReadConfigFiles(error, true)) {
- fprintf(stderr, "Error reading configuration file: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error reading configuration file: %s\n", error.c_str());
return false;
}
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
try {
SelectParams(gArgs.GetChainName());
} catch (const std::exception& e) {
- fprintf(stderr, "Error: %s\n", e.what());
+ tfm::format(std::cerr, "Error: %s\n", e.what());
return false;
}
// Error out when loose non-argument tokens are encountered on command line
for (int i = 1; i < argc; i++) {
if (!IsSwitchChar(argv[i][0])) {
- fprintf(stderr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]);
+ tfm::format(std::cerr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]);
return false;
}
}
@@ -150,18 +146,18 @@ static bool AppInit(int argc, char* argv[])
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
- fprintf(stdout, "Bitcoin server starting\n");
+ tfm::format(std::cout, "Bitcoin server starting\n");
// Daemonize
if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
- fprintf(stderr, "Error: daemon() failed: %s\n", strerror(errno));
+ tfm::format(std::cerr, "Error: daemon() failed: %s\n", strerror(errno));
return false;
}
#if defined(MAC_OSX)
#pragma GCC diagnostic pop
#endif
#else
- fprintf(stderr, "Error: -daemon is not supported on this operating system\n");
+ tfm::format(std::cerr, "Error: -daemon is not supported on this operating system\n");
return false;
#endif // HAVE_DECL_DAEMON
}
diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp
index b47d9774ca..f87612edef 100644
--- a/src/consensus/merkle.cpp
+++ b/src/consensus/merkle.cpp
@@ -4,7 +4,6 @@
#include <consensus/merkle.h>
#include <hash.h>
-#include <util/strencodings.h>
/* WARNING! If you're reading this because you're learning about crypto
and/or designing a new system that will use merkle trees, keep in mind
diff --git a/src/core_read.cpp b/src/core_read.cpp
index a879a375ce..a3c9cf0159 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -11,7 +11,6 @@
#include <serialize.h>
#include <streams.h>
#include <univalue.h>
-#include <util/system.h>
#include <util/strencodings.h>
#include <version.h>
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 765a170307..4d64446d7b 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -13,7 +13,6 @@
#include <streams.h>
#include <univalue.h>
#include <util/system.h>
-#include <util/moneystr.h>
#include <util/strencodings.h>
UniValue ValueFromAmount(const CAmount& amount)
diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp
index 2dc2133434..b3fb927760 100644
--- a/src/crypto/aes.cpp
+++ b/src/crypto/aes.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <crypto/aes.h>
-#include <crypto/common.h>
#include <assert.h>
#include <string.h>
diff --git a/src/crypto/sha256_avx2.cpp b/src/crypto/sha256_avx2.cpp
index 068e0e5ff6..90a72516a4 100644
--- a/src/crypto/sha256_avx2.cpp
+++ b/src/crypto/sha256_avx2.cpp
@@ -3,7 +3,6 @@
#include <stdint.h>
#include <immintrin.h>
-#include <crypto/sha256.h>
#include <crypto/common.h>
namespace sha256d64_avx2 {
diff --git a/src/crypto/sha256_sse41.cpp b/src/crypto/sha256_sse41.cpp
index adca870e2d..fc79f46f7f 100644
--- a/src/crypto/sha256_sse41.cpp
+++ b/src/crypto/sha256_sse41.cpp
@@ -3,7 +3,6 @@
#include <stdint.h>
#include <immintrin.h>
-#include <crypto/sha256.h>
#include <crypto/common.h>
namespace sha256d64_sse41 {
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index fcf760a4c6..c7a119440b 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -9,7 +9,6 @@
#include <key_io.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
-#include <random.h>
#include <sync.h>
#include <util/system.h>
#include <util/strencodings.h>
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index 20f33baf2c..c3ce8d7af0 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -53,7 +53,7 @@ struct DBHeightKey {
int height;
DBHeightKey() : height(0) {}
- DBHeightKey(int height_in) : height(height_in) {}
+ explicit DBHeightKey(int height_in) : height(height_in) {}
template<typename Stream>
void Serialize(Stream& s) const
@@ -76,7 +76,7 @@ struct DBHeightKey {
struct DBHashKey {
uint256 hash;
- DBHashKey(const uint256& hash_in) : hash(hash_in) {}
+ explicit DBHashKey(const uint256& hash_in) : hash(hash_in) {}
ADD_SERIALIZE_METHODS;
diff --git a/src/init.cpp b/src/init.cpp
index 2bb270647a..5d7c3b9af7 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -51,7 +51,6 @@
#include <util/moneystr.h>
#include <util/validation.h>
#include <validationinterface.h>
-#include <warnings.h>
#include <walletinitinterface.h>
#include <stdint.h>
#include <stdio.h>
@@ -109,14 +108,13 @@ static fs::path GetPidFile()
NODISCARD static bool CreatePidFile()
{
- FILE* file = fsbridge::fopen(GetPidFile(), "w");
+ fsbridge::ofstream file{GetPidFile()};
if (file) {
#ifdef WIN32
- fprintf(file, "%d\n", GetCurrentProcessId());
+ tfm::format(file, "%d\n", GetCurrentProcessId());
#else
- fprintf(file, "%d\n", getpid());
+ tfm::format(file, "%d\n", getpid());
#endif
- fclose(file);
return true;
} else {
return InitError(strprintf(_("Unable to create the PID file '%s': %s"), GetPidFile().string(), std::strerror(errno)));
@@ -259,7 +257,7 @@ void Shutdown(InitInterfaces& interfaces)
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
if (pcoinsTip != nullptr) {
- FlushStateToDisk();
+ ::ChainstateActive().ForceFlushStateToDisk();
}
// After there are no more peers/RPC left to give us new data which may generate
@@ -275,7 +273,7 @@ void Shutdown(InitInterfaces& interfaces)
{
LOCK(cs_main);
if (pcoinsTip != nullptr) {
- FlushStateToDisk();
+ ::ChainstateActive().ForceFlushStateToDisk();
}
pcoinsTip.reset();
pcoinscatcher.reset();
@@ -378,10 +376,14 @@ void SetupServerArgs()
"-allowselfsignedrootcertificates", "-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-rootcertificates=<file>", "-splash", "-uiplatform"};
gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS);
+#if HAVE_SYSTEM
gArgs.AddArg("-alertnotify=<cmd>", "Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)", false, OptionsCategory::OPTIONS);
+#endif
gArgs.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-blocksdir=<dir>", "Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)", false, OptionsCategory::OPTIONS);
+#if HAVE_SYSTEM
gArgs.AddArg("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)", false, OptionsCategory::OPTIONS);
+#endif
gArgs.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Transactions from the wallet or RPC are not affected. (default: %u)", DEFAULT_BLOCKSONLY), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS);
@@ -525,7 +527,6 @@ void SetupServerArgs()
gArgs.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), false, OptionsCategory::NODE_RELAY);
- gArgs.AddArg("-mempoolreplacement", strprintf("Enable transaction replacement in the memory pool (default: %u)", DEFAULT_ENABLE_REPLACEMENT), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)",
CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-whitelistforcerelay", strprintf("Force relay of transactions from whitelisted peers even if the transactions were already in the mempool or violate local relay policy (default: %d)", DEFAULT_WHITELISTFORCERELAY), false, OptionsCategory::NODE_RELAY);
@@ -582,6 +583,7 @@ std::string LicenseInfo()
"\n";
}
+#if HAVE_SYSTEM
static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex)
{
if (initialSync || !pBlockIndex)
@@ -594,6 +596,7 @@ static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex
t.detach(); // thread runs free
}
}
+#endif
static bool fHaveGenesis = false;
static Mutex g_genesis_wait_mutex;
@@ -855,12 +858,6 @@ void InitLogging()
{
LogInstance().m_print_to_file = !gArgs.IsArgNegated("-debuglogfile");
LogInstance().m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
-
- // Add newlines to the logfile to distinguish this execution from the last
- // one; called before console logging is set up, so this is only sent to
- // debug.log.
- LogPrintf("\n\n\n\n\n");
-
LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
LogInstance().m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
LogInstance().m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
@@ -1177,15 +1174,6 @@ bool AppInitParameterInteraction()
nMaxTipAge = gArgs.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
- fEnableReplacement = gArgs.GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT);
- if ((!fEnableReplacement) && gArgs.IsArgSet("-mempoolreplacement")) {
- // Minimal effort at forwards compatibility
- std::string strReplacementModeList = gArgs.GetArg("-mempoolreplacement", ""); // default is impossible
- std::vector<std::string> vstrReplacementModes;
- boost::split(vstrReplacementModes, strReplacementModeList, boost::is_any_of(","));
- fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end());
- }
-
return true;
}
@@ -1197,7 +1185,7 @@ static bool LockDataDirectory(bool probeOnly)
return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), datadir.string()));
}
if (!LockDirectory(datadir, ".lock", probeOnly)) {
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), datadir.string(), _(PACKAGE_NAME)));
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), datadir.string(), PACKAGE_NAME));
}
return true;
}
@@ -1215,7 +1203,7 @@ bool AppInitSanityChecks()
// Sanity check
if (!InitSanityCheck())
- return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
+ return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME));
// Probe the data directory lock to give an early error message, if possible
// We cannot hold the data directory lock here, as the forking for daemon() hasn't yet happened,
@@ -1249,10 +1237,10 @@ bool AppInitMain(InitInterfaces& interfaces)
// and because this needs to happen before any other debug.log printing
LogInstance().ShrinkDebugFile();
}
- if (!LogInstance().OpenDebugLog()) {
+ }
+ if (!LogInstance().StartLogging()) {
return InitError(strprintf("Could not open debug log file %s",
LogInstance().m_file_path.string()));
- }
}
if (!LogInstance().m_log_timestamps)
@@ -1693,7 +1681,7 @@ bool AppInitMain(InitInterfaces& interfaces)
nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
if (!fReindex) {
uiInterface.InitMessage(_("Pruning blockstore..."));
- PruneAndFlush();
+ ::ChainstateActive().PruneAndFlush();
}
}
@@ -1726,8 +1714,10 @@ bool AppInitMain(InitInterfaces& interfaces)
fHaveGenesis = true;
}
+#if HAVE_SYSTEM
if (gArgs.IsArgSet("-blocknotify"))
uiInterface.NotifyBlockTip_connect(BlockNotifyCallback);
+#endif
std::vector<fs::path> vImportFiles;
for (const std::string& strFile : gArgs.GetArgs("-loadblock")) {
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index a864f21f04..02f39cef8e 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -205,7 +205,7 @@ public:
class RpcHandlerImpl : public Handler
{
public:
- RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
+ explicit RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
{
m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
if (!m_wrapped_command) return false;
@@ -334,8 +334,8 @@ public:
return ::fHavePruned;
}
bool p2pEnabled() override { return g_connman != nullptr; }
- bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !IsInitialBlockDownload(); }
- bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
+ bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); }
+ bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
bool shutdownRequested() override { return ShutdownRequested(); }
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 618cd02ea6..584d218dba 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -23,7 +23,6 @@
#include <policy/settings.h>
#include <primitives/block.h>
#include <rpc/server.h>
-#include <scheduler.h>
#include <shutdown.h>
#include <sync.h>
#include <txmempool.h>
@@ -197,7 +196,7 @@ public:
}
return GuessVerificationProgress(Params().TxData(), tip);
}
- bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
+ bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
bool getReindex() override { return ::fReindex; }
bool getImporting() override { return ::fImporting; }
void setNetworkActive(bool active) override
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index b57299d78d..34c982e1e6 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -5,29 +5,21 @@
#include <interfaces/wallet.h>
#include <amount.h>
-#include <chain.h>
#include <consensus/validation.h>
-#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/handler.h>
-#include <net.h>
#include <policy/feerate.h>
#include <policy/fees.h>
-#include <policy/policy.h>
#include <primitives/transaction.h>
-#include <rpc/server.h>
-#include <scheduler.h>
-#include <script/ismine.h>
#include <script/standard.h>
#include <support/allocators/secure.h>
#include <sync.h>
-#include <timedata.h>
#include <ui_interface.h>
#include <uint256.h>
#include <util/system.h>
-#include <validation.h>
#include <wallet/feebumper.h>
#include <wallet/fees.h>
+#include <wallet/ismine.h>
#include <wallet/rpcwallet.h>
#include <wallet/load.h>
#include <wallet/wallet.h>
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 7096f54047..9c9b29a813 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -7,7 +7,6 @@
#include <amount.h> // For CAmount
#include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation)
-#include <script/ismine.h> // For isminefilter, isminetype
#include <script/standard.h> // For CTxDestination
#include <support/allocators/secure.h> // For SecureString
#include <ui_interface.h> // For ChangeType
@@ -25,7 +24,10 @@ class CCoinControl;
class CFeeRate;
class CKey;
class CWallet;
+enum isminetype : unsigned int;
enum class FeeReason;
+typedef uint8_t isminefilter;
+
enum class OutputType;
struct CRecipient;
diff --git a/src/key.cpp b/src/key.cpp
index c17f6a0ae2..3ba21753a2 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -5,7 +5,6 @@
#include <key.h>
-#include <arith_uint256.h>
#include <crypto/common.h>
#include <crypto/hmac_sha512.h>
#include <random.h>
diff --git a/src/logging.cpp b/src/logging.cpp
index 3eda4995db..dc2d130a2a 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -39,28 +39,50 @@ static int FileWriteStr(const std::string &str, FILE *fp)
return fwrite(str.data(), 1, str.size(), fp);
}
-bool BCLog::Logger::OpenDebugLog()
+bool BCLog::Logger::StartLogging()
{
- std::lock_guard<std::mutex> scoped_lock(m_file_mutex);
+ std::lock_guard<std::mutex> scoped_lock(m_cs);
+ assert(m_buffering);
assert(m_fileout == nullptr);
- assert(!m_file_path.empty());
- m_fileout = fsbridge::fopen(m_file_path, "a");
- if (!m_fileout) {
- return false;
+ if (m_print_to_file) {
+ assert(!m_file_path.empty());
+ m_fileout = fsbridge::fopen(m_file_path, "a");
+ if (!m_fileout) {
+ return false;
+ }
+
+ setbuf(m_fileout, nullptr); // unbuffered
+
+ // Add newlines to the logfile to distinguish this execution from the
+ // last one.
+ FileWriteStr("\n\n\n\n\n", m_fileout);
}
- setbuf(m_fileout, nullptr); // unbuffered
// dump buffered messages from before we opened the log
+ m_buffering = false;
while (!m_msgs_before_open.empty()) {
- FileWriteStr(m_msgs_before_open.front(), m_fileout);
+ const std::string& s = m_msgs_before_open.front();
+
+ if (m_print_to_file) FileWriteStr(s, m_fileout);
+ if (m_print_to_console) fwrite(s.data(), 1, s.size(), stdout);
+
m_msgs_before_open.pop_front();
}
+ if (m_print_to_console) fflush(stdout);
return true;
}
+void BCLog::Logger::DisconnectTestLogger()
+{
+ std::lock_guard<std::mutex> scoped_lock(m_cs);
+ m_buffering = true;
+ if (m_fileout != nullptr) fclose(m_fileout);
+ m_fileout = nullptr;
+}
+
void BCLog::Logger::EnableCategory(BCLog::LogFlags flag)
{
m_categories |= flag;
@@ -202,8 +224,9 @@ std::string BCLog::Logger::LogTimestampStr(const std::string& str)
return strStamped;
}
-void BCLog::Logger::LogPrintStr(const std::string &str)
+void BCLog::Logger::LogPrintStr(const std::string& str)
{
+ std::lock_guard<std::mutex> scoped_lock(m_cs);
std::string str_prefixed = str;
if (m_log_threadnames && m_started_new_line) {
@@ -214,32 +237,31 @@ void BCLog::Logger::LogPrintStr(const std::string &str)
m_started_new_line = !str.empty() && str[str.size()-1] == '\n';
+ if (m_buffering) {
+ // buffer if we haven't started logging yet
+ m_msgs_before_open.push_back(str_prefixed);
+ return;
+ }
+
if (m_print_to_console) {
// print to console
fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
fflush(stdout);
}
if (m_print_to_file) {
- std::lock_guard<std::mutex> scoped_lock(m_file_mutex);
-
- // buffer if we haven't opened the log yet
- if (m_fileout == nullptr) {
- m_msgs_before_open.push_back(str_prefixed);
- }
- else
- {
- // reopen the log file, if requested
- if (m_reopen_file) {
- m_reopen_file = false;
- FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
- if (new_fileout) {
- setbuf(new_fileout, nullptr); // unbuffered
- fclose(m_fileout);
- m_fileout = new_fileout;
- }
+ assert(m_fileout != nullptr);
+
+ // reopen the log file, if requested
+ if (m_reopen_file) {
+ m_reopen_file = false;
+ FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
+ if (new_fileout) {
+ setbuf(new_fileout, nullptr); // unbuffered
+ fclose(m_fileout);
+ m_fileout = new_fileout;
}
- FileWriteStr(str_prefixed, m_fileout);
}
+ FileWriteStr(str_prefixed, m_fileout);
}
}
diff --git a/src/logging.h b/src/logging.h
index e399d4c307..75cd5353c0 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -60,9 +60,10 @@ namespace BCLog {
class Logger
{
private:
- FILE* m_fileout = nullptr;
- std::mutex m_file_mutex;
- std::list<std::string> m_msgs_before_open;
+ mutable std::mutex m_cs; // Can not use Mutex from sync.h because in debug mode it would cause a deadlock when a potential deadlock was detected
+ FILE* m_fileout = nullptr; // GUARDED_BY(m_cs)
+ std::list<std::string> m_msgs_before_open; // GUARDED_BY(m_cs)
+ bool m_buffering{true}; //!< Buffer messages before logging can be started. GUARDED_BY(m_cs)
/**
* m_started_new_line is a state variable that will suppress printing of
@@ -88,12 +89,20 @@ namespace BCLog {
std::atomic<bool> m_reopen_file{false};
/** Send a string to the log output */
- void LogPrintStr(const std::string &str);
+ void LogPrintStr(const std::string& str);
/** Returns whether logs will be written to any output */
- bool Enabled() const { return m_print_to_console || m_print_to_file; }
+ bool Enabled() const
+ {
+ std::lock_guard<std::mutex> scoped_lock(m_cs);
+ return m_buffering || m_print_to_console || m_print_to_file;
+ }
+
+ /** Start logging (and flush all buffered messages) */
+ bool StartLogging();
+ /** Only for testing */
+ void DisconnectTestLogger();
- bool OpenDebugLog();
void ShrinkDebugFile();
uint32_t GetCategoryMask() const { return m_categories.load(); }
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index a54268d655..052aebbc80 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -7,7 +7,6 @@
#include <hash.h>
#include <consensus/consensus.h>
-#include <util/strencodings.h>
CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<uint256>* txids)
diff --git a/src/miner.cpp b/src/miner.cpp
index 3d53515435..015645c9c6 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -13,8 +13,6 @@
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
-#include <hash.h>
-#include <net.h>
#include <policy/feerate.h>
#include <policy/policy.h>
#include <pow.h>
@@ -24,7 +22,6 @@
#include <util/moneystr.h>
#include <util/system.h>
#include <util/validation.h>
-#include <validationinterface.h>
#include <algorithm>
#include <queue>
diff --git a/src/net.cpp b/src/net.cpp
index 3c6f5a05f3..7d11111b25 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2039,7 +2039,7 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
{
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
- strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), _(PACKAGE_NAME));
+ strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), PACKAGE_NAME);
else
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
LogPrintf("%s\n", strError);
@@ -2287,8 +2287,8 @@ public:
WSACleanup();
#endif
}
-}
-instance_of_cnetcleanup;
+};
+static CNetCleanup instance_of_cnetcleanup;
void CConnman::Interrupt()
{
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index a3b865a69e..4b43b2cdf2 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -25,9 +25,7 @@
#include <scheduler.h>
#include <tinyformat.h>
#include <txmempool.h>
-#include <ui_interface.h>
#include <util/system.h>
-#include <util/moneystr.h>
#include <util/strencodings.h>
#include <util/validation.h>
@@ -70,11 +68,13 @@ static constexpr int32_t MAX_PEER_TX_IN_FLIGHT = 100;
/** Maximum number of announced transactions from a peer */
static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 2 * MAX_INV_SZ;
/** How many microseconds to delay requesting transactions from inbound peers */
-static constexpr int64_t INBOUND_PEER_TX_DELAY = 2 * 1000000;
+static constexpr int64_t INBOUND_PEER_TX_DELAY = 2 * 1000000; // 2 seconds
/** How long to wait (in microseconds) before downloading a transaction from an additional peer */
-static constexpr int64_t GETDATA_TX_INTERVAL = 60 * 1000000;
+static constexpr int64_t GETDATA_TX_INTERVAL = 60 * 1000000; // 1 minute
/** Maximum delay (in microseconds) for transaction requests to avoid biasing some peers over others. */
-static constexpr int64_t MAX_GETDATA_RANDOM_DELAY = 2 * 1000000;
+static constexpr int64_t MAX_GETDATA_RANDOM_DELAY = 2 * 1000000; // 2 seconds
+/** How long to wait (in microseconds) before expiring an in-flight getdata request to a peer */
+static constexpr int64_t TX_EXPIRY_INTERVAL = 10 * GETDATA_TX_INTERVAL;
static_assert(INBOUND_PEER_TX_DELAY >= MAX_GETDATA_RANDOM_DELAY,
"To preserve security, MAX_GETDATA_RANDOM_DELAY should not exceed INBOUND_PEER_DELAY");
/** Limit to avoid sending big packets. Not used in processing incoming GETDATA for compatibility */
@@ -345,8 +345,11 @@ struct CNodeState {
//! Store all the transactions a peer has recently announced
std::set<uint256> m_tx_announced;
- //! Store transactions which were requested by us
- std::set<uint256> m_tx_in_flight;
+ //! Store transactions which were requested by us, with timestamp
+ std::map<uint256, int64_t> m_tx_in_flight;
+
+ //! Periodically check for stuck getdata requests
+ int64_t m_check_expiry_timer{0};
};
TxDownloadState m_tx_download;
@@ -704,30 +707,40 @@ void UpdateTxRequestTime(const uint256& txid, int64_t request_time) EXCLUSIVE_LO
}
}
-
-void RequestTx(CNodeState* state, const uint256& txid, int64_t nNow) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+int64_t CalculateTxGetDataTime(const uint256& txid, int64_t current_time, bool use_inbound_delay) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- CNodeState::TxDownloadState& peer_download_state = state->m_tx_download;
- if (peer_download_state.m_tx_announced.size() >= MAX_PEER_TX_ANNOUNCEMENTS || peer_download_state.m_tx_announced.count(txid)) {
- // Too many queued announcements from this peer, or we already have
- // this announcement
- return;
- }
- peer_download_state.m_tx_announced.insert(txid);
-
int64_t process_time;
int64_t last_request_time = GetTxRequestTime(txid);
// First time requesting this tx
if (last_request_time == 0) {
- process_time = nNow;
+ process_time = current_time;
} else {
// Randomize the delay to avoid biasing some peers over others (such as due to
// fixed ordering of peer processing in ThreadMessageHandler)
process_time = last_request_time + GETDATA_TX_INTERVAL + GetRand(MAX_GETDATA_RANDOM_DELAY);
}
- // We delay processing announcements from non-preferred (eg inbound) peers
- if (!state->fPreferredDownload) process_time += INBOUND_PEER_TX_DELAY;
+ // We delay processing announcements from inbound peers
+ if (use_inbound_delay) process_time += INBOUND_PEER_TX_DELAY;
+
+ return process_time;
+}
+
+void RequestTx(CNodeState* state, const uint256& txid, int64_t nNow) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+{
+ CNodeState::TxDownloadState& peer_download_state = state->m_tx_download;
+ if (peer_download_state.m_tx_announced.size() >= MAX_PEER_TX_ANNOUNCEMENTS ||
+ peer_download_state.m_tx_process_time.size() >= MAX_PEER_TX_ANNOUNCEMENTS ||
+ peer_download_state.m_tx_announced.count(txid)) {
+ // Too many queued announcements from this peer, or we already have
+ // this announcement
+ return;
+ }
+ peer_download_state.m_tx_announced.insert(txid);
+
+ // Calculate the time to try requesting this transaction. Use
+ // fPreferredDownload as a proxy for outbound peers.
+ int64_t process_time = CalculateTxGetDataTime(txid, nNow, !state->fPreferredDownload);
peer_download_state.m_tx_process_time.emplace(process_time, txid);
}
@@ -1240,7 +1253,7 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
// the tip yet so we have no way to check this directly here. Instead we
// just check that there are currently no other blocks in flight.
else if (state.IsValid() &&
- !IsInitialBlockDownload() &&
+ !::ChainstateActive().IsInitialBlockDownload() &&
mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
if (it != mapBlockSource.end()) {
MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, connman);
@@ -1542,16 +1555,28 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
}
}
+ // Unknown types in the GetData stay in vRecvGetData and block any future
+ // message from this peer, see vRecvGetData check in ProcessMessages().
+ // Depending on future p2p changes, we might either drop unknown getdata on
+ // the floor or disconnect the peer.
+
pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it);
if (!vNotFound.empty()) {
// Let the peer know that we didn't find what it asked for, so it doesn't
- // have to wait around forever. Currently only SPV clients actually care
- // about this message: it's needed when they are recursively walking the
- // dependencies of relevant unconfirmed transactions. SPV clients want to
- // do that because they want to know about (and store and rebroadcast and
- // risk analyze) the dependencies of transactions relevant to them, without
- // having to download the entire memory pool.
+ // have to wait around forever.
+ // SPV clients care about this message: it's needed when they are
+ // recursively walking the dependencies of relevant unconfirmed
+ // transactions. SPV clients want to do that because they want to know
+ // about (and store and rebroadcast and risk analyze) the dependencies
+ // of transactions relevant to them, without having to download the
+ // entire memory pool.
+ // Also, other nodes can use these messages to automatically request a
+ // transaction from some other peer that annnounced it, and stop
+ // waiting for us to respond.
+ // In normal operation, we often send NOTFOUND messages for parents of
+ // transactions that we relay; if a peer is missing a parent, they may
+ // assume we have them and request the parents from us.
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound));
}
}
@@ -1728,7 +1753,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
}
// If we're in IBD, we want outbound peers that will serve us a useful
// chain. Disconnect peers that are on chains with insufficient work.
- if (IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
+ if (::ChainstateActive().IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
// When nCount < MAX_HEADERS_RESULTS, we know we have no more
// headers to fetch from this peer.
if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
@@ -1994,7 +2019,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!pfrom->fInbound)
{
// Advertise our address
- if (fListen && !IsInitialBlockDownload())
+ if (fListen && !::ChainstateActive().IsInitialBlockDownload())
{
CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
FastRandomContext insecure_rand;
@@ -2229,7 +2254,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->AddInventoryKnown(inv);
if (fBlocksOnly) {
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->GetId());
- } else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload()) {
+ } else if (!fAlreadyHave && !fImporting && !fReindex && !::ChainstateActive().IsInitialBlockDownload()) {
RequestTx(State(pfrom->GetId()), inv.hash, nNow);
}
}
@@ -2387,7 +2412,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
LOCK(cs_main);
- if (IsInitialBlockDownload() && !pfrom->fWhitelisted) {
+ if (::ChainstateActive().IsInitialBlockDownload() && !pfrom->fWhitelisted) {
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->GetId());
return true;
}
@@ -2609,7 +2634,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
- if (!IsInitialBlockDownload())
+ if (!::ChainstateActive().IsInitialBlockDownload())
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
return true;
}
@@ -3148,8 +3173,27 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
if (strCommand == NetMsgType::NOTFOUND) {
- // We do not care about the NOTFOUND message, but logging an Unknown Command
- // message would be undesirable as we transmit it ourselves.
+ // Remove the NOTFOUND transactions from the peer
+ LOCK(cs_main);
+ CNodeState *state = State(pfrom->GetId());
+ std::vector<CInv> vInv;
+ vRecv >> vInv;
+ if (vInv.size() <= MAX_PEER_TX_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ for (CInv &inv : vInv) {
+ if (inv.type == MSG_TX || inv.type == MSG_WITNESS_TX) {
+ // If we receive a NOTFOUND message for a txid we requested, erase
+ // it from our data structures for this peer.
+ auto in_flight_it = state->m_tx_download.m_tx_in_flight.find(inv.hash);
+ if (in_flight_it == state->m_tx_download.m_tx_in_flight.end()) {
+ // Skip any further work if this is a spurious NOTFOUND
+ // message.
+ continue;
+ }
+ state->m_tx_download.m_tx_in_flight.erase(in_flight_it);
+ state->m_tx_download.m_tx_announced.erase(inv.hash);
+ }
+ }
+ }
return true;
}
@@ -3221,6 +3265,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
return false;
// this maintains the order of responses
+ // and prevents vRecvGetData to grow unbounded
if (!pfrom->vRecvGetData.empty()) return true;
if (!pfrom->orphan_work_set.empty()) return true;
@@ -3524,7 +3569,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Address refresh broadcast
int64_t nNow = GetTimeMicros();
- if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
+ if (!::ChainstateActive().IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
AdvertiseLocal(pto);
pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
@@ -3925,7 +3970,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Message: getdata (blocks)
//
std::vector<CInv> vGetData;
- if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !::ChainstateActive().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
std::vector<const CBlockIndex*> vToDownload;
NodeId staller = -1;
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
@@ -3947,9 +3992,33 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
//
// Message: getdata (non-blocks)
//
+
+ // For robustness, expire old requests after a long timeout, so that
+ // we can resume downloading transactions from a peer even if they
+ // were unresponsive in the past.
+ // Eventually we should consider disconnecting peers, but this is
+ // conservative.
+ if (state.m_tx_download.m_check_expiry_timer <= nNow) {
+ for (auto it=state.m_tx_download.m_tx_in_flight.begin(); it != state.m_tx_download.m_tx_in_flight.end();) {
+ if (it->second <= nNow - TX_EXPIRY_INTERVAL) {
+ LogPrint(BCLog::NET, "timeout of inflight tx %s from peer=%d\n", it->first.ToString(), pto->GetId());
+ state.m_tx_download.m_tx_announced.erase(it->first);
+ state.m_tx_download.m_tx_in_flight.erase(it++);
+ } else {
+ ++it;
+ }
+ }
+ // On average, we do this check every TX_EXPIRY_INTERVAL. Randomize
+ // so that we're not doing this for all peers at the same time.
+ state.m_tx_download.m_check_expiry_timer = nNow + TX_EXPIRY_INTERVAL/2 + GetRand(TX_EXPIRY_INTERVAL);
+ }
+
auto& tx_process_time = state.m_tx_download.m_tx_process_time;
while (!tx_process_time.empty() && tx_process_time.begin()->first <= nNow && state.m_tx_download.m_tx_in_flight.size() < MAX_PEER_TX_IN_FLIGHT) {
- const uint256& txid = tx_process_time.begin()->second;
+ const uint256 txid = tx_process_time.begin()->second;
+ // Erase this entry from tx_process_time (it may be added back for
+ // processing at a later time, see below)
+ tx_process_time.erase(tx_process_time.begin());
CInv inv(MSG_TX | GetFetchFlags(pto), txid);
if (!AlreadyHave(inv)) {
// If this transaction was last requested more than 1 minute ago,
@@ -3963,20 +4032,20 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
vGetData.clear();
}
UpdateTxRequestTime(inv.hash, nNow);
- state.m_tx_download.m_tx_in_flight.insert(inv.hash);
+ state.m_tx_download.m_tx_in_flight.emplace(inv.hash, nNow);
} else {
// This transaction is in flight from someone else; queue
// up processing to happen after the download times out
// (with a slight delay for inbound peers, to prefer
// requests to outbound peers).
- RequestTx(&state, txid, nNow);
+ int64_t next_process_time = CalculateTxGetDataTime(txid, nNow, !state.fPreferredDownload);
+ tx_process_time.emplace(next_process_time, txid);
}
} else {
// We have already seen this transaction, no need to download.
state.m_tx_download.m_tx_announced.erase(inv.hash);
state.m_tx_download.m_tx_in_flight.erase(inv.hash);
}
- tx_process_time.erase(tx_process_time.begin());
}
@@ -4023,4 +4092,5 @@ public:
mapOrphanTransactions.clear();
mapOrphanTransactionsByPrev.clear();
}
-} instance_of_cnetprocessingcleanup;
+};
+static CNetProcessingCleanup instance_of_cnetprocessingcleanup;
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 6ee2d8a4b3..4fbfa2b5c8 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -204,6 +204,11 @@ bool CNetAddr::IsRFC4843() const
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
}
+bool CNetAddr::IsRFC7343() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x20);
+}
+
/**
* @returns Whether or not this is a dummy address that maps an onion address
* into IPv6.
@@ -234,7 +239,7 @@ bool CNetAddr::IsLocal() const
* be used to refer to an actual host.
*
* @note A valid address may or may not be publicly routable on the global
- * internet. As in, the set of valid addreses is a superset of the set of
+ * internet. As in, the set of valid addresses is a superset of the set of
* publicly routable addresses.
*
* @see CNetAddr::IsRoutable()
@@ -282,14 +287,14 @@ bool CNetAddr::IsValid() const
* @returns Whether or not this network address is publicly routable on the
* global internet.
*
- * @note A routable address is always valid. As in, the set of routable addreses
+ * @note A routable address is always valid. As in, the set of routable addresses
* is a subset of the set of valid addresses.
*
* @see CNetAddr::IsValid()
*/
bool CNetAddr::IsRoutable() const
{
- return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal() || IsInternal());
+ return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsRFC7343() || IsLocal() || IsInternal());
}
/**
diff --git a/src/netaddress.h b/src/netaddress.h
index 8230e40606..673eaf8d7b 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -63,7 +63,8 @@ class CNetAddr
bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16)
bool IsRFC4193() const; // IPv6 unique local (FC00::/7)
bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32)
- bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28)
+ bool IsRFC4843() const; // IPv6 ORCHID (deprecated) (2001:10::/28)
+ bool IsRFC7343() const; // IPv6 ORCHIDv2 (2001:20::/28)
bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
bool IsRFC6052() const; // IPv6 well-known prefix for IPv4-embedded address (64:FF9B::/96)
bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) (actually defined in RFC2765)
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 6c386a9ade..78b3b6ae3a 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -5,10 +5,7 @@
#include <netbase.h>
-#include <hash.h>
#include <sync.h>
-#include <uint256.h>
-#include <random.h>
#include <tinyformat.h>
#include <util/system.h>
#include <util/strencodings.h>
diff --git a/src/noui.cpp b/src/noui.cpp
index c7d8fee0ba..caab9f326e 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -18,26 +18,30 @@ bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& ca
{
bool fSecure = style & CClientUIInterface::SECURE;
style &= ~CClientUIInterface::SECURE;
+ bool prefix = !(style & CClientUIInterface::MSG_NOPREFIX);
+ style &= ~CClientUIInterface::MSG_NOPREFIX;
std::string strCaption;
- // Check for usage of predefined caption
- switch (style) {
- case CClientUIInterface::MSG_ERROR:
- strCaption += _("Error");
- break;
- case CClientUIInterface::MSG_WARNING:
- strCaption += _("Warning");
- break;
- case CClientUIInterface::MSG_INFORMATION:
- strCaption += _("Information");
- break;
- default:
- strCaption += caption; // Use supplied caption (can be empty)
+ if (prefix) {
+ switch (style) {
+ case CClientUIInterface::MSG_ERROR:
+ strCaption = "Error: ";
+ break;
+ case CClientUIInterface::MSG_WARNING:
+ strCaption = "Warning: ";
+ break;
+ case CClientUIInterface::MSG_INFORMATION:
+ strCaption = "Information: ";
+ break;
+ default:
+ strCaption = caption + ": "; // Use supplied caption (can be empty)
+ }
}
- if (!fSecure)
- LogPrintf("%s: %s\n", strCaption, message);
- fprintf(stderr, "%s: %s\n", strCaption.c_str(), message.c_str());
+ if (!fSecure) {
+ LogPrintf("%s%s\n", strCaption, message);
+ }
+ tfm::format(std::cerr, "%s%s\n", strCaption.c_str(), message.c_str());
return false;
}
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 6456eec016..5d538606c2 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -4,7 +4,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <policy/fees.h>
-#include <policy/policy.h>
#include <clientversion.h>
#include <primitives/transaction.h>
@@ -48,7 +47,7 @@ private:
std::vector<double> txCtAvg;
// Count the total # of txs confirmed within Y blocks in each bucket
- // Track the historical moving average of theses totals over blocks
+ // Track the historical moving average of these totals over blocks
std::vector<std::vector<double>> confAvg; // confAvg[Y][X]
// Track moving avg of txs which have been evicted from the mempool
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 6e61f76178..16683bf5ad 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -43,7 +43,6 @@ enum class FeeReason {
PAYTXFEE,
FALLBACK,
REQUIRED,
- MAXTXFEE,
};
/* Used to determine type of fee estimation requested */
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 63a3d06267..51de5841ec 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -9,10 +9,6 @@
#include <consensus/validation.h>
#include <coins.h>
-#include <policy/settings.h>
-#include <tinyformat.h>
-#include <util/system.h>
-#include <util/strencodings.h>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
diff --git a/src/prevector.h b/src/prevector.h
index ea8707389a..9d576321b6 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -378,6 +378,21 @@ public:
fill(ptr, first, last);
}
+ inline void resize_uninitialized(size_type new_size) {
+ // resize_uninitialized changes the size of the prevector but does not initialize it.
+ // If size < new_size, the added elements must be initialized explicitly.
+ if (capacity() < new_size) {
+ change_capacity(new_size);
+ _size += new_size - size();
+ return;
+ }
+ if (new_size < size()) {
+ erase(item_ptr(new_size), end());
+ } else {
+ _size += new_size - size();
+ }
+ }
+
iterator erase(iterator pos) {
return erase(pos, pos + 1);
}
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index a0c2e3f125..60c7c2d160 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -7,7 +7,6 @@
#include <hash.h>
#include <tinyformat.h>
-#include <util/strencodings.h>
#include <crypto/common.h>
uint256 CBlockHeader::GetHash() const
diff --git a/src/psbt.cpp b/src/psbt.cpp
index 97bda51a63..fe74002e82 100644
--- a/src/psbt.cpp
+++ b/src/psbt.cpp
@@ -2,9 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <coins.h>
-#include <consensus/tx_verify.h>
-#include <policy/policy.h>
#include <psbt.h>
#include <util/strencodings.h>
@@ -215,6 +212,25 @@ bool PSBTInputSigned(const PSBTInput& input)
return !input.final_script_sig.empty() || !input.final_script_witness.IsNull();
}
+void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index)
+{
+ const CTxOut& out = psbt.tx->vout.at(index);
+ PSBTOutput& psbt_out = psbt.outputs.at(index);
+
+ // Fill a SignatureData with output info
+ SignatureData sigdata;
+ psbt_out.FillSignatureData(sigdata);
+
+ // Construct a would-be spend of this output, to update sigdata with.
+ // Note that ProduceSignature is used to fill in metadata (not actual signatures),
+ // so provider does not need to provide any private keys (it can be a HidingSigningProvider).
+ MutableTransactionSignatureCreator creator(psbt.tx.get_ptr(), /* index */ 0, out.nValue, SIGHASH_ALL);
+ ProduceSignature(provider, creator, out.scriptPubKey, sigdata);
+
+ // Put redeem_script, witness_script, key paths, into PSBTOutput.
+ psbt_out.FromSignatureData(sigdata);
+}
+
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash, SignatureData* out_sigdata, bool use_dummy)
{
PSBTInput& input = psbt.inputs.at(index);
diff --git a/src/psbt.h b/src/psbt.h
index 1bc1e91a84..f3840b9ed3 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -565,6 +565,12 @@ bool PSBTInputSigned(const PSBTInput& input);
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool use_dummy = false);
+/** Updates a PSBTOutput with information from provider.
+ *
+ * This fills in the redeem_script, witness_script, and hd_keypaths where possible.
+ */
+void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index);
+
/**
* Finalizes a PSBT if possible, combining partial signatures.
*
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 50d6afabcd..d8c39e8862 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -10,7 +10,6 @@
#include <qt/forms/ui_addressbookpage.h>
#include <qt/addresstablemodel.h>
-#include <qt/bitcoingui.h>
#include <qt/csvmodelwriter.h>
#include <qt/editaddressdialog.h>
#include <qt/guiutil.h>
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index c3143e948a..fa6c9c9f7a 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -7,7 +7,6 @@
#include <qt/guiutil.h>
#include <qt/walletmodel.h>
-#include <interfaces/node.h>
#include <key_io.h>
#include <wallet/wallet.h>
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index 00c446cc63..8a6b205cd8 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -5,8 +5,6 @@
#include <qt/bantablemodel.h>
#include <qt/clientmodel.h>
-#include <qt/guiconstants.h>
-#include <qt/guiutil.h>
#include <interfaces/node.h>
#include <sync.h>
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 81255aaae9..cf0b48b545 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -31,13 +31,9 @@
#include <interfaces/node.h>
#include <noui.h>
#include <util/threadnames.h>
-#include <rpc/server.h>
#include <ui_interface.h>
#include <uint256.h>
#include <util/system.h>
-#include <warnings.h>
-
-#include <walletinitinterface.h>
#include <memory>
#include <stdint.h>
@@ -334,7 +330,7 @@ void BitcoinApplication::initializeResult(bool success)
if(success)
{
// Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
- qWarning() << "Platform customization:" << platformStyle->getName();
+ qInfo() << "Platform customization:" << platformStyle->getName();
#ifdef ENABLE_WALLET
m_wallet_controller = new WalletController(m_node, platformStyle, optionsModel, this);
#ifdef ENABLE_BIP70
@@ -417,7 +413,6 @@ static void SetupUIArgs()
gArgs.AddArg("-uiplatform", strprintf("Select platform to customize UI for (one of windows, macosx, other; default: %s)", BitcoinGUI::DEFAULT_UIPLATFORM), true, OptionsCategory::GUI);
}
-#ifndef BITCOIN_QT_TEST
int GuiMain(int argc, char* argv[])
{
#ifdef WIN32
@@ -440,16 +435,17 @@ int GuiMain(int argc, char* argv[])
Q_INIT_RESOURCE(bitcoin);
Q_INIT_RESOURCE(bitcoin_locale);
- BitcoinApplication app(*node, argc, argv);
// Generate high-dpi pixmaps
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#if QT_VERSION >= 0x050600
- QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
#ifdef Q_OS_MAC
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
#endif
+ BitcoinApplication app(*node, argc, argv);
+
// Register meta types used for QMetaObject::invokeMethod
qRegisterMetaType< bool* >();
// Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
@@ -463,7 +459,7 @@ int GuiMain(int argc, char* argv[])
SetupUIArgs();
std::string error;
if (!node->parseParameters(argc, argv, error)) {
- QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME),
+ QMessageBox::critical(nullptr, PACKAGE_NAME,
QObject::tr("Error parsing command line arguments: %1.").arg(QString::fromStdString(error)));
return EXIT_FAILURE;
}
@@ -500,12 +496,12 @@ int GuiMain(int argc, char* argv[])
/// - Do not call GetDataDir(true) before this step finishes
if (!fs::is_directory(GetDataDir(false)))
{
- QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME),
+ QMessageBox::critical(nullptr, PACKAGE_NAME,
QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", ""))));
return EXIT_FAILURE;
}
if (!node->readConfigFiles(error)) {
- QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME),
+ QMessageBox::critical(nullptr, PACKAGE_NAME,
QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error)));
return EXIT_FAILURE;
}
@@ -520,7 +516,7 @@ int GuiMain(int argc, char* argv[])
try {
node->selectParams(gArgs.GetChainName());
} catch(std::exception &e) {
- QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what()));
+ QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(e.what()));
return EXIT_FAILURE;
}
#ifdef ENABLE_WALLET
@@ -577,7 +573,7 @@ int GuiMain(int argc, char* argv[])
if (app.baseInitialize()) {
app.requestInitialize();
#if defined(Q_OS_WIN)
- WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
+ WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(PACKAGE_NAME), (HWND)app.getMainWinId());
#endif
app.exec();
app.requestShutdown();
@@ -596,4 +592,3 @@ int GuiMain(int argc, char* argv[])
}
return rv;
}
-#endif // BITCOIN_QT_TEST
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index ff66df376b..266e16ebeb 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -294,15 +294,15 @@ void BitcoinGUI::createActions()
quitAction->setStatusTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
- aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About %1").arg(tr(PACKAGE_NAME)), this);
- aboutAction->setStatusTip(tr("Show information about %1").arg(tr(PACKAGE_NAME)));
+ aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About %1").arg(PACKAGE_NAME), this);
+ aboutAction->setStatusTip(tr("Show information about %1").arg(PACKAGE_NAME));
aboutAction->setMenuRole(QAction::AboutRole);
aboutAction->setEnabled(false);
aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this);
- optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(tr(PACKAGE_NAME)));
+ optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(PACKAGE_NAME));
optionsAction->setMenuRole(QAction::PreferencesRole);
optionsAction->setEnabled(false);
toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
@@ -335,15 +335,16 @@ void BitcoinGUI::createActions()
openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
m_open_wallet_action = new QAction(tr("Open Wallet"), this);
- m_open_wallet_action->setMenu(new QMenu(this));
+ m_open_wallet_action->setEnabled(false);
m_open_wallet_action->setStatusTip(tr("Open a wallet"));
+ m_open_wallet_menu = new QMenu(this);
m_close_wallet_action = new QAction(tr("Close Wallet..."), this);
m_close_wallet_action->setStatusTip(tr("Close wallet"));
showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
showHelpMessageAction->setMenuRole(QAction::NoRole);
- showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(tr(PACKAGE_NAME)));
+ showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(PACKAGE_NAME));
connect(quitAction, &QAction::triggered, qApp, QApplication::quit);
connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked);
@@ -368,15 +369,14 @@ void BitcoinGUI::createActions()
connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses);
connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedReceivingAddresses);
connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked);
- connect(m_open_wallet_action->menu(), &QMenu::aboutToShow, [this] {
- m_open_wallet_action->menu()->clear();
- std::vector<std::string> available_wallets = m_wallet_controller->getWalletsAvailableToOpen();
- std::vector<std::string> wallets = m_node.listWalletDir();
- for (const auto& path : wallets) {
+ connect(m_open_wallet_menu, &QMenu::aboutToShow, [this] {
+ m_open_wallet_menu->clear();
+ for (const std::pair<const std::string, bool>& i : m_wallet_controller->listWalletDir()) {
+ const std::string& path = i.first;
QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
- QAction* action = m_open_wallet_action->menu()->addAction(name);
+ QAction* action = m_open_wallet_menu->addAction(name);
- if (std::find(available_wallets.begin(), available_wallets.end(), path) == available_wallets.end()) {
+ if (i.second) {
// This wallet is already loaded
action->setEnabled(false);
continue;
@@ -409,8 +409,8 @@ void BitcoinGUI::createActions()
assert(invoked);
});
}
- if (wallets.empty()) {
- QAction* action = m_open_wallet_action->menu()->addAction(tr("No wallets available"));
+ if (m_open_wallet_menu->isEmpty()) {
+ QAction* action = m_open_wallet_menu->addAction(tr("No wallets available"));
action->setEnabled(false);
}
});
@@ -633,10 +633,13 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller)
m_wallet_controller = wallet_controller;
+ m_open_wallet_action->setEnabled(true);
+ m_open_wallet_action->setMenu(m_open_wallet_menu);
+
connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet);
connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet);
- for (WalletModel* wallet_model : m_wallet_controller->getWallets()) {
+ for (WalletModel* wallet_model : m_wallet_controller->getOpenWallets()) {
addWallet(wallet_model);
}
}
@@ -725,7 +728,7 @@ void BitcoinGUI::createTrayIcon()
#ifndef Q_OS_MAC
if (QSystemTrayIcon::isSystemTrayAvailable()) {
trayIcon = new QSystemTrayIcon(m_network_style->getTrayAndWindowIcon(), this);
- QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + m_network_style->getTitleAddText();
+ QString toolTip = tr("%1 client").arg(PACKAGE_NAME) + " " + m_network_style->getTitleAddText();
trayIcon->setToolTip(toolTip);
}
#endif
@@ -1035,49 +1038,51 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
progressBar->setToolTip(tooltip);
}
-void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, bool *ret)
+void BitcoinGUI::message(const QString& title, QString message, unsigned int style, bool* ret)
{
- QString strTitle = tr("Bitcoin"); // default title
+ // Default title. On macOS, the window title is ignored (as required by the macOS Guidelines).
+ QString strTitle{PACKAGE_NAME};
// Default to information icon
int nMBoxIcon = QMessageBox::Information;
int nNotifyIcon = Notificator::Information;
- QString msgType;
+ bool prefix = !(style & CClientUIInterface::MSG_NOPREFIX);
+ style &= ~CClientUIInterface::MSG_NOPREFIX;
- // Prefer supplied title over style based title
+ QString msgType;
if (!title.isEmpty()) {
msgType = title;
- }
- else {
+ } else {
switch (style) {
case CClientUIInterface::MSG_ERROR:
msgType = tr("Error");
+ if (prefix) message = tr("Error: %1").arg(message);
break;
case CClientUIInterface::MSG_WARNING:
msgType = tr("Warning");
+ if (prefix) message = tr("Warning: %1").arg(message);
break;
case CClientUIInterface::MSG_INFORMATION:
msgType = tr("Information");
+ // No need to prepend the prefix here.
break;
default:
break;
}
}
- // Append title to "Bitcoin - "
- if (!msgType.isEmpty())
+
+ if (!msgType.isEmpty()) {
strTitle += " - " + msgType;
+ }
- // Check for error/warning icon
if (style & CClientUIInterface::ICON_ERROR) {
nMBoxIcon = QMessageBox::Critical;
nNotifyIcon = Notificator::Critical;
- }
- else if (style & CClientUIInterface::ICON_WARNING) {
+ } else if (style & CClientUIInterface::ICON_WARNING) {
nMBoxIcon = QMessageBox::Warning;
nNotifyIcon = Notificator::Warning;
}
- // Display message
if (style & CClientUIInterface::MODAL) {
// Check for buttons, use OK as default, if none was supplied
QMessageBox::StandardButton buttons;
@@ -1090,9 +1095,9 @@ void BitcoinGUI::message(const QString &title, const QString &message, unsigned
int r = mBox.exec();
if (ret != nullptr)
*ret = r == QMessageBox::Ok;
- }
- else
+ } else {
notificator->notify(static_cast<Notificator::Class>(nNotifyIcon), strTitle, message);
+ }
}
void BitcoinGUI::changeEvent(QEvent *e)
@@ -1286,7 +1291,7 @@ void BitcoinGUI::updateProxyIcon()
void BitcoinGUI::updateWindowTitle()
{
- QString window_title = tr(PACKAGE_NAME);
+ QString window_title = PACKAGE_NAME;
#ifdef ENABLE_WALLET
if (walletFrame) {
WalletModel* const wallet_model = walletFrame->currentWalletModel();
@@ -1341,6 +1346,7 @@ void BitcoinGUI::showProgress(const QString &title, int nProgress)
if (progressDialog) {
progressDialog->close();
progressDialog->deleteLater();
+ progressDialog = nullptr;
}
} else if (progressDialog) {
progressDialog->setValue(nProgress);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index b58ccbb455..46ced79007 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -148,6 +148,7 @@ private:
QAction* openAction = nullptr;
QAction* showHelpMessageAction = nullptr;
QAction* m_open_wallet_action{nullptr};
+ QMenu* m_open_wallet_menu{nullptr};
QAction* m_close_wallet_action{nullptr};
QAction* m_wallet_selector_label_action = nullptr;
QAction* m_wallet_selector_action = nullptr;
@@ -219,7 +220,7 @@ public Q_SLOTS:
@see CClientUIInterface::MessageBoxFlags
@param[in] ret pointer to a bool that will be modified to whether Ok was clicked (modal only)
*/
- void message(const QString &title, const QString &message, unsigned int style, bool *ret = nullptr);
+ void message(const QString& title, QString message, unsigned int style, bool* ret = nullptr);
#ifdef ENABLE_WALLET
void setCurrentWallet(WalletModel* wallet_model);
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index dc997e96cc..87736cd185 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -9,14 +9,13 @@
#define UNUSED
#endif
static const char UNUSED *bitcoin_strings[] = {
-QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin Core"),
QT_TRANSLATE_NOOP("bitcoin-core", "The %s developers"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"-maxtxfee is set very high! Fees this large could be paid on a single "
"transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Can't generate a change-address key. Private keys are disabled for this "
-"wallet."),
+"Can't generate a change-address key. No keys in the internal keypool and "
+"can't generate any keys."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. %s is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -88,9 +87,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: The network does not appear to fully agree! Some miners appear to "
"be experiencing issues."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Warning: Unknown block versions being mined! It's possible unknown rules are "
-"in effect"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; "
"if your balance or transactions are incorrect you should restore from a "
"backup."),
@@ -124,15 +120,13 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet %s. Duplicate -wallet fi
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error upgrading chainstate database"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: A fatal internal error occurred, see debug.log for details"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low for %s"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is too low!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to rescan the wallet during initialization"),
QT_TRANSLATE_NOOP("bitcoin-core", "Importing..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"),
@@ -150,6 +144,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."),
QT_TRANSLATE_NOOP("bitcoin-core", "Prune cannot be configured with a negative value."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -blockfilterindex."),
QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -txindex."),
QT_TRANSLATE_NOOP("bitcoin-core", "Pruning blockstore..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Reducing -maxconnections from %d to %d, because of system limitations."),
@@ -179,9 +174,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large for fee policy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer. %s is probably already running."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unable to create the PID file '%s': %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate initial keys"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate keys"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to start HTTP server. See debug log for details."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -blockfilterindex value %s."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported logging category %s=%s."),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading UTXO database"),
@@ -189,9 +186,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading txindex database"),
QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe characters."),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet(s)..."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Wallet %s resides outside wallet directory %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart %s to complete"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Warning"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: unknown new rules activated (versionbit %i)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Zapping all transactions from wallet..."),
};
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 8aa1fdba4d..b27f8a744f 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -4,8 +4,6 @@
#include <qt/bitcoinunits.h>
-#include <primitives/transaction.h>
-
#include <QStringList>
BitcoinUnits::BitcoinUnits(QObject *parent):
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 88a35534c2..ce950150df 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -9,18 +9,12 @@
#include <qt/guiutil.h>
#include <qt/peertablemodel.h>
-#include <chain.h>
-#include <chainparams.h>
#include <clientversion.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
-#include <validation.h>
#include <net.h>
#include <netbase.h>
-#include <txmempool.h>
-#include <ui_interface.h>
#include <util/system.h>
-#include <warnings.h>
#include <stdint.h>
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index d5dd62178f..03d18d2845 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -10,12 +10,10 @@
#include <qt/forms/ui_coincontroldialog.h>
#include <qt/addresstablemodel.h>
-#include <base58.h>
#include <qt/bitcoinunits.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
-#include <txmempool.h>
#include <qt/walletmodel.h>
#include <wallet/coincontrol.h>
@@ -23,8 +21,6 @@
#include <key_io.h>
#include <policy/fees.h>
#include <policy/policy.h>
-#include <validation.h> // For mempool
-#include <wallet/fees.h>
#include <wallet/wallet.h>
#include <QApplication>
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index f0b976001e..6e52c5e477 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -636,6 +636,9 @@
<property name="placeholderText">
<string/>
</property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
</widget>
</item>
</layout>
@@ -1480,6 +1483,19 @@
</property>
</widget>
</item>
+ <item row="18" column="0">
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
</widget>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 45f21d50fc..70e52c9f1d 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -60,6 +60,7 @@
#include <objc/objc-runtime.h>
#include <CoreServices/CoreServices.h>
+#include <QProcess>
#endif
namespace GUIUtil {
@@ -399,7 +400,15 @@ bool openBitcoinConf()
configFile.close();
/* Open bitcoin.conf with the associated application */
- return QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig)));
+ bool res = QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig)));
+#ifdef Q_OS_MAC
+ // Workaround for macOS-specific behavior; see #15409.
+ if (!res) {
+ res = QProcess::startDetached("/usr/bin/open", QStringList{"-t", boostPathToQString(pathConfig)});
+ }
+#endif
+
+ return res;
}
ToolTipToRichTextFilter::ToolTipToRichTextFilter(int _size_threshold, QObject *parent) :
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index c595361934..102e37e471 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -119,16 +119,16 @@ Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_siz
m_chain_state_size(chain_state_size)
{
ui->setupUi(this);
- ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME)));
- ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME)));
+ ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(PACKAGE_NAME));
+ ui->storageLabel->setText(ui->storageLabel->text().arg(PACKAGE_NAME));
ui->lblExplanation1->setText(ui->lblExplanation1->text()
- .arg(tr(PACKAGE_NAME))
+ .arg(PACKAGE_NAME)
.arg(m_blockchain_size)
.arg(2009)
.arg(tr("Bitcoin"))
);
- ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(tr(PACKAGE_NAME)));
+ ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(PACKAGE_NAME));
uint64_t pruneTarget = std::max<int64_t>(0, gArgs.GetArg("-prune", 0));
requiredSpace = m_blockchain_size;
@@ -145,7 +145,7 @@ Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_siz
}
requiredSpace += m_chain_state_size;
ui->sizeWarningLabel->setText(
- tr("%1 will download and store a copy of the Bitcoin block chain.").arg(tr(PACKAGE_NAME)) + " " +
+ tr("%1 will download and store a copy of the Bitcoin block chain.").arg(PACKAGE_NAME) + " " +
storageRequiresMsg.arg(requiredSpace) + " " +
tr("The wallet will also be stored in this directory.")
);
@@ -221,7 +221,7 @@ bool Intro::pickDataDirectory(interfaces::Node& node)
}
break;
} catch (const fs::filesystem_error&) {
- QMessageBox::critical(nullptr, tr(PACKAGE_NAME),
+ QMessageBox::critical(nullptr, PACKAGE_NAME,
tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir));
/* fall through, back to choosing screen */
}
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index c6ecbc3f87..bff7469071 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -59,7 +59,7 @@
<translation>&amp;Delete</translation>
</message>
<message>
- <location filename="../addressbookpage.cpp" line="+85"/>
+ <location filename="../addressbookpage.cpp" line="+84"/>
<source>Choose the address to send coins to</source>
<translation type="unfinished"></translation>
</message>
@@ -90,7 +90,7 @@
</message>
<message>
<location line="+5"/>
- <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <source>These are your Bitcoin addresses for receiving payments. Use the &apos;Create new receiving address&apos; button in the receive tab to create new addresses.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -132,7 +132,7 @@
<context>
<name>AddressTableModel</name>
<message>
- <location filename="../addresstablemodel.cpp" line="+164"/>
+ <location filename="../addresstablemodel.cpp" line="+163"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
@@ -297,7 +297,7 @@
<context>
<name>BanTableModel</name>
<message>
- <location filename="../bantablemodel.cpp" line="+88"/>
+ <location filename="../bantablemodel.cpp" line="+86"/>
<source>IP/Netmask</source>
<translation type="unfinished"></translation>
</message>
@@ -315,12 +315,12 @@
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+574"/>
+ <location line="+638"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-652"/>
+ <location line="-716"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@@ -400,12 +400,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+157"/>
+ <location line="+217"/>
<source>Wallet:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+330"/>
+ <location line="+334"/>
<source>Click to disable network activity.</source>
<translation type="unfinished"></translation>
</message>
@@ -430,12 +430,12 @@
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
- <location line="+315"/>
+ <location line="+317"/>
<source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-970"/>
+ <location line="-1036"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -465,12 +465,7 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
- <location line="+660"/>
- <source>Bitcoin</source>
- <translation>Bitcoin</translation>
- </message>
- <message>
- <location line="-733"/>
+ <location line="-73"/>
<source>&amp;Send</source>
<translation>&amp;Send</translation>
</message>
@@ -505,12 +500,12 @@
<translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation>
</message>
<message>
- <location line="+61"/>
+ <location line="+118"/>
<source>&amp;File</source>
<translation>&amp;File</translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+14"/>
<source>&amp;Settings</source>
<translation>&amp;Settings</translation>
</message>
@@ -525,7 +520,7 @@
<translation>Tabs toolbar</translation>
</message>
<message>
- <location line="-211"/>
+ <location line="-271"/>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
@@ -545,12 +540,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+10"/>
<source>&amp;Command-line options</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+484"/>
+ <location line="+540"/>
<source>%n active connection(s) to Bitcoin network</source>
<translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
@@ -591,27 +586,27 @@
<translation>Transactions after this will not yet be visible.</translation>
</message>
<message>
- <location line="+27"/>
+ <location line="+28"/>
<source>Error</source>
<translation>Error</translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>Warning</source>
<translation>Warning</translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>Information</source>
<translation>Information</translation>
</message>
<message>
- <location line="-78"/>
+ <location line="-81"/>
<source>Up to date</source>
<translation>Up to date</translation>
</message>
<message>
- <location line="-593"/>
+ <location line="-657"/>
<source>&amp;Sending addresses</source>
<translation type="unfinished"></translation>
</message>
@@ -621,12 +616,52 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+6"/>
+ <source>Open Wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Open a wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Close Wallet...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Close wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
<source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+63"/>
+ <location line="+30"/>
+ <source>default wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+13"/>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>Open Wallet Failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+15"/>
+ <source>No wallets available</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+48"/>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Window</translation>
</message>
@@ -651,7 +686,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+228"/>
+ <location line="+232"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
@@ -666,7 +701,17 @@
<translation>Catching up...</translation>
</message>
<message>
- <location line="+151"/>
+ <location line="+50"/>
+ <source>Error: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Warning: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+99"/>
<source>Date: %1
</source>
<translation type="unfinished"></translation>
@@ -737,7 +782,7 @@
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+395"/>
+ <location filename="../bitcoin.cpp" line="+390"/>
<source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
<translation type="unfinished"></translation>
</message>
@@ -830,7 +875,7 @@
<translation type="unfinished">Confirmed</translation>
</message>
<message>
- <location filename="../coincontroldialog.cpp" line="+58"/>
+ <location filename="../coincontroldialog.cpp" line="+54"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
@@ -1031,7 +1076,7 @@
<context>
<name>HelpMessageDialog</name>
<message>
- <location filename="../utilitydialog.cpp" line="+44"/>
+ <location filename="../utilitydialog.cpp" line="+39"/>
<source>version</source>
<translation type="unfinished">version</translation>
</message>
@@ -1120,7 +1165,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+80"/>
+ <location line="+75"/>
<source>Error: Specified data directory &quot;%1&quot; cannot be created.</source>
<translation type="unfinished"></translation>
</message>
@@ -1171,7 +1216,7 @@
<message>
<location line="+7"/>
<location line="+26"/>
- <location filename="../modaloverlay.cpp" line="+140"/>
+ <location filename="../modaloverlay.cpp" line="+141"/>
<source>Unknown...</source>
<translation type="unfinished"></translation>
</message>
@@ -1207,8 +1252,8 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../modaloverlay.cpp" line="-1"/>
- <source>Unknown. Syncing Headers (%1)...</source>
+ <location filename="../modaloverlay.cpp" line="+6"/>
+ <source>Unknown. Syncing Headers (%1, %2%)...</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -1540,12 +1585,12 @@
<translation>default</translation>
</message>
<message>
- <location line="+63"/>
+ <location line="+67"/>
<source>none</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+93"/>
+ <location line="+89"/>
<source>Confirm options reset</source>
<translation>Confirm options reset</translation>
</message>
@@ -1689,7 +1734,7 @@
<name>PaymentServer</name>
<message>
<location filename="../paymentserver.cpp" line="+226"/>
- <location line="+338"/>
+ <location line="+346"/>
<location line="+42"/>
<location line="+110"/>
<location line="+14"/>
@@ -1698,7 +1743,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-521"/>
+ <location line="-529"/>
<source>Cannot start bitcoin: click-to-pay handler</source>
<translation type="unfinished"></translation>
</message>
@@ -1706,14 +1751,14 @@
<location line="+62"/>
<location line="+9"/>
<location line="+16"/>
+ <location line="+16"/>
<location line="+5"/>
- <location line="+12"/>
<location line="+7"/>
<source>URI handling</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-49"/>
+ <location line="-53"/>
<source>&apos;bitcoin://&apos; is not a valid URI. Use &apos;bitcoin:&apos; instead.</source>
<translation type="unfinished"></translation>
</message>
@@ -1728,12 +1773,13 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+16"/>
+ <location line="+36"/>
<source>Cannot process payment request because BIP70 support was not compiled in.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <location line="-32"/>
<source>Invalid payment address %1</source>
<translation type="unfinished"></translation>
</message>
@@ -1744,16 +1790,17 @@
</message>
<message>
<location line="+14"/>
+ <location line="+9"/>
<source>Payment request file handling</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="-8"/>
<source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+195"/>
+ <location line="+199"/>
<location line="+9"/>
<location line="+31"/>
<location line="+10"/>
@@ -1832,7 +1879,7 @@
<context>
<name>PeerTableModel</name>
<message>
- <location filename="../peertablemodel.cpp" line="+109"/>
+ <location filename="../peertablemodel.cpp" line="+108"/>
<source>User Agent</source>
<translation type="unfinished"></translation>
</message>
@@ -1865,17 +1912,17 @@
<context>
<name>QObject</name>
<message>
- <location filename="../bitcoinunits.cpp" line="+197"/>
+ <location filename="../bitcoinunits.cpp" line="+195"/>
<source>Amount</source>
<translation type="unfinished">Amount</translation>
</message>
<message>
- <location filename="../guiutil.cpp" line="+111"/>
+ <location filename="../guiutil.cpp" line="+108"/>
<source>Enter a Bitcoin address (e.g. %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+687"/>
+ <location line="+702"/>
<source>%1 d</source>
<translation type="unfinished"></translation>
</message>
@@ -1985,20 +2032,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+185"/>
- <source>%1 didn&apos;t yet exit safely...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../modaloverlay.cpp" line="-29"/>
- <source>unknown</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QObject::QObject</name>
- <message>
- <location filename="../bitcoin.cpp" line="-113"/>
+ <location filename="../bitcoin.cpp" line="+74"/>
<source>Error parsing command line arguments: %1.</source>
<translation type="unfinished"></translation>
</message>
@@ -2017,11 +2051,21 @@
<source>Error: %1</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <location line="+57"/>
+ <source>%1 didn&apos;t yet exit safely...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../modaloverlay.cpp" line="-36"/>
+ <source>unknown</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QRImageWidget</name>
<message>
- <location filename="../receiverequestdialog.cpp" line="+32"/>
+ <location filename="../qrimagewidget.cpp" line="+29"/>
<source>&amp;Save Image...</source>
<translation type="unfinished"></translation>
</message>
@@ -2031,6 +2075,21 @@
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+13"/>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>Error encoding URI into QR Code.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+38"/>
+ <source>QR code support not available.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+32"/>
<source>Save QR Code</source>
<translation type="unfinished"></translation>
@@ -2056,7 +2115,7 @@
<location line="+23"/>
<location line="+36"/>
<location line="+23"/>
- <location line="+713"/>
+ <location line="+716"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
@@ -2078,7 +2137,7 @@
<translation>N/A</translation>
</message>
<message>
- <location line="-1427"/>
+ <location line="-1430"/>
<source>Client version</source>
<translation>Client version</translation>
</message>
@@ -2178,7 +2237,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+238"/>
+ <location line="+241"/>
<source>&amp;Reset</source>
<translation type="unfinished"></translation>
</message>
@@ -2206,8 +2265,8 @@
</message>
<message>
<location line="+65"/>
- <location filename="../rpcconsole.cpp" line="+501"/>
- <location line="+754"/>
+ <location filename="../rpcconsole.cpp" line="+498"/>
+ <location line="+757"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
</message>
@@ -2242,13 +2301,13 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1161"/>
- <location line="+1069"/>
+ <location line="-1164"/>
+ <location line="+1072"/>
<source>User Agent</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-734"/>
+ <location line="-737"/>
<source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
<translation type="unfinished"></translation>
</message>
@@ -2263,7 +2322,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+641"/>
+ <location line="+644"/>
<source>Services</source>
<translation type="unfinished"></translation>
</message>
@@ -2313,7 +2372,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1166"/>
+ <location line="-1169"/>
<source>Last block time</source>
<translation>Last block time</translation>
</message>
@@ -2328,7 +2387,7 @@
<translation>&amp;Console</translation>
</message>
<message>
- <location line="+214"/>
+ <location line="+217"/>
<source>&amp;Network Traffic</source>
<translation type="unfinished"></translation>
</message>
@@ -2348,7 +2407,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/debugwindow.ui" line="-318"/>
+ <location filename="../forms/debugwindow.ui" line="-321"/>
<source>Debug log file</source>
<translation>Debug log file</translation>
</message>
@@ -2358,7 +2417,7 @@
<translation>Clear console</translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-249"/>
+ <location filename="../rpcconsole.cpp" line="-252"/>
<source>1 &amp;hour</source>
<translation type="unfinished"></translation>
</message>
@@ -2396,7 +2455,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+161"/>
+ <location line="+164"/>
<source>Welcome to the %1 RPC console.</source>
<translation type="unfinished"></translation>
</message>
@@ -2513,43 +2572,43 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-39"/>
- <location line="+153"/>
- <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
+ <location line="+136"/>
+ <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don&apos;t support them. When checked, an address compatible with older wallets will be created instead.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-59"/>
- <source>Clear all fields of the form.</source>
+ <location line="+3"/>
+ <source>Generate legacy address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Clear</source>
+ <location line="-178"/>
+ <location line="+153"/>
+ <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+78"/>
- <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don&apos;t support them. When unchecked, an address compatible with older wallets will be created instead.</source>
+ <location line="-76"/>
+ <source>&amp;Create new receiving address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Generate native segwit (Bech32) address</source>
+ <location line="+17"/>
+ <source>Clear all fields of the form.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+61"/>
- <source>Requested payments history</source>
+ <location line="+3"/>
+ <source>Clear</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-162"/>
- <source>&amp;Request payment</source>
+ <location line="+142"/>
+ <source>Requested payments history</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+187"/>
+ <location line="+25"/>
<source>Show the selected request (does the same as double clicking an entry)</source>
<translation type="unfinished"></translation>
</message>
@@ -2569,7 +2628,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../receivecoinsdialog.cpp" line="+47"/>
+ <location filename="../receivecoinsdialog.cpp" line="+45"/>
<source>Copy URI</source>
<translation type="unfinished"></translation>
</message>
@@ -2612,7 +2671,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../receiverequestdialog.cpp" line="+65"/>
+ <location filename="../receiverequestdialog.cpp" line="+63"/>
<source>Request payment to %1</source>
<translation type="unfinished"></translation>
</message>
@@ -2651,16 +2710,6 @@
<source>Wallet</source>
<translation type="unfinished">Wallet</translation>
</message>
- <message>
- <location line="+11"/>
- <source>Resulting URI too long, try to reduce the text for label / message.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+5"/>
- <source>Error encoding URI into QR Code.</source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -2704,7 +2753,7 @@
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
- <location filename="../sendcoinsdialog.cpp" line="+593"/>
+ <location filename="../sendcoinsdialog.cpp" line="+600"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -2891,7 +2940,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>S&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-505"/>
+ <location filename="../sendcoinsdialog.cpp" line="-512"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@@ -2931,10 +2980,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+133"/>
- <location line="+5"/>
- <location line="+6"/>
- <location line="+4"/>
+ <location line="+117"/>
+ <source> from wallet &apos;%1&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+14"/>
+ <location line="+11"/>
+ <source>%1 to &apos;%2&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-6"/>
+ <location line="+10"/>
<source>%1 to %2</source>
<translation type="unfinished"></translation>
</message>
@@ -2954,12 +3012,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-61"/>
- <source>from wallet %1</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+40"/>
+ <location line="-21"/>
<source>Please, review your transaction.</source>
<translation type="unfinished"></translation>
</message>
@@ -2979,12 +3032,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+9"/>
+ <source>To review recipient list click &quot;Show Details...&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Confirm send coins</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+191"/>
+ <location line="+190"/>
<source>The recipient address is not valid. Please recheck.</source>
<translation type="unfinished"></translation>
</message>
@@ -3179,7 +3237,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>SendConfirmationDialog</name>
<message>
- <location filename="../sendcoinsdialog.cpp" line="+83"/>
+ <location filename="../sendcoinsdialog.cpp" line="+88"/>
<location line="+5"/>
<source>Yes</source>
<translation type="unfinished"></translation>
@@ -3399,7 +3457,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionDesc</name>
<message numerus="yes">
- <location filename="../transactiondesc.cpp" line="+35"/>
+ <location filename="../transactiondesc.cpp" line="+34"/>
<source>Open for %n more block(s)</source>
<translation>
<numerusform>Open for %n more block</numerusform>
@@ -3640,7 +3698,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionTableModel</name>
<message>
- <location filename="../transactiontablemodel.cpp" line="+227"/>
+ <location filename="../transactiontablemodel.cpp" line="+223"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -3776,7 +3834,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionView</name>
<message>
- <location filename="../transactionview.cpp" line="+71"/>
+ <location filename="../transactionview.cpp" line="+70"/>
<location line="+16"/>
<source>All</source>
<translation type="unfinished"></translation>
@@ -3975,12 +4033,30 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
- <location filename="../bitcoingui.cpp" line="+154"/>
+ <location filename="../bitcoingui.cpp" line="+155"/>
<source>Unit to show amounts in. Click to select another unit.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
+ <name>WalletController</name>
+ <message>
+ <location filename="../walletcontroller.cpp" line="+70"/>
+ <source>Close wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Are you sure you wish to close wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>WalletFrame</name>
<message>
<location filename="../walletframe.cpp" line="+29"/>
@@ -4043,7 +4119,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+35"/>
+ <location line="+30"/>
<source>default wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -4099,7 +4175,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>bitcoin-core</name>
<message>
- <location filename="../bitcoinstrings.cpp" line="+29"/>
+ <location filename="../bitcoinstrings.cpp" line="+28"/>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished"></translation>
</message>
@@ -4119,7 +4195,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+74"/>
+ <location line="+70"/>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
<translation type="unfinished"></translation>
</message>
@@ -4129,22 +4205,22 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+30"/>
+ <location line="+31"/>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-172"/>
- <source>Bitcoin Core</source>
- <translation type="unfinished">Bitcoin Core</translation>
+ <location line="-168"/>
+ <source>The %s developers</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>The %s developers</source>
+ <location line="+4"/>
+ <source>Can&apos;t generate a change-address key. No keys in the internal keypool and can&apos;t generate any keys.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+3"/>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
<translation type="unfinished"></translation>
</message>
@@ -4199,7 +4275,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+7"/>
<source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
<translation type="unfinished"></translation>
</message>
@@ -4290,11 +4366,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+6"/>
- <source>Error: Disk space is low!</source>
- <translation>Error: Disk space is low!</translation>
- </message>
- <message>
- <location line="+1"/>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation>Failed to listen on any port. Use -listen=0 if you want this.</translation>
</message>
@@ -4314,7 +4385,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>Incorrect or no genesis block found. Wrong datadir for network?</translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+1"/>
<source>Initialization sanity check failed. %s is shutting down.</source>
<translation type="unfinished"></translation>
</message>
@@ -4334,22 +4405,27 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+23"/>
<source>Specified blocks directory &quot;%s&quot; does not exist.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+24"/>
+ <location line="+26"/>
<source>Upgrading txindex database</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-42"/>
+ <location line="-45"/>
<source>Loading P2P addresses...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="-15"/>
+ <source>Error: Disk space is too low!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+16"/>
<source>Loading banlist...</source>
<translation type="unfinished"></translation>
</message>
@@ -4364,7 +4440,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished"></translation>
</message>
@@ -4394,12 +4470,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+3"/>
<source>Unable to generate keys</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>Unsupported logging category %s=%s.</source>
<translation type="unfinished"></translation>
</message>
@@ -4419,12 +4495,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>Verifying blocks...</translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+2"/>
<source>Wallet needed to be rewritten: restart %s to complete</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-158"/>
+ <location line="-155"/>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4439,7 +4515,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+38"/>
+ <location line="+35"/>
<source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
<translation type="unfinished"></translation>
</message>
@@ -4454,17 +4530,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+2"/>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
- <source>Information</source>
- <translation>Information</translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+8"/>
<source>Invalid -onion address or hostname: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
@@ -4489,7 +4560,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+3"/>
+ <source>Prune mode is incompatible with -blockfilterindex.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
<translation type="unfinished"></translation>
</message>
@@ -4556,26 +4632,26 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+2"/>
- <source>Unable to generate initial keys</source>
+ <source>Unable to create the PID file &apos;%s&apos;: %s</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
- <source>Verifying wallet(s)...</source>
+ <location line="+1"/>
+ <source>Unable to generate initial keys</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>Wallet %s resides outside wallet directory %s</source>
+ <location line="+3"/>
+ <source>Unknown -blockfilterindex value %s.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Warning</source>
- <translation>Warning</translation>
+ <location line="+7"/>
+ <source>Verifying wallet(s)...</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Warning: unknown new rules activated (versionbit %i)</source>
<translation type="unfinished"></translation>
</message>
@@ -4585,7 +4661,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-182"/>
+ <location line="-178"/>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<translation type="unfinished"></translation>
</message>
@@ -4606,11 +4682,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+14"/>
- <source>Warning: Unknown block versions being mined! It&apos;s possible unknown rules are in effect</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
<source>Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; if your balance or transactions are incorrect you should restore from a backup.</source>
<translation type="unfinished"></translation>
</message>
@@ -4625,12 +4696,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+20"/>
<source>Keypool ran out, please call keypoolrefill first</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+20"/>
+ <location line="+21"/>
<source>Starting network threads...</source>
<translation type="unfinished"></translation>
</message>
@@ -4665,22 +4736,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+10"/>
<source>Unknown network specified in -onlynet: &apos;%s&apos;</source>
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-48"/>
+ <location line="-51"/>
<source>Insufficient funds</source>
<translation>Insufficient funds</translation>
</message>
<message>
- <location line="-120"/>
- <source>Can&apos;t generate a change-address key. Private keys are disabled for this wallet.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+8"/>
+ <location line="-107"/>
<source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source>
<translation type="unfinished"></translation>
</message>
@@ -4695,12 +4761,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+24"/>
+ <location line="+21"/>
<source>Cannot write to data directory &apos;%s&apos;; check permissions.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+39"/>
+ <location line="+37"/>
<source>Loading block index...</source>
<translation>Loading block index...</translation>
</message>
@@ -4710,24 +4776,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>Loading wallet...</translation>
</message>
<message>
- <location line="-42"/>
+ <location line="-40"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
<message>
- <location line="+50"/>
+ <location line="+49"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-42"/>
+ <location line="-41"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
- <message>
- <location line="+12"/>
- <source>Error</source>
- <translation>Error</translation>
- </message>
</context>
</TS>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 40dc7bf400..57cafaaac0 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -87,12 +87,12 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
/* Display elements init */
QDir translations(":translations");
- ui->bitcoinAtStartup->setToolTip(ui->bitcoinAtStartup->toolTip().arg(tr(PACKAGE_NAME)));
- ui->bitcoinAtStartup->setText(ui->bitcoinAtStartup->text().arg(tr(PACKAGE_NAME)));
+ ui->bitcoinAtStartup->setToolTip(ui->bitcoinAtStartup->toolTip().arg(PACKAGE_NAME));
+ ui->bitcoinAtStartup->setText(ui->bitcoinAtStartup->text().arg(PACKAGE_NAME));
- ui->openBitcoinConfButton->setToolTip(ui->openBitcoinConfButton->toolTip().arg(tr(PACKAGE_NAME)));
+ ui->openBitcoinConfButton->setToolTip(ui->openBitcoinConfButton->toolTip().arg(PACKAGE_NAME));
- ui->lang->setToolTip(ui->lang->toolTip().arg(tr(PACKAGE_NAME)));
+ ui->lang->setToolTip(ui->lang->toolTip().arg(PACKAGE_NAME));
ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
for (const QString &langStr : translations.entryList())
{
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 5b4fb4cc18..f3974b1c85 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -172,7 +172,7 @@ static void CopySettings(QSettings& dst, const QSettings& src)
/** Back up a QSettings to an ini-formatted file. */
static void BackupSettings(const fs::path& filename, const QSettings& src)
{
- qWarning() << "Backing up GUI settings to" << GUIUtil::boostPathToQString(filename);
+ qInfo() << "Backing up GUI settings to" << GUIUtil::boostPathToQString(filename);
QSettings dst(GUIUtil::boostPathToQString(filename), QSettings::IniFormat);
dst.clear();
CopySettings(dst, src);
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 43dccec4ea..c99515fe1c 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -488,7 +488,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
continue;
}
}
- qWarning() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
+ qInfo() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
// Project for another day:
// Fetch certificate revocation lists, and add them to certStore.
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 496aeebf7d..85b691c470 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -9,7 +9,6 @@
#include <qt/guiutil.h>
#include <interfaces/node.h>
-#include <validation.h> // for cs_main
#include <sync.h>
#include <QDebug>
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index d537d759de..fca2a4e8c5 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -4,8 +4,6 @@
#include <qt/platformstyle.h>
-#include <qt/guiconstants.h>
-
#include <QApplication>
#include <QColor>
#include <QImage>
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index fc58090dcd..c58717e21e 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -7,9 +7,7 @@
#include <qt/receivecoinsdialog.h>
#include <qt/forms/ui_receivecoinsdialog.h>
-#include <qt/addressbookpage.h>
#include <qt/addresstablemodel.h>
-#include <qt/bitcoinunits.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/receiverequestdialog.h>
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index 20b29145a0..e492502002 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -8,7 +8,6 @@
#include <qt/bitcoinunits.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
-#include <qt/qrimagewidget.h>
#include <QClipboard>
#include <QPixmap>
diff --git a/src/qt/res/movies/makespinner.sh b/src/qt/res/movies/makespinner.sh
index f47c66e02c..3507837da9 100755
--- a/src/qt/res/movies/makespinner.sh
+++ b/src/qt/res/movies/makespinner.sh
@@ -9,6 +9,6 @@ FRAMEDIR=$(dirname $0)
for i in {0..35}
do
frame=$(printf "%03d" $i)
- angle=$(($i * 10))
+ angle=$((i * 10))
convert $FRAMEDIR/../src/spinner.png -background "rgba(0,0,0,0.0)" -distort SRT $angle $FRAMEDIR/spinner-$frame.png
done
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 8b6dcf0445..84b4a2d0d8 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -457,7 +457,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
QChar nonbreaking_hyphen(8209);
ui->dataDir->setToolTip(ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir"));
ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(QString(nonbreaking_hyphen) + "blocksdir"));
- ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(tr(PACKAGE_NAME)));
+ ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(PACKAGE_NAME));
if (platformStyle->getImagesOnButtons()) {
ui->openDebugLogfileButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
@@ -677,6 +677,9 @@ void RPCConsole::setClientModel(ClientModel *model)
wordList.sort();
autoCompleter = new QCompleter(wordList, this);
autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
+ // ui->lineEdit is initially disabled because running commands is only
+ // possible from now on.
+ ui->lineEdit->setEnabled(true);
ui->lineEdit->setCompleter(autoCompleter);
autoCompleter->popup()->installEventFilter(this);
// Start thread to execute RPC commands.
@@ -801,7 +804,7 @@ void RPCConsole::clear(bool clearHistory)
QString clsKey = "Ctrl-L";
#endif
- message(CMD_REPLY, (tr("Welcome to the %1 RPC console.").arg(tr(PACKAGE_NAME)) + "<br>" +
+ message(CMD_REPLY, (tr("Welcome to the %1 RPC console.").arg(PACKAGE_NAME) + "<br>" +
tr("Use up and down arrows to navigate history, and %1 to clear screen.").arg("<b>"+clsKey+"</b>") + "<br>" +
tr("Type %1 for an overview of available commands.").arg("<b>help</b>") + "<br>" +
tr("For more information on using this console type %1.").arg("<b>help-console</b>") +
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 8a0b265834..cb9efe9319 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -279,18 +279,16 @@ void SendCoinsDialog::on_sendButton_clicked()
QStringList formatted;
for (const SendCoinsRecipient &rcp : currentTransaction.getRecipients())
{
- // generate bold amount string with wallet name in case of multiwallet
- QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
+ // generate amount string with wallet name in case of multiwallet
+ QString amount = BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
if (model->isMultiwallet()) {
- amount.append(" <u>"+tr("from wallet %1").arg(GUIUtil::HtmlEscape(model->getWalletName()))+"</u> ");
+ amount.append(tr(" from wallet '%1'").arg(model->getWalletName()));
}
- amount.append("</b>");
- // generate monospace address string
- QString address = "<span style='font-family: monospace;'>" + rcp.address;
- address.append("</span>");
+
+ // generate address string
+ QString address = rcp.address;
QString recipientElement;
- recipientElement = "<br />";
#ifdef ENABLE_BIP70
if (!rcp.paymentRequest.IsInitialized()) // normal payment
@@ -298,7 +296,7 @@ void SendCoinsDialog::on_sendButton_clicked()
{
if(rcp.label.length() > 0) // label with address
{
- recipientElement.append(tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.label)));
+ recipientElement.append(tr("%1 to '%2'").arg(amount, rcp.label));
recipientElement.append(QString(" (%1)").arg(address));
}
else // just address
@@ -309,7 +307,7 @@ void SendCoinsDialog::on_sendButton_clicked()
#ifdef ENABLE_BIP70
else if(!rcp.authenticatedMerchant.isEmpty()) // authenticated payment request
{
- recipientElement.append(tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.authenticatedMerchant)));
+ recipientElement.append(tr("%1 to '%2'").arg(amount, rcp.authenticatedMerchant));
}
else // unauthenticated payment request
{
@@ -323,7 +321,7 @@ void SendCoinsDialog::on_sendButton_clicked()
QString questionString = tr("Are you sure you want to send?");
questionString.append("<br /><span style='font-size:10pt;'>");
questionString.append(tr("Please, review your transaction."));
- questionString.append("</span><br />%1");
+ questionString.append("</span>%1");
if(txFee > 0)
{
@@ -364,8 +362,17 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append(QString("<br /><span style='font-size:10pt; font-weight:normal;'>(=%1)</span>")
.arg(alternativeUnits.join(" " + tr("or") + " ")));
- SendConfirmationDialog confirmationDialog(tr("Confirm send coins"),
- questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this);
+ QString informative_text;
+ QString detailed_text;
+ if (formatted.size() > 1) {
+ questionString = questionString.arg("");
+ informative_text = tr("To review recipient list click \"Show Details...\"");
+ detailed_text = formatted.join("\n\n");
+ } else {
+ questionString = questionString.arg("<br /><br />" + formatted.at(0));
+ }
+
+ SendConfirmationDialog confirmationDialog(tr("Confirm send coins"), questionString, informative_text, detailed_text, SEND_CONFIRM_DELAY, this);
confirmationDialog.exec();
QMessageBox::StandardButton retval = static_cast<QMessageBox::StandardButton>(confirmationDialog.result());
@@ -881,10 +888,15 @@ void SendCoinsDialog::coinControlUpdateLabels()
}
}
-SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int _secDelay,
- QWidget *parent) :
- QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(_secDelay)
+SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text, const QString& detailed_text, int _secDelay, QWidget* parent)
+ : QMessageBox(parent), secDelay(_secDelay)
{
+ setIcon(QMessageBox::Question);
+ setWindowTitle(title); // On macOS, the window title is ignored (as required by the macOS Guidelines).
+ setText(text);
+ setInformativeText(informative_text);
+ setDetailedText(detailed_text);
+ setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
setDefaultButton(QMessageBox::Cancel);
yesButton = button(QMessageBox::Yes);
updateYesButton();
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 337a72b878..c6c1816877 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -108,7 +108,7 @@ class SendConfirmationDialog : public QMessageBox
Q_OBJECT
public:
- SendConfirmationDialog(const QString &title, const QString &text, int secDelay = SEND_CONFIRM_DELAY, QWidget *parent = nullptr);
+ SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, QWidget* parent = nullptr);
int exec();
private Q_SLOTS:
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 0126a2920e..dcb9d1923f 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -39,7 +39,7 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw
devicePixelRatio = static_cast<QGuiApplication*>(QCoreApplication::instance())->devicePixelRatio();
// define text to place
- QString titleText = tr(PACKAGE_NAME);
+ QString titleText = PACKAGE_NAME;
QString versionText = QString("Version %1").arg(QString::fromStdString(FormatFullVersion()));
QString copyrightText = QString::fromUtf8(CopyrightHolders(strprintf("\xc2\xA9 %u-%u ", 2009, COPYRIGHT_YEAR)).c_str());
QString titleAddText = networkStyle->getTitleAddText();
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 2ba1c2604c..11a518ebd2 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -4,8 +4,6 @@
#include <interfaces/chain.h>
#include <interfaces/node.h>
-#include <qt/addressbookpage.h>
-#include <qt/addresstablemodel.h>
#include <qt/editaddressdialog.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
@@ -14,7 +12,6 @@
#include <key.h>
#include <key_io.h>
-#include <pubkey.h>
#include <wallet/wallet.h>
#include <QApplication>
diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp
index da25d83175..49e9e072a8 100644
--- a/src/qt/test/apptests.cpp
+++ b/src/qt/test/apptests.cpp
@@ -5,20 +5,19 @@
#include <qt/test/apptests.h>
#include <chainparams.h>
-#include <init.h>
+#include <key.h>
#include <qt/bitcoin.h>
#include <qt/bitcoingui.h>
#include <qt/networkstyle.h>
#include <qt/rpcconsole.h>
#include <shutdown.h>
+#include <test/setup_common.h>
+#include <univalue.h>
#include <validation.h>
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
-#ifdef ENABLE_WALLET
-#include <wallet/db.h>
-#endif
#include <QAction>
#include <QEventLoop>
@@ -29,9 +28,6 @@
#include <QtGlobal>
#include <QtTest/QtTestWidgets>
#include <QtTest/QtTestGui>
-#include <new>
-#include <string>
-#include <univalue.h>
namespace {
//! Call getblockchaininfo RPC and check first field of JSON output.
@@ -66,6 +62,10 @@ void AppTests::appTests()
}
#endif
+ BasicTestingSetup test{CBaseChainParams::REGTEST}; // Create a temp data directory to backup the gui settings to
+ ECC_Stop(); // Already started by the common test setup, so stop it to avoid interference
+ LogInstance().DisconnectTestLogger();
+
m_app.parameterSetup();
m_app.createOptionsModel(true /* reset settings */);
QScopedPointer<const NetworkStyle> style(
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index f0eca899fc..6cafe05461 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -13,7 +13,7 @@
#include <random.h>
#include <script/script.h>
#include <script/standard.h>
-#include <util/system.h>
+#include <test/setup_common.h>
#include <util/strencodings.h>
#include <openssl/x509.h>
@@ -66,7 +66,7 @@ static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsig
void PaymentServerTests::paymentServerTests()
{
- SelectParams(CBaseChainParams::MAIN);
+ BasicTestingSetup testing_setup(CBaseChainParams::MAIN);
auto node = interfaces::MakeNode();
OptionsModel optionsModel(*node);
PaymentServer* server = new PaymentServer(nullptr, false);
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index b0bd89b290..3c2ffa6c00 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -4,12 +4,7 @@
#include <qt/test/rpcnestedtests.h>
-#include <chainparams.h>
-#include <consensus/validation.h>
-#include <fs.h>
#include <interfaces/node.h>
-#include <validation.h>
-#include <rpc/register.h>
#include <rpc/server.h>
#include <qt/rpcconsole.h>
#include <test/setup_common.h>
diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h
index e33f4e3da1..97143ff78a 100644
--- a/src/qt/test/rpcnestedtests.h
+++ b/src/qt/test/rpcnestedtests.h
@@ -8,9 +8,6 @@
#include <QObject>
#include <QTest>
-#include <txdb.h>
-#include <txmempool.h>
-
class RPCNestedTests : public QObject
{
Q_OBJECT
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index a2bf53973b..6bda8dc6eb 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -6,14 +6,13 @@
#include <config/bitcoin-config.h>
#endif
-#include <chainparams.h>
#include <interfaces/node.h>
#include <qt/bitcoin.h>
#include <qt/test/apptests.h>
#include <qt/test/rpcnestedtests.h>
-#include <util/system.h>
#include <qt/test/uritests.h>
#include <qt/test/compattests.h>
+#include <test/setup_common.h>
#ifdef ENABLE_WALLET
#include <qt/test/addressbooktests.h>
@@ -43,19 +42,19 @@ Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
#endif
#endif
-extern void noui_connect();
-
// This is all you need to run all the tests
int main(int argc, char *argv[])
{
- SetupEnvironment();
- SetupNetworking();
- SelectParams(CBaseChainParams::REGTEST);
- noui_connect();
- ClearDatadirCache();
- fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000));
- fs::create_directories(pathTemp);
- gArgs.ForceSetArg("-datadir", pathTemp.string());
+ // Initialize persistent globals with the testing setup state for sanity.
+ // E.g. -datadir in gArgs is set to a temp directory dummy value (instead
+ // of defaulting to the default datadir), or globalChainParams is set to
+ // regtest params.
+ //
+ // All tests must use their own testing setup (if needed).
+ {
+ BasicTestingSetup dummy{CBaseChainParams::REGTEST};
+ }
+
auto node = interfaces::MakeNode();
bool fInvalid = false;
@@ -109,7 +108,5 @@ int main(int argc, char *argv[])
}
#endif
- fs::remove_all(pathTemp);
-
return fInvalid;
}
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index ab40e9962b..e54915ec75 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -1,10 +1,8 @@
#include <qt/test/wallettests.h>
#include <qt/test/util.h>
-#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/node.h>
-#include <base58.h>
#include <qt/bitcoinamountfield.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
index 1588be8da3..006007be63 100644
--- a/src/qt/trafficgraphwidget.cpp
+++ b/src/qt/trafficgraphwidget.cpp
@@ -104,6 +104,7 @@ void TrafficGraphWidget::paintEvent(QPaintEvent *)
}
}
+ painter.setRenderHint(QPainter::Antialiasing);
if(!vSamplesIn.empty()) {
QPainterPath p;
paintPath(p, vSamplesIn);
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 0d070d9e87..ebe7925368 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -20,9 +20,8 @@
#include <script/script.h>
#include <timedata.h>
#include <util/system.h>
-#include <wallet/db.h>
-#include <wallet/wallet.h>
#include <policy/policy.h>
+#include <wallet/ismine.h>
#include <stdint.h>
#include <string>
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index aa785553c8..9de90759fa 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -5,11 +5,9 @@
#include <qt/transactionrecord.h>
#include <chain.h>
-#include <consensus/consensus.h>
#include <interfaces/wallet.h>
#include <key_io.h>
-#include <timedata.h>
-#include <validation.h>
+#include <wallet/ismine.h>
#include <stdint.h>
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 631a9b891d..6fe35b13cf 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -15,11 +15,7 @@
#include <core_io.h>
#include <interfaces/handler.h>
-#include <interfaces/node.h>
-#include <sync.h>
#include <uint256.h>
-#include <util/system.h>
-#include <validation.h>
#include <QColor>
#include <QDateTime>
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 762ec434a1..17e174e57a 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -10,7 +10,6 @@
#include <qt/editaddressdialog.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
-#include <qt/sendcoinsdialog.h>
#include <qt/transactiondescdialog.h>
#include <qt/transactionfilterproxy.h>
#include <qt/transactionrecord.h>
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index b051dd159b..6509a701f3 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -11,17 +11,12 @@
#include <qt/forms/ui_helpmessagedialog.h>
#include <qt/bitcoingui.h>
-#include <qt/clientmodel.h>
-#include <qt/guiconstants.h>
-#include <qt/intro.h>
#ifdef ENABLE_BIP70
#include <qt/paymentrequestplus.h>
#endif
-#include <qt/guiutil.h>
#include <clientversion.h>
#include <init.h>
-#include <interfaces/node.h>
#include <util/system.h>
#include <util/strencodings.h>
@@ -41,7 +36,7 @@ HelpMessageDialog::HelpMessageDialog(interfaces::Node& node, QWidget *parent, bo
{
ui->setupUi(this);
- QString version = tr(PACKAGE_NAME) + " " + tr("version") + " " + QString::fromStdString(FormatFullVersion());
+ QString version = QString{PACKAGE_NAME} + " " + tr("version") + " " + QString::fromStdString(FormatFullVersion());
/* On x86 add a bit specifier to the version so that users can distinguish between
* 32 and 64 bit builds. On other architectures, 32/64 bit may be more ambiguous.
*/
@@ -53,7 +48,7 @@ HelpMessageDialog::HelpMessageDialog(interfaces::Node& node, QWidget *parent, bo
if (about)
{
- setWindowTitle(tr("About %1").arg(tr(PACKAGE_NAME)));
+ setWindowTitle(tr("About %1").arg(PACKAGE_NAME));
std::string licenseInfo = LicenseInfo();
/// HTML-format the license message from the core
@@ -129,7 +124,7 @@ HelpMessageDialog::~HelpMessageDialog()
void HelpMessageDialog::printToConsole()
{
// On other operating systems, the expected action is to print the message to the console.
- fprintf(stdout, "%s\n", qPrintable(text));
+ tfm::format(std::cout, "%s\n", qPrintable(text));
}
void HelpMessageDialog::showOrPrint()
@@ -155,7 +150,7 @@ ShutdownWindow::ShutdownWindow(QWidget *parent, Qt::WindowFlags f):
{
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(new QLabel(
- tr("%1 is shutting down...").arg(tr(PACKAGE_NAME)) + "<br /><br />" +
+ tr("%1 is shutting down...").arg(PACKAGE_NAME) + "<br /><br />" +
tr("Do not shut down the computer until this window disappears.")));
setLayout(layout);
}
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index 019bd65823..4d489d7f44 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -40,19 +40,22 @@ WalletController::~WalletController()
m_activity_thread.wait();
}
-std::vector<WalletModel*> WalletController::getWallets() const
+std::vector<WalletModel*> WalletController::getOpenWallets() const
{
QMutexLocker locker(&m_mutex);
return m_wallets;
}
-std::vector<std::string> WalletController::getWalletsAvailableToOpen() const
+std::map<std::string, bool> WalletController::listWalletDir() const
{
QMutexLocker locker(&m_mutex);
- std::vector<std::string> wallets = m_node.listWalletDir();
+ std::map<std::string, bool> wallets;
+ for (const std::string& name : m_node.listWalletDir()) {
+ wallets[name] = false;
+ }
for (WalletModel* wallet_model : m_wallets) {
- auto it = std::remove(wallets.begin(), wallets.end(), wallet_model->wallet().getWalletName());
- if (it != wallets.end()) wallets.erase(it);
+ auto it = wallets.find(wallet_model->wallet().getWalletName());
+ if (it != wallets.end()) it->second = true;
}
return wallets;
}
diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h
index 19b3a82253..03039dd795 100644
--- a/src/qt/walletcontroller.h
+++ b/src/qt/walletcontroller.h
@@ -8,7 +8,7 @@
#include <qt/walletmodel.h>
#include <sync.h>
-#include <list>
+#include <map>
#include <memory>
#include <vector>
@@ -40,8 +40,12 @@ public:
WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent);
~WalletController();
- std::vector<WalletModel*> getWallets() const;
- std::vector<std::string> getWalletsAvailableToOpen() const;
+ //! Returns wallet models currently open.
+ std::vector<WalletModel*> getOpenWallets() const;
+
+ //! Returns all wallet names in the wallet dir mapped to whether the wallet
+ //! is loaded.
+ std::map<std::string, bool> listWalletDir() const;
OpenWalletActivity* openWallet(const std::string& name, QWidget* parent = nullptr);
void closeWallet(WalletModel* wallet_model, QWidget* parent = nullptr);
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index a2b295df21..c1eba61749 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -221,9 +221,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return TransactionCreationFailed;
}
- // reject absurdly high fee. (This can never happen because the
- // wallet caps the fee at m_default_max_tx_fee. This merely serves as a
- // belt-and-suspenders check)
+ // Reject absurdly high fee
if (nFeeRequired > m_wallet->getDefaultMaxTxFee())
return AbsurdFee;
}
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index 2694d67800..8c0dc276b0 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -8,7 +8,6 @@
#include <qt/walletmodeltransaction.h>
-#include <interfaces/node.h>
#include <policy/policy.h>
WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) :
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 5f6f93d948..be47f67f95 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -316,6 +316,7 @@ void WalletView::showProgress(const QString &title, int nProgress)
if (progressDialog) {
progressDialog->close();
progressDialog->deleteLater();
+ progressDialog = nullptr;
}
} else if (progressDialog) {
if (progressDialog->wasCanceled()) {
diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp
index 08cae76add..b177b22b3f 100644
--- a/src/qt/winshutdownmonitor.cpp
+++ b/src/qt/winshutdownmonitor.cpp
@@ -63,7 +63,7 @@ void WinShutdownMonitor::registerShutdownBlockReason(const QString& strReason, c
}
if (shutdownBRCreate(mainWinId, strReason.toStdWString().c_str()))
- qWarning() << "registerShutdownBlockReason: Successfully registered: " + strReason;
+ qInfo() << "registerShutdownBlockReason: Successfully registered: " + strReason;
else
qWarning() << "registerShutdownBlockReason: Failed to register: " + strReason;
}
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 56018caf24..743efc1e65 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -6,7 +6,6 @@
#include <rpc/blockchain.h>
#include <amount.h>
-#include <base58.h>
#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
@@ -15,8 +14,6 @@
#include <core_io.h>
#include <hash.h>
#include <index/blockfilterindex.h>
-#include <index/txindex.h>
-#include <key_io.h>
#include <policy/feerate.h>
#include <policy/policy.h>
#include <policy/rbf.h>
@@ -44,9 +41,9 @@
#include <boost/thread/thread.hpp> // boost::thread::interrupt
+#include <condition_variable>
#include <memory>
#include <mutex>
-#include <condition_variable>
struct CUpdatedBlock
{
@@ -171,7 +168,8 @@ static UniValue getblockcount(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getblockcount",
- "\nReturns the number of blocks in the longest blockchain.\n",
+ "\nReturns the height of the most-work fully-validated chain.\n"
+ "The genesis block has height 0.\n",
{},
RPCResult{
"n (numeric) The current block count\n"
@@ -191,7 +189,7 @@ static UniValue getbestblockhash(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"getbestblockhash",
- "\nReturns the hash of the best (tip) block in the longest blockchain.\n",
+ "\nReturns the hash of the best (tip) block in the most-work fully-validated chain.\n",
{},
RPCResult{
"\"hex\" (string) the block hash, hex-encoded\n"
@@ -1063,7 +1061,12 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
}
PruneBlockFilesManual(height);
- return uint64_t(height);
+ const CBlockIndex* block = ::ChainActive().Tip();
+ assert(block);
+ while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
+ block = block->pprev;
+ }
+ return uint64_t(block->nHeight);
}
static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
@@ -1095,7 +1098,7 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ);
CCoinsStats stats;
- FlushStateToDisk();
+ ::ChainstateActive().ForceFlushStateToDisk();
if (GetUTXOStats(pcoinsdbview.get(), stats)) {
ret.pushKV("height", (int64_t)stats.nHeight);
ret.pushKV("bestblock", stats.hashBlock.GetHex());
@@ -1302,7 +1305,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
RPCResult{
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
- " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
+ " \"blocks\": xxxxxx, (numeric) the height of the most-work fully-validated chain. The genesis block has height 0\n"
" \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
" \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
@@ -1360,7 +1363,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
obj.pushKV("difficulty", (double)GetDifficulty(tip));
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
- obj.pushKV("initialblockdownload", IsInitialBlockDownload());
+ obj.pushKV("initialblockdownload", ::ChainstateActive().IsInitialBlockDownload());
obj.pushKV("chainwork", tip->nChainWork.GetHex());
obj.pushKV("size_on_disk", CalculateCurrentUsage());
obj.pushKV("pruned", fPruneMode);
@@ -2244,41 +2247,12 @@ UniValue scantxoutset(const JSONRPCRequest& request)
// loop through the scan objects
for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
- std::string desc_str;
- std::pair<int64_t, int64_t> range = {0, 1000};
- if (scanobject.isStr()) {
- desc_str = scanobject.get_str();
- } else if (scanobject.isObject()) {
- UniValue desc_uni = find_value(scanobject, "desc");
- if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object");
- desc_str = desc_uni.get_str();
- UniValue range_uni = find_value(scanobject, "range");
- if (!range_uni.isNull()) {
- range = ParseDescriptorRange(range_uni);
- }
- } else {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object");
- }
-
FlatSigningProvider provider;
- auto desc = Parse(desc_str, provider);
- if (!desc) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor '%s'", desc_str));
- }
- if (!desc->IsRange()) {
- range.first = 0;
- range.second = 0;
- }
- for (int i = range.first; i <= range.second; ++i) {
- std::vector<CScript> scripts;
- if (!desc->Expand(i, provider, scripts, provider)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str));
- }
- for (const auto& script : scripts) {
- std::string inferred = InferDescriptor(script, provider)->ToString();
- needles.emplace(script);
- descriptors.emplace(std::move(script), std::move(inferred));
- }
+ auto scripts = EvalDescriptorStringOrObject(scanobject, provider);
+ for (const auto& script : scripts) {
+ std::string inferred = InferDescriptor(script, provider)->ToString();
+ needles.emplace(script);
+ descriptors.emplace(std::move(script), std::move(inferred));
}
}
@@ -2292,7 +2266,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
std::unique_ptr<CCoinsViewCursor> pcursor;
{
LOCK(cs_main);
- FlushStateToDisk();
+ ::ChainstateActive().ForceFlushStateToDisk();
pcursor = std::unique_ptr<CCoinsViewCursor>(pcoinsdbview->Cursor());
assert(pcursor);
}
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 4144a17bc3..3cd661e067 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -28,6 +28,7 @@ public:
static const CRPCConvertParam vRPCConvertParams[] =
{
{ "setmocktime", 0, "timestamp" },
+ { "utxoupdatepsbt", 1, "descriptors" },
{ "generatetoaddress", 0, "nblocks" },
{ "generatetoaddress", 2, "maxtries" },
{ "getnetworkhashps", 0, "nblocks" },
@@ -36,6 +37,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendtoaddress", 4, "subtractfeefromamount" },
{ "sendtoaddress", 5 , "replaceable" },
{ "sendtoaddress", 6 , "conf_target" },
+ { "sendtoaddress", 8, "avoid_reuse" },
{ "settxfee", 0, "amount" },
{ "sethdseed", 0, "newkeypool" },
{ "getreceivedbyaddress", 1, "minconf" },
@@ -48,6 +50,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listreceivedbylabel", 2, "include_watchonly" },
{ "getbalance", 1, "minconf" },
{ "getbalance", 2, "include_watchonly" },
+ { "getbalance", 3, "avoid_reuse" },
{ "getblockhash", 0, "height" },
{ "waitforblockheight", 0, "height" },
{ "waitforblockheight", 1, "timeout" },
@@ -141,6 +144,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "setban", 2, "bantime" },
{ "setban", 3, "absolute" },
{ "setnetworkactive", 0, "state" },
+ { "setwalletflag", 1, "value" },
{ "getmempoolancestors", 1, "verbose" },
{ "getmempooldescendants", 1, "verbose" },
{ "bumpfee", 1, "options" },
@@ -162,6 +166,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "rescanblockchain", 1, "stop_height"},
{ "createwallet", 1, "disable_private_keys"},
{ "createwallet", 2, "blank"},
+ { "createwallet", 4, "avoid_reuse"},
{ "getnodeaddresses", 0, "count"},
{ "stop", 0, "wait" },
};
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 1831562100..6636a8a29a 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -103,7 +103,6 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request)
static UniValue generateBlocks(const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
{
- static const int nInnerLoopCount = 0x10000;
int nHeightEnd = 0;
int nHeight = 0;
@@ -124,14 +123,14 @@ static UniValue generateBlocks(const CScript& coinbase_script, int nGenerate, ui
LOCK(cs_main);
IncrementExtraNonce(pblock, ::ChainActive().Tip(), nExtraNonce);
}
- while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
+ while (nMaxTries > 0 && pblock->nNonce < std::numeric_limits<uint32_t>::max() && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus()) && !ShutdownRequested()) {
++pblock->nNonce;
--nMaxTries;
}
- if (nMaxTries == 0) {
+ if (nMaxTries == 0 || ShutdownRequested()) {
break;
}
- if (pblock->nNonce == nInnerLoopCount) {
+ if (pblock->nNonce == std::numeric_limits<uint32_t>::max()) {
continue;
}
std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
@@ -442,7 +441,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0)
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
- if (IsInitialBlockDownload())
+ if (::ChainstateActive().IsInitialBlockDownload())
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
static unsigned int nTransactionsUpdatedLast;
@@ -469,7 +468,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
}
- // Release the wallet and main lock while waiting
+ // Release lock while waiting
LEAVE_CRITICAL_SECTION(cs_main);
{
checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1);
@@ -480,6 +479,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout)
{
// Timeout: Check transactions for update
+ // without holding ::mempool.cs to avoid deadlocks
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP)
break;
checktxtime += std::chrono::seconds(10);
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 72a2919712..7a1bdec7b9 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -3,25 +3,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <chain.h>
-#include <clientversion.h>
-#include <core_io.h>
#include <crypto/ripemd160.h>
#include <key_io.h>
-#include <validation.h>
#include <httpserver.h>
-#include <net.h>
-#include <netbase.h>
#include <outputtype.h>
#include <rpc/blockchain.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <script/descriptor.h>
-#include <timedata.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <util/validation.h>
-#include <warnings.h>
#include <stdint.h>
#include <tuple>
@@ -130,9 +122,9 @@ static UniValue createmultisig(const JSONRPCRequest& request)
}
// Construct using pay-to-script-hash:
- const CScript inner = CreateMultisigRedeemscript(required, pubkeys);
CBasicKeyStore keystore;
- const CTxDestination dest = AddAndGetDestinationForScript(keystore, inner, output_type);
+ CScript inner;
+ const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner);
UniValue result(UniValue::VOBJ);
result.pushKV("address", EncodeDestination(dest));
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index e49c3e031f..d993a88458 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -5,7 +5,6 @@
#include <rpc/server.h>
#include <banman.h>
-#include <chainparams.h>
#include <clientversion.h>
#include <core_io.h>
#include <net.h>
@@ -17,7 +16,6 @@
#include <rpc/util.h>
#include <sync.h>
#include <timedata.h>
-#include <ui_interface.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <validation.h>
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index 23999b305a..33b0130a94 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -10,7 +10,6 @@
#include <util/system.h>
#include <util/strencodings.h>
#include <util/time.h>
-#include <version.h>
/**
* JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index b3926786db..6ac16622c2 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -6,21 +6,16 @@
#include <chain.h>
#include <coins.h>
#include <compat/byteswap.h>
-#include <consensus/tx_verify.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <index/txindex.h>
-#include <init.h>
-#include <interfaces/chain.h>
#include <key_io.h>
#include <keystore.h>
#include <merkleblock.h>
#include <node/coin.h>
#include <node/psbt.h>
#include <node/transaction.h>
-#include <policy/policy.h>
#include <policy/rbf.h>
-#include <policy/settings.h>
#include <primitives/transaction.h>
#include <psbt.h>
#include <rpc/rawtransaction_util.h>
@@ -31,7 +26,6 @@
#include <script/sign.h>
#include <script/standard.h>
#include <uint256.h>
-#include <util/bip32.h>
#include <util/moneystr.h>
#include <util/strencodings.h>
#include <validation.h>
@@ -45,7 +39,7 @@
/** High fee for sendrawtransaction and testmempoolaccept.
* By default, transaction with a fee higher than this will be rejected by the
- * RPCs. This can be overriden with the maxfeerate argument.
+ * RPCs. This can be overridden with the maxfeerate argument.
*/
constexpr static CAmount DEFAULT_MAX_RAW_TX_FEE{COIN / 10};
@@ -202,7 +196,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
}
errmsg = "No such transaction found in the provided block";
} else if (!g_txindex) {
- errmsg = "No such mempool transaction. Use -txindex to enable blockchain transaction queries";
+ errmsg = "No such mempool transaction. Use -txindex or provide a block hash to enable blockchain transaction queries";
} else if (!f_txindex_ready) {
errmsg = "No such mempool transaction. Blockchain transactions are still in the process of being indexed";
} else {
@@ -432,14 +426,17 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
static UniValue decoderawtransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
- RPCHelpMan{"decoderawtransaction",
+ const RPCHelpMan help{"decoderawtransaction",
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"},
- {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction\n"
- " If iswitness is not present, heuristic tests will be used in decoding"},
+ {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
+ "If iswitness is not present, heuristic tests will be used in decoding.\n"
+ "If true, only witness deserialization will be tried.\n"
+ "If false, only non-witness deserialization will be tried.\n"
+ "This boolean should reflect whether the transaction has inputs\n"
+ "(e.g. fully valid, or on-chain transactions), if known by the caller."
+ },
},
RPCResult{
"{\n"
@@ -486,7 +483,11 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
HelpExampleCli("decoderawtransaction", "\"hexstring\"")
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
},
- }.ToString());
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
@@ -748,8 +749,8 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
"}\n"
},
RPCExamples{
- HelpExampleCli("signrawtransactionwithkey", "\"myhex\"")
- + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\"")
+ HelpExampleCli("signrawtransactionwithkey", "\"myhex\" \"[\\\"key1\\\",\\\"key2\\\"]\"")
+ + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\", \"[\\\"key1\\\",\\\"key2\\\"]\"")
},
}.ToString());
@@ -1423,19 +1424,20 @@ UniValue createpsbt(const JSONRPCRequest& request)
UniValue converttopsbt(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
- throw std::runtime_error(
- RPCHelpMan{"converttopsbt",
+ const RPCHelpMan help{"converttopsbt",
"\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n"
"createpsbt and walletcreatefundedpsbt should be used for new applications.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of a raw transaction"},
- {"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", "If true, any signatures in the input will be discarded and conversion.\n"
+ {"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", "If true, any signatures in the input will be discarded and conversion\n"
" will continue. If false, RPC will fail if any signatures are present."},
{"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
- " If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n"
- " will be tried. If false, only non-witness deserialization will be tried. Only has an effect if\n"
- " permitsigdata is true."},
+ "If iswitness is not present, heuristic tests will be used in decoding.\n"
+ "If true, only witness deserialization will be tried.\n"
+ "If false, only non-witness deserialization will be tried.\n"
+ "This boolean should reflect whether the transaction has inputs\n"
+ "(e.g. fully valid, or on-chain transactions), if known by the caller."
+ },
},
RPCResult{
" \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n"
@@ -1446,8 +1448,11 @@ UniValue converttopsbt(const JSONRPCRequest& request)
"\nConvert the transaction to a PSBT\n"
+ HelpExampleCli("converttopsbt", "\"rawtransaction\"")
},
- }.ToString());
+ };
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true);
@@ -1456,8 +1461,8 @@ UniValue converttopsbt(const JSONRPCRequest& request)
bool permitsigdata = request.params[1].isNull() ? false : request.params[1].get_bool();
bool witness_specified = !request.params[2].isNull();
bool iswitness = witness_specified ? request.params[2].get_bool() : false;
- bool try_witness = permitsigdata ? (witness_specified ? iswitness : true) : false;
- bool try_no_witness = permitsigdata ? (witness_specified ? !iswitness : true) : true;
+ const bool try_witness = witness_specified ? iswitness : true;
+ const bool try_no_witness = witness_specified ? !iswitness : true;
if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}
@@ -1490,12 +1495,19 @@ UniValue converttopsbt(const JSONRPCRequest& request)
UniValue utxoupdatepsbt(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1) {
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw std::runtime_error(
RPCHelpMan{"utxoupdatepsbt",
- "\nUpdates a PSBT with witness UTXOs retrieved from the UTXO set or the mempool.\n",
+ "\nUpdates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set or the mempool.\n",
{
- {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}
+ {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
+ {"descriptors", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "An array of either strings or objects", {
+ {"", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
+ {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with an output descriptor and extra information", {
+ {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
+ {"range", RPCArg::Type::RANGE, "1000", "Up to what index HD chains should be explored (either end or [begin,end])"},
+ }},
+ }},
},
RPCResult {
" \"psbt\" (string) The base64-encoded partially signed transaction with inputs updated\n"
@@ -1505,7 +1517,7 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
}}.ToString());
}
- RPCTypeCheck(request.params, {UniValue::VSTR}, true);
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}, true);
// Unserialize the transactions
PartiallySignedTransaction psbtx;
@@ -1514,6 +1526,17 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
+ // Parse descriptors, if any.
+ FlatSigningProvider provider;
+ if (!request.params[1].isNull()) {
+ auto descs = request.params[1].get_array();
+ for (size_t i = 0; i < descs.size(); ++i) {
+ EvalDescriptorStringOrObject(descs[i], provider);
+ }
+ }
+ // We don't actually need private keys further on; hide them as a precaution.
+ HidingSigningProvider public_provider(&provider, /* nosign */ true, /* nobip32derivs */ false);
+
// Fetch previous transactions (inputs):
CCoinsView viewDummy;
CCoinsViewCache view(&viewDummy);
@@ -1540,11 +1563,19 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
const Coin& coin = view.AccessCoin(psbtx.tx->vin[i].prevout);
- std::vector<std::vector<unsigned char>> solutions_data;
- txnouttype which_type = Solver(coin.out.scriptPubKey, solutions_data);
- if (which_type == TX_WITNESS_V0_SCRIPTHASH || which_type == TX_WITNESS_V0_KEYHASH || which_type == TX_WITNESS_UNKNOWN) {
+ if (IsSegWitOutput(provider, coin.out.scriptPubKey)) {
input.witness_utxo = coin.out;
}
+
+ // Update script/keypath information using descriptor data.
+ // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
+ // we don't actually care about those here, in fact.
+ SignPSBTInput(public_provider, psbtx, i, /* sighash_type */ 1);
+ }
+
+ // Update script/keypath information using descriptor data.
+ for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
+ UpdatePSBTOutput(public_provider, psbtx, i);
}
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
@@ -1745,7 +1776,7 @@ static const CRPCCommand commands[] =
{ "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} },
{ "rawtransactions", "createpsbt", &createpsbt, {"inputs","outputs","locktime","replaceable"} },
{ "rawtransactions", "converttopsbt", &converttopsbt, {"hexstring","permitsigdata","iswitness"} },
- { "rawtransactions", "utxoupdatepsbt", &utxoupdatepsbt, {"psbt"} },
+ { "rawtransactions", "utxoupdatepsbt", &utxoupdatepsbt, {"psbt", "descriptors"} },
{ "rawtransactions", "joinpsbts", &joinpsbts, {"txs"} },
{ "rawtransactions", "analyzepsbt", &analyzepsbt, {"psbt"} },
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index 8af491977c..14fcb628eb 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -7,7 +7,6 @@
#include <coins.h>
#include <core_io.h>
-#include <interfaces/chain.h>
#include <key_io.h>
#include <keystore.h>
#include <policy/policy.h>
@@ -222,6 +221,9 @@ UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival
// Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH).
keystore->AddCScript(GetScriptForWitness(witnessScript));
}
+ if (rs.isNull() && ws.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Missing redeemScript/witnessScript");
+ }
}
}
}
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 9df4070cbb..145b99b567 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -7,11 +7,9 @@
#include <fs.h>
#include <key_io.h>
-#include <random.h>
#include <rpc/util.h>
#include <shutdown.h>
#include <sync.h>
-#include <ui_interface.h>
#include <util/strencodings.h>
#include <util/system.h>
@@ -212,7 +210,8 @@ static UniValue getrpcinfo(const JSONRPCRequest& request)
" \"method\" (string) The name of the RPC command \n"
" \"duration\" (numeric) The running time in microseconds\n"
" },...\n"
- " ]\n"
+ " ],\n"
+ " \"logpath\": \"xxx\" (string) The complete file path to the debug log\n"
"}\n"
},
RPCExamples{
@@ -234,6 +233,10 @@ static UniValue getrpcinfo(const JSONRPCRequest& request)
UniValue result(UniValue::VOBJ);
result.pushKV("active_commands", active_commands);
+ const std::string path = LogInstance().m_file_path.string();
+ UniValue log_path(UniValue::VSTR, path);
+ result.pushKV("logpath", log_path);
+
return result;
}
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 9cdb22001f..67ccb225b5 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -4,7 +4,9 @@
#include <key_io.h>
#include <keystore.h>
+#include <outputtype.h>
#include <rpc/util.h>
+#include <script/descriptor.h>
#include <tinyformat.h>
#include <util/strencodings.h>
@@ -150,8 +152,8 @@ CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in)
return vchPubKey;
}
-// Creates a multisig redeemscript from a given list of public keys and number required.
-CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys)
+// Creates a multisig address from a given list of public keys, number of signatures required, and the address type
+CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, CKeyStore& keystore, CScript& script_out)
{
// Gather public keys
if (required < 1) {
@@ -164,13 +166,24 @@ CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey
throw JSONRPCError(RPC_INVALID_PARAMETER, "Number of keys involved in the multisignature address creation > 16\nReduce the number");
}
- CScript result = GetScriptForMultisig(required, pubkeys);
+ script_out = GetScriptForMultisig(required, pubkeys);
- if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)));
+ if (script_out.size() > MAX_SCRIPT_ELEMENT_SIZE) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", script_out.size(), MAX_SCRIPT_ELEMENT_SIZE)));
}
- return result;
+ // Check if any keys are uncompressed. If so, the type is legacy
+ for (const CPubKey& pk : pubkeys) {
+ if (!pk.IsCompressed()) {
+ type = OutputType::LEGACY;
+ break;
+ }
+ }
+
+ // Make the address
+ CTxDestination dest = AddAndGetDestinationForScript(keystore, script_out, type);
+
+ return dest;
}
class DescribeAddressVisitor : public boost::static_visitor<UniValue>
@@ -685,3 +698,40 @@ std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value)
}
return {low, high};
}
+
+std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider)
+{
+ std::string desc_str;
+ std::pair<int64_t, int64_t> range = {0, 1000};
+ if (scanobject.isStr()) {
+ desc_str = scanobject.get_str();
+ } else if (scanobject.isObject()) {
+ UniValue desc_uni = find_value(scanobject, "desc");
+ if (desc_uni.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor needs to be provided in scan object");
+ desc_str = desc_uni.get_str();
+ UniValue range_uni = find_value(scanobject, "range");
+ if (!range_uni.isNull()) {
+ range = ParseDescriptorRange(range_uni);
+ }
+ } else {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object");
+ }
+
+ auto desc = Parse(desc_str, provider);
+ if (!desc) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor '%s'", desc_str));
+ }
+ if (!desc->IsRange()) {
+ range.first = 0;
+ range.second = 0;
+ }
+ std::vector<CScript> ret;
+ for (int i = range.first; i <= range.second; ++i) {
+ std::vector<CScript> scripts;
+ if (!desc->Expand(i, provider, scripts, provider)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys: '%s'", desc_str));
+ }
+ std::move(scripts.begin(), scripts.end(), std::back_inserter(ret));
+ }
+ return ret;
+}
diff --git a/src/rpc/util.h b/src/rpc/util.h
index e4fa8fc3d7..ae3c3d63e0 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -6,8 +6,11 @@
#define BITCOIN_RPC_UTIL_H
#include <node/transaction.h>
+#include <outputtype.h>
#include <pubkey.h>
#include <rpc/protocol.h>
+#include <script/script.h>
+#include <script/sign.h>
#include <script/standard.h>
#include <univalue.h>
@@ -70,7 +73,7 @@ extern std::string HelpExampleRpc(const std::string& methodname, const std::stri
CPubKey HexToPubKey(const std::string& hex_in);
CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in);
-CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys);
+CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, CKeyStore& keystore, CScript& script_out);
UniValue DescribeAddress(const CTxDestination& dest);
@@ -83,6 +86,9 @@ UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_s
//! Parse a JSON range specified as int64, or [int64, int64]
std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value);
+/** Evaluate a descriptor given as a string, or as a {"desc":...,"range":...} object, with default range of 1000. */
+std::vector<CScript> EvalDescriptorStringOrObject(const UniValue& scanobject, FlatSigningProvider& provider);
+
struct RPCArg {
enum class Type {
OBJ,
@@ -220,7 +226,7 @@ struct RPCResults {
struct RPCExamples {
const std::string m_examples;
- RPCExamples(
+ explicit RPCExamples(
std::string examples)
: m_examples(std::move(examples))
{
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 9be87fabb0..50119ba184 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -164,6 +164,9 @@ struct PubkeyProvider
/** Get the descriptor string form including private data (if available in arg). */
virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;
+
+ /** Derive a private key, if private data is available in arg. */
+ virtual bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const = 0;
};
class OriginPubkeyProvider final : public PubkeyProvider
@@ -195,6 +198,10 @@ public:
ret = "[" + OriginString() + "]" + std::move(sub);
return true;
}
+ bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
+ {
+ return m_provider->GetPrivKey(pos, arg, key);
+ }
};
/** An object representing a parsed constant public key in a descriptor. */
@@ -222,6 +229,10 @@ public:
ret = EncodeSecret(key);
return true;
}
+ bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
+ {
+ return arg.GetKey(m_pubkey.GetID(), key);
+ }
};
enum class DeriveType {
@@ -266,14 +277,9 @@ public:
{
if (key) {
if (IsHardened()) {
- CExtKey extkey;
- if (!GetExtKey(arg, extkey)) return false;
- for (auto entry : m_path) {
- extkey.Derive(extkey, entry);
- }
- if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
- if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL);
- *key = extkey.Neuter().pubkey;
+ CKey priv_key;
+ if (!GetPrivKey(pos, arg, priv_key)) return false;
+ *key = priv_key.GetPubKey();
} else {
// TODO: optimize by caching
CExtPubKey extkey = m_extkey;
@@ -312,6 +318,18 @@ public:
}
return true;
}
+ bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
+ {
+ CExtKey extkey;
+ if (!GetExtKey(arg, extkey)) return false;
+ for (auto entry : m_path) {
+ extkey.Derive(extkey, entry);
+ }
+ if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
+ if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL);
+ key = extkey.key;
+ return true;
+ }
};
/** Base class for all Descriptor implementations. */
@@ -462,6 +480,20 @@ public:
Span<const unsigned char> span = MakeSpan(cache);
return ExpandHelper(pos, DUMMY_SIGNING_PROVIDER, &span, output_scripts, out, nullptr) && span.size() == 0;
}
+
+ void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const final
+ {
+ for (const auto& p : m_pubkey_args) {
+ CKey key;
+ if (!p->GetPrivKey(pos, provider, key)) continue;
+ out.keys.emplace(key.GetPubKey().GetID(), key);
+ }
+ if (m_script_arg) {
+ FlatSigningProvider subprovider;
+ m_script_arg->ExpandPrivate(pos, provider, subprovider);
+ out = Merge(out, subprovider);
+ }
+ }
};
/** Construct a vector with one element, which is moved into it. */
diff --git a/src/script/descriptor.h b/src/script/descriptor.h
index 907a102284..af7ae229ca 100644
--- a/src/script/descriptor.h
+++ b/src/script/descriptor.h
@@ -60,6 +60,14 @@ struct Descriptor {
* out: scripts and public keys necessary for solving the expanded scriptPubKeys will be put here (may be equal to provider).
*/
virtual bool ExpandFromCache(int pos, const std::vector<unsigned char>& cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const = 0;
+
+ /** Expand the private key for a descriptor at a specified position, if possible.
+ *
+ * pos: the position at which to expand the descriptor. If IsRange() is false, this is ignored.
+ * provider: the provider to query for the private keys.
+ * out: any private keys available for the specified pos will be placed here.
+ */
+ virtual void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const = 0;
};
/** Parse a descriptor string. Included private keys are put in out.
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 982aa241e7..0666a385d1 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -5,7 +5,6 @@
#include <script/script.h>
-#include <tinyformat.h>
#include <util/strencodings.h>
const char* GetOpName(opcodetype opcode)
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 94005cf6f3..eaf5363bd7 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -5,7 +5,6 @@
#include <script/sigcache.h>
-#include <memusage.h>
#include <pubkey.h>
#include <random.h>
#include <uint256.h>
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 36dd68a3d8..5320dc0876 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -505,3 +505,19 @@ FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvide
ret.origins.insert(b.origins.begin(), b.origins.end());
return ret;
}
+
+bool IsSegWitOutput(const SigningProvider& provider, const CScript& script)
+{
+ std::vector<valtype> solutions;
+ auto whichtype = Solver(script, solutions);
+ if (whichtype == TX_WITNESS_V0_SCRIPTHASH || whichtype == TX_WITNESS_V0_KEYHASH || whichtype == TX_WITNESS_UNKNOWN) return true;
+ if (whichtype == TX_SCRIPTHASH) {
+ auto h160 = uint160(solutions[0]);
+ CScript subscript;
+ if (provider.GetCScript(h160, subscript)) {
+ whichtype = Solver(subscript, solutions);
+ if (whichtype == TX_WITNESS_V0_SCRIPTHASH || whichtype == TX_WITNESS_V0_KEYHASH || whichtype == TX_WITNESS_UNKNOWN) return true;
+ }
+ }
+ return false;
+}
diff --git a/src/script/sign.h b/src/script/sign.h
index f746325b90..e5c0329a61 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -232,4 +232,7 @@ void UpdateInput(CTxIn& input, const SignatureData& data);
* Solvability is unrelated to whether we consider this output to be ours. */
bool IsSolvable(const SigningProvider& provider, const CScript& script);
+/** Check whether a scriptPubKey is known to be segwit. */
+bool IsSegWitOutput(const SigningProvider& provider, const CScript& script);
+
#endif // BITCOIN_SCRIPT_SIGN_H
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 91a301bcdf..b7d6cd925c 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -8,8 +8,6 @@
#include <crypto/sha256.h>
#include <pubkey.h>
#include <script/script.h>
-#include <util/system.h>
-#include <util/strencodings.h>
typedef std::vector<unsigned char> valtype;
diff --git a/src/serialize.h b/src/serialize.h
index b001ee1324..1dc27d84eb 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -670,7 +670,7 @@ void Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&)
while (i < nSize)
{
unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
- v.resize(i + blk);
+ v.resize_uninitialized(i + blk);
is.read((char*)&v[i], blk * sizeof(T));
i += blk;
}
@@ -688,8 +688,8 @@ void Unserialize_impl(Stream& is, prevector<N, T>& v, const V&)
nMid += 5000000 / sizeof(T);
if (nMid > nSize)
nMid = nSize;
- v.resize(nMid);
- for (; i < nMid; i++)
+ v.resize_uninitialized(nMid);
+ for (; i < nMid; ++i)
Unserialize(is, v[i]);
}
}
diff --git a/src/support/cleanse.cpp b/src/support/cleanse.cpp
index 17a4a4c2b2..ecb00510f7 100644
--- a/src/support/cleanse.cpp
+++ b/src/support/cleanse.cpp
@@ -11,33 +11,25 @@
#include <Windows.h> // For SecureZeroMemory.
#endif
-/* Compilers have a bad habit of removing "superfluous" memset calls that
- * are trying to zero memory. For example, when memset()ing a buffer and
- * then free()ing it, the compiler might decide that the memset is
- * unobservable and thus can be removed.
- *
- * Previously we used OpenSSL which tried to stop this by a) implementing
- * memset in assembly on x86 and b) putting the function in its own file
- * for other platforms.
- *
- * This change removes those tricks in favour of using asm directives to
- * scare the compiler away. As best as our compiler folks can tell, this is
- * sufficient and will continue to be so.
- *
- * Adam Langley <agl@google.com>
- * Commit: ad1907fe73334d6c696c8539646c21b11178f20f
- * BoringSSL (LICENSE: ISC)
- */
void memory_cleanse(void *ptr, size_t len)
{
- std::memset(ptr, 0, len);
-
- /* As best as we can tell, this is sufficient to break any optimisations that
- might try to eliminate "superfluous" memsets. If there's an easy way to
- detect memset_s, it would be better to use that. */
#if defined(_MSC_VER)
+ /* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
SecureZeroMemory(ptr, len);
#else
+ std::memset(ptr, 0, len);
+
+ /* Memory barrier that scares the compiler away from optimizing out the memset.
+ *
+ * Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
+ * in BoringSSL (ISC License):
+ * As best as we can tell, this is sufficient to break any optimisations that
+ * might try to eliminate "superfluous" memsets.
+ * This method is used in memzero_explicit() the Linux kernel, too. Its advantage is that it
+ * is pretty efficient because the compiler can still implement the memset() efficiently,
+ * just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
+ * Yang et al. (USENIX Security 2017) for more background.
+ */
__asm__ __volatile__("" : : "r"(ptr) : "memory");
#endif
}
diff --git a/src/support/cleanse.h b/src/support/cleanse.h
index 5298214e44..b03520315d 100644
--- a/src/support/cleanse.h
+++ b/src/support/cleanse.h
@@ -8,7 +8,8 @@
#include <stdlib.h>
-// Attempt to overwrite data in the specified memory span.
+/** Secure overwrite a buffer (possibly containing secret data) with zero-bytes. The write
+ * operation will not be optimized out by the compiler. */
void memory_cleanse(void *ptr, size_t len);
#endif // BITCOIN_SUPPORT_CLEANSE_H
diff --git a/src/sync.cpp b/src/sync.cpp
index c2767b200a..20258d8e9a 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -57,7 +57,7 @@ struct CLockLocation {
std::string ToString() const
{
- return tfm::format(
+ return strprintf(
"%s %s:%s%s (in thread %s)",
mutexName, sourceFile, itostr(sourceLine), (fTry ? " (TRY)" : ""), m_thread_name);
}
@@ -118,7 +118,7 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch,
LogPrintf(" %s\n", i.second.ToString());
}
if (g_debug_lockorder_abort) {
- fprintf(stderr, "Assertion failed: detected inconsistent lock order at %s:%i, details in debug log.\n", __FILE__, __LINE__);
+ tfm::format(std::cerr, "Assertion failed: detected inconsistent lock order at %s:%i, details in debug log.\n", __FILE__, __LINE__);
abort();
}
throw std::logic_error("potential deadlock detected");
@@ -175,7 +175,7 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine,
for (const std::pair<void*, CLockLocation>& i : g_lockstack)
if (i.first == cs)
return;
- fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
+ tfm::format(std::cerr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
abort();
}
@@ -183,7 +183,7 @@ void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLi
{
for (const std::pair<void*, CLockLocation>& i : g_lockstack) {
if (i.first == cs) {
- fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
+ tfm::format(std::cerr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
abort();
}
}
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index f255691704..e333763f27 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <util/memory.h>
#include <util/system.h>
-#include <support/allocators/secure.h>
#include <test/setup_common.h>
#include <memory>
diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp
index 809c627d27..9ac87261b6 100644
--- a/src/test/arith_uint256_tests.cpp
+++ b/src/test/arith_uint256_tests.cpp
@@ -11,7 +11,6 @@
#include <uint256.h>
#include <arith_uint256.h>
#include <string>
-#include <version.h>
#include <test/setup_common.h>
BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup)
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 0c0423c0db..662878750e 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -4,9 +4,10 @@
#include <boost/test/unit_test.hpp>
+#include <clientversion.h>
#include <key.h>
#include <key_io.h>
-#include <uint256.h>
+#include <streams.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <test/setup_common.h>
diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp
index 13afcca375..ca75563ef0 100644
--- a/src/test/blockchain_tests.cpp
+++ b/src/test/blockchain_tests.cpp
@@ -2,6 +2,7 @@
#include <stdlib.h>
+#include <chain.h>
#include <rpc/blockchain.h>
#include <test/setup_common.h>
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index f57e1a0ebd..dac201a35f 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -6,7 +6,7 @@
#include <consensus/merkle.h>
#include <chainparams.h>
#include <pow.h>
-#include <random.h>
+#include <streams.h>
#include <test/setup_common.h>
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index 7ba483173c..cf87aa9303 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -10,6 +10,7 @@
#include <pow.h>
#include <test/setup_common.h>
#include <script/standard.h>
+#include <util/time.h>
#include <validation.h>
#include <boost/test/unit_test.hpp>
@@ -267,8 +268,6 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
{
- SetDataDir("tempdir");
-
BlockFilterIndex* filter_index;
filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 408a7fbda4..d796444419 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <util/memory.h>
#include <util/system.h>
#include <util/time.h>
#include <validation.h>
@@ -17,8 +18,6 @@
#include <condition_variable>
#include <unordered_set>
-#include <memory>
-#include <random.h>
// BasicTestingSetup not sufficient because nScriptCheckThreads is not set
// otherwise.
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 665975ca67..948591196c 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -3,14 +3,14 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <attributes.h>
+#include <clientversion.h>
#include <coins.h>
-#include <consensus/validation.h>
#include <script/standard.h>
+#include <streams.h>
#include <test/setup_common.h>
#include <uint256.h>
#include <undo.h>
#include <util/strencodings.h>
-#include <validation.h>
#include <map>
#include <vector>
@@ -280,6 +280,7 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) {
BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
{
SeedInsecureRand(/* deterministic */ true);
+ g_mock_deterministic_tests = true;
bool spent_a_duplicate_coinbase = false;
// A simple map to track what we expect the cache stack to represent.
@@ -474,6 +475,8 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// Verify coverage.
BOOST_CHECK(spent_a_duplicate_coinbase);
+
+ g_mock_deterministic_tests = false;
}
BOOST_AUTO_TEST_CASE(ccoins_serialization)
diff --git a/src/test/compilerbug_tests.cpp b/src/test/compilerbug_tests.cpp
new file mode 100644
index 0000000000..74e1eac3ea
--- /dev/null
+++ b/src/test/compilerbug_tests.cpp
@@ -0,0 +1,43 @@
+// Copyright (c) 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 <test/setup_common.h>
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(compilerbug_tests, BasicTestingSetup)
+
+#if defined(__GNUC__)
+// This block will also be built under clang, which is fine (as it supports noinline)
+void __attribute__ ((noinline)) set_one(unsigned char* ptr)
+{
+ *ptr = 1;
+}
+
+int __attribute__ ((noinline)) check_zero(unsigned char const* in, unsigned int len)
+{
+ for (unsigned int i = 0; i < len; ++i) {
+ if (in[i] != 0) return 0;
+ }
+ return 1;
+}
+
+void set_one_on_stack() {
+ unsigned char buf[1];
+ set_one(buf);
+}
+
+BOOST_AUTO_TEST_CASE(gccbug_90348) {
+ // Test for GCC bug 90348. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90348
+ for (int i = 0; i <= 4; ++i) {
+ unsigned char in[4];
+ for (int j = 0; j < i; ++j) {
+ in[j] = 0;
+ set_one_on_stack(); // Apparently modifies in[0]
+ }
+ BOOST_CHECK(check_zero(in, i));
+ }
+}
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 35911e507f..4e2acca4c3 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -567,7 +567,7 @@ BOOST_AUTO_TEST_CASE(poly1305_testvector)
BOOST_AUTO_TEST_CASE(hkdf_hmac_sha256_l32_tests)
{
- // Use rfc5869 test vectors but trucated to 32 bytes (our implementation only support length 32)
+ // Use rfc5869 test vectors but truncated to 32 bytes (our implementation only support length 32)
TestHKDF_SHA256_32(
/* IKM */ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
/* salt */ "000102030405060708090a0b0c",
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index 0bde92c18d..efcadd51fc 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -4,8 +4,8 @@
#include <dbwrapper.h>
#include <uint256.h>
-#include <random.h>
#include <test/setup_common.h>
+#include <util/memory.h>
#include <memory>
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = SetDataDir(std::string("dbwrapper").append(obfuscate ? "_true" : "_false"));
+ fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'k';
uint256 in = InsecureRand256();
@@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = SetDataDir(std::string("dbwrapper_batch").append(obfuscate ? "_true" : "_false"));
+ fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'i';
@@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = SetDataDir(std::string("dbwrapper_iterator").append(obfuscate ? "_true" : "_false"));
+ fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
// The two keys are intentionally chosen for ordering
@@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
{
// We're going to share this fs::path between two wrappers
- fs::path ph = SetDataDir("existing_data_no_obfuscate");
+ fs::path ph = GetDataDir() / "existing_data_no_obfuscate";
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
@@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
BOOST_AUTO_TEST_CASE(existing_data_reindex)
{
// We're going to share this fs::path between two wrappers
- fs::path ph = SetDataDir("existing_data_reindex");
+ fs::path ph = GetDataDir() / "existing_data_reindex";
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
@@ -199,7 +199,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_AUTO_TEST_CASE(iterator_ordering)
{
- fs::path ph = SetDataDir("iterator_ordering");
+ fs::path ph = GetDataDir() / "iterator_ordering";
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<256; ++x) {
uint8_t key = x;
@@ -277,7 +277,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
{
char buf[10];
- fs::path ph = SetDataDir("iterator_string_ordering");
+ fs::path ph = GetDataDir() / "iterator_string_ordering";
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<10; ++x) {
for (int y = 0; y < 10; y++) {
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index d47f395c15..93883d1d98 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -9,10 +9,11 @@
#include <keystore.h>
#include <net.h>
#include <net_processing.h>
-#include <pow.h>
#include <script/sign.h>
#include <serialize.h>
+#include <util/memory.h>
#include <util/system.h>
+#include <util/time.h>
#include <validation.h>
#include <test/setup_common.h>
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index 1db2f8054c..740d805cce 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -2,8 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <clientversion.h>
#include <flatfile.h>
+#include <streams.h>
#include <test/setup_common.h>
+#include <util/system.h>
#include <boost/test/unit_test.hpp>
@@ -11,7 +14,7 @@ BOOST_FIXTURE_TEST_SUITE(flatfile_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(flatfile_filename)
{
- auto data_dir = SetDataDir("flatfile_test");
+ const auto data_dir = GetDataDir();
FlatFilePos pos(456, 789);
@@ -24,7 +27,7 @@ BOOST_AUTO_TEST_CASE(flatfile_filename)
BOOST_AUTO_TEST_CASE(flatfile_open)
{
- auto data_dir = SetDataDir("flatfile_test");
+ const auto data_dir = GetDataDir();
FlatFileSeq seq(data_dir, "a", 16 * 1024);
std::string line1("A purely peer-to-peer version of electronic cash would allow online "
@@ -85,7 +88,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
BOOST_AUTO_TEST_CASE(flatfile_allocate)
{
- auto data_dir = SetDataDir("flatfile_test");
+ const auto data_dir = GetDataDir();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
@@ -105,7 +108,7 @@ BOOST_AUTO_TEST_CASE(flatfile_allocate)
BOOST_AUTO_TEST_CASE(flatfile_flush)
{
- auto data_dir = SetDataDir("flatfile_test");
+ const auto data_dir = GetDataDir();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index 6bd6bb1be3..6d5a6641f0 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -4,6 +4,7 @@
//
#include <fs.h>
#include <test/setup_common.h>
+#include <util/system.h>
#include <boost/test/unit_test.hpp>
@@ -11,7 +12,7 @@ BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(fsbridge_fstream)
{
- fs::path tmpfolder = SetDataDir("fsbridge_fstream");
+ fs::path tmpfolder = GetDataDir();
// tmpfile1 should be the same as tmpfile2
fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃";
fs::path tmpfile2 = tmpfolder / L"fs_tests_₿_🏃";
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index 97d7633715..9364ac4a32 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <addrdb.h>
#include <addrman.h>
#include <blockencodings.h>
#include <chain.h>
@@ -11,8 +12,6 @@
#include <net.h>
#include <primitives/block.h>
#include <protocol.h>
-#include <pubkey.h>
-#include <script/script.h>
#include <streams.h>
#include <undo.h>
#include <version.h>
@@ -20,8 +19,6 @@
#include <stdint.h>
#include <unistd.h>
-#include <algorithm>
-#include <memory>
#include <vector>
#include <test/fuzz/fuzz.h>
diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h
index 8b03a7e46e..4e009d9b54 100644
--- a/src/test/fuzz/fuzz.h
+++ b/src/test/fuzz/fuzz.h
@@ -5,7 +5,6 @@
#ifndef BITCOIN_TEST_FUZZ_FUZZ_H
#define BITCOIN_TEST_FUZZ_FUZZ_H
-#include <functional>
#include <stdint.h>
#include <vector>
diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp
index 2c0bfa360c..9b90d66755 100644
--- a/src/test/fuzz/script_flags.cpp
+++ b/src/test/fuzz/script_flags.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <script/interpreter.h>
-#include <script/script.h>
#include <streams.h>
#include <version.h>
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index 325b7002f2..d91fcb0034 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -2,13 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <clientversion.h>
#include <crypto/siphash.h>
#include <hash.h>
#include <util/strencodings.h>
#include <test/setup_common.h>
-#include <vector>
-
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup)
diff --git a/src/test/key_properties.cpp b/src/test/key_properties.cpp
index 8b508ed7f7..abcfc4547b 100644
--- a/src/test/key_properties.cpp
+++ b/src/test/key_properties.cpp
@@ -3,13 +3,9 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key.h>
-#include <base58.h>
-#include <script/script.h>
#include <uint256.h>
#include <util/system.h>
-#include <util/strencodings.h>
#include <test/setup_common.h>
-#include <string>
#include <vector>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 1b95105eab..3e99dcaa40 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -5,7 +5,6 @@
#include <key.h>
#include <key_io.h>
-#include <script/script.h>
#include <uint256.h>
#include <util/system.h>
#include <util/strencodings.h>
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 0f74b379c0..c6a3de2285 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -5,11 +5,11 @@
#include <policy/policy.h>
#include <txmempool.h>
#include <util/system.h>
+#include <util/time.h>
#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
-#include <list>
#include <vector>
BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup)
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 4321d7d16e..4bd40687a6 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -7,15 +7,14 @@
#include <consensus/consensus.h>
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
-#include <consensus/validation.h>
#include <miner.h>
#include <policy/policy.h>
-#include <pubkey.h>
#include <script/standard.h>
#include <txmempool.h>
#include <uint256.h>
#include <util/strencodings.h>
#include <util/system.h>
+#include <util/time.h>
#include <validation.h>
#include <test/setup_common.h>
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 682f1bee26..11e79937be 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -9,7 +9,7 @@
#include <script/script_error.h>
#include <script/interpreter.h>
#include <script/sign.h>
-#include <script/ismine.h>
+#include <tinyformat.h>
#include <uint256.h>
#include <test/setup_common.h>
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 54d18c0a1c..fed65afdbf 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -1,16 +1,19 @@
// Copyright (c) 2012-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 <addrdb.h>
#include <addrman.h>
+#include <clientversion.h>
#include <test/setup_common.h>
#include <string>
#include <boost/test/unit_test.hpp>
-#include <hash.h>
#include <serialize.h>
#include <streams.h>
#include <net.h>
#include <netbase.h>
#include <chainparams.h>
+#include <util/memory.h>
#include <util/system.h>
#include <memory>
@@ -89,7 +92,6 @@ BOOST_AUTO_TEST_CASE(cnode_listen_port)
BOOST_AUTO_TEST_CASE(caddrdb_read)
{
- SetDataDir("caddrdb_read");
CAddrManUncorrupted addrmanUncorrupted;
addrmanUncorrupted.MakeDeterministic();
@@ -135,7 +137,6 @@ BOOST_AUTO_TEST_CASE(caddrdb_read)
BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
{
- SetDataDir("caddrdb_read_corrupted");
CAddrManCorrupted addrmanCorrupted;
addrmanCorrupted.MakeDeterministic();
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index dd5e3eb6d5..86c0cecbf1 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -59,6 +59,7 @@ BOOST_AUTO_TEST_CASE(netbase_properties)
BOOST_CHECK(ResolveIP("FC00::").IsRFC4193());
BOOST_CHECK(ResolveIP("2001::2").IsRFC4380());
BOOST_CHECK(ResolveIP("2001:10::").IsRFC4843());
+ BOOST_CHECK(ResolveIP("2001:20::").IsRFC7343());
BOOST_CHECK(ResolveIP("FE80::").IsRFC4862());
BOOST_CHECK(ResolveIP("64:FF9B::").IsRFC6052());
BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor());
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 149094fc00..016a4f471b 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -7,6 +7,7 @@
#include <txmempool.h>
#include <uint256.h>
#include <util/system.h>
+#include <util/time.h>
#include <test/setup_common.h>
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index 653433bfce..1123d4202c 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -5,7 +5,6 @@
#include <chain.h>
#include <chainparams.h>
#include <pow.h>
-#include <random.h>
#include <util/system.h>
#include <test/setup_common.h>
diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp
index 141be50f50..fc1f946bba 100644
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -183,6 +183,26 @@ public:
pre_vector = pre_vector_alt;
}
+ void resize_uninitialized(realtype values) {
+ size_t r = values.size();
+ size_t s = real_vector.size() / 2;
+ if (real_vector.capacity() < s + r) {
+ real_vector.reserve(s + r);
+ }
+ real_vector.resize(s);
+ pre_vector.resize_uninitialized(s);
+ for (auto v : values) {
+ real_vector.push_back(v);
+ }
+ auto p = pre_vector.size();
+ pre_vector.resize_uninitialized(p + r);
+ for (auto v : values) {
+ pre_vector[p] = v;
+ ++p;
+ }
+ test();
+ }
+
~prevector_tester() {
BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString());
}
@@ -260,6 +280,14 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt)
if (InsecureRandBits(5) == 18) {
test.move();
}
+ if (InsecureRandBits(5) == 19) {
+ unsigned int num = 1 + (InsecureRandBits(4));
+ std::vector<int> values(num);
+ for (auto &v : values) {
+ v = InsecureRand32();
+ }
+ test.resize_uninitialized(values);
+ }
}
}
}
diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp
index 2b01acf7fa..41ca8029e5 100644
--- a/src/test/raii_event_tests.cpp
+++ b/src/test/raii_event_tests.cpp
@@ -14,8 +14,6 @@
#include <test/setup_common.h>
-#include <vector>
-
#include <boost/test/unit_test.hpp>
static std::map<void*, short> tags;
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 07d1326bcb..5ae0812243 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -9,10 +9,8 @@
#include <core_io.h>
#include <init.h>
#include <interfaces/chain.h>
-#include <key_io.h>
-#include <netbase.h>
-
#include <test/setup_common.h>
+#include <util/time.h>
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index 9c4606f1b3..735b67c06e 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/tx_verify.h>
-#include <core_io.h>
#include <key.h>
#include <keystore.h>
#include <validation.h>
@@ -12,7 +11,6 @@
#include <script/script_error.h>
#include <policy/settings.h>
#include <script/sign.h>
-#include <script/ismine.h>
#include <test/setup_common.h>
#include <vector>
@@ -99,7 +97,6 @@ BOOST_AUTO_TEST_CASE(sign)
txTo[i].vin[0].prevout.n = i;
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1;
- BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
}
for (int i = 0; i < 8; i++)
{
@@ -196,7 +193,6 @@ BOOST_AUTO_TEST_CASE(set)
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1*CENT;
txTo[i].vout[0].scriptPubKey = inner[i];
- BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
}
for (int i = 0; i < 4; i++)
{
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index 9f50083335..046b220e3f 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -4,9 +4,7 @@
#include <key.h>
#include <keystore.h>
-#include <script/ismine.h>
#include <script/script.h>
-#include <script/script_error.h>
#include <script/standard.h>
#include <test/setup_common.h>
@@ -372,364 +370,4 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_)
BOOST_CHECK(result == expected);
}
-BOOST_AUTO_TEST_CASE(script_standard_IsMine)
-{
- CKey keys[2];
- CPubKey pubkeys[2];
- for (int i = 0; i < 2; i++) {
- keys[i].MakeNewKey(true);
- pubkeys[i] = keys[i].GetPubKey();
- }
-
- CKey uncompressedKey;
- uncompressedKey.MakeNewKey(false);
- CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
-
- CScript scriptPubKey;
- isminetype result;
-
- // P2PK compressed
- {
- CBasicKeyStore keystore;
- scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
-
- // Keystore does not have key
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has key
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2PK uncompressed
- {
- CBasicKeyStore keystore;
- scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
-
- // Keystore does not have key
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has key
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2PKH compressed
- {
- CBasicKeyStore keystore;
- scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
-
- // Keystore does not have key
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has key
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2PKH uncompressed
- {
- CBasicKeyStore keystore;
- scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
-
- // Keystore does not have key
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has key
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2SH
- {
- CBasicKeyStore keystore;
-
- CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
- scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
-
- // Keystore does not have redeemScript or key
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has redeemScript but no key
- BOOST_CHECK(keystore.AddCScript(redeemScript));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has redeemScript and key
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // (P2PKH inside) P2SH inside P2SH (invalid)
- {
- CBasicKeyStore keystore;
-
- CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
- CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner));
- scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript));
-
- BOOST_CHECK(keystore.AddCScript(redeemscript));
- BOOST_CHECK(keystore.AddCScript(redeemscript_inner));
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // (P2PKH inside) P2SH inside P2WSH (invalid)
- {
- CBasicKeyStore keystore;
-
- CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0]));
- CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript));
- scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
-
- BOOST_CHECK(keystore.AddCScript(witnessscript));
- BOOST_CHECK(keystore.AddCScript(redeemscript));
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // P2WPKH inside P2WSH (invalid)
- {
- CBasicKeyStore keystore;
-
- CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
- scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
-
- BOOST_CHECK(keystore.AddCScript(witnessscript));
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // (P2PKH inside) P2WSH inside P2WSH (invalid)
- {
- CBasicKeyStore keystore;
-
- CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
- CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
- scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
-
- BOOST_CHECK(keystore.AddCScript(witnessscript_inner));
- BOOST_CHECK(keystore.AddCScript(witnessscript));
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // P2WPKH compressed
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
-
- scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
-
- // Keystore implicitly has key and P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2WPKH uncompressed
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
-
- scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(uncompressedPubkey)));
-
- // Keystore has key, but no P2SH redeemScript
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has key and P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // scriptPubKey multisig
- {
- CBasicKeyStore keystore;
-
- scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
-
- // Keystore does not have any keys
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has 1/2 keys
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has 2/2 keys
- BOOST_CHECK(keystore.AddKey(keys[1]));
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has 2/2 keys and the script
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // P2SH multisig
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
- BOOST_CHECK(keystore.AddKey(keys[1]));
-
- CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
- scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
-
- // Keystore has no redeemScript
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has redeemScript
- BOOST_CHECK(keystore.AddCScript(redeemScript));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2WSH multisig with compressed keys
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
- BOOST_CHECK(keystore.AddKey(keys[1]));
-
- CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
- scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
-
- // Keystore has keys, but no witnessScript or P2SH redeemScript
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has keys and witnessScript, but no P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(witnessScript));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has keys, witnessScript, P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2WSH multisig with uncompressed key
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
- BOOST_CHECK(keystore.AddKey(keys[1]));
-
- CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
- scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
-
- // Keystore has keys, but no witnessScript or P2SH redeemScript
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has keys and witnessScript, but no P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(witnessScript));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has keys, witnessScript, P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // P2WSH multisig wrapped in P2SH
- {
- CBasicKeyStore keystore;
-
- CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
- CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
- scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
-
- // Keystore has no witnessScript, P2SH redeemScript, or keys
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has witnessScript and P2SH redeemScript, but no keys
- BOOST_CHECK(keystore.AddCScript(redeemScript));
- BOOST_CHECK(keystore.AddCScript(witnessScript));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has keys, witnessScript, P2SH redeemScript
- BOOST_CHECK(keystore.AddKey(keys[0]));
- BOOST_CHECK(keystore.AddKey(keys[1]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // OP_RETURN
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
-
- scriptPubKey.clear();
- scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // witness unspendable
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
-
- scriptPubKey.clear();
- scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb"));
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // witness unknown
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
-
- scriptPubKey.clear();
- scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb"));
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // Nonstandard
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
-
- scriptPubKey.clear();
- scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-}
-
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 4798909e2f..ae903df0ad 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -14,12 +14,12 @@
#include <util/strencodings.h>
#include <test/setup_common.h>
#include <rpc/util.h>
+#include <streams.h>
#if defined(HAVE_CONSENSUS_LIB)
#include <script/bitcoinconsensus.h>
#endif
-#include <fstream>
#include <stdint.h>
#include <string>
#include <vector>
diff --git a/src/test/scriptnum10.h b/src/test/scriptnum10.h
index e763b64275..2c89a18331 100644
--- a/src/test/scriptnum10.h
+++ b/src/test/scriptnum10.h
@@ -6,7 +6,6 @@
#ifndef BITCOIN_TEST_SCRIPTNUM10_H
#define BITCOIN_TEST_SCRIPTNUM10_H
-#include <algorithm>
#include <limits>
#include <stdexcept>
#include <stdint.h>
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 2fab309aa4..8a8620938e 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -6,6 +6,7 @@
#include <streams.h>
#include <hash.h>
#include <test/setup_common.h>
+#include <util/strencodings.h>
#include <stdint.h>
diff --git a/src/test/setup_common.cpp b/src/test/setup_common.cpp
index 5b454da52b..24c7d51898 100644
--- a/src/test/setup_common.cpp
+++ b/src/test/setup_common.cpp
@@ -10,17 +10,22 @@
#include <consensus/params.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
+#include <init.h>
#include <miner.h>
-#include <net_processing.h>
+#include <net.h>
#include <noui.h>
#include <pow.h>
#include <rpc/register.h>
#include <rpc/server.h>
#include <script/sigcache.h>
#include <streams.h>
-#include <ui_interface.h>
+#include <txdb.h>
+#include <util/memory.h>
+#include <util/strencodings.h>
+#include <util/time.h>
#include <util/validation.h>
#include <validation.h>
+#include <validationinterface.h>
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
@@ -35,6 +40,13 @@ std::ostream& operator<<(std::ostream& os, const uint256& num)
BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
: m_path_root(fs::temp_directory_path() / "test_common_" PACKAGE_NAME / strprintf("%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(1 << 30))))
{
+ fs::create_directories(m_path_root);
+ gArgs.ForceSetArg("-datadir", m_path_root.string());
+ ClearDatadirCache();
+ SelectParams(chainName);
+ gArgs.ForceSetArg("-printtoconsole", "0");
+ InitLogging();
+ LogInstance().StartLogging();
SHA256AutoDetect();
ECC_Start();
SetupEnvironment();
@@ -42,7 +54,6 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
InitSignatureCache();
InitScriptExecutionCache();
fCheckBlockIndex = true;
- SelectParams(chainName);
static bool noui_connected = false;
if (!noui_connected) {
noui_connect();
@@ -52,27 +63,17 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
BasicTestingSetup::~BasicTestingSetup()
{
+ LogInstance().DisconnectTestLogger();
fs::remove_all(m_path_root);
ECC_Stop();
}
-fs::path BasicTestingSetup::SetDataDir(const std::string& name)
-{
- fs::path ret = m_path_root / name;
- fs::create_directories(ret);
- gArgs.ForceSetArg("-datadir", ret.string());
- return ret;
-}
-
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
{
- SetDataDir("tempdir");
const CChainParams& chainparams = Params();
// Ideally we'd move all the RPC tests to the functional testing framework
// instead of unit tests, but for now we need these here.
-
RegisterAllCoreRPCCommands(tableRPC);
- ClearDatadirCache();
// We have to run a scheduler thread to prevent ActivateBestChain
// from blocking due to queue overrun.
diff --git a/src/test/setup_common.h b/src/test/setup_common.h
index 893eca216d..6c9494898c 100644
--- a/src/test/setup_common.h
+++ b/src/test/setup_common.h
@@ -11,10 +11,8 @@
#include <pubkey.h>
#include <random.h>
#include <scheduler.h>
-#include <txdb.h>
#include <txmempool.h>
-#include <memory>
#include <type_traits>
#include <boost/thread.hpp>
@@ -54,22 +52,19 @@ static inline bool InsecureRandBool() { return g_insecure_rand_ctx.randbool(); }
static constexpr CAmount CENT{1000000};
/** Basic testing setup.
- * This just configures logging and chain parameters.
+ * This just configures logging, data dir and chain parameters.
*/
struct BasicTestingSetup {
ECCVerifyHandle globalVerifyHandle;
explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~BasicTestingSetup();
-
- fs::path SetDataDir(const std::string& name);
-
private:
const fs::path m_path_root;
};
/** Testing setup that configures a complete environment.
- * Included are data directory, coins database, script check threads setup.
+ * Included are coins database, script check threads setup.
*/
struct TestingSetup : public BasicTestingSetup {
boost::thread_group threadGroup;
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index 5c12ec13d2..a32f2cda92 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <consensus/consensus.h>
#include <consensus/tx_verify.h>
-#include <consensus/validation.h>
#include <pubkey.h>
#include <key.h>
#include <script/script.h>
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 4e37199c63..b812cef801 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <streams.h>
-#include <support/allocators/zeroafterfree.h>
#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/torcontrol_tests.cpp b/src/test/torcontrol_tests.cpp
index 6d8459f5b1..d846062d9b 100644
--- a/src/test/torcontrol_tests.cpp
+++ b/src/test/torcontrol_tests.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#include <test/setup_common.h>
-#include <torcontrol.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index f5ff18c055..f77b77a972 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -20,6 +20,7 @@
#include <script/sign.h>
#include <script/script_error.h>
#include <script/standard.h>
+#include <streams.h>
#include <util/strencodings.h>
#include <map>
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index 19561d4f67..d794d09d30 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -8,7 +8,6 @@
#include <test/setup_common.h>
#include <util/system.h>
#include <util/time.h>
-#include <validation.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp
index 26ae7be202..2356e0ccdc 100644
--- a/src/test/txvalidation_tests.cpp
+++ b/src/test/txvalidation_tests.cpp
@@ -3,8 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <validation.h>
-#include <txmempool.h>
-#include <amount.h>
#include <consensus/validation.h>
#include <primitives/transaction.h>
#include <script/script.h>
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index fe30d5f3a7..45c97fa2aa 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -5,17 +5,11 @@
#include <consensus/validation.h>
#include <key.h>
#include <validation.h>
-#include <miner.h>
-#include <pubkey.h>
#include <txmempool.h>
-#include <random.h>
#include <script/standard.h>
#include <script/sign.h>
#include <test/setup_common.h>
-#include <util/time.h>
-#include <core_io.h>
#include <keystore.h>
-#include <policy/policy.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp
index c1749fb856..33a118c2bb 100644
--- a/src/test/uint256_tests.cpp
+++ b/src/test/uint256_tests.cpp
@@ -1,19 +1,17 @@
// Copyright (c) 2011-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 <arith_uint256.h>
+#include <streams.h>
#include <uint256.h>
#include <version.h>
#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
-#include <stdint.h>
#include <sstream>
#include <iomanip>
-#include <limits>
-#include <cmath>
#include <string>
-#include <stdio.h>
BOOST_FIXTURE_TEST_SUITE(uint256_tests, BasicTestingSetup)
diff --git a/src/test/util.cpp b/src/test/util.cpp
index 64ecc6623a..a2ea648324 100644
--- a/src/test/util.cpp
+++ b/src/test/util.cpp
@@ -6,22 +6,17 @@
#include <chainparams.h>
#include <consensus/merkle.h>
-#include <consensus/validation.h>
#include <key_io.h>
#include <miner.h>
#include <outputtype.h>
#include <pow.h>
-#include <scheduler.h>
#include <script/standard.h>
-#include <txdb.h>
#include <validation.h>
#include <validationinterface.h>
#ifdef ENABLE_WALLET
#include <wallet/wallet.h>
#endif
-#include <boost/thread.hpp>
-
const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj";
#ifdef ENABLE_WALLET
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 8fee66d6c3..9960573b33 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -5,14 +5,15 @@
#include <util/system.h>
#include <clientversion.h>
-#include <primitives/transaction.h>
#include <sync.h>
#include <test/util.h>
#include <util/strencodings.h>
#include <util/moneystr.h>
+#include <util/time.h>
#include <test/setup_common.h>
#include <stdint.h>
+#include <thread>
#include <vector>
#ifndef WIN32
#include <signal.h>
@@ -1398,7 +1399,7 @@ static void TestOtherProcess(fs::path dirname, std::string lockname, int fd)
BOOST_AUTO_TEST_CASE(test_LockDirectory)
{
- fs::path dirname = SetDataDir("test_LockDirectory") / fs::unique_path();
+ fs::path dirname = GetDataDir() / "lock_dir";
const std::string lockname = ".lock";
#ifndef WIN32
// Revert SIGCHLD to default, otherwise boost.test will catch and fail on
@@ -1487,7 +1488,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
BOOST_AUTO_TEST_CASE(test_DirIsWritable)
{
// Should be able to write to the data dir.
- fs::path tmpdirname = SetDataDir("test_DirIsWritable");
+ fs::path tmpdirname = GetDataDir();
BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
// Should not be able to write to a non-existent dir.
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 5dee034b20..b3368d44b6 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -10,14 +10,20 @@
#include <miner.h>
#include <pow.h>
#include <random.h>
+#include <script/standard.h>
#include <test/setup_common.h>
+#include <util/time.h>
#include <validation.h>
#include <validationinterface.h>
+#include <thread>
+
struct RegtestingSetup : public TestingSetup {
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {}
};
+static const std::vector<unsigned char> V_OP_TRUE{OP_TRUE};
+
BOOST_FIXTURE_TEST_SUITE(validation_block_tests, RegtestingSetup)
struct TestSubscriber : public CValidationInterface {
@@ -59,8 +65,21 @@ std::shared_ptr<CBlock> Block(const uint256& prev_hash)
pblock->hashPrevBlock = prev_hash;
pblock->nTime = ++time;
+ pubKey.clear();
+ {
+ WitnessV0ScriptHash witness_program;
+ CSHA256().Write(&V_OP_TRUE[0], V_OP_TRUE.size()).Finalize(witness_program.begin());
+ pubKey << OP_0 << ToByteVector(witness_program);
+ }
+
+ // Make the coinbase transaction with two outputs:
+ // One zero-value one that has a unique pubkey to make sure that blocks at the same height can have a different hash
+ // Another one that has the coinbase reward in a P2WSH with OP_TRUE as witness program to make it easy to spend
CMutableTransaction txCoinbase(*pblock->vtx[0]);
- txCoinbase.vout.resize(1);
+ txCoinbase.vout.resize(2);
+ txCoinbase.vout[1].scriptPubKey = pubKey;
+ txCoinbase.vout[1].nValue = txCoinbase.vout[0].nValue;
+ txCoinbase.vout[0].nValue = 0;
txCoinbase.vin[0].scriptWitness.SetNull();
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
@@ -69,6 +88,9 @@ std::shared_ptr<CBlock> Block(const uint256& prev_hash)
std::shared_ptr<CBlock> FinalizeBlock(std::shared_ptr<CBlock> pblock)
{
+ LOCK(cs_main); // For LookupBlockIndex
+ GenerateCoinbaseCommitment(*pblock, LookupBlockIndex(pblock->hashPrevBlock), Params().GetConsensus());
+
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
@@ -79,13 +101,13 @@ std::shared_ptr<CBlock> FinalizeBlock(std::shared_ptr<CBlock> pblock)
}
// construct a valid block
-const std::shared_ptr<const CBlock> GoodBlock(const uint256& prev_hash)
+std::shared_ptr<const CBlock> GoodBlock(const uint256& prev_hash)
{
return FinalizeBlock(Block(prev_hash));
}
// construct an invalid block (but with a valid header)
-const std::shared_ptr<const CBlock> BadBlock(const uint256& prev_hash)
+std::shared_ptr<const CBlock> BadBlock(const uint256& prev_hash)
{
auto pblock = Block(prev_hash);
@@ -185,4 +207,131 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
BOOST_CHECK_EQUAL(sub.m_expected_tip, ::ChainActive().Tip()->GetBlockHash());
}
+/**
+ * Test that mempool updates happen atomically with reorgs.
+ *
+ * This prevents RPC clients, among others, from retrieving immediately-out-of-date mempool data
+ * during large reorgs.
+ *
+ * The test verifies this by creating a chain of `num_txs` blocks, matures their coinbases, and then
+ * submits txns spending from their coinbase to the mempool. A fork chain is then processed,
+ * invalidating the txns and evicting them from the mempool.
+ *
+ * We verify that the mempool updates atomically by polling it continuously
+ * from another thread during the reorg and checking that its size only changes
+ * once. The size changing exactly once indicates that the polling thread's
+ * view of the mempool is either consistent with the chain state before reorg,
+ * or consistent with the chain state after the reorg, and not just consistent
+ * with some intermediate state during the reorg.
+ */
+BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
+{
+ bool ignored;
+ auto ProcessBlock = [&ignored](std::shared_ptr<const CBlock> block) -> bool {
+ return ProcessNewBlock(Params(), block, /* fForceProcessing */ true, /* fNewBlock */ &ignored);
+ };
+
+ // Process all mined blocks
+ BOOST_REQUIRE(ProcessBlock(std::make_shared<CBlock>(Params().GenesisBlock())));
+ auto last_mined = GoodBlock(Params().GenesisBlock().GetHash());
+ BOOST_REQUIRE(ProcessBlock(last_mined));
+
+ // Run the test multiple times
+ for (int test_runs = 3; test_runs > 0; --test_runs) {
+ BOOST_CHECK_EQUAL(last_mined->GetHash(), ::ChainActive().Tip()->GetBlockHash());
+
+ // Later on split from here
+ const uint256 split_hash{last_mined->hashPrevBlock};
+
+ // Create a bunch of transactions to spend the miner rewards of the
+ // most recent blocks
+ std::vector<CTransactionRef> txs;
+ for (int num_txs = 22; num_txs > 0; --num_txs) {
+ CMutableTransaction mtx;
+ mtx.vin.push_back(CTxIn{COutPoint{last_mined->vtx[0]->GetHash(), 1}, CScript{}});
+ mtx.vin[0].scriptWitness.stack.push_back(V_OP_TRUE);
+ mtx.vout.push_back(last_mined->vtx[0]->vout[1]);
+ mtx.vout[0].nValue -= 1000;
+ txs.push_back(MakeTransactionRef(mtx));
+
+ last_mined = GoodBlock(last_mined->GetHash());
+ BOOST_REQUIRE(ProcessBlock(last_mined));
+ }
+
+ // Mature the inputs of the txs
+ for (int j = COINBASE_MATURITY; j > 0; --j) {
+ last_mined = GoodBlock(last_mined->GetHash());
+ BOOST_REQUIRE(ProcessBlock(last_mined));
+ }
+
+ // Mine a reorg (and hold it back) before adding the txs to the mempool
+ const uint256 tip_init{last_mined->GetHash()};
+
+ std::vector<std::shared_ptr<const CBlock>> reorg;
+ last_mined = GoodBlock(split_hash);
+ reorg.push_back(last_mined);
+ for (size_t j = COINBASE_MATURITY + txs.size() + 1; j > 0; --j) {
+ last_mined = GoodBlock(last_mined->GetHash());
+ reorg.push_back(last_mined);
+ }
+
+ // Add the txs to the tx pool
+ {
+ LOCK(cs_main);
+ CValidationState state;
+ std::list<CTransactionRef> plTxnReplaced;
+ for (const auto& tx : txs) {
+ BOOST_REQUIRE(AcceptToMemoryPool(
+ ::mempool,
+ state,
+ tx,
+ /* pfMissingInputs */ &ignored,
+ &plTxnReplaced,
+ /* bypass_limits */ false,
+ /* nAbsurdFee */ 0));
+ }
+ }
+
+ // Check that all txs are in the pool
+ {
+ LOCK(::mempool.cs);
+ BOOST_CHECK_EQUAL(::mempool.mapTx.size(), txs.size());
+ }
+
+ // Run a thread that simulates an RPC caller that is polling while
+ // validation is doing a reorg
+ std::thread rpc_thread{[&]() {
+ // This thread is checking that the mempool either contains all of
+ // the transactions invalidated by the reorg, or none of them, and
+ // not some intermediate amount.
+ while (true) {
+ LOCK(::mempool.cs);
+ if (::mempool.mapTx.size() == 0) {
+ // We are done with the reorg
+ break;
+ }
+ // Internally, we might be in the middle of the reorg, but
+ // externally the reorg to the most-proof-of-work chain should
+ // be atomic. So the caller assumes that the returned mempool
+ // is consistent. That is, it has all txs that were there
+ // before the reorg.
+ assert(::mempool.mapTx.size() == txs.size());
+ continue;
+ }
+ LOCK(cs_main);
+ // We are done with the reorg, so the tip must have changed
+ assert(tip_init != ::ChainActive().Tip()->GetBlockHash());
+ }};
+
+ // Submit the reorg in this thread to invalidate and remove the txs from the tx pool
+ for (const auto& b : reorg) {
+ ProcessBlock(b);
+ }
+ // Check that the reorg was eventually successful
+ BOOST_CHECK_EQUAL(last_mined->GetHash(), ::ChainActive().Tip()->GetBlockHash());
+
+ // We can join the other thread, which returns when the reorg was successful
+ rpc_thread.join();
+ }
+}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/timedata.cpp b/src/timedata.cpp
index 9c022c9ad1..f4613eeec8 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -12,7 +12,6 @@
#include <sync.h>
#include <ui_interface.h>
#include <util/system.h>
-#include <util/strencodings.h>
#include <warnings.h>
@@ -101,7 +100,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
if (!fMatch)
{
fDone = true;
- std::string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), _(PACKAGE_NAME));
+ std::string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), PACKAGE_NAME);
SetMiscWarning(strMessage);
uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
}
diff --git a/src/tinyformat.h b/src/tinyformat.h
index 14b7cd3026..182f518a0b 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -1063,6 +1063,7 @@ std::string format(const std::string &fmt, const Args&... args)
} // namespace tinyformat
+/** Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for details) */
#define strprintf tfm::format
#endif // TINYFORMAT_H_INCLUDED
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 550e23b222..a1c730ba08 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <chainparams.h>
#include <torcontrol.h>
#include <util/strencodings.h>
#include <netbase.h>
@@ -412,7 +413,7 @@ public:
TorController(struct event_base* base, const std::string& target);
~TorController();
- /** Get name fo file to store private key in */
+ /** Get name of file to store private key in */
fs::path GetPrivateKeyFile();
/** Reconnect, after getting disconnected */
@@ -500,7 +501,7 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe
}
return;
}
- service = LookupNumeric(std::string(service_id+".onion").c_str(), GetListenPort());
+ service = LookupNumeric(std::string(service_id+".onion").c_str(), Params().GetDefaultPort());
LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString());
if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) {
LogPrint(BCLog::TOR, "tor: Cached service private key to %s\n", GetPrivateKeyFile().string());
@@ -534,9 +535,8 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
if (private_key.empty()) // No private key, generate one
private_key = "NEW:RSA1024"; // Explicitly request RSA1024 - see issue #9214
// Request hidden service, redirect port.
- // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient
- // choice. TODO; refactor the shutdown sequence some day.
- _conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()),
+ // Note that the 'virtual' port is always the default port to avoid decloaking nodes using other ports.
+ _conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, Params().GetDefaultPort(), GetListenPort()),
std::bind(&TorController::add_onion_cb, this, std::placeholders::_1, std::placeholders::_2));
} else {
LogPrintf("tor: Authentication failed\n");
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 494b87ad48..73fe2a8ee4 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -5,8 +5,6 @@
#include <txdb.h>
-#include <chainparams.h>
-#include <hash.h>
#include <random.h>
#include <pow.h>
#include <shutdown.h>
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 80dbd9c19d..9257cff718 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -13,8 +13,6 @@
#include <policy/fees.h>
#include <policy/settings.h>
#include <reverse_iterator.h>
-#include <streams.h>
-#include <timedata.h>
#include <util/system.h>
#include <util/moneystr.h>
#include <util/time.h>
@@ -106,7 +104,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan
// for each such descendant, also update the ancestor state to include the parent.
void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate)
{
- LOCK(cs);
+ AssertLockHeld(cs);
// For each entry in vHashesToUpdate, store the set of in-mempool, but not
// in-vHashesToUpdate transactions, so that we don't have to recalculate
// descendants when we come across a previously seen entry.
@@ -324,8 +322,8 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee,
assert(int(nSigOpCostWithAncestors) >= 0);
}
-CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator) :
- nTransactionsUpdated(0), minerPolicyEstimator(estimator)
+CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator)
+ : nTransactionsUpdated(0), minerPolicyEstimator(estimator)
{
_clear(); //lock free clear
@@ -343,13 +341,11 @@ bool CTxMemPool::isSpent(const COutPoint& outpoint) const
unsigned int CTxMemPool::GetTransactionsUpdated() const
{
- LOCK(cs);
return nTransactionsUpdated;
}
void CTxMemPool::AddTransactionsUpdated(unsigned int n)
{
- LOCK(cs);
nTransactionsUpdated += n;
}
@@ -461,8 +457,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries& setDescendants
void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReason reason)
{
// Remove transaction from memory pool
- {
- LOCK(cs);
+ AssertLockHeld(cs);
setEntries txToRemove;
txiter origit = mapTx.find(origTx.GetHash());
if (origit != mapTx.end()) {
@@ -487,13 +482,12 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReaso
}
RemoveStaged(setAllRemoves, false, reason);
- }
}
void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags)
{
// Remove transactions spending a coinbase which are now immature and no-longer-final transactions
- LOCK(cs);
+ AssertLockHeld(cs);
setEntries txToRemove;
for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
const CTransaction& tx = it->GetTx();
@@ -549,7 +543,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx)
*/
void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight)
{
- LOCK(cs);
+ AssertLockHeld(cs);
std::vector<const CTxMemPoolEntry*> entries;
for (const auto& tx : vtx)
{
@@ -924,7 +918,7 @@ void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPool
}
int CTxMemPool::Expire(int64_t time) {
- LOCK(cs);
+ AssertLockHeld(cs);
indexed_transaction_set::index<entry_time>::type::iterator it = mapTx.get<entry_time>().begin();
setEntries toremove;
while (it != mapTx.get<entry_time>().end() && it->GetTime() < time) {
@@ -1017,7 +1011,7 @@ void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
}
void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining) {
- LOCK(cs);
+ AssertLockHeld(cs);
unsigned nTxnRemoved = 0;
CFeeRate maxFeeRateRemoved(0);
diff --git a/src/txmempool.h b/src/txmempool.h
index ce0b762336..565dd61f0f 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -6,12 +6,13 @@
#ifndef BITCOIN_TXMEMPOOL_H
#define BITCOIN_TXMEMPOOL_H
+#include <atomic>
+#include <map>
#include <memory>
#include <set>
-#include <map>
-#include <vector>
-#include <utility>
#include <string>
+#include <utility>
+#include <vector>
#include <amount.h>
#include <coins.h>
@@ -443,7 +444,7 @@ class CTxMemPool
{
private:
uint32_t nCheckFrequency GUARDED_BY(cs); //!< Value n means that n times in 2^32 we check.
- unsigned int nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
+ std::atomic<unsigned int> nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
CBlockPolicyEstimator* minerPolicyEstimator;
uint64_t totalTxSize; //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.
@@ -513,21 +514,12 @@ public:
* `mempool.cs` whenever adding transactions to the mempool and whenever
* changing the chain tip. It's necessary to keep both mutexes locked until
* the mempool is consistent with the new chain tip and fully populated.
- *
- * @par Consistency bug
- *
- * The second guarantee above is not currently enforced, but
- * https://github.com/bitcoin/bitcoin/pull/14193 will fix it. No known code
- * in bitcoin currently depends on second guarantee, but it is important to
- * fix for third party code that needs be able to frequently poll the
- * mempool without locking `cs_main` and without encountering missing
- * transactions during reorgs.
*/
mutable RecursiveMutex cs;
indexed_transaction_set mapTx GUARDED_BY(cs);
using txiter = indexed_transaction_set::nth_index<0>::type::const_iterator;
- std::vector<std::pair<uint256, txiter> > vTxHashes; //!< All tx witness hashes/entries in mapTx, in random order
+ std::vector<std::pair<uint256, txiter>> vTxHashes GUARDED_BY(cs); //!< All tx witness hashes/entries in mapTx, in random order
struct CompareIteratorByHash {
bool operator()(const txiter &a, const txiter &b) const {
@@ -582,10 +574,10 @@ public:
void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
- void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
- void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- void removeConflicts(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
- void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);
+ void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ void removeForReorg(const CCoinsViewCache* pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
+ void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs);
void clear();
void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); //lock free
@@ -598,7 +590,7 @@ public:
* Check that none of this transactions inputs are in the mempool, and thus
* the tx is not dependent on other mempool transactions to be included in a block.
*/
- bool HasNoInputsOf(const CTransaction& tx) const;
+ bool HasNoInputsOf(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Affect CreateNewBlock prioritisation of transactions */
void PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta);
@@ -632,7 +624,7 @@ public:
* for). Note: vHashesToUpdate should be the set of transactions from the
* disconnected block that have been accepted back into the mempool.
*/
- void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
/** Try to calculate all in-mempool ancestors of entry.
* (these are all calculated including the tx itself)
@@ -663,10 +655,10 @@ public:
* pvNoSpendsRemaining, if set, will be populated with the list of outpoints
* which are not in mempool which no longer have any spends in this mempool.
*/
- void TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining=nullptr);
+ void TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. */
- int Expire(int64_t time);
+ int Expire(int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
/**
* Calculate the ancestor and descendant count for the given transaction.
diff --git a/src/ui_interface.cpp b/src/ui_interface.cpp
index 31a95486d7..d310637145 100644
--- a/src/ui_interface.cpp
+++ b/src/ui_interface.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <ui_interface.h>
-#include <util/system.h>
#include <boost/signals2/last_value.hpp>
#include <boost/signals2/signal.hpp>
@@ -22,7 +21,8 @@ struct UISignals {
boost::signals2::signal<CClientUIInterface::NotifyBlockTipSig> NotifyBlockTip;
boost::signals2::signal<CClientUIInterface::NotifyHeaderTipSig> NotifyHeaderTip;
boost::signals2::signal<CClientUIInterface::BannedListChangedSig> BannedListChanged;
-} g_ui_signals;
+};
+static UISignals g_ui_signals;
#define ADD_SIGNALS_IMPL_WRAPPER(signal_name) \
boost::signals2::connection CClientUIInterface::signal_name##_connect(std::function<signal_name##Sig> fn) \
diff --git a/src/ui_interface.h b/src/ui_interface.h
index d408f6f889..5e0380dc45 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -69,6 +69,9 @@ public:
/** Force blocking, modal message box dialog (not just OS notification) */
MODAL = 0x10000000U,
+ /** Do not prepend error/warning prefix */
+ MSG_NOPREFIX = 0x20000000U,
+
/** Do not print contents of message to debug log */
SECURE = 0x40000000U,
diff --git a/src/uint256.cpp b/src/uint256.cpp
index e3bc9712e8..ea7164c1f0 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -37,16 +37,15 @@ void base_blob<BITS>::SetHex(const char* psz)
psz += 2;
// hex string to uint
- const char* pbegin = psz;
- while (::HexDigit(*psz) != -1)
- psz++;
- psz--;
+ size_t digits = 0;
+ while (::HexDigit(psz[digits]) != -1)
+ digits++;
unsigned char* p1 = (unsigned char*)data;
unsigned char* pend = p1 + WIDTH;
- while (psz >= pbegin && p1 < pend) {
- *p1 = ::HexDigit(*psz--);
- if (psz >= pbegin) {
- *p1 |= ((unsigned char)::HexDigit(*psz--) << 4);
+ while (digits > 0 && p1 < pend) {
+ *p1 = ::HexDigit(psz[--digits]);
+ if (digits > 0) {
+ *p1 |= ((unsigned char)::HexDigit(psz[--digits]) << 4);
p1++;
}
}
diff --git a/src/util/error.cpp b/src/util/error.cpp
index 68ffd8b046..9331a92ad7 100644
--- a/src/util/error.cpp
+++ b/src/util/error.cpp
@@ -27,6 +27,8 @@ std::string TransactionErrorString(const TransactionError err)
return "PSBTs not compatible (different transactions)";
case TransactionError::SIGHASH_MISMATCH:
return "Specified sighash value does not match existing value";
+ case TransactionError::MAX_FEE_EXCEEDED:
+ return "Fee exceeds maximum configured by -maxtxfee";
// no default case, so the compiler can warn about missing cases
}
assert(false);
diff --git a/src/util/error.h b/src/util/error.h
index d93309551b..0fd474b962 100644
--- a/src/util/error.h
+++ b/src/util/error.h
@@ -27,6 +27,7 @@ enum class TransactionError {
INVALID_PSBT,
PSBT_MISMATCH,
SIGHASH_MISMATCH,
+ MAX_FEE_EXCEEDED,
};
std::string TransactionErrorString(const TransactionError error);
diff --git a/src/util/fees.cpp b/src/util/fees.cpp
index 5fdaa1284c..cf16d5e44f 100644
--- a/src/util/fees.cpp
+++ b/src/util/fees.cpp
@@ -18,7 +18,6 @@ std::string StringForFeeReason(FeeReason reason) {
{FeeReason::PAYTXFEE, "PayTxFee set"},
{FeeReason::FALLBACK, "Fallback fee"},
{FeeReason::REQUIRED, "Minimum Required Fee"},
- {FeeReason::MAXTXFEE, "MaxTxFee limit"}
};
auto reason_string = fee_reason_strings.find(reason);
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 6925bda4ef..72b37b9187 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -1,13 +1,11 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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 <util/system.h>
#include <chainparamsbase.h>
-#include <random.h>
-#include <serialize.h>
#include <util/strencodings.h>
#include <stdarg.h>
@@ -675,7 +673,7 @@ void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
{
std::string message = FormatException(pex, pszThread);
LogPrintf("\n\n************************\n%s\n", message);
- fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
+ tfm::format(std::cerr, "\n\n************************\n%s\n", message.c_str());
}
fs::path GetDefaultDataDir()
@@ -707,19 +705,16 @@ fs::path GetDefaultDataDir()
static fs::path g_blocks_path_cache_net_specific;
static fs::path pathCached;
static fs::path pathCachedNetSpecific;
-static CCriticalSection csPathCached;
+static RecursiveMutex csPathCached;
const fs::path &GetBlocksDir()
{
-
LOCK(csPathCached);
-
fs::path &path = g_blocks_path_cache_net_specific;
- // This can be called during exceptions by LogPrintf(), so we cache the
- // value so we don't have to do memory allocations after that.
- if (!path.empty())
- return path;
+ // Cache the path to avoid calling fs::create_directories on every call of
+ // this function
+ if (!path.empty()) return path;
if (gArgs.IsArgSet("-blocksdir")) {
path = fs::system_complete(gArgs.GetArg("-blocksdir", ""));
@@ -739,15 +734,12 @@ const fs::path &GetBlocksDir()
const fs::path &GetDataDir(bool fNetSpecific)
{
-
LOCK(csPathCached);
-
fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
- // This can be called during exceptions by LogPrintf(), so we cache the
- // value so we don't have to do memory allocations after that.
- if (!path.empty())
- return path;
+ // Cache the path to avoid calling fs::create_directories on every call of
+ // this function
+ if (!path.empty()) return path;
if (gArgs.IsArgSet("-datadir")) {
path = fs::system_complete(gArgs.GetArg("-datadir", ""));
@@ -935,7 +927,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
}
}
for (const std::string& to_include : includeconf) {
- fprintf(stderr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", to_include.c_str());
+ tfm::format(std::cerr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", to_include.c_str());
}
}
}
@@ -1122,6 +1114,7 @@ fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
}
#endif
+#if HAVE_SYSTEM
void runCommand(const std::string& strCommand)
{
if (strCommand.empty()) return;
@@ -1133,6 +1126,7 @@ void runCommand(const std::string& strCommand)
if (nErr)
LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
}
+#endif
void SetupEnvironment()
{
@@ -1190,10 +1184,11 @@ int GetNumCores()
std::string CopyrightHolders(const std::string& strPrefix)
{
- std::string strCopyrightHolders = strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION));
+ const auto copyright_devs = strprintf(_(COPYRIGHT_HOLDERS), COPYRIGHT_HOLDERS_SUBSTITUTION);
+ std::string strCopyrightHolders = strPrefix + copyright_devs;
- // Check for untranslated substitution to make sure Bitcoin Core copyright is not removed by accident
- if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Bitcoin Core") == std::string::npos) {
+ // Make sure Bitcoin Core copyright is not removed by accident
+ if (copyright_devs.find("Bitcoin Core") == std::string::npos) {
strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers";
}
return strCopyrightHolders;
diff --git a/src/util/system.h b/src/util/system.h
index 1a83cb67b1..dda9156488 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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.
@@ -20,18 +20,16 @@
#include <fs.h>
#include <logging.h>
#include <sync.h>
-#include <util/threadnames.h>
#include <tinyformat.h>
#include <util/memory.h>
+#include <util/threadnames.h>
#include <util/time.h>
-#include <atomic>
#include <exception>
#include <map>
#include <set>
#include <stdint.h>
#include <string>
-#include <unordered_set>
#include <utility>
#include <vector>
@@ -85,12 +83,15 @@ fs::path GetDefaultDataDir();
// The blocks directory is always net specific.
const fs::path &GetBlocksDir();
const fs::path &GetDataDir(bool fNetSpecific = true);
+/** Tests only */
void ClearDatadirCache();
fs::path GetConfigFile(const std::string& confPath);
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
+#if HAVE_SYSTEM
void runCommand(const std::string& strCommand);
+#endif
/**
* Most paths passed as configuration arguments are treated as relative to
diff --git a/src/validation.cpp b/src/validation.cpp
index 436c62261b..262b6856a4 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -20,7 +20,6 @@
#include <index/txindex.h>
#include <policy/fees.h>
#include <policy/policy.h>
-#include <policy/rbf.h>
#include <policy/settings.h>
#include <pow.h>
#include <primitives/block.h>
@@ -60,165 +59,27 @@
#define MICRO 0.000001
#define MILLI 0.001
-/**
- * Global state
- */
-namespace {
- struct CBlockIndexWorkComparator
- {
- bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
- // First sort by most total work, ...
- if (pa->nChainWork > pb->nChainWork) return false;
- if (pa->nChainWork < pb->nChainWork) return true;
-
- // ... then by earliest time received, ...
- if (pa->nSequenceId < pb->nSequenceId) return false;
- if (pa->nSequenceId > pb->nSequenceId) return true;
-
- // Use pointer address as tie breaker (should only happen with blocks
- // loaded from disk, as those all have id 0).
- if (pa < pb) return false;
- if (pa > pb) return true;
-
- // Identical blocks.
- return false;
- }
- };
-} // anon namespace
-
-enum DisconnectResult
-{
- DISCONNECT_OK, // All good.
- DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
- DISCONNECT_FAILED // Something else went wrong.
-};
-
-class ConnectTrace;
-
-/**
- * CChainState stores and provides an API to update our local knowledge of the
- * current best chain and header tree.
- *
- * It generally provides access to the current block tree, as well as functions
- * to provide new data, which it will appropriately validate and incorporate in
- * its state as necessary.
- *
- * Eventually, the API here is targeted at being exposed externally as a
- * consumable libconsensus library, so any functions added must only call
- * other class member functions, pure functions in other parts of the consensus
- * library, callbacks via the validation interface, or read/write-to-disk
- * functions (eventually this will also be via callbacks).
- */
-class CChainState {
-private:
- /**
- * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
- * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
- * missing the data for the block.
- */
- std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
-
- /**
- * Every received block is assigned a unique and increasing identifier, so we
- * know which one to give priority in case of a fork.
- */
- CCriticalSection cs_nBlockSequenceId;
- /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
- int32_t nBlockSequenceId = 1;
- /** Decreasing counter (used by subsequent preciousblock calls). */
- int32_t nBlockReverseSequenceId = -1;
- /** chainwork for the last block that preciousblock has been applied to. */
- arith_uint256 nLastPreciousChainwork = 0;
-
- /** In order to efficiently track invalidity of headers, we keep the set of
- * blocks which we tried to connect and found to be invalid here (ie which
- * were set to BLOCK_FAILED_VALID since the last restart). We can then
- * walk this set and check if a new header is a descendant of something in
- * this set, preventing us from having to walk mapBlockIndex when we try
- * to connect a bad block and fail.
- *
- * While this is more complicated than marking everything which descends
- * from an invalid block as invalid at the time we discover it to be
- * invalid, doing so would require walking all of mapBlockIndex to find all
- * descendants. Since this case should be very rare, keeping track of all
- * BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
- * well.
- *
- * Because we already walk mapBlockIndex in height-order at startup, we go
- * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
- * instead of putting things in this set.
- */
- std::set<CBlockIndex*> m_failed_blocks;
-
- /**
- * the ChainState CriticalSection
- * A lock that must be held when modifying this ChainState - held in ActivateBestChain()
- */
- CCriticalSection m_cs_chainstate;
-
-public:
- //! The current chain of blockheaders we consult and build on.
- //! @see CChain, CBlockIndex.
- CChain m_chain;
- BlockMap mapBlockIndex GUARDED_BY(cs_main);
- std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
- CBlockIndex *pindexBestInvalid = nullptr;
-
- bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) LOCKS_EXCLUDED(cs_main);
+bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
+ // First sort by most total work, ...
+ if (pa->nChainWork > pb->nChainWork) return false;
+ if (pa->nChainWork < pb->nChainWork) return true;
- /**
- * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
- * that it doesn't descend from an invalid block, and then add it to mapBlockIndex.
- */
- bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- // Block (dis)connection on a given view:
- DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
- bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
- CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- // Block disconnection on our pcoinsTip:
- bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- // Manual block validity manipulation:
- bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
- bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
- void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
- bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main);
- bool LoadGenesisBlock(const CChainParams& chainparams);
-
- void PruneBlockIndexCandidates();
-
- void UnloadBlockIndex();
+ // ... then by earliest time received, ...
+ if (pa->nSequenceId < pb->nSequenceId) return false;
+ if (pa->nSequenceId > pb->nSequenceId) return true;
-private:
- bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- /** Create a new block index entry for a given block hash */
- CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- /**
- * Make various assertions about the state of the block index.
- *
- * By default this only executes fully when using the Regtest chain; see: fCheckBlockIndex.
- */
- void CheckBlockIndex(const Consensus::Params& consensusParams);
+ // Use pointer address as tie breaker (should only happen with blocks
+ // loaded from disk, as those all have id 0).
+ if (pa < pb) return false;
+ if (pa > pb) return true;
- void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ // Identical blocks.
+ return false;
+}
- bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+static CChainState g_chainstate;
- //! Mark a block as not having block data
- void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-} g_chainstate;
+CChainState& ChainstateActive() { return g_chainstate; }
CChain& ChainActive() { return g_chainstate.m_chain; }
@@ -234,7 +95,7 @@ CChain& ChainActive() { return g_chainstate.m_chain; }
*/
RecursiveMutex cs_main;
-BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex;
+BlockMap& mapBlockIndex = ::ChainstateActive().mapBlockIndex;
CBlockIndex *pindexBestHeader = nullptr;
Mutex g_best_block_mutex;
std::condition_variable g_best_block_cv;
@@ -250,7 +111,6 @@ bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300;
uint64_t nPruneTarget = 0;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
-bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
uint256 hashAssumeValid;
arith_uint256 nMinimumChainWork;
@@ -265,12 +125,12 @@ CScript COINBASE_FLAGS;
// Internal stuff
namespace {
- CBlockIndex *&pindexBestInvalid = g_chainstate.pindexBestInvalid;
+ CBlockIndex *&pindexBestInvalid = ::ChainstateActive().pindexBestInvalid;
/** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
* Pruned nodes may have entries where B is missing data.
*/
- std::multimap<CBlockIndex*, CBlockIndex*>& mapBlocksUnlinked = g_chainstate.mapBlocksUnlinked;
+ std::multimap<CBlockIndex*, CBlockIndex*>& mapBlocksUnlinked = ::ChainstateActive().mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile;
@@ -311,15 +171,7 @@ std::unique_ptr<CCoinsViewDB> pcoinsdbview;
std::unique_ptr<CCoinsViewCache> pcoinsTip;
std::unique_ptr<CBlockTreeDB> pblocktree;
-enum class FlushStateMode {
- NONE,
- IF_NEEDED,
- PERIODIC,
- ALWAYS
-};
-
// See definition for documentation
-static bool FlushStateToDisk(const CChainParams& chainParams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0);
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
@@ -452,7 +304,8 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag
// Returns the script flags which should be checked for a given block
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& chainparams);
-static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) {
+static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
+{
int expired = pool.Expire(GetTime() - age);
if (expired != 0) {
LogPrint(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired);
@@ -467,7 +320,7 @@ static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
- if (IsInitialBlockDownload())
+ if (::ChainstateActive().IsInitialBlockDownload())
return false;
if (::ChainActive().Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE))
return false;
@@ -489,7 +342,7 @@ static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
* and instead just erase from the mempool as needed.
*/
-static void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs)
{
AssertLockHeld(cs_main);
std::vector<uint256> vHashUpdate;
@@ -633,15 +486,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// unconfirmed ancestors anyway; doing otherwise is hopelessly
// insecure.
bool fReplacementOptOut = true;
- if (fEnableReplacement)
+ for (const CTxIn &_txin : ptxConflicting->vin)
{
- for (const CTxIn &_txin : ptxConflicting->vin)
+ if (_txin.nSequence <= MAX_BIP125_RBF_SEQUENCE)
{
- if (_txin.nSequence <= MAX_BIP125_RBF_SEQUENCE)
- {
- fReplacementOptOut = false;
- break;
- }
+ fReplacementOptOut = false;
+ break;
}
}
if (fReplacementOptOut) {
@@ -992,7 +842,7 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
}
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
CValidationState stateDummy;
- FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC);
+ ::ChainstateActive().FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC);
return res;
}
@@ -1168,35 +1018,39 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
return nSubsidy;
}
-bool IsInitialBlockDownload()
+// Note that though this is marked const, we may end up modifying `m_cached_finished_ibd`, which
+// is a performance-related implementation detail. This function must be marked
+// `const` so that `CValidationInterface` clients (which are given a `const CChainState*`)
+// can call it.
+//
+bool CChainState::IsInitialBlockDownload() const
{
- // Once this function has returned false, it must remain false.
- static std::atomic<bool> latchToFalse{false};
// Optimization: pre-test latch before taking the lock.
- if (latchToFalse.load(std::memory_order_relaxed))
+ if (m_cached_finished_ibd.load(std::memory_order_relaxed))
return false;
LOCK(cs_main);
- if (latchToFalse.load(std::memory_order_relaxed))
+ if (m_cached_finished_ibd.load(std::memory_order_relaxed))
return false;
if (fImporting || fReindex)
return true;
- if (::ChainActive().Tip() == nullptr)
+ if (m_chain.Tip() == nullptr)
return true;
- if (::ChainActive().Tip()->nChainWork < nMinimumChainWork)
+ if (m_chain.Tip()->nChainWork < nMinimumChainWork)
return true;
- if (::ChainActive().Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
+ if (m_chain.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
return true;
LogPrintf("Leaving InitialBlockDownload (latching to false)\n");
- latchToFalse.store(true, std::memory_order_relaxed);
+ m_cached_finished_ibd.store(true, std::memory_order_relaxed);
return false;
}
-CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr;
+static CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr;
static void AlertNotify(const std::string& strMessage)
{
uiInterface.NotifyAlertChanged();
+#if HAVE_SYSTEM
std::string strCmd = gArgs.GetArg("-alertnotify", "");
if (strCmd.empty()) return;
@@ -1210,6 +1064,7 @@ static void AlertNotify(const std::string& strMessage)
std::thread t(runCommand, strCmd);
t.detach(); // thread runs free
+#endif
}
static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -1217,7 +1072,7 @@ static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks
// (we assume we don't get stuck on a fork before finishing our initial sync)
- if (IsInitialBlockDownload())
+ if (::ChainstateActive().IsInitialBlockDownload())
return;
// If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
@@ -1522,20 +1377,22 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex)
}
/** Abort with a message */
-static bool AbortNode(const std::string& strMessage, const std::string& userMessage="")
+static bool AbortNode(const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0)
{
SetMiscWarning(strMessage);
LogPrintf("*** %s\n", strMessage);
- uiInterface.ThreadSafeMessageBox(
- userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage,
- "", CClientUIInterface::MSG_ERROR);
+ if (!userMessage.empty()) {
+ uiInterface.ThreadSafeMessageBox(userMessage, "", CClientUIInterface::MSG_ERROR | prefix);
+ } else {
+ uiInterface.ThreadSafeMessageBox(_("Error: A fatal internal error occurred, see debug.log for details"), "", CClientUIInterface::MSG_ERROR | CClientUIInterface::MSG_NOPREFIX);
+ }
StartShutdown();
return false;
}
-static bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage="")
+static bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0)
{
- AbortNode(strMessage, userMessage);
+ AbortNode(strMessage, userMessage, prefix);
return state.Error(strMessage);
}
@@ -2089,16 +1946,12 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
return true;
}
-/**
- * Update the on-disk chain state.
- * The caches and indexes are flushed depending on the mode we're called with
- * if they're too large, if it's been a while since the last write,
- * or always and in all cases if we're in prune mode and are deleting files.
- *
- * If FlushStateMode::NONE is used, then FlushStateToDisk(...) won't do anything
- * besides checking if we need to prune.
- */
-bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight) {
+bool CChainState::FlushStateToDisk(
+ const CChainParams& chainparams,
+ CValidationState &state,
+ FlushStateMode mode,
+ int nManualPruneHeight)
+{
int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
LOCK(cs_main);
static int64_t nLastWrite = 0;
@@ -2150,7 +2003,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
if (fDoFullFlush || fPeriodicWrite) {
// Depend on nMinDiskSpace to ensure we can write block index
if (!CheckDiskSpace(GetBlocksDir())) {
- return AbortNode(state, "Disk space is low!", _("Error: Disk space is low!"));
+ return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX);
}
// First make sure all block and undo data is flushed to disk.
FlushBlockFile();
@@ -2185,7 +2038,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
// an overestimation, as most will delete an existing entry or
// overwrite one. Still, use a conservative safety factor of 2.
if (!CheckDiskSpace(GetDataDir(), 48 * 2 * 2 * pcoinsTip->GetCacheSize())) {
- return AbortNode(state, "Disk space is low!", _("Error: Disk space is low!"));
+ return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX);
}
// Flush the chainstate (which may refer to block index entries).
if (!pcoinsTip->Flush())
@@ -2196,7 +2049,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
}
if (full_flush_completed) {
// Update best block in wallet (so we can detect restored wallets).
- GetMainSignals().ChainStateFlushed(::ChainActive().GetLocator());
+ GetMainSignals().ChainStateFlushed(m_chain.GetLocator());
}
} catch (const std::runtime_error& e) {
return AbortNode(state, std::string("System error while flushing: ") + e.what());
@@ -2204,19 +2057,20 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
return true;
}
-void FlushStateToDisk() {
+void CChainState::ForceFlushStateToDisk() {
CValidationState state;
const CChainParams& chainparams = Params();
- if (!FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
+ if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
}
}
-void PruneAndFlush() {
+void CChainState::PruneAndFlush() {
CValidationState state;
fCheckForPruning = true;
const CChainParams& chainparams = Params();
- if (!FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) {
+
+ if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) {
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
}
}
@@ -2250,7 +2104,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
}
std::string warningMessages;
- if (!IsInitialBlockDownload())
+ if (!::ChainstateActive().IsInitialBlockDownload())
{
int nUpgraded = 0;
const CBlockIndex* pindex = pindexNew;
@@ -2641,7 +2495,7 @@ static void NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) {
if (pindexHeader != pindexHeaderOld) {
fNotify = true;
- fInitialBlockDownload = IsInitialBlockDownload();
+ fInitialBlockDownload = ::ChainstateActive().IsInitialBlockDownload();
pindexHeaderOld = pindexHeader;
}
}
@@ -2696,7 +2550,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
LimitValidationInterfaceQueue();
{
- LOCK(cs_main);
+ LOCK2(cs_main, ::mempool.cs); // Lock transaction pool for at least as long as it takes for connectTrace to be consumed
CBlockIndex* starting_tip = m_chain.Tip();
bool blocks_connected = false;
do {
@@ -2767,7 +2621,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
}
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
- return g_chainstate.ActivateBestChain(state, chainparams, std::move(pblock));
+ return ::ChainstateActive().ActivateBestChain(state, chainparams, std::move(pblock));
}
bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
@@ -2799,7 +2653,7 @@ bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& par
return ActivateBestChain(state, params, std::shared_ptr<const CBlock>());
}
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) {
- return g_chainstate.PreciousBlock(state, params, pindex);
+ return ::ChainstateActive().PreciousBlock(state, params, pindex);
}
bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
@@ -2816,6 +2670,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
LimitValidationInterfaceQueue();
LOCK(cs_main);
+ LOCK(::mempool.cs); // Lock for as long as disconnectpool is in scope to make sure UpdateMempoolForReorg is called after DisconnectTip without unlocking in between
if (!m_chain.Contains(pindex)) break;
pindex_was_in_chain = true;
CBlockIndex *invalid_walk_tip = m_chain.Tip();
@@ -2888,7 +2743,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
}
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
- return g_chainstate.InvalidateBlock(state, chainparams, pindex);
+ return ::ChainstateActive().InvalidateBlock(state, chainparams, pindex);
}
void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
@@ -2926,7 +2781,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
}
void ResetBlockFailureFlags(CBlockIndex *pindex) {
- return g_chainstate.ResetBlockFailureFlags(pindex);
+ return ::ChainstateActive().ResetBlockFailureFlags(pindex);
}
CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
@@ -3050,7 +2905,7 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n
bool out_of_space;
size_t bytes_allocated = BlockFileSeq().Allocate(pos, nAddSize, out_of_space);
if (out_of_space) {
- return AbortNode("Disk space is low!", _("Error: Disk space is low!"));
+ return AbortNode("Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX);
}
if (bytes_allocated != 0 && fPruneMode) {
fCheckForPruning = true;
@@ -3074,7 +2929,7 @@ static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, un
bool out_of_space;
size_t bytes_allocated = UndoFileSeq().Allocate(pos, nAddSize, out_of_space);
if (out_of_space) {
- return AbortNode(state, "Disk space is low!", _("Error: Disk space is low!"));
+ return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX);
}
if (bytes_allocated != 0 && fPruneMode) {
fCheckForPruning = true;
@@ -3464,7 +3319,7 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
LOCK(cs_main);
for (const CBlockHeader& header : headers) {
CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
- if (!g_chainstate.AcceptBlockHeader(header, state, chainparams, &pindex)) {
+ if (!::ChainstateActive().AcceptBlockHeader(header, state, chainparams, &pindex)) {
if (first_invalid) *first_invalid = header;
return false;
}
@@ -3595,7 +3450,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus());
if (ret) {
// Store to disk
- ret = g_chainstate.AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
+ ret = ::ChainstateActive().AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
}
if (!ret) {
GetMainSignals().BlockChecked(*pblock, state);
@@ -3606,7 +3461,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
NotifyHeaderTip();
CValidationState state; // Only used to report errors, not invalidity - ignore it
- if (!g_chainstate.ActivateBestChain(state, chainparams, pblock))
+ if (!::ChainstateActive().ActivateBestChain(state, chainparams, pblock))
return error("%s: ActivateBestChain failed (%s)", __func__, FormatStateMessage(state));
return true;
@@ -3630,7 +3485,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state));
if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev))
return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state));
- if (!g_chainstate.ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
+ if (!::ChainstateActive().ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
return false;
assert(state.IsValid());
@@ -3725,7 +3580,8 @@ void PruneBlockFilesManual(int nManualPruneHeight)
{
CValidationState state;
const CChainParams& chainparams = Params();
- if (!FlushStateToDisk(chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) {
+ if (!::ChainstateActive().FlushStateToDisk(
+ chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) {
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
}
}
@@ -3769,7 +3625,7 @@ static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfte
// To avoid excessive prune events negating the benefit of high dbcache
// values, we should not prune too rapidly.
// So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon.
- if (IsInitialBlockDownload()) {
+ if (::ChainstateActive().IsInitialBlockDownload()) {
// Since this is only relevant during IBD, we use a fixed 10%
nBuffer += nPruneTarget / 10;
}
@@ -3898,7 +3754,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- if (!g_chainstate.LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
+ if (!::ChainstateActive().LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
return false;
// Load block file info
@@ -3963,7 +3819,7 @@ bool LoadChainTip(const CChainParams& chainparams)
}
::ChainActive().SetTip(pindex);
- g_chainstate.PruneBlockIndexCandidates();
+ ::ChainstateActive().PruneBlockIndexCandidates();
LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n",
::ChainActive().Tip()->GetBlockHash().ToString(), ::ChainActive().Height(),
@@ -4036,7 +3892,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
assert(coins.GetBestBlock() == pindex->GetBlockHash());
- DisconnectResult res = g_chainstate.DisconnectBlock(block, pindex, coins);
+ DisconnectResult res = ::ChainstateActive().DisconnectBlock(block, pindex, coins);
if (res == DISCONNECT_FAILED) {
return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
}
@@ -4071,7 +3927,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
CBlock block;
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
- if (!g_chainstate.ConnectBlock(block, state, pindex, coins, chainparams))
+ if (!::ChainstateActive().ConnectBlock(block, state, pindex, coins, chainparams))
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state));
}
}
@@ -4170,7 +4026,7 @@ bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view)
}
bool ReplayBlocks(const CChainParams& params, CCoinsView* view) {
- return g_chainstate.ReplayBlocks(params, view);
+ return ::ChainstateActive().ReplayBlocks(params, view);
}
//! Helper for CChainState::RewindBlockIndex
@@ -4248,7 +4104,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
// Loop until the tip is below nHeight, or we reach a pruned block.
while (!ShutdownRequested()) {
{
- LOCK(cs_main);
+ LOCK2(cs_main, ::mempool.cs);
// Make sure nothing changed from under us (this won't happen because RewindBlockIndex runs before importing/network are active)
assert(tip == m_chain.Tip());
if (tip == nullptr || tip->nHeight < nHeight) break;
@@ -4303,7 +4159,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
}
bool RewindBlockIndex(const CChainParams& params) {
- if (!g_chainstate.RewindBlockIndex(params)) {
+ if (!::ChainstateActive().RewindBlockIndex(params)) {
return false;
}
@@ -4313,7 +4169,7 @@ bool RewindBlockIndex(const CChainParams& params) {
// and skip it here, we're about to -reindex-chainstate anyway, so
// it'll get called a bunch real soon.
CValidationState state;
- if (!FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
+ if (!::ChainstateActive().FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
return false;
}
@@ -4354,7 +4210,7 @@ void UnloadBlockIndex()
mapBlockIndex.clear();
fHavePruned = false;
- g_chainstate.UnloadBlockIndex();
+ ::ChainstateActive().UnloadBlockIndex();
}
bool LoadBlockIndex(const CChainParams& chainparams)
@@ -4406,7 +4262,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
bool LoadGenesisBlock(const CChainParams& chainparams)
{
- return g_chainstate.LoadGenesisBlock(chainparams);
+ return ::ChainstateActive().LoadGenesisBlock(chainparams);
}
bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos *dbp)
@@ -4471,7 +4327,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
CBlockIndex* pindex = LookupBlockIndex(hash);
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
CValidationState state;
- if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) {
+ if (::ChainstateActive().AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) {
nLoaded++;
}
if (state.IsError()) {
@@ -4508,7 +4364,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
head.ToString());
LOCK(cs_main);
CValidationState dummy;
- if (g_chainstate.AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
+ if (::ChainstateActive().AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
{
nLoaded++;
queue.push_back(pblockrecursive->GetHash());
@@ -4907,4 +4763,5 @@ public:
delete (*it1).second;
mapBlockIndex.clear();
}
-} instance_of_cmaincleanup;
+};
+static CMainCleanup instance_of_cmaincleanup;
diff --git a/src/validation.h b/src/validation.h
index ad978f0e05..9573d62048 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -18,6 +18,7 @@
#include <protocol.h> // For CMessageHeader::MessageStartChars
#include <script/script_error.h>
#include <sync.h>
+#include <txmempool.h> // For CTxMemPool::cs
#include <versionbits.h>
#include <algorithm>
@@ -31,6 +32,7 @@
#include <utility>
#include <vector>
+class CChainState;
class CBlockIndex;
class CBlockTreeDB;
class CBlockUndo;
@@ -44,6 +46,7 @@ class CTxMemPool;
class CValidationState;
struct ChainTxData;
+struct DisconnectedBlockTransactions;
struct PrecomputedTransactionData;
struct LockPoints;
@@ -114,8 +117,6 @@ static const char* const DEFAULT_BLOCKFILTERINDEX = "0";
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
/** Default for -persistmempool */
static const bool DEFAULT_PERSIST_MEMPOOL = true;
-/** Default for -mempoolreplacement */
-static const bool DEFAULT_ENABLE_REPLACEMENT = true;
/** Default for using fee filter */
static const bool DEFAULT_FEEFILTER = true;
@@ -158,7 +159,6 @@ extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee;
/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
extern int64_t nMaxTipAge;
-extern bool fEnableReplacement;
/** Block hash whose ancestors we will assume to have valid scripts without checking them. */
extern uint256 hashAssumeValid;
@@ -247,8 +247,6 @@ bool LoadChainTip(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_m
void UnloadBlockIndex();
/** Run an instance of the script checking thread */
void ThreadScriptCheck(int worker_num);
-/** Check whether we are doing an initial block download (synchronizing from disk or network) */
-bool IsInitialBlockDownload();
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, const CBlockIndex* const blockIndex = nullptr);
/**
@@ -276,10 +274,6 @@ void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
*/
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
-/** Flush all state, indexes and buffers to disk. */
-void FlushStateToDisk();
-/** Prune block files and flush state to disk. */
-void PruneAndFlush();
/** Prune block files up to a given height */
void PruneBlockFilesManual(int nManualPruneHeight);
@@ -422,6 +416,186 @@ inline CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIR
/** Find the last common block between the parameter chain and a locator. */
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+enum DisconnectResult
+{
+ DISCONNECT_OK, // All good.
+ DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
+ DISCONNECT_FAILED // Something else went wrong.
+};
+
+class ConnectTrace;
+
+/** @see CChainState::FlushStateToDisk */
+enum class FlushStateMode {
+ NONE,
+ IF_NEEDED,
+ PERIODIC,
+ ALWAYS
+};
+
+struct CBlockIndexWorkComparator
+{
+ bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const;
+};
+
+/**
+ * CChainState stores and provides an API to update our local knowledge of the
+ * current best chain and header tree.
+ *
+ * It generally provides access to the current block tree, as well as functions
+ * to provide new data, which it will appropriately validate and incorporate in
+ * its state as necessary.
+ *
+ * Eventually, the API here is targeted at being exposed externally as a
+ * consumable libconsensus library, so any functions added must only call
+ * other class member functions, pure functions in other parts of the consensus
+ * library, callbacks via the validation interface, or read/write-to-disk
+ * functions (eventually this will also be via callbacks).
+ */
+class CChainState {
+private:
+ /**
+ * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
+ * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
+ * missing the data for the block.
+ */
+ std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
+
+ /**
+ * Every received block is assigned a unique and increasing identifier, so we
+ * know which one to give priority in case of a fork.
+ */
+ CCriticalSection cs_nBlockSequenceId;
+ /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
+ int32_t nBlockSequenceId = 1;
+ /** Decreasing counter (used by subsequent preciousblock calls). */
+ int32_t nBlockReverseSequenceId = -1;
+ /** chainwork for the last block that preciousblock has been applied to. */
+ arith_uint256 nLastPreciousChainwork = 0;
+
+ /** In order to efficiently track invalidity of headers, we keep the set of
+ * blocks which we tried to connect and found to be invalid here (ie which
+ * were set to BLOCK_FAILED_VALID since the last restart). We can then
+ * walk this set and check if a new header is a descendant of something in
+ * this set, preventing us from having to walk mapBlockIndex when we try
+ * to connect a bad block and fail.
+ *
+ * While this is more complicated than marking everything which descends
+ * from an invalid block as invalid at the time we discover it to be
+ * invalid, doing so would require walking all of mapBlockIndex to find all
+ * descendants. Since this case should be very rare, keeping track of all
+ * BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
+ * well.
+ *
+ * Because we already walk mapBlockIndex in height-order at startup, we go
+ * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
+ * instead of putting things in this set.
+ */
+ std::set<CBlockIndex*> m_failed_blocks;
+
+ /**
+ * the ChainState CriticalSection
+ * A lock that must be held when modifying this ChainState - held in ActivateBestChain()
+ */
+ CCriticalSection m_cs_chainstate;
+
+ /**
+ * Whether this chainstate is undergoing initial block download.
+ *
+ * Mutable because we need to be able to mark IsInitialBlockDownload()
+ * const, which latches this for caching purposes.
+ */
+ mutable std::atomic<bool> m_cached_finished_ibd{false};
+
+public:
+ //! The current chain of blockheaders we consult and build on.
+ //! @see CChain, CBlockIndex.
+ CChain m_chain;
+ BlockMap mapBlockIndex GUARDED_BY(cs_main);
+ std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
+ CBlockIndex *pindexBestInvalid = nullptr;
+
+ bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ /**
+ * Update the on-disk chain state.
+ * The caches and indexes are flushed depending on the mode we're called with
+ * if they're too large, if it's been a while since the last write,
+ * or always and in all cases if we're in prune mode and are deleting files.
+ *
+ * If FlushStateMode::NONE is used, then FlushStateToDisk(...) won't do anything
+ * besides checking if we need to prune.
+ */
+ bool FlushStateToDisk(
+ const CChainParams& chainparams,
+ CValidationState &state,
+ FlushStateMode mode,
+ int nManualPruneHeight = 0);
+
+ //! Unconditionally flush all changes to disk.
+ void ForceFlushStateToDisk();
+
+ //! Prune blockfiles from the disk if necessary and then flush chainstate changes
+ //! if we pruned.
+ void PruneAndFlush();
+
+ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) LOCKS_EXCLUDED(cs_main);
+
+ /**
+ * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
+ * that it doesn't descend from an invalid block, and then add it to mapBlockIndex.
+ */
+ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ // Block (dis)connection on a given view:
+ DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
+ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
+ CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ // Block disconnection on our pcoinsTip:
+ bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
+
+ // Manual block validity manipulation:
+ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
+ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
+ void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
+ bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main);
+ bool LoadGenesisBlock(const CChainParams& chainparams);
+
+ void PruneBlockIndexCandidates();
+
+ void UnloadBlockIndex();
+
+ /** Check whether we are doing an initial block download (synchronizing from disk or network) */
+ bool IsInitialBlockDownload() const;
+
+private:
+ bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
+ bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
+
+ CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ /** Create a new block index entry for a given block hash */
+ CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ /**
+ * Make various assertions about the state of the block index.
+ *
+ * By default this only executes fully when using the Regtest chain; see: fCheckBlockIndex.
+ */
+ void CheckBlockIndex(const Consensus::Params& consensusParams);
+
+ void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ //! Mark a block as not having block data
+ void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+};
+
/** Mark a block as precious and reorganize.
*
* May not be called in a
@@ -435,6 +609,9 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
/** Remove invalidity status from a block and its descendants. */
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+/** @returns the most-work valid chainstate. */
+CChainState& ChainstateActive();
+
/** @returns the most-work chain. */
CChain& ChainActive();
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 5d0ee1d1fc..59a620ab95 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -8,8 +8,6 @@
#include <primitives/block.h>
#include <scheduler.h>
#include <txmempool.h>
-#include <util/system.h>
-#include <validation.h>
#include <list>
#include <atomic>
diff --git a/src/validationinterface.h b/src/validationinterface.h
index ea1b2e7e76..3ce617b827 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -16,7 +16,6 @@ extern CCriticalSection cs_main;
class CBlock;
class CBlockIndex;
struct CBlockLocator;
-class CBlockIndex;
class CConnman;
class CValidationInterface;
class CValidationState;
diff --git a/src/wallet/coincontrol.cpp b/src/wallet/coincontrol.cpp
index 87d2c4f06e..60bce66839 100644
--- a/src/wallet/coincontrol.cpp
+++ b/src/wallet/coincontrol.cpp
@@ -13,6 +13,7 @@ void CCoinControl::SetNull()
fAllowOtherInputs = false;
fAllowWatchOnly = false;
m_avoid_partial_spends = gArgs.GetBoolArg("-avoidpartialspends", DEFAULT_AVOIDPARTIALSPENDS);
+ m_avoid_address_reuse = false;
setSelected.clear();
m_feerate.reset();
fOverrideFeeRate = false;
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index 12ba032dff..249c402e4d 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -34,6 +34,8 @@ public:
boost::optional<bool> m_signal_bip125_rbf;
//! Avoid partial use of funds sent to a given address
bool m_avoid_partial_spends;
+ //! Forbids inclusion of dirty (previously used) addresses
+ bool m_avoid_address_reuse;
//! Fee estimation mode to control arguments to estimateSmartFee
FeeEstimateMode m_fee_mode;
//! Minimum chain depth value for coin availability
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 8633d8701b..b5f90deabd 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -5,11 +5,7 @@
#include <wallet/db.h>
-#include <addrman.h>
-#include <hash.h>
-#include <protocol.h>
#include <util/strencodings.h>
-#include <wallet/walletutil.h>
#include <stdint.h>
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 15ddd5cb97..46cf6b7616 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -10,14 +10,10 @@
#include <wallet/wallet.h>
#include <policy/fees.h>
#include <policy/policy.h>
-#include <policy/rbf.h>
-#include <validation.h> //for mempool access
-#include <txmempool.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/system.h>
#include <util/validation.h>
-#include <net.h>
//! Check whether transaction has descendant in wallet or mempool, or has been
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
index 59d05a771a..2792058f2a 100644
--- a/src/wallet/fees.cpp
+++ b/src/wallet/fees.cpp
@@ -5,9 +5,7 @@
#include <wallet/fees.h>
-#include <policy/policy.h>
#include <util/system.h>
-#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/wallet.h>
@@ -20,14 +18,7 @@ CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes)
CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinControl& coin_control, FeeCalculation* feeCalc)
{
- CAmount fee_needed = GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
- // Always obey the maximum
- const CAmount max_tx_fee = wallet.m_default_max_tx_fee;
- if (fee_needed > max_tx_fee) {
- fee_needed = max_tx_fee;
- if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
- }
- return fee_needed;
+ return GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
}
CFeeRate GetRequiredFeeRate(const CWallet& wallet)
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 0b8afd5a5d..4c327c77ae 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -3,18 +3,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <chainparams.h>
#include <init.h>
#include <interfaces/chain.h>
#include <net.h>
-#include <scheduler.h>
#include <outputtype.h>
-#include <util/error.h>
#include <util/system.h>
#include <util/moneystr.h>
-#include <validation.h>
#include <walletinitinterface.h>
-#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
#include <wallet/walletutil.h>
@@ -39,7 +34,7 @@ const WalletInitInterface& g_wallet_init_interface = WalletInit();
void WalletInit::AddWalletOptions() const
{
gArgs.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), false, OptionsCategory::WALLET);
- gArgs.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)", DEFAULT_AVOIDPARTIALSPENDS), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u (always enabled for wallets with \"avoid_reuse\" enabled))", DEFAULT_AVOIDPARTIALSPENDS), false, OptionsCategory::WALLET);
gArgs.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", false, OptionsCategory::WALLET);
gArgs.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", false, OptionsCategory::WALLET);
gArgs.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
@@ -62,7 +57,9 @@ void WalletInit::AddWalletOptions() const
gArgs.AddArg("-wallet=<path>", "Specify wallet database path. Can be specified multiple times to load multiple wallets. Path is interpreted relative to <walletdir> if it is not absolute, and will be created if it does not exist (as a directory containing a wallet.dat file and log files). For backwards compatibility this will also accept names of existing data files in <walletdir>.)", false, OptionsCategory::WALLET);
gArgs.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), false, OptionsCategory::WALLET);
gArgs.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", false, OptionsCategory::WALLET);
+#if HAVE_SYSTEM
gArgs.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)", false, OptionsCategory::WALLET);
+#endif
gArgs.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), false, OptionsCategory::WALLET);
gArgs.AddArg("-zapwallettxes=<mode>", "Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup"
" (1 = keep tx meta data e.g. payment request information, 2 = drop tx meta data)", false, OptionsCategory::WALLET);
diff --git a/src/script/ismine.cpp b/src/wallet/ismine.cpp
index 75fc2e84f1..6138d4ae44 100644
--- a/src/script/ismine.cpp
+++ b/src/wallet/ismine.cpp
@@ -3,13 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <script/ismine.h>
+#include <wallet/ismine.h>
#include <key.h>
-#include <keystore.h>
#include <script/script.h>
#include <script/sign.h>
-
+#include <wallet/wallet.h>
typedef std::vector<unsigned char> valtype;
@@ -46,7 +45,7 @@ bool PermitsUncompressed(IsMineSigVersion sigversion)
return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
}
-bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
+bool HaveKeys(const std::vector<valtype>& pubkeys, const CWallet& keystore)
{
for (const valtype& pubkey : pubkeys) {
CKeyID keyID = CPubKey(pubkey).GetID();
@@ -55,7 +54,7 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
return true;
}
-IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
+IsMineResult IsMineInner(const CWallet& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
{
IsMineResult ret = IsMineResult::NO;
@@ -172,7 +171,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
} // namespace
-isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)
+isminetype IsMine(const CWallet& keystore, const CScript& scriptPubKey)
{
switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) {
case IsMineResult::INVALID:
@@ -186,7 +185,7 @@ isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)
assert(false);
}
-isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest)
+isminetype IsMine(const CWallet& keystore, const CTxDestination& dest)
{
CScript script = GetScriptForDestination(dest);
return IsMine(keystore, script);
diff --git a/src/script/ismine.h b/src/wallet/ismine.h
index 55e28e225a..41555fcb93 100644
--- a/src/script/ismine.h
+++ b/src/wallet/ismine.h
@@ -3,31 +3,33 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_SCRIPT_ISMINE_H
-#define BITCOIN_SCRIPT_ISMINE_H
+#ifndef BITCOIN_WALLET_ISMINE_H
+#define BITCOIN_WALLET_ISMINE_H
#include <script/standard.h>
#include <stdint.h>
#include <bitset>
-class CKeyStore;
+class CWallet;
class CScript;
/** IsMine() return codes */
-enum isminetype
+enum isminetype : unsigned int
{
ISMINE_NO = 0,
ISMINE_WATCH_ONLY = 1 << 0,
ISMINE_SPENDABLE = 1 << 1,
+ ISMINE_USED = 1 << 2,
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE,
+ ISMINE_ALL_USED = ISMINE_ALL | ISMINE_USED,
ISMINE_ENUM_ELEMENTS,
};
/** used for bitflags of isminetype */
typedef uint8_t isminefilter;
-isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
-isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
+isminetype IsMine(const CWallet& wallet, const CScript& scriptPubKey);
+isminetype IsMine(const CWallet& wallet, const CTxDestination& dest);
/**
* Cachable amount subdivided into watchonly and spendable parts.
@@ -48,4 +50,4 @@ struct CachableAmount
}
};
-#endif // BITCOIN_SCRIPT_ISMINE_H
+#endif // BITCOIN_WALLET_ISMINE_H
diff --git a/src/wallet/psbtwallet.cpp b/src/wallet/psbtwallet.cpp
index ce4788dee1..721a244afb 100644
--- a/src/wallet/psbtwallet.cpp
+++ b/src/wallet/psbtwallet.cpp
@@ -44,16 +44,7 @@ TransactionError FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& ps
// Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
- const CTxOut& out = psbtx.tx->vout.at(i);
- PSBTOutput& psbt_out = psbtx.outputs.at(i);
-
- // Fill a SignatureData with output info
- SignatureData sigdata;
- psbt_out.FillSignatureData(sigdata);
-
- MutableTransactionSignatureCreator creator(psbtx.tx.get_ptr(), 0, out.nValue, 1);
- ProduceSignature(HidingSigningProvider(pwallet, true, !bip32derivs), creator, out.scriptPubKey, sigdata);
- psbt_out.FromSignatureData(sigdata);
+ UpdatePSBTOutput(HidingSigningProvider(pwallet, true, !bip32derivs), psbtx, i);
}
return TransactionError::OK;
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index ee1b792f9b..3112dca9f5 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -16,7 +16,6 @@
#include <util/bip32.h>
#include <util/system.h>
#include <util/time.h>
-#include <validation.h>
#include <wallet/wallet.h>
#include <wallet/rpcwallet.h>
@@ -1166,8 +1165,7 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
- // Expand all descriptors to get public keys and scripts.
- // TODO: get private keys from descriptors too
+ // Expand all descriptors to get public keys and scripts, and private keys if available.
for (int i = range_start; i <= range_end; ++i) {
FlatSigningProvider out_keys;
std::vector<CScript> scripts_temp;
@@ -1181,7 +1179,10 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
import_data.import_scripts.emplace(x.second);
}
+ parsed_desc->ExpandPrivate(i, keys, out_keys);
+
std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
+ std::copy(out_keys.keys.begin(), out_keys.keys.end(), std::inserter(privkey_map, privkey_map.end()));
import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end());
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 71d62a47dc..eae5f876ea 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -4,33 +4,27 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <amount.h>
-#include <chain.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <init.h>
#include <interfaces/chain.h>
#include <key_io.h>
-#include <net.h>
#include <node/transaction.h>
#include <outputtype.h>
#include <policy/feerate.h>
#include <policy/fees.h>
-#include <policy/policy.h>
#include <policy/rbf.h>
#include <rpc/rawtransaction_util.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <script/descriptor.h>
#include <script/sign.h>
-#include <shutdown.h>
-#include <timedata.h>
#include <util/bip32.h>
#include <util/fees.h>
#include <util/moneystr.h>
#include <util/system.h>
#include <util/url.h>
#include <util/validation.h>
-#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/feebumper.h>
#include <wallet/psbtwallet.h>
@@ -47,6 +41,17 @@
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
+static inline bool GetAvoidReuseFlag(CWallet * const pwallet, const UniValue& param) {
+ bool can_avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
+ bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
+
+ if (avoid_reuse && !can_avoid_reuse) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
+ }
+
+ return avoid_reuse;
+}
+
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
@@ -310,7 +315,7 @@ static UniValue setlabel(const JSONRPCRequest& request)
static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue)
{
- CAmount curBalance = pwallet->GetBalance().m_mine_trusted;
+ CAmount curBalance = pwallet->GetBalance(0, coin_control.m_avoid_address_reuse).m_mine_trusted;
// Check amount
if (nValue <= 0)
@@ -357,7 +362,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 9)
throw std::runtime_error(
RPCHelpMan{"sendtoaddress",
"\nSend an amount to a given address." +
@@ -378,6 +383,8 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
" \"UNSET\"\n"
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\""},
+ {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
+ " dirty if they have previously been used in a transaction."},
},
RPCResult{
"\"txid\" (string) The transaction id.\n"
@@ -434,6 +441,9 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
}
}
+ coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(pwallet, request.params[8]);
+ // We also enable partial spend avoidance if reuse avoidance is set.
+ coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse;
EnsureWalletIsUnlocked(pwallet);
@@ -723,7 +733,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || (request.params.size() > 3 ))
+ if (request.fHelp || request.params.size() > 4)
throw std::runtime_error(
RPCHelpMan{"getbalance",
"\nReturns the total available balance.\n"
@@ -733,6 +743,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
{"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
{"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."},
{"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Also include balance in watch-only addresses (see 'importaddress')"},
+ {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."},
},
RPCResult{
"amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this wallet.\n"
@@ -769,7 +780,9 @@ static UniValue getbalance(const JSONRPCRequest& request)
include_watchonly = true;
}
- const auto bal = pwallet->GetBalance(min_depth);
+ bool avoid_reuse = GetAvoidReuseFlag(pwallet, request.params[3]);
+
+ const auto bal = pwallet->GetBalance(min_depth, avoid_reuse);
return ValueFromAmount(bal.m_mine_trusted + (include_watchonly ? bal.m_watchonly_trusted : 0));
}
@@ -1023,8 +1036,8 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
}
// Construct using pay-to-script-hash:
- CScript inner = CreateMultisigRedeemscript(required, pubkeys);
- CTxDestination dest = AddAndGetDestinationForScript(*pwallet, inner, output_type);
+ CScript inner;
+ CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, *pwallet, inner);
pwallet->SetAddressBook(dest, label, "send");
UniValue result(UniValue::VOBJ);
@@ -2124,6 +2137,10 @@ static UniValue encryptwallet(const JSONRPCRequest& request)
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
+ if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet does not contain private keys, nothing to encrypt.");
+ }
+
if (pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
}
@@ -2392,6 +2409,7 @@ static UniValue getbalances(const JSONRPCRequest& request)
" \"trusted\": xxx (numeric) trusted balance (outputs created by the wallet or confirmed outputs)\n"
" \"untrusted_pending\": xxx (numeric) untrusted pending balance (outputs created by others that are in the mempool)\n"
" \"immature\": xxx (numeric) balance from immature coinbase outputs\n"
+ " \"used\": xxx (numeric) (only present if avoid_reuse is set) balance from coins sent to addresses that were previously spent from (potentially privacy violating)\n"
" },\n"
" \"watchonly\": { (object) watchonly balances (not present if wallet does not watch anything)\n"
" \"trusted\": xxx (numeric) trusted balance (outputs created by the wallet or confirmed outputs)\n"
@@ -2424,6 +2442,12 @@ static UniValue getbalances(const JSONRPCRequest& request)
balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
+ if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
+ // If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get
+ // the total balance, and then subtract bal to get the reused address balance.
+ const auto full_bal = wallet.GetBalance(0, false);
+ balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending));
+ }
balances.pushKV("mine", balances_mine);
}
if (wallet.HaveWatchOnly()) {
@@ -2463,6 +2487,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
" \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
" \"hdseedid\": \"<hash160>\" (string, optional) the Hash160 of the HD seed (only present when HD is enabled)\n"
" \"private_keys_enabled\": true|false (boolean) false if privatekeys are disabled for this wallet (enforced watch-only wallet)\n"
+ " \"avoid_reuse\": true|false (boolean) whether this wallet tracks clean/dirty coins in terms of reuse\n"
" \"scanning\": (json object) current scanning details, or false if no scan is in progress\n"
" {\n"
" \"duration\" : xxxx (numeric) elapsed seconds since scan start\n"
@@ -2511,6 +2536,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
obj.pushKV("hdseedid", seed_id.GetHex());
}
obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
+ obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
if (pwallet->IsScanning()) {
UniValue scanning(UniValue::VOBJ);
scanning.pushKV("duration", pwallet->ScanningDuration() / 1000);
@@ -2639,6 +2665,76 @@ static UniValue loadwallet(const JSONRPCRequest& request)
return obj;
}
+static UniValue setwalletflag(const JSONRPCRequest& request)
+{
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ std::string flags = "";
+ for (auto& it : WALLET_FLAG_MAP)
+ if (it.second & MUTABLE_WALLET_FLAGS)
+ flags += (flags == "" ? "" : ", ") + it.first;
+ throw std::runtime_error(
+ RPCHelpMan{"setwalletflag",
+ "\nChange the state of the given wallet flag for a wallet.\n",
+ {
+ {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
+ {"value", RPCArg::Type::BOOL, /* default */ "true", "The new state."},
+ },
+ RPCResult{
+ "{\n"
+ " \"flag_name\": string (string) The name of the flag that was modified\n"
+ " \"flag_state\": bool (bool) The new state of the flag\n"
+ " \"warnings\": string (string) Any warnings associated with the change\n"
+ "}\n"
+ },
+ RPCExamples{
+ HelpExampleCli("setwalletflag", "avoid_reuse")
+ + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
+ },
+ }.ToString());
+ }
+
+ std::string flag_str = request.params[0].get_str();
+ bool value = request.params[1].isNull() || request.params[1].get_bool();
+
+ if (!WALLET_FLAG_MAP.count(flag_str)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
+ }
+
+ auto flag = WALLET_FLAG_MAP.at(flag_str);
+
+ if (!(flag & MUTABLE_WALLET_FLAGS)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
+ }
+
+ UniValue res(UniValue::VOBJ);
+
+ if (pwallet->IsWalletFlagSet(flag) == value) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
+ }
+
+ res.pushKV("flag_name", flag_str);
+ res.pushKV("flag_state", value);
+
+ if (value) {
+ pwallet->SetWalletFlag(flag);
+ } else {
+ pwallet->UnsetWalletFlag(flag);
+ }
+
+ if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
+ res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
+ }
+
+ return res;
+}
+
static UniValue createwallet(const JSONRPCRequest& request)
{
const RPCHelpMan help{
@@ -2649,6 +2745,7 @@ static UniValue createwallet(const JSONRPCRequest& request)
{"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
{"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
+ {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false", "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
},
RPCResult{
"{\n"
@@ -2690,6 +2787,10 @@ static UniValue createwallet(const JSONRPCRequest& request)
flags |= WALLET_FLAG_BLANK_WALLET;
}
+ if (!request.params[4].isNull() && request.params[4].get_bool()) {
+ flags |= WALLET_FLAG_AVOID_REUSE;
+ }
+
WalletLocation location(request.params[0].get_str());
if (location.Exists()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet " + location.GetName() + " already exists.");
@@ -2791,9 +2892,8 @@ static UniValue listunspent(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 5)
- throw std::runtime_error(
- RPCHelpMan{"listunspent",
+ const RPCHelpMan help{
+ "listunspent",
"\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filter to only include txouts paid to specified addresses.\n",
@@ -2830,6 +2930,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
" \"witnessScript\" : \"script\" (string) witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH\n"
" \"spendable\" : xxx, (bool) Whether we have the private keys to spend this output\n"
" \"solvable\" : xxx, (bool) Whether we know how to spend this output, ignoring the lack of keys\n"
+ " \"reused\" : xxx, (bool) (only present if avoid_reuse is set) Whether this output is reused/dirty (sent to an address that was previously spent from)\n"
" \"desc\" : xxx, (string, only when solvable) A descriptor for spending this output\n"
" \"safe\" : xxx (bool) Whether this output is considered safe to spend. Unconfirmed transactions\n"
" from outside keys and unconfirmed replacement transactions are considered unsafe\n"
@@ -2845,7 +2946,11 @@ static UniValue listunspent(const JSONRPCRequest& request)
+ HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'")
+ HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
},
- }.ToString());
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
int nMinDepth = 1;
if (!request.params[0].isNull()) {
@@ -2909,17 +3014,22 @@ static UniValue listunspent(const JSONRPCRequest& request)
UniValue results(UniValue::VARR);
std::vector<COutput> vecOutputs;
{
+ CCoinControl cctl;
+ cctl.m_avoid_address_reuse = false;
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
- pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, nullptr, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
+ pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
}
LOCK(pwallet->cs_wallet);
+ const bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
+
for (const COutput& out : vecOutputs) {
CTxDestination address;
const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
bool fValidAddress = ExtractDestination(scriptPubKey, address);
+ bool reused = avoid_reuse && pwallet->IsUsedDestination(address);
if (destinations.size() && (!fValidAddress || !destinations.count(address)))
continue;
@@ -2976,6 +3086,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
auto descriptor = InferDescriptor(scriptPubKey, *pwallet);
entry.pushKV("desc", descriptor->ToString());
}
+ if (avoid_reuse) entry.pushKV("reused", reused);
entry.pushKV("safe", out.fSafe);
results.push_back(entry);
}
@@ -3108,9 +3219,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
- throw std::runtime_error(
- RPCHelpMan{"fundrawtransaction",
+ const RPCHelpMan help{"fundrawtransaction",
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
"This will not modify existing inputs, and will add at most one change output to the outputs.\n"
"No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
@@ -3149,8 +3258,13 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
" \"CONSERVATIVE\""},
},
"options"},
- {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction \n"
- " If iswitness is not present, heuristic tests will be used in decoding"},
+ {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
+ "If iswitness is not present, heuristic tests will be used in decoding.\n"
+ "If true, only witness deserialization will be tried.\n"
+ "If false, only non-witness deserialization will be tried.\n"
+ "This boolean should reflect whether the transaction has inputs\n"
+ "(e.g. fully valid, or on-chain transactions), if known by the caller."
+ },
},
RPCResult{
"{\n"
@@ -3169,7 +3283,11 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
"\nSend the transaction\n"
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
},
- }.ToString());
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
@@ -4180,13 +4298,13 @@ static const CRPCCommand commands[] =
{ "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} },
{ "wallet", "backupwallet", &backupwallet, {"destination"} },
{ "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
- { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase"} },
+ { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse"} },
{ "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
{ "wallet", "dumpwallet", &dumpwallet, {"filename"} },
{ "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
{ "wallet", "getaddressesbylabel", &getaddressesbylabel, {"label"} },
{ "wallet", "getaddressinfo", &getaddressinfo, {"address"} },
- { "wallet", "getbalance", &getbalance, {"dummy","minconf","include_watchonly"} },
+ { "wallet", "getbalance", &getbalance, {"dummy","minconf","include_watchonly","avoid_reuse"} },
{ "wallet", "getnewaddress", &getnewaddress, {"label","address_type"} },
{ "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} },
{ "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
@@ -4217,10 +4335,11 @@ static const CRPCCommand commands[] =
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
{ "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
{ "wallet", "sendmany", &sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
- { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode","avoid_reuse"} },
{ "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} },
{ "wallet", "setlabel", &setlabel, {"address","label"} },
{ "wallet", "settxfee", &settxfee, {"amount"} },
+ { "wallet", "setwalletflag", &setwalletflag, {"flag","value"} },
{ "wallet", "signmessage", &signmessage, {"address","message"} },
{ "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} },
{ "wallet", "unloadwallet", &unloadwallet, {"wallet_name"} },
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index e4950af4e5..c961456572 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -16,7 +16,7 @@ BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(getwalletenv_file)
{
std::string test_name = "test_name.dat";
- fs::path datadir = SetDataDir("tempdir");
+ const fs::path datadir = GetDataDir();
fs::path file_path = datadir / test_name;
std::ofstream f(file_path.BOOST_FILESYSTEM_C_STR);
f.close();
@@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(getwalletenv_file)
BOOST_AUTO_TEST_CASE(getwalletenv_directory)
{
std::string expected_name = "wallet.dat";
- fs::path datadir = SetDataDir("tempdir");
+ const fs::path datadir = GetDataDir();
std::string filename;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(datadir, filename);
@@ -40,8 +40,8 @@ BOOST_AUTO_TEST_CASE(getwalletenv_directory)
BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_multiple)
{
- fs::path datadir = SetDataDir("tempdir");
- fs::path datadir_2 = SetDataDir("tempdir_2");
+ fs::path datadir = GetDataDir() / "1";
+ fs::path datadir_2 = GetDataDir() / "2";
std::string filename;
std::shared_ptr<BerkeleyEnvironment> env_1 = GetWalletEnv(datadir, filename);
@@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_multiple)
BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_free_instance)
{
- fs::path datadir = SetDataDir("tempdir");
- fs::path datadir_2 = SetDataDir("tempdir_2");
+ fs::path datadir = GetDataDir() / "1";
+ fs::path datadir_2 = GetDataDir() / "2";
std::string filename;
std::shared_ptr <BerkeleyEnvironment> env_1_a = GetWalletEnv(datadir, filename);
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index 3b828d57f9..86ba0013fe 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <fs.h>
+#include <util/system.h>
#include <wallet/test/init_test_fixture.h>
@@ -13,7 +14,7 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainNam
std::string sep;
sep += fs::path::preferred_separator;
- m_datadir = SetDataDir("tempdir");
+ m_datadir = GetDataDir();
m_cwd = fs::current_path();
m_walletdir_path_cases["default"] = m_datadir / "wallets";
@@ -41,4 +42,4 @@ InitWalletDirTestingSetup::~InitWalletDirTestingSetup()
void InitWalletDirTestingSetup::SetWalletDir(const fs::path& walletdir_path)
{
gArgs.ForceSetArg("-walletdir", walletdir_path.string());
-} \ No newline at end of file
+}
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
index 9e5208b453..1816fca257 100644
--- a/src/wallet/test/init_tests.cpp
+++ b/src/wallet/test/init_tests.cpp
@@ -5,13 +5,9 @@
#include <boost/test/unit_test.hpp>
#include <test/setup_common.h>
+#include <util/system.h>
#include <wallet/test/init_test_fixture.h>
-#include <init.h>
-#include <walletinitinterface.h>
-#include <wallet/wallet.h>
-
-
BOOST_FIXTURE_TEST_SUITE(init_tests, InitWalletDirTestingSetup)
BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default)
diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp
new file mode 100644
index 0000000000..062fef7748
--- /dev/null
+++ b/src/wallet/test/ismine_tests.cpp
@@ -0,0 +1,398 @@
+// Copyright (c) 2017-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 <key.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <test/setup_common.h>
+#include <wallet/ismine.h>
+#include <wallet/wallet.h>
+
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_FIXTURE_TEST_SUITE(ismine_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(ismine_standard)
+{
+ CKey keys[2];
+ CPubKey pubkeys[2];
+ for (int i = 0; i < 2; i++) {
+ keys[i].MakeNewKey(true);
+ pubkeys[i] = keys[i].GetPubKey();
+ }
+
+ CKey uncompressedKey;
+ uncompressedKey.MakeNewKey(false);
+ CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
+ std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain();
+
+ CScript scriptPubKey;
+ isminetype result;
+
+ // P2PK compressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has key
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2PK uncompressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has key
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2PKH compressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has key
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2PKH uncompressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has key
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2SH
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+
+ // Keystore does not have redeemScript or key
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has redeemScript but no key
+ BOOST_CHECK(keystore.AddCScript(redeemScript));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has redeemScript and key
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // (P2PKH inside) P2SH inside P2SH (invalid)
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
+ CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner));
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript));
+
+ BOOST_CHECK(keystore.AddCScript(redeemscript));
+ BOOST_CHECK(keystore.AddCScript(redeemscript_inner));
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // (P2PKH inside) P2SH inside P2WSH (invalid)
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0]));
+ CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript));
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
+
+ BOOST_CHECK(keystore.AddCScript(witnessscript));
+ BOOST_CHECK(keystore.AddCScript(redeemscript));
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // P2WPKH inside P2WSH (invalid)
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
+
+ BOOST_CHECK(keystore.AddCScript(witnessscript));
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // (P2PKH inside) P2WSH inside P2WSH (invalid)
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
+ CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
+
+ BOOST_CHECK(keystore.AddCScript(witnessscript_inner));
+ BOOST_CHECK(keystore.AddCScript(witnessscript));
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // P2WPKH compressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+
+ scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
+
+ // Keystore implicitly has key and P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2WPKH uncompressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+
+ scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(uncompressedPubkey)));
+
+ // Keystore has key, but no P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has key and P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // scriptPubKey multisig
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
+
+ // Keystore does not have any keys
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has 1/2 keys
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has 2/2 keys
+ BOOST_CHECK(keystore.AddKey(keys[1]));
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has 2/2 keys and the script
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // P2SH multisig
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+ BOOST_CHECK(keystore.AddKey(keys[1]));
+
+ CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+
+ // Keystore has no redeemScript
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has redeemScript
+ BOOST_CHECK(keystore.AddCScript(redeemScript));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2WSH multisig with compressed keys
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ BOOST_CHECK(keystore.AddKey(keys[1]));
+
+ CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
+
+ // Keystore has keys, but no witnessScript or P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has keys and witnessScript, but no P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(witnessScript));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2WSH multisig with uncompressed key
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+ BOOST_CHECK(keystore.AddKey(keys[1]));
+
+ CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
+
+ // Keystore has keys, but no witnessScript or P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has keys and witnessScript, but no P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(witnessScript));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // P2WSH multisig wrapped in P2SH
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
+ CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+
+ // Keystore has no witnessScript, P2SH redeemScript, or keys
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has witnessScript and P2SH redeemScript, but no keys
+ BOOST_CHECK(keystore.AddCScript(redeemScript));
+ BOOST_CHECK(keystore.AddCScript(witnessScript));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ BOOST_CHECK(keystore.AddKey(keys[1]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // OP_RETURN
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // witness unspendable
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb"));
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // witness unknown
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb"));
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // Nonstandard
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index 4753c7f313..0400f1207c 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -3,13 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key_io.h>
-#include <script/sign.h>
#include <util/bip32.h>
#include <util/strencodings.h>
#include <wallet/psbtwallet.h>
-#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
-#include <univalue.h>
#include <boost/test/unit_test.hpp>
#include <test/setup_common.h>
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index e352c81519..ba0843f352 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -4,10 +4,6 @@
#include <wallet/test/wallet_test_fixture.h>
-#include <rpc/server.h>
-#include <wallet/db.h>
-#include <wallet/rpcwallet.h>
-
WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
: TestingSetup(chainName),
m_wallet(m_chain.get(), WalletLocation(), WalletDatabase::CreateMock())
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 922bb0fe65..ef95d0544f 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -5,9 +5,7 @@
#include <wallet/wallet.h>
#include <memory>
-#include <set>
#include <stdint.h>
-#include <utility>
#include <vector>
#include <consensus/validation.h>
@@ -192,7 +190,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
auto locked_chain = chain->lock();
LockAssertion lock(::cs_main);
- std::string backup_file = (SetDataDir("importwallet_rescan") / "wallet.backup").string();
+ std::string backup_file = (GetDataDir() / "wallet.backup").string();
// Import key into wallet and call dumpwallet to create backup file.
{
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index e86147b5d0..7f14a4a7c3 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -14,17 +14,12 @@
#include <key.h>
#include <key_io.h>
#include <keystore.h>
-#include <net.h>
#include <policy/fees.h>
#include <policy/policy.h>
-#include <policy/rbf.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/descriptor.h>
#include <script/script.h>
-#include <shutdown.h>
-#include <timedata.h>
-#include <txmempool.h>
#include <util/bip32.h>
#include <util/error.h>
#include <util/fees.h>
@@ -41,6 +36,14 @@
#include <boost/algorithm/string/replace.hpp>
+const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS{
+ {WALLET_FLAG_AVOID_REUSE,
+ "You need to rescan the blockchain in order to correctly mark used "
+ "destinations in the past. Until this is done, some destinations may "
+ "be considered unused, even if the opposite is the case."
+ },
+};
+
static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10;
static CCriticalSection cs_wallets;
@@ -937,6 +940,37 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
return success;
}
+void CWallet::SetUsedDestinationState(const uint256& hash, unsigned int n, bool used)
+{
+ const CWalletTx* srctx = GetWalletTx(hash);
+ if (!srctx) return;
+
+ CTxDestination dst;
+ if (ExtractDestination(srctx->tx->vout[n].scriptPubKey, dst)) {
+ if (::IsMine(*this, dst)) {
+ LOCK(cs_wallet);
+ if (used && !GetDestData(dst, "used", nullptr)) {
+ AddDestData(dst, "used", "p"); // p for "present", opposite of absent (null)
+ } else if (!used && GetDestData(dst, "used", nullptr)) {
+ EraseDestData(dst, "used");
+ }
+ }
+ }
+}
+
+bool CWallet::IsUsedDestination(const CTxDestination& dst) const
+{
+ LOCK(cs_wallet);
+ return ::IsMine(*this, dst) && GetDestData(dst, "used", nullptr);
+}
+
+bool CWallet::IsUsedDestination(const uint256& hash, unsigned int n) const
+{
+ CTxDestination dst;
+ const CWalletTx* srctx = GetWalletTx(hash);
+ return srctx && ExtractDestination(srctx->tx->vout[n].scriptPubKey, dst) && IsUsedDestination(dst);
+}
+
bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
{
LOCK(cs_wallet);
@@ -945,6 +979,14 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
uint256 hash = wtxIn.GetHash();
+ if (IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
+ // Mark used destinations
+ for (const CTxIn& txin : wtxIn.tx->vin) {
+ const COutPoint& op = txin.prevout;
+ SetUsedDestinationState(op.hash, op.n, true);
+ }
+ }
+
// Inserts only if not already there, returns tx inserted or tx found
std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn));
CWalletTx& wtx = (*ret.first).second;
@@ -1008,6 +1050,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
// Notify UI of new or updated transaction
NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+#if HAVE_SYSTEM
// notify an external script when a wallet transaction comes in or is updated
std::string strCmd = gArgs.GetArg("-walletnotify", "");
@@ -1017,6 +1060,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
std::thread t(runCommand, strCmd);
t.detach(); // thread runs free
}
+#endif
return true;
}
@@ -1562,7 +1606,7 @@ void CWallet::UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag)
throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
}
-bool CWallet::IsWalletFlagSet(uint64_t flag)
+bool CWallet::IsWalletFlagSet(uint64_t flag) const
{
return (m_wallet_flags & flag);
}
@@ -1571,7 +1615,7 @@ bool CWallet::SetWalletFlags(uint64_t overwriteFlags, bool memonly)
{
LOCK(cs_wallet);
m_wallet_flags = overwriteFlags;
- if (((overwriteFlags & g_known_wallet_flags) >> 32) ^ (overwriteFlags >> 32)) {
+ if (((overwriteFlags & KNOWN_WALLET_FLAGS) >> 32) ^ (overwriteFlags >> 32)) {
// contains unknown non-tolerable wallet flags
return false;
}
@@ -2064,7 +2108,7 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
return 0;
// Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future).
- bool allow_cache = filter == ISMINE_SPENDABLE || filter == ISMINE_WATCH_ONLY;
+ bool allow_cache = (filter & ISMINE_ALL) && (filter & ISMINE_ALL) != ISMINE_ALL;
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsImmatureCoinBase(locked_chain))
@@ -2074,12 +2118,12 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
return m_amounts[AVAILABLE_CREDIT].m_value[filter];
}
+ bool allow_used_addresses = (filter & ISMINE_USED) || !pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
CAmount nCredit = 0;
uint256 hashTx = GetHash();
for (unsigned int i = 0; i < tx->vout.size(); i++)
{
- if (!pwallet->IsSpent(locked_chain, hashTx, i))
- {
+ if (!pwallet->IsSpent(locked_chain, hashTx, i) && (allow_used_addresses || !pwallet->IsUsedDestination(hashTx, i))) {
const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, filter);
if (!MoneyRange(nCredit))
@@ -2221,9 +2265,10 @@ void MaybeResendWalletTxs()
*/
-CWallet::Balance CWallet::GetBalance(const int min_depth) const
+CWallet::Balance CWallet::GetBalance(const int min_depth, bool avoid_reuse) const
{
Balance ret;
+ isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED;
{
auto locked_chain = chain().lock();
LOCK(cs_wallet);
@@ -2232,8 +2277,8 @@ CWallet::Balance CWallet::GetBalance(const int min_depth) const
const CWalletTx& wtx = entry.second;
const bool is_trusted{wtx.IsTrusted(*locked_chain)};
const int tx_depth{wtx.GetDepthInMainChain(*locked_chain)};
- const CAmount tx_credit_mine{wtx.GetAvailableCredit(*locked_chain, /* fUseCache */ true, ISMINE_SPENDABLE)};
- const CAmount tx_credit_watchonly{wtx.GetAvailableCredit(*locked_chain, /* fUseCache */ true, ISMINE_WATCH_ONLY)};
+ const CAmount tx_credit_mine{wtx.GetAvailableCredit(*locked_chain, /* fUseCache */ true, ISMINE_SPENDABLE | reuse_filter)};
+ const CAmount tx_credit_watchonly{wtx.GetAvailableCredit(*locked_chain, /* fUseCache */ true, ISMINE_WATCH_ONLY | reuse_filter)};
if (is_trusted && tx_depth >= min_depth) {
ret.m_mine_trusted += tx_credit_mine;
ret.m_watchonly_trusted += tx_credit_watchonly;
@@ -2271,6 +2316,9 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
vCoins.clear();
CAmount nTotal = 0;
+ // Either the WALLET_FLAG_AVOID_REUSE flag is not set (in which case we always allow), or we default to avoiding, and only in the case where
+ // a coin control object is provided, and has the avoid address reuse flag set to false, do we allow already used addresses
+ bool allow_used_addresses = !IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE) || (coinControl && !coinControl->m_avoid_address_reuse);
for (const auto& entry : mapWallet)
{
@@ -2352,6 +2400,10 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
continue;
}
+ if (!allow_used_addresses && IsUsedDestination(wtxid, i)) {
+ continue;
+ }
+
bool solvable = IsSolvable(*this, wtx.tx->vout[i].scriptPubKey);
bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
@@ -2644,6 +2696,11 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
}
}
+ if (nFeeRet > this->m_default_max_tx_fee) {
+ strFailReason = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
+ return false;
+ }
+
return true;
}
@@ -4062,12 +4119,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
walletFile));
}
else if (nLoadWalletRet == DBErrors::TOO_NEW) {
- chain.initError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, _(PACKAGE_NAME)));
+ chain.initError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, PACKAGE_NAME));
return nullptr;
}
else if (nLoadWalletRet == DBErrors::NEED_REWRITE)
{
- chain.initError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)));
+ chain.initError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), PACKAGE_NAME));
return nullptr;
}
else {
@@ -4142,16 +4199,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
walletInstance->SetMinVersion(FEATURE_LATEST);
- if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- //selective allow to set flags
- walletInstance->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
- } else if (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET) {
- walletInstance->SetWalletFlag(WALLET_FLAG_BLANK_WALLET);
- } else {
+ walletInstance->SetWalletFlags(wallet_creation_flags, false);
+ if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
// generate a new seed
CPubKey seed = walletInstance->GenerateNewSeed();
walletInstance->SetHDSeed(seed);
- } // Otherwise, do not generate a new seed
+ }
// Top up the keypool
if (walletInstance->CanGenerateKeys() && !walletInstance->TopUpKeyPool()) {
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 87aff09039..7b5465c219 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -11,7 +11,6 @@
#include <interfaces/handler.h>
#include <outputtype.h>
#include <policy/feerate.h>
-#include <script/ismine.h>
#include <script/sign.h>
#include <streams.h>
#include <tinyformat.h>
@@ -21,6 +20,7 @@
#include <validationinterface.h>
#include <wallet/coinselection.h>
#include <wallet/crypter.h>
+#include <wallet/ismine.h>
#include <wallet/walletdb.h>
#include <wallet/walletutil.h>
@@ -120,6 +120,10 @@ enum WalletFlags : uint64_t {
// wallet flags in the upper section (> 1 << 31) will lead to not opening the wallet if flag is unknown
// unknown wallet flags in the lower section <= (1 << 31) will be tolerated
+ // will categorize coins as clean (not reused) and dirty (reused), and handle
+ // them with privacy considerations in mind
+ WALLET_FLAG_AVOID_REUSE = (1ULL << 0),
+
// Indicates that the metadata has already been upgraded to contain key origins
WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1),
@@ -139,7 +143,23 @@ enum WalletFlags : uint64_t {
WALLET_FLAG_BLANK_WALLET = (1ULL << 33),
};
-static constexpr uint64_t g_known_wallet_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET | WALLET_FLAG_KEY_ORIGIN_METADATA;
+static constexpr uint64_t KNOWN_WALLET_FLAGS =
+ WALLET_FLAG_AVOID_REUSE
+ | WALLET_FLAG_BLANK_WALLET
+ | WALLET_FLAG_KEY_ORIGIN_METADATA
+ | WALLET_FLAG_DISABLE_PRIVATE_KEYS;
+
+static constexpr uint64_t MUTABLE_WALLET_FLAGS =
+ WALLET_FLAG_AVOID_REUSE;
+
+static const std::map<std::string,WalletFlags> WALLET_FLAG_MAP{
+ {"avoid_reuse", WALLET_FLAG_AVOID_REUSE},
+ {"blank", WALLET_FLAG_BLANK_WALLET},
+ {"key_origin_metadata", WALLET_FLAG_KEY_ORIGIN_METADATA},
+ {"disable_private_keys", WALLET_FLAG_DISABLE_PRIVATE_KEYS},
+};
+
+extern const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS;
/** A key from a CWallet's keypool
*
@@ -924,6 +944,12 @@ public:
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const;
bool IsSpent(interfaces::Chain::Lock& locked_chain, const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ // Whether this or any UTXO with the same CTxDestination has been spent.
+ bool IsUsedDestination(const CTxDestination& dst) const;
+ bool IsUsedDestination(const uint256& hash, unsigned int n) const;
+ void SetUsedDestinationState(const uint256& hash, unsigned int n, bool used);
+
std::vector<OutputGroup> GroupOutputs(const std::vector<COutput>& outputs, bool single_coin) const;
bool IsLockedCoin(uint256 hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -1036,7 +1062,7 @@ public:
CAmount m_watchonly_untrusted_pending{0};
CAmount m_watchonly_immature{0};
};
- Balance GetBalance(int min_depth = 0) const;
+ Balance GetBalance(int min_depth = 0, bool avoid_reuse = true) const;
CAmount GetAvailableBalance(const CCoinControl* coinControl = nullptr) const;
OutputType TransactionChangeType(OutputType change_type, const std::vector<CRecipient>& vecSend);
@@ -1288,7 +1314,7 @@ public:
void UnsetWalletFlag(uint64_t flag);
/** check if a certain wallet flag is set */
- bool IsWalletFlagSet(uint64_t flag);
+ bool IsWalletFlagSet(uint64_t flag) const;
/** overwrite all flags by the given uint64_t
returns false if unknown, non-tolerable flags are present */
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index c6132a2686..0843194511 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <base58.h>
#include <fs.h>
#include <util/system.h>
#include <wallet/wallet.h>
@@ -23,7 +22,7 @@ static void WalletToolReleaseWallet(CWallet* wallet)
static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path)
{
if (fs::exists(path)) {
- fprintf(stderr, "Error: File exists already\n");
+ tfm::format(std::cerr, "Error: File exists already\n");
return nullptr;
}
// dummy chain interface
@@ -31,7 +30,7 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
bool first_run = true;
DBErrors load_wallet_ret = wallet_instance->LoadWallet(first_run);
if (load_wallet_ret != DBErrors::LOAD_OK) {
- fprintf(stderr, "Error creating %s", name.c_str());
+ tfm::format(std::cerr, "Error creating %s", name.c_str());
return nullptr;
}
@@ -41,7 +40,7 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
CPubKey seed = wallet_instance->GenerateNewSeed();
wallet_instance->SetHDSeed(seed);
- fprintf(stdout, "Topping up keypool...\n");
+ tfm::format(std::cout, "Topping up keypool...\n");
wallet_instance->TopUpKeyPool();
return wallet_instance;
}
@@ -49,7 +48,7 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path)
{
if (!fs::exists(path)) {
- fprintf(stderr, "Error: Wallet files does not exist\n");
+ tfm::format(std::cerr, "Error: Wallet files does not exist\n");
return nullptr;
}
@@ -60,28 +59,28 @@ static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::pa
bool first_run;
load_wallet_ret = wallet_instance->LoadWallet(first_run);
} catch (const std::runtime_error&) {
- fprintf(stderr, "Error loading %s. Is wallet being used by another process?\n", name.c_str());
+ tfm::format(std::cerr, "Error loading %s. Is wallet being used by another process?\n", name.c_str());
return nullptr;
}
if (load_wallet_ret != DBErrors::LOAD_OK) {
wallet_instance = nullptr;
if (load_wallet_ret == DBErrors::CORRUPT) {
- fprintf(stderr, "Error loading %s: Wallet corrupted", name.c_str());
+ tfm::format(std::cerr, "Error loading %s: Wallet corrupted", name.c_str());
return nullptr;
} else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) {
- fprintf(stderr, "Error reading %s! All keys read correctly, but transaction data"
+ tfm::format(std::cerr, "Error reading %s! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect.",
name.c_str());
} else if (load_wallet_ret == DBErrors::TOO_NEW) {
- fprintf(stderr, "Error loading %s: Wallet requires newer version of %s",
+ tfm::format(std::cerr, "Error loading %s: Wallet requires newer version of %s",
name.c_str(), PACKAGE_NAME);
return nullptr;
} else if (load_wallet_ret == DBErrors::NEED_REWRITE) {
- fprintf(stderr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME);
+ tfm::format(std::cerr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME);
return nullptr;
} else {
- fprintf(stderr, "Error loading %s", name.c_str());
+ tfm::format(std::cerr, "Error loading %s", name.c_str());
return nullptr;
}
}
@@ -93,12 +92,12 @@ static void WalletShowInfo(CWallet* wallet_instance)
{
LOCK(wallet_instance->cs_wallet);
- fprintf(stdout, "Wallet info\n===========\n");
- fprintf(stdout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
- fprintf(stdout, "HD (hd seed available): %s\n", wallet_instance->GetHDChain().seed_id.IsNull() ? "no" : "yes");
- fprintf(stdout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
- fprintf(stdout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
- fprintf(stdout, "Address Book: %zu\n", wallet_instance->mapAddressBook.size());
+ tfm::format(std::cout, "Wallet info\n===========\n");
+ tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
+ tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->GetHDChain().seed_id.IsNull() ? "no" : "yes");
+ tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
+ tfm::format(std::cout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
+ tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->mapAddressBook.size());
}
bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
@@ -113,12 +112,12 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
}
} else if (command == "info") {
if (!fs::exists(path)) {
- fprintf(stderr, "Error: no wallet file at %s\n", name.c_str());
+ tfm::format(std::cerr, "Error: no wallet file at %s\n", name.c_str());
return false;
}
std::string error;
if (!WalletBatch::VerifyEnvironment(path, error)) {
- fprintf(stderr, "Error loading %s. Is wallet being used by other process?\n", name.c_str());
+ tfm::format(std::cerr, "Error loading %s. Is wallet being used by other process?\n", name.c_str());
return false;
}
std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path);
@@ -126,7 +125,7 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
WalletShowInfo(wallet_instance.get());
wallet_instance->Flush(true);
} else {
- fprintf(stderr, "Invalid command: %s\n", command.c_str());
+ tfm::format(std::cerr, "Invalid command: %s\n", command.c_str());
return false;
}
diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h
index da848a747b..7ee2505631 100644
--- a/src/wallet/wallettool.h
+++ b/src/wallet/wallettool.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_WALLET_WALLETTOOL_H
#define BITCOIN_WALLET_WALLETTOOL_H
-#include <script/ismine.h>
+#include <wallet/ismine.h>
#include <wallet/wallet.h>
namespace WalletTool {
diff --git a/src/warnings.cpp b/src/warnings.cpp
index 8ac9ee09db..5542412a7f 100644
--- a/src/warnings.cpp
+++ b/src/warnings.cpp
@@ -4,7 +4,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <sync.h>
-#include <clientversion.h>
#include <util/system.h>
#include <warnings.h>
diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp
index 6a9661e3e8..a5f3be8f5b 100644
--- a/src/zmq/zmqabstractnotifier.cpp
+++ b/src/zmq/zmqabstractnotifier.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <zmq/zmqabstractnotifier.h>
-#include <util/system.h>
const int CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM;
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index 6826cf62d6..de59b71b8f 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -7,7 +7,6 @@
#include <version.h>
#include <validation.h>
-#include <streams.h>
#include <util/system.h>
void zmqError(const char *str)