aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am31
-rw-r--r--src/Makefile.qt.include32
-rw-r--r--src/Makefile.qttest.include14
-rw-r--r--src/Makefile.test.include25
-rw-r--r--src/addrdb.cpp2
-rw-r--r--src/addrman.h55
-rw-r--r--src/arith_uint256.cpp4
-rw-r--r--src/base58.cpp7
-rw-r--r--src/bench/bech32.cpp2
-rw-r--r--src/bench/bench_bitcoin.cpp4
-rw-r--r--src/bench/block_assemble.cpp3
-rw-r--r--src/bench/checkblock.cpp4
-rw-r--r--src/bench/checkqueue.cpp2
-rw-r--r--src/bench/coin_selection.cpp7
-rw-r--r--src/bench/crypto_hash.cpp3
-rw-r--r--src/bench/examples.cpp2
-rw-r--r--src/bitcoin-cli.cpp9
-rw-r--r--src/bitcoin-tx.cpp10
-rw-r--r--src/bitcoind.cpp16
-rw-r--r--src/blockencodings.cpp5
-rw-r--r--src/blockfilter.cpp1
-rw-r--r--src/blockfilter.h5
-rw-r--r--src/chainparams.cpp4
-rw-r--r--src/chainparamsbase.cpp4
-rw-r--r--src/coins.cpp1
-rw-r--r--src/coins.h2
-rw-r--r--src/consensus/merkle.cpp2
-rw-r--r--src/consensus/tx_verify.cpp2
-rw-r--r--src/core_read.cpp4
-rw-r--r--src/core_write.cpp6
-rw-r--r--src/crypto/siphash.cpp173
-rw-r--r--src/crypto/siphash.h47
-rw-r--r--src/dbwrapper.h4
-rw-r--r--src/dummywallet.cpp20
-rw-r--r--src/fs.cpp105
-rw-r--r--src/fs.h51
-rw-r--r--src/hash.cpp168
-rw-r--r--src/hash.h35
-rw-r--r--src/httprpc.cpp4
-rw-r--r--src/httpserver.cpp26
-rw-r--r--src/index/base.cpp4
-rw-r--r--src/index/txindex.cpp2
-rw-r--r--src/init.cpp56
-rw-r--r--src/init.h19
-rw-r--r--src/interfaces/README.md2
-rw-r--r--src/interfaces/chain.cpp44
-rw-r--r--src/interfaces/chain.h84
-rw-r--r--src/interfaces/handler.cpp2
-rw-r--r--src/interfaces/node.cpp24
-rw-r--r--src/interfaces/node.h6
-rw-r--r--src/interfaces/wallet.cpp147
-rw-r--r--src/interfaces/wallet.h6
-rw-r--r--src/key_io.cpp2
-rw-r--r--src/keystore.cpp2
-rw-r--r--src/logging.cpp2
-rw-r--r--src/merkleblock.cpp2
-rw-r--r--src/miner.cpp4
-rw-r--r--src/net.cpp493
-rw-r--r--src/net.h6
-rw-r--r--src/net_processing.cpp23
-rw-r--r--src/net_processing.h2
-rw-r--r--src/netaddress.cpp2
-rw-r--r--src/netbase.cpp30
-rw-r--r--src/noui.cpp2
-rw-r--r--src/policy/fees.cpp2
-rw-r--r--src/policy/fees.h6
-rw-r--r--src/policy/policy.cpp4
-rw-r--r--src/policy/rbf.cpp2
-rw-r--r--src/prevector.h16
-rw-r--r--src/primitives/block.cpp2
-rw-r--r--src/primitives/transaction.cpp2
-rw-r--r--src/primitives/transaction.h4
-rw-r--r--src/protocol.cpp4
-rw-r--r--src/qt/README.md4
-rw-r--r--src/qt/bantablemodel.cpp2
-rw-r--r--src/qt/bitcoin.cpp20
-rw-r--r--src/qt/bitcoingui.cpp100
-rw-r--r--src/qt/bitcoingui.h11
-rw-r--r--src/qt/callback.h30
-rw-r--r--src/qt/clientmodel.cpp7
-rw-r--r--src/qt/clientmodel.h1
-rw-r--r--src/qt/coincontroldialog.cpp5
-rw-r--r--src/qt/forms/debugwindow.ui68
-rw-r--r--src/qt/guiutil.cpp42
-rw-r--r--src/qt/guiutil.h3
-rw-r--r--src/qt/intro.cpp2
-rw-r--r--src/qt/macdockiconhandler.h21
-rw-r--r--src/qt/macdockiconhandler.mm100
-rw-r--r--src/qt/macos_appnap.h24
-rw-r--r--src/qt/macos_appnap.mm71
-rw-r--r--src/qt/optionsdialog.cpp14
-rw-r--r--src/qt/paymentrequestplus.cpp2
-rw-r--r--src/qt/paymentserver.cpp301
-rw-r--r--src/qt/paymentserver.h44
-rw-r--r--src/qt/rpcconsole.cpp7
-rw-r--r--src/qt/sendcoinsdialog.cpp8
-rw-r--r--src/qt/sendcoinsentry.cpp10
-rw-r--r--src/qt/splashscreen.cpp2
-rw-r--r--src/qt/test/addressbooktests.cpp19
-rw-r--r--src/qt/test/compattests.cpp6
-rw-r--r--src/qt/test/paymentservertests.cpp4
-rw-r--r--src/qt/test/rpcnestedtests.cpp2
-rw-r--r--src/qt/test/test_main.cpp8
-rw-r--r--src/qt/test/util.cpp11
-rw-r--r--src/qt/test/wallettests.cpp24
-rw-r--r--src/qt/transactiondesc.cpp15
-rw-r--r--src/qt/transactiondesc.h2
-rw-r--r--src/qt/transactionrecord.cpp2
-rw-r--r--src/qt/transactionrecord.h2
-rw-r--r--src/qt/transactiontablemodel.cpp7
-rw-r--r--src/qt/transactionview.cpp6
-rw-r--r--src/qt/utilitydialog.cpp4
-rw-r--r--src/qt/walletmodel.cpp15
-rw-r--r--src/qt/walletmodel.h16
-rw-r--r--src/qt/walletmodeltransaction.cpp6
-rw-r--r--src/qt/walletmodeltransaction.h1
-rw-r--r--src/qt/walletview.cpp8
-rw-r--r--src/qt/winshutdownmonitor.cpp2
-rw-r--r--src/random.cpp4
-rw-r--r--src/rest.cpp2
-rw-r--r--src/rpc/blockchain.cpp32
-rw-r--r--src/rpc/client.cpp4
-rw-r--r--src/rpc/mining.cpp12
-rw-r--r--src/rpc/misc.cpp14
-rw-r--r--src/rpc/net.cpp4
-rw-r--r--src/rpc/protocol.cpp16
-rw-r--r--src/rpc/rawtransaction.cpp47
-rw-r--r--src/rpc/rawtransaction.h6
-rw-r--r--src/rpc/server.cpp4
-rw-r--r--src/rpc/util.cpp4
-rw-r--r--src/rpc/util.h6
-rw-r--r--src/script/descriptor.cpp126
-rw-r--r--src/script/ismine.cpp14
-rw-r--r--src/script/script.cpp2
-rw-r--r--src/script/script.h6
-rw-r--r--src/script/sigcache.cpp2
-rw-r--r--src/script/sign.cpp68
-rw-r--r--src/script/sign.h40
-rw-r--r--src/script/standard.cpp4
-rw-r--r--src/sync.cpp2
-rw-r--r--src/test/addrman_tests.cpp4
-rw-r--r--src/test/allocator_tests.cpp2
-rw-r--r--src/test/amount_tests.cpp57
-rw-r--r--src/test/base32_tests.cpp2
-rw-r--r--src/test/base58_tests.cpp2
-rw-r--r--src/test/base64_tests.cpp2
-rw-r--r--src/test/bip32_tests.cpp4
-rw-r--r--src/test/blockfilter_tests.cpp2
-rw-r--r--src/test/bloom_tests.cpp4
-rw-r--r--src/test/checkqueue_tests.cpp4
-rw-r--r--src/test/coins_tests.cpp2
-rw-r--r--src/test/compress_tests.cpp2
-rw-r--r--src/test/crypto_tests.cpp2
-rw-r--r--src/test/denialofservice_tests.cpp2
-rw-r--r--src/test/descriptor_tests.cpp42
-rw-r--r--src/test/fs_tests.cpp56
-rw-r--r--src/test/getarg_tests.cpp2
-rw-r--r--src/test/hash_tests.cpp3
-rw-r--r--src/test/key_io_tests.cpp2
-rw-r--r--src/test/key_properties.cpp4
-rw-r--r--src/test/key_tests.cpp4
-rw-r--r--src/test/mempool_tests.cpp2
-rw-r--r--src/test/miner_tests.cpp8
-rw-r--r--src/test/net_tests.cpp2
-rw-r--r--src/test/netbase_tests.cpp2
-rw-r--r--src/test/policyestimator_tests.cpp2
-rw-r--r--src/test/pow_tests.cpp4
-rw-r--r--src/test/rpc_tests.cpp7
-rw-r--r--src/test/script_tests.cpp12
-rw-r--r--src/test/sighash_tests.cpp4
-rw-r--r--src/test/skiplist_tests.cpp3
-rw-r--r--src/test/transaction_tests.cpp2
-rw-r--r--src/test/txindex_tests.cpp4
-rw-r--r--src/test/txvalidationcache_tests.cpp2
-rw-r--r--src/test/util_tests.cpp6
-rw-r--r--src/threadsafety.h11
-rw-r--r--src/timedata.cpp4
-rw-r--r--src/torcontrol.cpp4
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txmempool.cpp8
-rw-r--r--src/txmempool.h15
-rw-r--r--src/ui_interface.cpp2
-rw-r--r--src/uint256.cpp4
-rw-r--r--src/undo.h1
-rw-r--r--src/util/bytevectorhash.cpp18
-rw-r--r--src/util/bytevectorhash.h26
-rw-r--r--src/util/memory.h (renamed from src/utilmemory.h)4
-rw-r--r--src/util/moneystr.cpp (renamed from src/utilmoneystr.cpp)10
-rw-r--r--src/util/moneystr.h (renamed from src/utilmoneystr.h)6
-rw-r--r--src/util/strencodings.cpp (renamed from src/utilstrencodings.cpp)7
-rw-r--r--src/util/strencodings.h (renamed from src/utilstrencodings.h)22
-rw-r--r--src/util/system.cpp (renamed from src/util.cpp)46
-rw-r--r--src/util/system.h (renamed from src/util.h)26
-rw-r--r--src/util/time.cpp (renamed from src/utiltime.cpp)2
-rw-r--r--src/util/time.h (renamed from src/utiltime.h)6
-rw-r--r--src/validation.cpp19
-rw-r--r--src/validation.h6
-rw-r--r--src/validationinterface.cpp2
-rw-r--r--src/wallet/coincontrol.cpp2
-rw-r--r--src/wallet/coinselection.cpp4
-rw-r--r--src/wallet/crypter.cpp2
-rw-r--r--src/wallet/db.cpp33
-rw-r--r--src/wallet/db.h9
-rw-r--r--src/wallet/feebumper.cpp27
-rw-r--r--src/wallet/fees.cpp2
-rw-r--r--src/wallet/init.cpp83
-rw-r--r--src/wallet/rpcdump.cpp314
-rw-r--r--src/wallet/rpcwallet.cpp481
-rw-r--r--src/wallet/rpcwallet.h2
-rw-r--r--src/wallet/test/coinselector_tests.cpp3
-rw-r--r--src/wallet/test/init_test_fixture.cpp44
-rw-r--r--src/wallet/test/init_test_fixture.h24
-rw-r--r--src/wallet/test/init_tests.cpp78
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp10
-rw-r--r--src/wallet/test/wallet_crypto_tests.cpp2
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp3
-rw-r--r--src/wallet/test/wallet_test_fixture.h3
-rw-r--r--src/wallet/test/wallet_tests.cpp50
-rw-r--r--src/wallet/wallet.cpp238
-rw-r--r--src/wallet/wallet.h146
-rw-r--r--src/wallet/walletdb.cpp4
-rw-r--r--src/wallet/walletutil.cpp66
-rw-r--r--src/wallet/walletutil.h28
-rw-r--r--src/walletinitinterface.h17
-rw-r--r--src/warnings.cpp2
-rw-r--r--src/zmq/zmqabstractnotifier.cpp3
-rw-r--r--src/zmq/zmqabstractnotifier.h11
-rw-r--r--src/zmq/zmqnotificationinterface.cpp9
-rw-r--r--src/zmq/zmqpublishnotifier.cpp18
-rw-r--r--src/zmq/zmqpublishnotifier.h2
-rw-r--r--src/zmq/zmqrpc.cpp4
231 files changed, 3481 insertions, 2145 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 7a2e9fa5e8..8dd0d31839 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -125,6 +125,7 @@ BITCOIN_CORE_H = \
index/txindex.h \
indirectmap.h \
init.h \
+ interfaces/chain.h \
interfaces/handler.h \
interfaces/node.h \
interfaces/wallet.h \
@@ -183,10 +184,11 @@ BITCOIN_CORE_H = \
txmempool.h \
ui_interface.h \
undo.h \
- util.h \
- utilmemory.h \
- utilmoneystr.h \
- utiltime.h \
+ util/bytevectorhash.h \
+ util/system.h \
+ util/memory.h \
+ util/moneystr.h \
+ util/time.h \
validation.h \
validationinterface.h \
versionbits.h \
@@ -232,6 +234,7 @@ libbitcoin_server_a_SOURCES = \
httpserver.cpp \
index/base.cpp \
index/txindex.cpp \
+ interfaces/chain.cpp \
interfaces/handler.cpp \
interfaces/node.cpp \
init.cpp \
@@ -321,7 +324,9 @@ crypto_libbitcoin_crypto_base_a_SOURCES = \
crypto/sha256.cpp \
crypto/sha256.h \
crypto/sha512.cpp \
- crypto/sha512.h
+ crypto/sha512.h \
+ crypto/siphash.cpp \
+ crypto/siphash.h
if USE_ASM
crypto_libbitcoin_crypto_base_a_SOURCES += crypto/sha256_sse4.cpp
@@ -377,8 +382,8 @@ libbitcoin_consensus_a_SOURCES = \
tinyformat.h \
uint256.cpp \
uint256.h \
- utilstrencodings.cpp \
- utilstrencodings.h \
+ util/strencodings.cpp \
+ util/strencodings.h \
version.h
# common: shared between bitcoind, and bitcoin-qt and non-server tools
@@ -427,10 +432,11 @@ libbitcoin_util_a_SOURCES = \
support/cleanse.cpp \
sync.cpp \
threadinterrupt.cpp \
- util.cpp \
- utilmoneystr.cpp \
- utilstrencodings.cpp \
- utiltime.cpp \
+ util/bytevectorhash.cpp \
+ util/system.cpp \
+ util/moneystr.cpp \
+ util/strencodings.cpp \
+ util/time.cpp \
$(BITCOIN_CORE_H)
if GLIBC_BACK_COMPAT
@@ -461,6 +467,7 @@ endif
bitcoind_LDADD = \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_WALLET) \
+ $(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_COMMON) \
$(LIBUNIVALUE) \
$(LIBBITCOIN_UTIL) \
@@ -587,9 +594,11 @@ if HARDEN
$(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS)
endif
+if ENABLE_BIP70
%.pb.cc %.pb.h: %.proto
@test -f $(PROTOC)
$(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(<D) $<
+endif
if EMBEDDED_LEVELDB
include Makefile.leveldb.include
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index c7a1963135..445849e3d8 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -122,7 +122,6 @@ QT_MOC_CPP = \
qt/moc_bitcoinamountfield.cpp \
qt/moc_bitcoingui.cpp \
qt/moc_bitcoinunits.cpp \
- qt/moc_callback.cpp \
qt/moc_clientmodel.cpp \
qt/moc_coincontroldialog.cpp \
qt/moc_coincontroltreewidget.cpp \
@@ -163,12 +162,12 @@ QT_MOC_CPP = \
BITCOIN_MM = \
qt/macdockiconhandler.mm \
- qt/macnotificationhandler.mm
+ qt/macnotificationhandler.mm \
+ qt/macos_appnap.mm
QT_MOC = \
qt/bitcoin.moc \
qt/bitcoinamountfield.moc \
- qt/callback.moc \
qt/intro.moc \
qt/overviewpage.moc \
qt/rpcconsole.moc
@@ -178,9 +177,15 @@ QT_QRC = qt/bitcoin.qrc
QT_QRC_LOCALE_CPP = qt/qrc_bitcoin_locale.cpp
QT_QRC_LOCALE = qt/bitcoin_locale.qrc
+if ENABLE_BIP70
PROTOBUF_CC = qt/paymentrequest.pb.cc
PROTOBUF_H = qt/paymentrequest.pb.h
PROTOBUF_PROTO = qt/paymentrequest.proto
+else
+PROTOBUF_CC =
+PROTOBUF_H =
+PROTOBUF_PROTO =
+endif
BITCOIN_QT_H = \
qt/addressbookpage.h \
@@ -191,7 +196,6 @@ BITCOIN_QT_H = \
qt/bitcoinamountfield.h \
qt/bitcoingui.h \
qt/bitcoinunits.h \
- qt/callback.h \
qt/clientmodel.h \
qt/coincontroldialog.h \
qt/coincontroltreewidget.h \
@@ -202,6 +206,7 @@ BITCOIN_QT_H = \
qt/intro.h \
qt/macdockiconhandler.h \
qt/macnotificationhandler.h \
+ qt/macos_appnap.h \
qt/modaloverlay.h \
qt/networkstyle.h \
qt/notificator.h \
@@ -330,7 +335,6 @@ BITCOIN_QT_WALLET_CPP = \
qt/editaddressdialog.cpp \
qt/openuridialog.cpp \
qt/overviewpage.cpp \
- qt/paymentrequestplus.cpp \
qt/paymentserver.cpp \
qt/receivecoinsdialog.cpp \
qt/receiverequestdialog.cpp \
@@ -349,13 +353,19 @@ BITCOIN_QT_WALLET_CPP = \
qt/walletmodeltransaction.cpp \
qt/walletview.cpp
+BITCOIN_QT_WALLET_BIP70_CPP = \
+ qt/paymentrequestplus.cpp
+
BITCOIN_QT_CPP = $(BITCOIN_QT_BASE_CPP)
if TARGET_WINDOWS
BITCOIN_QT_CPP += $(BITCOIN_QT_WINDOWS_CPP)
endif
if ENABLE_WALLET
BITCOIN_QT_CPP += $(BITCOIN_QT_WALLET_CPP)
-endif
+if ENABLE_BIP70
+BITCOIN_QT_CPP += $(BITCOIN_QT_WALLET_BIP70_CPP)
+endif # ENABLE_BIP70
+endif # ENABLE_WALLET
RES_IMAGES =
@@ -409,8 +419,16 @@ if ENABLE_ZMQ
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
- $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
+if ENABLE_BIP70
+qt_bitcoin_qt_LDADD += $(SSL_LIBS)
+else
+if TARGET_WINDOWS
+qt_bitcoin_qt_LDADD += $(SSL_LIBS)
+endif
+endif
+qt_bitcoin_qt_LDADD += $(CRYPTO_LIBS)
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_bitcoin_qt_LIBTOOLFLAGS = $(AM_LIBTOOLFLAGS) --tag CXX
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 4b14212b2e..db7873e8b7 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -13,9 +13,12 @@ TEST_QT_MOC_CPP = \
if ENABLE_WALLET
TEST_QT_MOC_CPP += \
qt/test/moc_addressbooktests.cpp \
- qt/test/moc_paymentservertests.cpp \
qt/test/moc_wallettests.cpp
-endif
+if ENABLE_BIP70
+TEST_QT_MOC_CPP += \
+ qt/test/moc_paymentservertests.cpp
+endif # ENABLE_BIP70
+endif # ENABLE_WALLET
TEST_QT_H = \
qt/test/addressbooktests.h \
@@ -48,10 +51,13 @@ qt_test_test_bitcoin_qt_SOURCES = \
if ENABLE_WALLET
qt_test_test_bitcoin_qt_SOURCES += \
qt/test/addressbooktests.cpp \
- qt/test/paymentservertests.cpp \
qt/test/wallettests.cpp \
wallet/test/wallet_test_fixture.cpp
-endif
+if ENABLE_BIP70
+qt_test_test_bitcoin_qt_SOURCES += \
+ qt/test/paymentservertests.cpp
+endif # ENABLE_BIP70
+endif # ENABLE_WALLET
nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 8a537ed4f6..a31852c94f 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -51,6 +51,7 @@ BITCOIN_TESTS =\
test/cuckoocache_tests.cpp \
test/denialofservice_tests.cpp \
test/descriptor_tests.cpp \
+ test/fs_tests.cpp \
test/getarg_tests.cpp \
test/hash_tests.cpp \
test/key_io_tests.cpp \
@@ -110,11 +111,14 @@ BITCOIN_TESTS += \
wallet/test/psbt_wallet_tests.cpp \
wallet/test/wallet_tests.cpp \
wallet/test/wallet_crypto_tests.cpp \
- wallet/test/coinselector_tests.cpp
+ wallet/test/coinselector_tests.cpp \
+ wallet/test/init_tests.cpp
BITCOIN_TEST_SUITE += \
wallet/test/wallet_test_fixture.cpp \
- wallet/test/wallet_test_fixture.h
+ wallet/test/wallet_test_fixture.h \
+ wallet/test/init_test_fixture.cpp \
+ wallet/test/init_test_fixture.h
endif
test_test_bitcoin_SOURCES = $(BITCOIN_TEST_SUITE) $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
@@ -161,11 +165,19 @@ nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
$(BITCOIN_TESTS): $(GENERATED_TEST_FILES)
-CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES)
+CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) $(BITCOIN_TESTS:=.log)
CLEANFILES += $(CLEAN_BITCOIN_TEST)
+if TARGET_WINDOWS
bitcoin_test: $(TEST_BINARY)
+else
+if ENABLE_BENCH
+bitcoin_test: $(TEST_BINARY) $(BENCH_BINARY)
+else
+bitcoin_test: $(TEST_BINARY)
+endif
+endif
bitcoin_test_check: $(TEST_BINARY) FORCE
$(MAKE) check-TESTS TESTS=$^
@@ -180,6 +192,13 @@ if BUILD_BITCOIN_TX
endif
@echo "Running test/util/rpcauth-test.py..."
$(PYTHON) $(top_builddir)/test/util/rpcauth-test.py
+if TARGET_WINDOWS
+else
+if ENABLE_BENCH
+ @echo "Running bench/bench_bitcoin -evals=1 -scaling=0..."
+ $(BENCH_BINARY) -evals=1 -scaling=0 > /dev/null
+endif
+endif
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
if EMBEDDED_UNIVALUE
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 3eae2b5127..1590bce074 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -12,7 +12,7 @@
#include <random.h>
#include <streams.h>
#include <tinyformat.h>
-#include <util.h>
+#include <util/system.h>
namespace {
diff --git a/src/addrman.h b/src/addrman.h
index cf1949c28c..b97feb6f08 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -11,7 +11,7 @@
#include <random.h>
#include <sync.h>
#include <timedata.h>
-#include <util.h>
+#include <util/system.h>
#include <map>
#include <set>
@@ -187,36 +187,37 @@ public:
*/
class CAddrMan
{
-private:
+protected:
//! critical section to protect the inner data structures
mutable CCriticalSection cs;
+private:
//! last used nId
- int nIdCount;
+ int nIdCount GUARDED_BY(cs);
//! table with information about all nIds
- std::map<int, CAddrInfo> mapInfo;
+ std::map<int, CAddrInfo> mapInfo GUARDED_BY(cs);
//! find an nId based on its network address
- std::map<CNetAddr, int> mapAddr;
+ std::map<CNetAddr, int> mapAddr GUARDED_BY(cs);
//! randomly-ordered vector of all nIds
- std::vector<int> vRandom;
+ std::vector<int> vRandom GUARDED_BY(cs);
// number of "tried" entries
- int nTried;
+ int nTried GUARDED_BY(cs);
//! list of "tried" buckets
- int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];
+ int vvTried[ADDRMAN_TRIED_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
//! number of (unique) "new" entries
- int nNew;
+ int nNew GUARDED_BY(cs);
//! list of "new" buckets
- int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE];
+ int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
//! last time Good was called (memory only)
- int64_t nLastGood;
+ int64_t nLastGood GUARDED_BY(cs);
//! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
std::set<int> m_tried_collisions;
@@ -229,58 +230,58 @@ protected:
FastRandomContext insecure_rand;
//! Find an entry.
- CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr);
+ CAddrInfo* Find(const CNetAddr& addr, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! find an entry, creating it if necessary.
//! nTime and nServices of the found node are updated, if necessary.
- CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr);
+ CAddrInfo* Create(const CAddress &addr, const CNetAddr &addrSource, int *pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Swap two elements in vRandom.
- void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2);
+ void SwapRandom(unsigned int nRandomPos1, unsigned int nRandomPos2) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Move an entry from the "new" table(s) to the "tried" table
- void MakeTried(CAddrInfo& info, int nId);
+ void MakeTried(CAddrInfo& info, int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Delete an entry. It must not be in tried, and have refcount 0.
- void Delete(int nId);
+ void Delete(int nId) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Clear a position in a "new" table. This is the only place where entries are actually deleted.
- void ClearNew(int nUBucket, int nUBucketPos);
+ void ClearNew(int nUBucket, int nUBucketPos) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Mark an entry "good", possibly moving it from "new" to "tried".
- void Good_(const CService &addr, bool test_before_evict, int64_t time);
+ void Good_(const CService &addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Add an entry to the "new" table.
- bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty);
+ bool Add_(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Mark an entry as attempted to connect.
- void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime);
+ void Attempt_(const CService &addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Select an address to connect to, if newOnly is set to true, only the new table is selected from.
- CAddrInfo Select_(bool newOnly);
+ CAddrInfo Select_(bool newOnly) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
- void ResolveCollisions_();
+ void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Return a random to-be-evicted tried table address.
- CAddrInfo SelectTriedCollision_();
+ CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Wraps GetRandInt to allow tests to override RandomInt and make it determinismistic.
virtual int RandomInt(int nMax);
#ifdef DEBUG_ADDRMAN
//! Perform consistency check. Returns an error code or zero.
- int Check_();
+ int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs);
#endif
//! Select several addresses at once.
- void GetAddr_(std::vector<CAddress> &vAddr);
+ void GetAddr_(std::vector<CAddress> &vAddr) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Mark an entry as currently-connected-to.
- void Connected_(const CService &addr, int64_t nTime);
+ void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Update an entry's service bits.
- void SetServices_(const CService &addr, ServiceFlags nServices);
+ void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
public:
/**
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index 13fa176f8b..aa66d13102 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -6,7 +6,7 @@
#include <arith_uint256.h>
#include <uint256.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <crypto/common.h>
#include <stdio.h>
@@ -176,7 +176,7 @@ unsigned int base_uint<BITS>::bits() const
for (int pos = WIDTH - 1; pos >= 0; pos--) {
if (pn[pos]) {
for (int nbits = 31; nbits > 0; nbits--) {
- if (pn[pos] & 1 << nbits)
+ if (pn[pos] & 1U << nbits)
return 32 * pos + nbits + 1;
}
return 32 * pos + 1;
diff --git a/src/base58.cpp b/src/base58.cpp
index 7020c24055..e3d2853399 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -6,6 +6,7 @@
#include <hash.h>
#include <uint256.h>
+#include <util/strencodings.h>
#include <assert.h>
#include <string.h>
@@ -34,7 +35,7 @@ static const int8_t mapBase58[256] = {
bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
{
// Skip leading spaces.
- while (*psz && isspace(*psz))
+ while (*psz && IsSpace(*psz))
psz++;
// Skip and count leading '1's.
int zeroes = 0;
@@ -48,7 +49,7 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
std::vector<unsigned char> b256(size);
// Process the characters.
static_assert(sizeof(mapBase58)/sizeof(mapBase58[0]) == 256, "mapBase58.size() should be 256"); // guarantee not out of range
- while (*psz && !isspace(*psz)) {
+ while (*psz && !IsSpace(*psz)) {
// Decode base58 character
int carry = mapBase58[(uint8_t)*psz];
if (carry == -1) // Invalid b58 character
@@ -64,7 +65,7 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
psz++;
}
// Skip trailing spaces.
- while (isspace(*psz))
+ while (IsSpace(*psz))
psz++;
if (*psz != 0)
return false;
diff --git a/src/bench/bech32.cpp b/src/bench/bech32.cpp
index 8b80e17391..3c4b453a23 100644
--- a/src/bench/bech32.cpp
+++ b/src/bench/bech32.cpp
@@ -6,7 +6,7 @@
#include <validation.h>
#include <bech32.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <vector>
#include <string>
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 4fa516cb81..32faba86b4 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -7,8 +7,8 @@
#include <crypto/sha256.h>
#include <key.h>
#include <random.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <validation.h>
#include <memory>
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index bc99b8cdcd..2def0b23e2 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -7,13 +7,14 @@
#include <coins.h>
#include <consensus/merkle.h>
#include <consensus/validation.h>
+#include <crypto/sha256.h>
#include <miner.h>
#include <policy/policy.h>
#include <pow.h>
#include <scheduler.h>
#include <txdb.h>
#include <txmempool.h>
-#include <utiltime.h>
+#include <util/time.h>
#include <validation.h>
#include <validationinterface.h>
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index 6f03581c4b..e325333c01 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -20,7 +20,7 @@ namespace block_bench {
static void DeserializeBlockTest(benchmark::State& state)
{
CDataStream stream((const char*)block_bench::block413567,
- (const char*)&block_bench::block413567[sizeof(block_bench::block413567)],
+ (const char*)block_bench::block413567 + sizeof(block_bench::block413567),
SER_NETWORK, PROTOCOL_VERSION);
char a = '\0';
stream.write(&a, 1); // Prevent compaction
@@ -36,7 +36,7 @@ static void DeserializeBlockTest(benchmark::State& state)
static void DeserializeAndCheckBlockTest(benchmark::State& state)
{
CDataStream stream((const char*)block_bench::block413567,
- (const char*)&block_bench::block413567[sizeof(block_bench::block413567)],
+ (const char*)block_bench::block413567 + sizeof(block_bench::block413567),
SER_NETWORK, PROTOCOL_VERSION);
char a = '\0';
stream.write(&a, 1); // Prevent compaction
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index 79689f6e0b..6ab542067a 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
-#include <util.h>
+#include <util/system.h>
#include <validation.h>
#include <checkqueue.h>
#include <prevector.h>
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 27c23d6834..8552ed34fd 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
+#include <interfaces/chain.h>
#include <wallet/wallet.h>
#include <wallet/coinselection.h>
@@ -33,7 +34,8 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<Ou
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
static void CoinSelection(benchmark::State& state)
{
- const CWallet wallet("dummy", WalletDatabase::CreateDummy());
+ auto chain = interfaces::MakeChain();
+ const CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
LOCK(wallet.cs_wallet);
// Add coins.
@@ -57,7 +59,8 @@ static void CoinSelection(benchmark::State& state)
}
typedef std::set<CInputCoin> CoinSet;
-static const CWallet testWallet("dummy", WalletDatabase::CreateDummy());
+static auto testChain = interfaces::MakeChain();
+static const CWallet testWallet(*testChain, WalletLocation(), WalletDatabase::CreateDummy());
std::vector<std::unique_ptr<CWalletTx>> wtxn;
// Copied from src/wallet/test/coinselector_tests.cpp
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index 5b0cf27e04..dc0b054420 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -9,11 +9,12 @@
#include <hash.h>
#include <random.h>
#include <uint256.h>
-#include <utiltime.h>
+#include <util/time.h>
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
#include <crypto/sha512.h>
+#include <crypto/siphash.h>
/* Number of bytes to hash per iteration */
static const uint64_t BUFFER_SIZE = 1000*1000;
diff --git a/src/bench/examples.cpp b/src/bench/examples.cpp
index 6d95e05ef6..e7ddd5a938 100644
--- a/src/bench/examples.cpp
+++ b/src/bench/examples.cpp
@@ -4,7 +4,7 @@
#include <bench/bench.h>
#include <validation.h>
-#include <utiltime.h>
+#include <util/time.h>
// Sanity test: this should loop ten times, and
// min/max/average should be close to 100ms.
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 09507fd249..dc1b46faf1 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -12,11 +12,12 @@
#include <fs.h>
#include <rpc/client.h>
#include <rpc/protocol.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <memory>
#include <stdio.h>
+#include <tuple>
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>
@@ -511,6 +512,10 @@ static int CommandLineRPC(int argc, char *argv[])
int main(int argc, char* argv[])
{
+#ifdef WIN32
+ util::WinCmdLineArgs winArgs;
+ std::tie(argc, argv) = winArgs.get();
+#endif
SetupEnvironment();
if (!SetupNetworking()) {
fprintf(stderr, "Error: Initializing networking failed\n");
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index a3fcb87675..bc91ca3641 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -18,9 +18,9 @@
#include <script/script.h>
#include <script/sign.h>
#include <univalue.h>
-#include <util.h>
-#include <utilmoneystr.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/moneystr.h>
+#include <util/strencodings.h>
#include <memory>
#include <stdio.h>
@@ -255,7 +255,7 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
throw std::runtime_error("invalid TX input vout '" + strVout + "'");
// extract the optional sequence number
- uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max();
+ uint32_t nSequenceIn = CTxIn::SEQUENCE_FINAL;
if (vStrInputParts.size() > 2)
nSequenceIn = std::stoul(vStrInputParts[2]);
@@ -356,7 +356,7 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
if (vStrInputParts.size() < numkeys + 3)
throw std::runtime_error("incorrect number of multisig pubkeys");
- if (required < 1 || required > 20 || numkeys < 1 || numkeys > 20 || numkeys < required)
+ if (required < 1 || required > MAX_PUBKEYS_PER_MULTISIG || numkeys < 1 || numkeys > MAX_PUBKEYS_PER_MULTISIG || numkeys < required)
throw std::runtime_error("multisig parameter mismatch. Required " \
+ std::to_string(required) + " of " + std::to_string(numkeys) + "signatures.");
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index bf04d95b50..1306ba3821 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -11,14 +11,15 @@
#include <clientversion.h>
#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.h>
+#include <util/system.h>
#include <httpserver.h>
#include <httprpc.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <walletinitinterface.h>
#include <stdio.h>
@@ -58,6 +59,9 @@ static void WaitForShutdown()
//
static bool AppInit(int argc, char* argv[])
{
+ InitInterfaces interfaces;
+ interfaces.chain = interfaces::MakeChain();
+
bool fRet = false;
//
@@ -164,7 +168,7 @@ static bool AppInit(int argc, char* argv[])
// If locking the data directory failed, exit immediately
return false;
}
- fRet = AppInitMain();
+ fRet = AppInitMain(interfaces);
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInit()");
@@ -178,13 +182,17 @@ static bool AppInit(int argc, char* argv[])
} else {
WaitForShutdown();
}
- Shutdown();
+ Shutdown(interfaces);
return fRet;
}
int main(int argc, char* argv[])
{
+#ifdef WIN32
+ util::WinCmdLineArgs winArgs;
+ std::tie(argc, argv) = winArgs.get();
+#endif
SetupEnvironment();
// Connect bitcoind signal handlers
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 4c57965bec..10f51931f0 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -6,12 +6,13 @@
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <chainparams.h>
-#include <hash.h>
+#include <crypto/sha256.h>
+#include <crypto/siphash.h>
#include <random.h>
#include <streams.h>
#include <txmempool.h>
#include <validation.h>
-#include <util.h>
+#include <util/system.h>
#include <unordered_map>
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index 91623fe70a..163e2a52ef 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <blockfilter.h>
+#include <crypto/siphash.h>
#include <hash.h>
#include <primitives/transaction.h>
#include <script/script.h>
diff --git a/src/blockfilter.h b/src/blockfilter.h
index 46833ac0be..871be11769 100644
--- a/src/blockfilter.h
+++ b/src/blockfilter.h
@@ -5,14 +5,15 @@
#ifndef BITCOIN_BLOCKFILTER_H
#define BITCOIN_BLOCKFILTER_H
-#include <set>
#include <stdint.h>
+#include <unordered_set>
#include <vector>
#include <primitives/block.h>
#include <serialize.h>
#include <uint256.h>
#include <undo.h>
+#include <util/bytevectorhash.h>
/**
* This implements a Golomb-coded set as defined in BIP 158. It is a
@@ -22,7 +23,7 @@ class GCSFilter
{
public:
typedef std::vector<unsigned char> Element;
- typedef std::set<Element> ElementSet;
+ typedef std::unordered_set<Element, ByteVectorHash> ElementSet;
private:
uint64_t m_siphash_k0;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 0574e2395e..4ce1b53880 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -8,8 +8,8 @@
#include <chainparamsseeds.h>
#include <consensus/merkle.h>
#include <tinyformat.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <versionbitsinfo.h>
#include <assert.h>
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 870640e77d..f0559a319a 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -6,8 +6,8 @@
#include <chainparamsbase.h>
#include <tinyformat.h>
-#include <util.h>
-#include <utilmemory.h>
+#include <util/system.h>
+#include <util/memory.h>
#include <assert.h>
diff --git a/src/coins.cpp b/src/coins.cpp
index f125b483bb..3ef9e0463c 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -6,6 +6,7 @@
#include <consensus/consensus.h>
#include <random.h>
+#include <version.h>
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
diff --git a/src/coins.h b/src/coins.h
index 3867a37b39..94493453f0 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -9,7 +9,7 @@
#include <primitives/transaction.h>
#include <compressor.h>
#include <core_memusage.h>
-#include <hash.h>
+#include <crypto/siphash.h>
#include <memusage.h>
#include <serialize.h>
#include <uint256.h>
diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp
index 2a87a936b1..b47d9774ca 100644
--- a/src/consensus/merkle.cpp
+++ b/src/consensus/merkle.cpp
@@ -4,7 +4,7 @@
#include <consensus/merkle.h>
#include <hash.h>
-#include <utilstrencodings.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/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
index 0628ec1d47..b17a8bb31d 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -12,7 +12,7 @@
// TODO remove the following dependencies
#include <chain.h>
#include <coins.h>
-#include <utilmoneystr.h>
+#include <util/moneystr.h>
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
{
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 301f99bc1c..3b82b2853c 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -11,8 +11,8 @@
#include <serialize.h>
#include <streams.h>
#include <univalue.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <version.h>
#include <boost/algorithm/string/classification.hpp>
diff --git a/src/core_write.cpp b/src/core_write.cpp
index b86490716f..765a170307 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -12,9 +12,9 @@
#include <serialize.h>
#include <streams.h>
#include <univalue.h>
-#include <util.h>
-#include <utilmoneystr.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/moneystr.h>
+#include <util/strencodings.h>
UniValue ValueFromAmount(const CAmount& amount)
{
diff --git a/src/crypto/siphash.cpp b/src/crypto/siphash.cpp
new file mode 100644
index 0000000000..e81957111a
--- /dev/null
+++ b/src/crypto/siphash.cpp
@@ -0,0 +1,173 @@
+// Copyright (c) 2016-2018 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 <crypto/siphash.h>
+
+#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
+
+#define SIPROUND do { \
+ v0 += v1; v1 = ROTL(v1, 13); v1 ^= v0; \
+ v0 = ROTL(v0, 32); \
+ v2 += v3; v3 = ROTL(v3, 16); v3 ^= v2; \
+ v0 += v3; v3 = ROTL(v3, 21); v3 ^= v0; \
+ v2 += v1; v1 = ROTL(v1, 17); v1 ^= v2; \
+ v2 = ROTL(v2, 32); \
+} while (0)
+
+CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
+{
+ v[0] = 0x736f6d6570736575ULL ^ k0;
+ v[1] = 0x646f72616e646f6dULL ^ k1;
+ v[2] = 0x6c7967656e657261ULL ^ k0;
+ v[3] = 0x7465646279746573ULL ^ k1;
+ count = 0;
+ tmp = 0;
+}
+
+CSipHasher& CSipHasher::Write(uint64_t data)
+{
+ uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
+
+ assert(count % 8 == 0);
+
+ v3 ^= data;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= data;
+
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ v[3] = v3;
+
+ count += 8;
+ return *this;
+}
+
+CSipHasher& CSipHasher::Write(const unsigned char* data, size_t size)
+{
+ uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
+ uint64_t t = tmp;
+ int c = count;
+
+ while (size--) {
+ t |= ((uint64_t)(*(data++))) << (8 * (c % 8));
+ c++;
+ if ((c & 7) == 0) {
+ v3 ^= t;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= t;
+ t = 0;
+ }
+ }
+
+ v[0] = v0;
+ v[1] = v1;
+ v[2] = v2;
+ v[3] = v3;
+ count = c;
+ tmp = t;
+
+ return *this;
+}
+
+uint64_t CSipHasher::Finalize() const
+{
+ uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
+
+ uint64_t t = tmp | (((uint64_t)count) << 56);
+
+ v3 ^= t;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= t;
+ v2 ^= 0xFF;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ return v0 ^ v1 ^ v2 ^ v3;
+}
+
+uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
+{
+ /* Specialized implementation for efficiency */
+ uint64_t d = val.GetUint64(0);
+
+ uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
+ uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
+ uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
+ uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
+
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(1);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(2);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(3);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ v3 ^= ((uint64_t)4) << 59;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= ((uint64_t)4) << 59;
+ v2 ^= 0xFF;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ return v0 ^ v1 ^ v2 ^ v3;
+}
+
+uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
+{
+ /* Specialized implementation for efficiency */
+ uint64_t d = val.GetUint64(0);
+
+ uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
+ uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
+ uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
+ uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
+
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(1);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(2);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = val.GetUint64(3);
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ d = (((uint64_t)36) << 56) | extra;
+ v3 ^= d;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= d;
+ v2 ^= 0xFF;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ return v0 ^ v1 ^ v2 ^ v3;
+}
diff --git a/src/crypto/siphash.h b/src/crypto/siphash.h
new file mode 100644
index 0000000000..b312f913f9
--- /dev/null
+++ b/src/crypto/siphash.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2016-2018 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_CRYPTO_SIPHASH_H
+#define BITCOIN_CRYPTO_SIPHASH_H
+
+#include <stdint.h>
+
+#include <uint256.h>
+
+/** SipHash-2-4 */
+class CSipHasher
+{
+private:
+ uint64_t v[4];
+ uint64_t tmp;
+ int count;
+
+public:
+ /** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */
+ CSipHasher(uint64_t k0, uint64_t k1);
+ /** Hash a 64-bit integer worth of data
+ * It is treated as if this was the little-endian interpretation of 8 bytes.
+ * This function can only be used when a multiple of 8 bytes have been written so far.
+ */
+ CSipHasher& Write(uint64_t data);
+ /** Hash arbitrary bytes. */
+ CSipHasher& Write(const unsigned char* data, size_t size);
+ /** Compute the 64-bit SipHash-2-4 of the data written so far. The object remains untouched. */
+ uint64_t Finalize() const;
+};
+
+/** Optimized SipHash-2-4 implementation for uint256.
+ *
+ * It is identical to:
+ * SipHasher(k0, k1)
+ * .Write(val.GetUint64(0))
+ * .Write(val.GetUint64(1))
+ * .Write(val.GetUint64(2))
+ * .Write(val.GetUint64(3))
+ * .Finalize()
+ */
+uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
+uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra);
+
+#endif // BITCOIN_CRYPTO_SIPHASH_H
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index 52f9efe17c..416f5e8399 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -9,8 +9,8 @@
#include <fs.h>
#include <serialize.h>
#include <streams.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <version.h>
#include <leveldb/db.h>
diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp
index 3714187a96..9211a7596b 100644
--- a/src/dummywallet.cpp
+++ b/src/dummywallet.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <stdio.h>
-#include <util.h>
+#include <util/system.h>
#include <walletinitinterface.h>
class CWallet;
@@ -14,13 +14,7 @@ public:
bool HasWalletSupport() const override {return false;}
void AddWalletOptions() const override;
bool ParameterInteraction() const override {return true;}
- void RegisterRPC(CRPCTable &) const override {}
- bool Verify() const override {return true;}
- bool Open() const override {LogPrintf("No wallet support compiled in!\n"); return true;}
- void Start(CScheduler& scheduler) const override {}
- void Flush() const override {}
- void Stop() const override {}
- void Close() const override {}
+ void Construct(InitInterfaces& interfaces) const override {LogPrintf("No wallet support compiled in!\n");}
};
void DummyWalletInit::AddWalletOptions() const
@@ -34,6 +28,16 @@ void DummyWalletInit::AddWalletOptions() const
const WalletInitInterface& g_wallet_init_interface = DummyWalletInit();
+fs::path GetWalletDir()
+{
+ throw std::logic_error("Wallet function called in non-wallet build.");
+}
+
+std::vector<fs::path> ListWalletDir()
+{
+ throw std::logic_error("Wallet function called in non-wallet build.");
+}
+
std::vector<std::shared_ptr<CWallet>> GetWallets()
{
throw std::logic_error("Wallet function called in non-wallet build.");
diff --git a/src/fs.cpp b/src/fs.cpp
index df79b5e3df..3c8f4c0247 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -3,6 +3,7 @@
#ifndef WIN32
#include <fcntl.h>
#else
+#define NOMINMAX
#include <codecvt>
#include <windows.h>
#endif
@@ -89,7 +90,7 @@ bool FileLock::TryLock()
return false;
}
_OVERLAPPED overlapped = {0};
- if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, 0, 0, &overlapped)) {
+ if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, std::numeric_limits<DWORD>::max(), std::numeric_limits<DWORD>::max(), &overlapped)) {
reason = GetErrorReason();
return false;
}
@@ -113,4 +114,106 @@ std::string get_filesystem_error_message(const fs::filesystem_error& e)
#endif
}
+#ifdef WIN32
+#ifdef __GLIBCXX__
+
+// reference: https://github.com/gcc-mirror/gcc/blob/gcc-7_3_0-release/libstdc%2B%2B-v3/include/std/fstream#L270
+
+static std::string openmodeToStr(std::ios_base::openmode mode)
+{
+ switch (mode & ~std::ios_base::ate) {
+ case std::ios_base::out:
+ case std::ios_base::out | std::ios_base::trunc:
+ return "w";
+ case std::ios_base::out | std::ios_base::app:
+ case std::ios_base::app:
+ return "a";
+ case std::ios_base::in:
+ return "r";
+ case std::ios_base::in | std::ios_base::out:
+ return "r+";
+ case std::ios_base::in | std::ios_base::out | std::ios_base::trunc:
+ return "w+";
+ case std::ios_base::in | std::ios_base::out | std::ios_base::app:
+ case std::ios_base::in | std::ios_base::app:
+ return "a+";
+ case std::ios_base::out | std::ios_base::binary:
+ case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary:
+ return "wb";
+ case std::ios_base::out | std::ios_base::app | std::ios_base::binary:
+ case std::ios_base::app | std::ios_base::binary:
+ return "ab";
+ case std::ios_base::in | std::ios_base::binary:
+ return "rb";
+ case std::ios_base::in | std::ios_base::out | std::ios_base::binary:
+ return "r+b";
+ case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary:
+ return "w+b";
+ case std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary:
+ case std::ios_base::in | std::ios_base::app | std::ios_base::binary:
+ return "a+b";
+ default:
+ return std::string();
+ }
+}
+
+void ifstream::open(const fs::path& p, std::ios_base::openmode mode)
+{
+ close();
+ m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
+ if (m_file == nullptr) {
+ return;
+ }
+ m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode);
+ rdbuf(&m_filebuf);
+ if (mode & std::ios_base::ate) {
+ seekg(0, std::ios_base::end);
+ }
+}
+
+void ifstream::close()
+{
+ if (m_file != nullptr) {
+ m_filebuf.close();
+ fclose(m_file);
+ }
+ m_file = nullptr;
+}
+
+void ofstream::open(const fs::path& p, std::ios_base::openmode mode)
+{
+ close();
+ m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str());
+ if (m_file == nullptr) {
+ return;
+ }
+ m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode);
+ rdbuf(&m_filebuf);
+ if (mode & std::ios_base::ate) {
+ seekp(0, std::ios_base::end);
+ }
+}
+
+void ofstream::close()
+{
+ if (m_file != nullptr) {
+ m_filebuf.close();
+ fclose(m_file);
+ }
+ m_file = nullptr;
+}
+#else // __GLIBCXX__
+
+static_assert(sizeof(*fs::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t),
+ "Warning: This build is using boost::filesystem ofstream and ifstream "
+ "implementations which will fail to open paths containing multibyte "
+ "characters. You should delete this static_assert to ignore this warning, "
+ "or switch to a different C++ standard library like the Microsoft C++ "
+ "Standard Library (where boost uses non-standard extensions to construct "
+ "stream objects with wide filenames), or the GNU libstdc++ library (where "
+ "a more complicated workaround has been implemented above).");
+
+#endif // __GLIBCXX__
+#endif // WIN32
+
} // fsbridge
diff --git a/src/fs.h b/src/fs.h
index a7074f446a..bdccb15232 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -7,6 +7,9 @@
#include <stdio.h>
#include <string>
+#if defined WIN32 && defined __GLIBCXX__
+#include <ext/stdio_filebuf.h>
+#endif
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -39,6 +42,54 @@ namespace fsbridge {
};
std::string get_filesystem_error_message(const fs::filesystem_error& e);
+
+ // GNU libstdc++ specific workaround for opening UTF-8 paths on Windows.
+ //
+ // On Windows, it is only possible to reliably access multibyte file paths through
+ // `wchar_t` APIs, not `char` APIs. But because the C++ standard doesn't
+ // require ifstream/ofstream `wchar_t` constructors, and the GNU library doesn't
+ // provide them (in contrast to the Microsoft C++ library, see
+ // https://stackoverflow.com/questions/821873/how-to-open-an-stdfstream-ofstream-or-ifstream-with-a-unicode-filename/822032#822032),
+ // Boost is forced to fall back to `char` constructors which may not work properly.
+ //
+ // Work around this issue by creating stream objects with `_wfopen` in
+ // combination with `__gnu_cxx::stdio_filebuf`. This workaround can be removed
+ // with an upgrade to C++17, where streams can be constructed directly from
+ // `std::filesystem::path` objects.
+
+#if defined WIN32 && defined __GLIBCXX__
+ class ifstream : public std::istream
+ {
+ public:
+ ifstream() = default;
+ explicit ifstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in) { open(p, mode); }
+ ~ifstream() { close(); }
+ void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in);
+ bool is_open() { return m_filebuf.is_open(); }
+ void close();
+
+ private:
+ __gnu_cxx::stdio_filebuf<char> m_filebuf;
+ FILE* m_file = nullptr;
+ };
+ class ofstream : public std::ostream
+ {
+ public:
+ ofstream() = default;
+ explicit ofstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out) { open(p, mode); }
+ ~ofstream() { close(); }
+ void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out);
+ bool is_open() { return m_filebuf.is_open(); }
+ void close();
+
+ private:
+ __gnu_cxx::stdio_filebuf<char> m_filebuf;
+ FILE* m_file = nullptr;
+ };
+#else // !(WIN32 && __GLIBCXX__)
+ typedef fs::ifstream ifstream;
+ typedef fs::ofstream ofstream;
+#endif // WIN32 && __GLIBCXX__
};
#endif // BITCOIN_FS_H
diff --git a/src/hash.cpp b/src/hash.cpp
index c049eea716..26150e5ca8 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -77,171 +77,3 @@ void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char he
num[3] = (nChild >> 0) & 0xFF;
CHMAC_SHA512(chainCode.begin(), chainCode.size()).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output);
}
-
-#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
-
-#define SIPROUND do { \
- v0 += v1; v1 = ROTL(v1, 13); v1 ^= v0; \
- v0 = ROTL(v0, 32); \
- v2 += v3; v3 = ROTL(v3, 16); v3 ^= v2; \
- v0 += v3; v3 = ROTL(v3, 21); v3 ^= v0; \
- v2 += v1; v1 = ROTL(v1, 17); v1 ^= v2; \
- v2 = ROTL(v2, 32); \
-} while (0)
-
-CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
-{
- v[0] = 0x736f6d6570736575ULL ^ k0;
- v[1] = 0x646f72616e646f6dULL ^ k1;
- v[2] = 0x6c7967656e657261ULL ^ k0;
- v[3] = 0x7465646279746573ULL ^ k1;
- count = 0;
- tmp = 0;
-}
-
-CSipHasher& CSipHasher::Write(uint64_t data)
-{
- uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
-
- assert(count % 8 == 0);
-
- v3 ^= data;
- SIPROUND;
- SIPROUND;
- v0 ^= data;
-
- v[0] = v0;
- v[1] = v1;
- v[2] = v2;
- v[3] = v3;
-
- count += 8;
- return *this;
-}
-
-CSipHasher& CSipHasher::Write(const unsigned char* data, size_t size)
-{
- uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
- uint64_t t = tmp;
- int c = count;
-
- while (size--) {
- t |= ((uint64_t)(*(data++))) << (8 * (c % 8));
- c++;
- if ((c & 7) == 0) {
- v3 ^= t;
- SIPROUND;
- SIPROUND;
- v0 ^= t;
- t = 0;
- }
- }
-
- v[0] = v0;
- v[1] = v1;
- v[2] = v2;
- v[3] = v3;
- count = c;
- tmp = t;
-
- return *this;
-}
-
-uint64_t CSipHasher::Finalize() const
-{
- uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
-
- uint64_t t = tmp | (((uint64_t)count) << 56);
-
- v3 ^= t;
- SIPROUND;
- SIPROUND;
- v0 ^= t;
- v2 ^= 0xFF;
- SIPROUND;
- SIPROUND;
- SIPROUND;
- SIPROUND;
- return v0 ^ v1 ^ v2 ^ v3;
-}
-
-uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
-{
- /* Specialized implementation for efficiency */
- uint64_t d = val.GetUint64(0);
-
- uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
- uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
- uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
- uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
-
- SIPROUND;
- SIPROUND;
- v0 ^= d;
- d = val.GetUint64(1);
- v3 ^= d;
- SIPROUND;
- SIPROUND;
- v0 ^= d;
- d = val.GetUint64(2);
- v3 ^= d;
- SIPROUND;
- SIPROUND;
- v0 ^= d;
- d = val.GetUint64(3);
- v3 ^= d;
- SIPROUND;
- SIPROUND;
- v0 ^= d;
- v3 ^= ((uint64_t)4) << 59;
- SIPROUND;
- SIPROUND;
- v0 ^= ((uint64_t)4) << 59;
- v2 ^= 0xFF;
- SIPROUND;
- SIPROUND;
- SIPROUND;
- SIPROUND;
- return v0 ^ v1 ^ v2 ^ v3;
-}
-
-uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
-{
- /* Specialized implementation for efficiency */
- uint64_t d = val.GetUint64(0);
-
- uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
- uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
- uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
- uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
-
- SIPROUND;
- SIPROUND;
- v0 ^= d;
- d = val.GetUint64(1);
- v3 ^= d;
- SIPROUND;
- SIPROUND;
- v0 ^= d;
- d = val.GetUint64(2);
- v3 ^= d;
- SIPROUND;
- SIPROUND;
- v0 ^= d;
- d = val.GetUint64(3);
- v3 ^= d;
- SIPROUND;
- SIPROUND;
- v0 ^= d;
- d = (((uint64_t)36) << 56) | extra;
- v3 ^= d;
- SIPROUND;
- SIPROUND;
- v0 ^= d;
- v2 ^= 0xFF;
- SIPROUND;
- SIPROUND;
- SIPROUND;
- SIPROUND;
- return v0 ^ v1 ^ v2 ^ v3;
-}
diff --git a/src/hash.h b/src/hash.h
index 3534a400b3..6acab0b161 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -194,39 +194,4 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
-/** SipHash-2-4 */
-class CSipHasher
-{
-private:
- uint64_t v[4];
- uint64_t tmp;
- int count;
-
-public:
- /** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */
- CSipHasher(uint64_t k0, uint64_t k1);
- /** Hash a 64-bit integer worth of data
- * It is treated as if this was the little-endian interpretation of 8 bytes.
- * This function can only be used when a multiple of 8 bytes have been written so far.
- */
- CSipHasher& Write(uint64_t data);
- /** Hash arbitrary bytes. */
- CSipHasher& Write(const unsigned char* data, size_t size);
- /** Compute the 64-bit SipHash-2-4 of the data written so far. The object remains untouched. */
- uint64_t Finalize() const;
-};
-
-/** Optimized SipHash-2-4 implementation for uint256.
- *
- * It is identical to:
- * SipHasher(k0, k1)
- * .Write(val.GetUint64(0))
- * .Write(val.GetUint64(1))
- * .Write(val.GetUint64(2))
- * .Write(val.GetUint64(3))
- * .Finalize()
- */
-uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
-uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra);
-
#endif // BITCOIN_HASH_H
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 4064251c71..fcf760a4c6 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -11,8 +11,8 @@
#include <rpc/server.h>
#include <random.h>
#include <sync.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <ui_interface.h>
#include <walletinitinterface.h>
#include <crypto/hmac_sha256.h>
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index c29f7a4375..91ebc4680c 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -6,8 +6,8 @@
#include <chainparamsbase.h>
#include <compat.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <netbase.h>
#include <rpc/protocol.h> // For HTTP status codes
#include <sync.h>
@@ -224,21 +224,25 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
}
std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
- LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
- RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());
-
// Early address-based allow check
if (!ClientAllowed(hreq->GetPeer())) {
+ LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Client network is not allowed RPC access\n",
+ hreq->GetPeer().ToString());
hreq->WriteReply(HTTP_FORBIDDEN);
return;
}
// Early reject unknown HTTP methods
if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
+ LogPrint(BCLog::HTTP, "HTTP request from %s rejected: Unknown HTTP request method\n",
+ hreq->GetPeer().ToString());
hreq->WriteReply(HTTP_BADMETHOD);
return;
}
+ LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
+ RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToString());
+
// Find registered handler for prefix
std::string strURI = hreq->GetURI();
std::string path;
@@ -292,26 +296,26 @@ static bool ThreadHTTP(struct event_base* base)
/** Bind HTTP server to specified addresses */
static bool HTTPBindAddresses(struct evhttp* http)
{
- int defaultPort = gArgs.GetArg("-rpcport", BaseParams().RPCPort());
+ int http_port = gArgs.GetArg("-rpcport", BaseParams().RPCPort());
std::vector<std::pair<std::string, uint16_t> > endpoints;
// Determine what addresses to bind to
if (!gArgs.IsArgSet("-rpcallowip")) { // Default to loopback if not allowing external IPs
- endpoints.push_back(std::make_pair("::1", defaultPort));
- endpoints.push_back(std::make_pair("127.0.0.1", defaultPort));
+ endpoints.push_back(std::make_pair("::1", http_port));
+ endpoints.push_back(std::make_pair("127.0.0.1", http_port));
if (gArgs.IsArgSet("-rpcbind")) {
LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
}
} else if (gArgs.IsArgSet("-rpcbind")) { // Specific bind address
for (const std::string& strRPCBind : gArgs.GetArgs("-rpcbind")) {
- int port = defaultPort;
+ int port = http_port;
std::string host;
SplitHostPort(strRPCBind, port, host);
endpoints.push_back(std::make_pair(host, port));
}
} else { // No specific bind address specified, bind to any
- endpoints.push_back(std::make_pair("::", defaultPort));
- endpoints.push_back(std::make_pair("0.0.0.0", defaultPort));
+ endpoints.push_back(std::make_pair("::", http_port));
+ endpoints.push_back(std::make_pair("0.0.0.0", http_port));
}
// Bind addresses
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 788f7adccd..4d4a7e1502 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -7,7 +7,7 @@
#include <shutdown.h>
#include <tinyformat.h>
#include <ui_interface.h>
-#include <util.h>
+#include <util/system.h>
#include <validation.h>
#include <warnings.h>
@@ -65,7 +65,7 @@ bool BaseIndex::Init()
return true;
}
-static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev)
+static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index f606c8993c..ba1c44765f 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -5,7 +5,7 @@
#include <index/txindex.h>
#include <shutdown.h>
#include <ui_interface.h>
-#include <util.h>
+#include <util/system.h>
#include <validation.h>
#include <boost/thread.hpp>
diff --git a/src/init.cpp b/src/init.cpp
index f9efaf7dc1..3ab97be329 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -19,6 +19,7 @@
#include <fs.h>
#include <httpserver.h>
#include <httprpc.h>
+#include <interfaces/chain.h>
#include <index/txindex.h>
#include <key.h>
#include <validation.h>
@@ -32,6 +33,7 @@
#include <rpc/server.h>
#include <rpc/register.h>
#include <rpc/blockchain.h>
+#include <rpc/util.h>
#include <script/standard.h>
#include <script/sigcache.h>
#include <scheduler.h>
@@ -41,8 +43,8 @@
#include <txmempool.h>
#include <torcontrol.h>
#include <ui_interface.h>
-#include <util.h>
-#include <utilmoneystr.h>
+#include <util/system.h>
+#include <util/moneystr.h>
#include <validationinterface.h>
#include <warnings.h>
#include <walletinitinterface.h>
@@ -62,6 +64,7 @@
#include <openssl/crypto.h>
#if ENABLE_ZMQ
+#include <zmq/zmqabstractnotifier.h>
#include <zmq/zmqnotificationinterface.h>
#include <zmq/zmqrpc.h>
#endif
@@ -156,7 +159,7 @@ void Interrupt()
}
}
-void Shutdown()
+void Shutdown(InitInterfaces& interfaces)
{
LogPrintf("%s: In progress...\n", __func__);
static CCriticalSection cs_Shutdown;
@@ -175,7 +178,9 @@ void Shutdown()
StopREST();
StopRPC();
StopHTTPServer();
- g_wallet_init_interface.Flush();
+ for (const auto& client : interfaces.chain_clients) {
+ client->flush();
+ }
StopMapPort();
// Because these depend on each-other, we make sure that neither can be
@@ -238,7 +243,9 @@ void Shutdown()
pcoinsdbview.reset();
pblocktree.reset();
}
- g_wallet_init_interface.Stop();
+ for (const auto& client : interfaces.chain_clients) {
+ client->stop();
+ }
#if ENABLE_ZMQ
if (g_zmq_notification_interface) {
@@ -258,7 +265,7 @@ void Shutdown()
UnregisterAllValidationInterfaces();
GetMainSignals().UnregisterBackgroundSignalScheduler();
GetMainSignals().UnregisterWithMempoolSignals(mempool);
- g_wallet_init_interface.Close();
+ interfaces.chain_clients.clear();
globalVerifyHandle.reset();
ECC_Stop();
LogPrintf("%s: done\n", __func__);
@@ -418,11 +425,19 @@ void SetupServerArgs()
gArgs.AddArg("-zmqpubhashtx=<address>", "Enable publish hash transaction in <address>", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubrawblock=<address>", "Enable publish raw block in <address>", false, OptionsCategory::ZMQ);
gArgs.AddArg("-zmqpubrawtx=<address>", "Enable publish raw transaction in <address>", false, OptionsCategory::ZMQ);
+ gArgs.AddArg("-zmqpubhashblockhwm=<n>", strprintf("Set publish hash block outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), false, OptionsCategory::ZMQ);
+ gArgs.AddArg("-zmqpubhashtxhwm=<n>", strprintf("Set publish hash transaction outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), false, OptionsCategory::ZMQ);
+ gArgs.AddArg("-zmqpubrawblockhwm=<n>", strprintf("Set publish raw block outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), false, OptionsCategory::ZMQ);
+ gArgs.AddArg("-zmqpubrawtxhwm=<n>", strprintf("Set publish raw transaction outbound message high water mark (default: %d)", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM), false, OptionsCategory::ZMQ);
#else
hidden_args.emplace_back("-zmqpubhashblock=<address>");
hidden_args.emplace_back("-zmqpubhashtx=<address>");
hidden_args.emplace_back("-zmqpubrawblock=<address>");
hidden_args.emplace_back("-zmqpubrawtx=<address>");
+ hidden_args.emplace_back("-zmqpubhashblockhwm=<n>");
+ hidden_args.emplace_back("-zmqpubhashtxhwm=<n>");
+ hidden_args.emplace_back("-zmqpubrawblockhwm=<n>");
+ hidden_args.emplace_back("-zmqpubrawtxhwm=<n>");
#endif
gArgs.AddArg("-checkblocks=<n>", strprintf("How many blocks to check at startup (default: %u, 0 = all)", DEFAULT_CHECKBLOCKS), true, OptionsCategory::DEBUG_TEST);
@@ -1149,7 +1164,7 @@ bool AppInitLockDataDirectory()
return true;
}
-bool AppInitMain()
+bool AppInitMain(InitInterfaces& interfaces)
{
const CChainParams& chainparams = Params();
// ********************************************************* Step 4a: application initialization
@@ -1212,11 +1227,20 @@ bool AppInitMain()
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
GetMainSignals().RegisterWithMempoolSignals(mempool);
+ // Create client interfaces for wallets that are supposed to be loaded
+ // according to -wallet and -disablewallet options. This only constructs
+ // the interfaces, it doesn't load wallet data. Wallets actually get loaded
+ // when load() and start() interface methods are called below.
+ g_wallet_init_interface.Construct(interfaces);
+
/* Register RPC commands regardless of -server setting so they will be
* available in the GUI RPC console even if external calls are disabled.
*/
RegisterAllCoreRPCCommands(tableRPC);
- g_wallet_init_interface.RegisterRPC(tableRPC);
+ for (const auto& client : interfaces.chain_clients) {
+ client->registerRpcs();
+ }
+ g_rpc_interfaces = &interfaces;
#if ENABLE_ZMQ
RegisterZMQRPCCommands(tableRPC);
#endif
@@ -1234,7 +1258,11 @@ bool AppInitMain()
}
// ********************************************************* Step 5: verify wallet database integrity
- if (!g_wallet_init_interface.Verify()) return false;
+ for (const auto& client : interfaces.chain_clients) {
+ if (!client->verify()) {
+ return false;
+ }
+ }
// ********************************************************* Step 6: network initialization
// Note that we absolutely cannot open any actual connections
@@ -1553,7 +1581,11 @@ bool AppInitMain()
}
// ********************************************************* Step 9: load wallet
- if (!g_wallet_init_interface.Open()) return false;
+ for (const auto& client : interfaces.chain_clients) {
+ if (!client->load()) {
+ return false;
+ }
+ }
// ********************************************************* Step 10: data directory maintenance
@@ -1699,7 +1731,9 @@ bool AppInitMain()
SetRPCWarmupFinished();
uiInterface.InitMessage(_("Done loading"));
- g_wallet_init_interface.Start(scheduler);
+ for (const auto& client : interfaces.chain_clients) {
+ client->start(scheduler);
+ }
return true;
}
diff --git a/src/init.h b/src/init.h
index c58ba5cfd3..1c59ca069e 100644
--- a/src/init.h
+++ b/src/init.h
@@ -8,10 +8,19 @@
#include <memory>
#include <string>
-#include <util.h>
+#include <util/system.h>
-class CScheduler;
-class CWallet;
+namespace interfaces {
+class Chain;
+class ChainClient;
+} // namespace interfaces
+
+//! Pointers to interfaces used during init and destroyed on shutdown.
+struct InitInterfaces
+{
+ std::unique_ptr<interfaces::Chain> chain;
+ std::vector<std::unique_ptr<interfaces::ChainClient>> chain_clients;
+};
namespace boost
{
@@ -20,7 +29,7 @@ class thread_group;
/** Interrupt threads */
void Interrupt();
-void Shutdown();
+void Shutdown(InitInterfaces& interfaces);
//!Initialize the logging infrastructure
void InitLogging();
//!Parameter interaction: change current parameters depending on various rules
@@ -54,7 +63,7 @@ bool AppInitLockDataDirectory();
* @note This should only be done after daemonization. Call Shutdown() if this function fails.
* @pre Parameters should be parsed and config file should be read, AppInitLockDataDirectory should have been called.
*/
-bool AppInitMain();
+bool AppInitMain(InitInterfaces& interfaces);
/**
* Setup the arguments for gArgs
diff --git a/src/interfaces/README.md b/src/interfaces/README.md
index e93b91d23c..57d41df746 100644
--- a/src/interfaces/README.md
+++ b/src/interfaces/README.md
@@ -4,7 +4,7 @@ The following interfaces are defined here:
* [`Chain`](chain.h) — used by wallet to access blockchain and mempool state. Added in [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
-* [`Chain::Client`](chain.h) — used by node to start & stop `Chain` clients. Added in [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
+* [`ChainClient`](chain.h) — used by node to start & stop `Chain` clients. Added in [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
* [`Node`](node.h) — used by GUI to start & stop bitcoin node. Added in [#10244](https://github.com/bitcoin/bitcoin/pull/10244).
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
new file mode 100644
index 0000000000..2571a91031
--- /dev/null
+++ b/src/interfaces/chain.cpp
@@ -0,0 +1,44 @@
+// Copyright (c) 2018 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 <interfaces/chain.h>
+
+#include <sync.h>
+#include <util/system.h>
+#include <validation.h>
+
+#include <memory>
+#include <utility>
+
+namespace interfaces {
+namespace {
+
+class LockImpl : public Chain::Lock
+{
+};
+
+class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
+{
+ using UniqueLock::UniqueLock;
+};
+
+class ChainImpl : public Chain
+{
+public:
+ std::unique_ptr<Chain::Lock> lock(bool try_lock) override
+ {
+ auto result = MakeUnique<LockingStateImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
+ if (try_lock && result && !*result) return {};
+ // std::move necessary on some compilers due to conversion from
+ // LockingStateImpl to Lock pointer
+ return std::move(result);
+ }
+ std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); }
+};
+
+} // namespace
+
+std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
+
+} // namespace interfaces
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
new file mode 100644
index 0000000000..fe5658de4b
--- /dev/null
+++ b/src/interfaces/chain.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2018 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_INTERFACES_CHAIN_H
+#define BITCOIN_INTERFACES_CHAIN_H
+
+#include <memory>
+#include <string>
+#include <vector>
+
+class CScheduler;
+
+namespace interfaces {
+
+//! Interface for giving wallet processes access to blockchain state.
+class Chain
+{
+public:
+ virtual ~Chain() {}
+
+ //! Interface for querying locked chain state, used by legacy code that
+ //! assumes state won't change between calls. New code should avoid using
+ //! the Lock interface and instead call higher-level Chain methods
+ //! that return more information so the chain doesn't need to stay locked
+ //! between calls.
+ class Lock
+ {
+ public:
+ virtual ~Lock() {}
+ };
+
+ //! Return Lock interface. Chain is locked when this is called, and
+ //! unlocked when the returned interface is freed.
+ virtual std::unique_ptr<Lock> lock(bool try_lock = false) = 0;
+
+ //! Return Lock interface assuming chain is already locked. This
+ //! method is temporary and is only used in a few places to avoid changing
+ //! behavior while code is transitioned to use the Chain::Lock interface.
+ virtual std::unique_ptr<Lock> assumeLocked() = 0;
+};
+
+//! Interface to let node manage chain clients (wallets, or maybe tools for
+//! monitoring and analysis in the future).
+class ChainClient
+{
+public:
+ virtual ~ChainClient() {}
+
+ //! Register rpcs.
+ virtual void registerRpcs() = 0;
+
+ //! Check for errors before loading.
+ virtual bool verify() = 0;
+
+ //! Load saved state.
+ virtual bool load() = 0;
+
+ //! Start client execution and provide a scheduler.
+ virtual void start(CScheduler& scheduler) = 0;
+
+ //! Save state to disk.
+ virtual void flush() = 0;
+
+ //! Shut down client.
+ virtual void stop() = 0;
+};
+
+//! Return implementation of Chain interface.
+std::unique_ptr<Chain> MakeChain();
+
+//! Return implementation of ChainClient interface for a wallet client. This
+//! function will be undefined in builds where ENABLE_WALLET is false.
+//!
+//! Currently, wallets are the only chain clients. But in the future, other
+//! types of chain clients could be added, such as tools for monitoring,
+//! analysis, or fee estimation. These clients need to expose their own
+//! MakeXXXClient functions returning their implementations of the ChainClient
+//! interface.
+std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames);
+
+} // namespace interfaces
+
+#endif // BITCOIN_INTERFACES_CHAIN_H
diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp
index ddf9b342d8..92601fc4e9 100644
--- a/src/interfaces/handler.cpp
+++ b/src/interfaces/handler.cpp
@@ -4,7 +4,7 @@
#include <interfaces/handler.h>
-#include <utilmemory.h>
+#include <util/memory.h>
#include <boost/signals2/connection.hpp>
#include <utility>
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index d95b41657c..1919e16a66 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -9,6 +9,7 @@
#include <chain.h>
#include <chainparams.h>
#include <init.h>
+#include <interfaces/chain.h>
#include <interfaces/handler.h>
#include <interfaces/wallet.h>
#include <net.h>
@@ -25,7 +26,7 @@
#include <sync.h>
#include <txmempool.h>
#include <ui_interface.h>
-#include <util.h>
+#include <util/system.h>
#include <validation.h>
#include <warnings.h>
@@ -38,6 +39,8 @@
#include <univalue.h>
class CWallet;
+fs::path GetWalletDir();
+std::vector<fs::path> ListWalletDir();
std::vector<std::shared_ptr<CWallet>> GetWallets();
namespace interfaces {
@@ -48,6 +51,8 @@ namespace {
class NodeImpl : public Node
{
+public:
+ NodeImpl() { m_interfaces.chain = MakeChain(); }
bool parseParameters(int argc, const char* const argv[], std::string& error) override
{
return gArgs.ParseParameters(argc, argv, error);
@@ -66,11 +71,11 @@ class NodeImpl : public Node
return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() &&
AppInitLockDataDirectory();
}
- bool appInitMain() override { return AppInitMain(); }
+ bool appInitMain() override { return AppInitMain(m_interfaces); }
void appShutdown() override
{
Interrupt();
- Shutdown();
+ Shutdown(m_interfaces);
}
void startShutdown() override { StartShutdown(); }
bool shutdownRequested() override { return ShutdownRequested(); }
@@ -218,6 +223,18 @@ class NodeImpl : public Node
LOCK(::cs_main);
return ::pcoinsTip->GetCoin(output, coin);
}
+ std::string getWalletDir() override
+ {
+ return GetWalletDir().string();
+ }
+ std::vector<std::string> listWalletDir() override
+ {
+ std::vector<std::string> paths;
+ for (auto& path : ListWalletDir()) {
+ paths.push_back(path.string());
+ }
+ return paths;
+ }
std::vector<std::unique_ptr<Wallet>> getWallets() override
{
std::vector<std::unique_ptr<Wallet>> wallets;
@@ -277,6 +294,7 @@ class NodeImpl : public Node
GuessVerificationProgress(Params().TxData(), block));
}));
}
+ InitInterfaces m_interfaces;
};
} // namespace
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 8185c015a9..1f8bbbff7a 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -173,6 +173,12 @@ public:
//! Get unspent outputs associated with a transaction.
virtual bool getUnspentOutput(const COutPoint& output, Coin& coin) = 0;
+ //! Return default wallet directory.
+ virtual std::string getWalletDir() = 0;
+
+ //! Return available wallets in wallet directory.
+ virtual std::vector<std::string> listWalletDir() = 0;
+
//! Return interfaces for accessing wallets (if any).
virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 566ae37509..672a557d41 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -7,12 +7,16 @@
#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>
@@ -20,10 +24,18 @@
#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/rpcwallet.h>
#include <wallet/wallet.h>
+#include <wallet/walletutil.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
namespace interfaces {
namespace {
@@ -41,7 +53,8 @@ public:
WalletOrderForm order_form,
std::string& reject_reason) override
{
- LOCK2(cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
CValidationState state;
if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), m_key, g_connman.get(), state)) {
reject_reason = state.GetRejectReason();
@@ -56,7 +69,7 @@ public:
};
//! Construct wallet tx struct.
-static WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, const CWalletTx& wtx)
{
WalletTx result;
result.tx = wtx.tx;
@@ -74,7 +87,7 @@ static WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) EXCLUSIVE_LO
IsMine(wallet, result.txout_address.back()) :
ISMINE_NO);
}
- result.credit = wtx.GetCredit(ISMINE_ALL);
+ result.credit = wtx.GetCredit(locked_chain, ISMINE_ALL);
result.debit = wtx.GetDebit(ISMINE_ALL);
result.change = wtx.GetChange();
result.time = wtx.GetTxTime();
@@ -84,32 +97,38 @@ static WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) EXCLUSIVE_LO
}
//! Construct wallet tx status struct.
-static WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx)
{
+ LockAnnotation lock(::cs_main); // Temporary, for CheckFinalTx below. Removed in upcoming commit.
+
WalletTxStatus result;
auto mi = ::mapBlockIndex.find(wtx.hashBlock);
CBlockIndex* block = mi != ::mapBlockIndex.end() ? mi->second : nullptr;
result.block_height = (block ? block->nHeight : std::numeric_limits<int>::max());
- result.blocks_to_maturity = wtx.GetBlocksToMaturity();
- result.depth_in_main_chain = wtx.GetDepthInMainChain();
+ result.blocks_to_maturity = wtx.GetBlocksToMaturity(locked_chain);
+ result.depth_in_main_chain = wtx.GetDepthInMainChain(locked_chain);
result.time_received = wtx.nTimeReceived;
result.lock_time = wtx.tx->nLockTime;
result.is_final = CheckFinalTx(*wtx.tx);
- result.is_trusted = wtx.IsTrusted();
+ result.is_trusted = wtx.IsTrusted(locked_chain);
result.is_abandoned = wtx.isAbandoned();
result.is_coinbase = wtx.IsCoinBase();
- result.is_in_main_chain = wtx.IsInMainChain();
+ result.is_in_main_chain = wtx.IsInMainChain(locked_chain);
return result;
}
//! Construct wallet TxOut struct.
-static WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+WalletTxOut MakeWalletTxOut(interfaces::Chain::Lock& locked_chain,
+ CWallet& wallet,
+ const CWalletTx& wtx,
+ int n,
+ int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{
WalletTxOut result;
result.txout = wtx.tx->vout[n];
result.time = wtx.GetTxTime();
result.depth_in_main_chain = depth;
- result.is_spent = wallet.IsSpent(wtx.GetHash(), n);
+ result.is_spent = wallet.IsSpent(locked_chain, wtx.GetHash(), n);
return result;
}
@@ -197,22 +216,26 @@ public:
}
void lockCoin(const COutPoint& output) override
{
- LOCK2(cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
return m_wallet.LockCoin(output);
}
void unlockCoin(const COutPoint& output) override
{
- LOCK2(cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
return m_wallet.UnlockCoin(output);
}
bool isLockedCoin(const COutPoint& output) override
{
- LOCK2(cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
return m_wallet.IsLockedCoin(output.hash, output.n);
}
void listLockedCoins(std::vector<COutPoint>& outputs) override
{
- LOCK2(cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
return m_wallet.ListLockedCoins(outputs);
}
std::unique_ptr<PendingWalletTx> createTransaction(const std::vector<CRecipient>& recipients,
@@ -222,9 +245,10 @@ public:
CAmount& fee,
std::string& fail_reason) override
{
- LOCK2(cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
auto pending = MakeUnique<PendingWalletTxImpl>(m_wallet);
- if (!m_wallet.CreateTransaction(recipients, pending->m_tx, pending->m_key, fee, change_pos,
+ if (!m_wallet.CreateTransaction(*locked_chain, recipients, pending->m_tx, pending->m_key, fee, change_pos,
fail_reason, coin_control, sign)) {
return {};
}
@@ -233,8 +257,9 @@ public:
bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet.TransactionCanBeAbandoned(txid); }
bool abandonTransaction(const uint256& txid) override
{
- LOCK2(cs_main, m_wallet.cs_wallet);
- return m_wallet.AbandonTransaction(txid);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
+ return m_wallet.AbandonTransaction(*locked_chain, txid);
}
bool transactionCanBeBumped(const uint256& txid) override
{
@@ -262,7 +287,8 @@ public:
}
CTransactionRef getTx(const uint256& txid) override
{
- LOCK2(::cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
auto mi = m_wallet.mapWallet.find(txid);
if (mi != m_wallet.mapWallet.end()) {
return mi->second.tx;
@@ -271,29 +297,30 @@ public:
}
WalletTx getWalletTx(const uint256& txid) override
{
- LOCK2(::cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
auto mi = m_wallet.mapWallet.find(txid);
if (mi != m_wallet.mapWallet.end()) {
- return MakeWalletTx(m_wallet, mi->second);
+ return MakeWalletTx(*locked_chain, m_wallet, mi->second);
}
return {};
}
std::vector<WalletTx> getWalletTxs() override
{
- LOCK2(::cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
std::vector<WalletTx> result;
result.reserve(m_wallet.mapWallet.size());
for (const auto& entry : m_wallet.mapWallet) {
- result.emplace_back(MakeWalletTx(m_wallet, entry.second));
+ result.emplace_back(MakeWalletTx(*locked_chain, m_wallet, entry.second));
}
return result;
}
bool tryGetTxStatus(const uint256& txid,
interfaces::WalletTxStatus& tx_status,
- int& num_blocks,
- int64_t& adjusted_time) override
+ int& num_blocks) override
{
- TRY_LOCK(::cs_main, locked_chain);
+ auto locked_chain = m_wallet.chain().lock(true /* try_lock */);
if (!locked_chain) {
return false;
}
@@ -306,26 +333,24 @@ public:
return false;
}
num_blocks = ::chainActive.Height();
- adjusted_time = GetAdjustedTime();
- tx_status = MakeWalletTxStatus(mi->second);
+ tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
return true;
}
WalletTx getWalletTxDetails(const uint256& txid,
WalletTxStatus& tx_status,
WalletOrderForm& order_form,
bool& in_mempool,
- int& num_blocks,
- int64_t& adjusted_time) override
+ int& num_blocks) override
{
- LOCK2(::cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
auto mi = m_wallet.mapWallet.find(txid);
if (mi != m_wallet.mapWallet.end()) {
num_blocks = ::chainActive.Height();
- adjusted_time = GetAdjustedTime();
in_mempool = mi->second.InMempool();
order_form = mi->second.vOrderForm;
- tx_status = MakeWalletTxStatus(mi->second);
- return MakeWalletTx(m_wallet, mi->second);
+ tx_status = MakeWalletTxStatus(*locked_chain, mi->second);
+ return MakeWalletTx(*locked_chain, m_wallet, mi->second);
}
return {};
}
@@ -345,7 +370,7 @@ public:
}
bool tryGetBalances(WalletBalances& balances, int& num_blocks) override
{
- TRY_LOCK(cs_main, locked_chain);
+ auto locked_chain = m_wallet.chain().lock(true /* try_lock */);
if (!locked_chain) return false;
TRY_LOCK(m_wallet.cs_wallet, locked_wallet);
if (!locked_wallet) {
@@ -362,49 +387,55 @@ public:
}
isminetype txinIsMine(const CTxIn& txin) override
{
- LOCK2(::cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
return m_wallet.IsMine(txin);
}
isminetype txoutIsMine(const CTxOut& txout) override
{
- LOCK2(::cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
return m_wallet.IsMine(txout);
}
CAmount getDebit(const CTxIn& txin, isminefilter filter) override
{
- LOCK2(::cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
return m_wallet.GetDebit(txin, filter);
}
CAmount getCredit(const CTxOut& txout, isminefilter filter) override
{
- LOCK2(::cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
return m_wallet.GetCredit(txout, filter);
}
CoinsList listCoins() override
{
- LOCK2(::cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
CoinsList result;
- for (const auto& entry : m_wallet.ListCoins()) {
+ for (const auto& entry : m_wallet.ListCoins(*locked_chain)) {
auto& group = result[entry.first];
for (const auto& coin : entry.second) {
- group.emplace_back(
- COutPoint(coin.tx->GetHash(), coin.i), MakeWalletTxOut(m_wallet, *coin.tx, coin.i, coin.nDepth));
+ group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i),
+ MakeWalletTxOut(*locked_chain, m_wallet, *coin.tx, coin.i, coin.nDepth));
}
}
return result;
}
std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override
{
- LOCK2(::cs_main, m_wallet.cs_wallet);
+ auto locked_chain = m_wallet.chain().lock();
+ LOCK(m_wallet.cs_wallet);
std::vector<WalletTxOut> result;
result.reserve(outputs.size());
for (const auto& output : outputs) {
result.emplace_back();
auto it = m_wallet.mapWallet.find(output.hash);
if (it != m_wallet.mapWallet.end()) {
- int depth = it->second.GetDepthInMainChain();
+ int depth = it->second.GetDepthInMainChain(*locked_chain);
if (depth >= 0) {
- result.back() = MakeWalletTxOut(m_wallet, it->second, output.n, depth);
+ result.back() = MakeWalletTxOut(*locked_chain, m_wallet, it->second, output.n, depth);
}
}
}
@@ -460,8 +491,32 @@ public:
CWallet& m_wallet;
};
+class WalletClientImpl : public ChainClient
+{
+public:
+ WalletClientImpl(Chain& chain, std::vector<std::string> wallet_filenames)
+ : m_chain(chain), m_wallet_filenames(std::move(wallet_filenames))
+ {
+ }
+ void registerRpcs() override { return RegisterWalletRPCCommands(::tableRPC); }
+ bool verify() override { return VerifyWallets(m_chain, m_wallet_filenames); }
+ bool load() override { return LoadWallets(m_chain, m_wallet_filenames); }
+ void start(CScheduler& scheduler) override { return StartWallets(scheduler); }
+ void flush() override { return FlushWallets(); }
+ void stop() override { return StopWallets(); }
+ ~WalletClientImpl() override { UnloadWallets(); }
+
+ Chain& m_chain;
+ std::vector<std::string> m_wallet_filenames;
+};
+
} // namespace
std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return MakeUnique<WalletImpl>(wallet); }
+std::unique_ptr<ChainClient> MakeWalletClient(Chain& chain, std::vector<std::string> wallet_filenames)
+{
+ return MakeUnique<WalletClientImpl>(chain, std::move(wallet_filenames));
+}
+
} // namespace interfaces
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 7aa91f37e1..c79b9afce3 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -178,16 +178,14 @@ public:
//! Try to get updated status for a particular transaction, if possible without blocking.
virtual bool tryGetTxStatus(const uint256& txid,
WalletTxStatus& tx_status,
- int& num_blocks,
- int64_t& adjusted_time) = 0;
+ int& num_blocks) = 0;
//! Get transaction details.
virtual WalletTx getWalletTxDetails(const uint256& txid,
WalletTxStatus& tx_status,
WalletOrderForm& order_form,
bool& in_mempool,
- int& num_blocks,
- int64_t& adjusted_time) = 0;
+ int& num_blocks) = 0;
//! Get balances.
virtual WalletBalances getBalances() = 0;
diff --git a/src/key_io.cpp b/src/key_io.cpp
index c6a541cdb1..282385f50d 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -7,7 +7,7 @@
#include <base58.h>
#include <bech32.h>
#include <script/script.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
diff --git a/src/keystore.cpp b/src/keystore.cpp
index b2012a04bb..148979cf35 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -5,7 +5,7 @@
#include <keystore.h>
-#include <util.h>
+#include <util/system.h>
void CBasicKeyStore::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey)
{
diff --git a/src/logging.cpp b/src/logging.cpp
index 0ae4f8121e..77dc2d0939 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -4,7 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <logging.h>
-#include <utiltime.h>
+#include <util/time.h>
const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index 7bbc45d38a..0c37bab1f8 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -7,7 +7,7 @@
#include <hash.h>
#include <consensus/consensus.h>
-#include <utilstrencodings.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 6d35f9ac37..feb86cab66 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -21,8 +21,8 @@
#include <primitives/transaction.h>
#include <script/standard.h>
#include <timedata.h>
-#include <util.h>
-#include <utilmoneystr.h>
+#include <util/system.h>
+#include <util/moneystr.h>
#include <validationinterface.h>
#include <algorithm>
diff --git a/src/net.cpp b/src/net.cpp
index f83f39a67d..65a308780a 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -18,7 +18,7 @@
#include <netbase.h>
#include <scheduler.h>
#include <ui_interface.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#ifdef WIN32
#include <string.h>
@@ -1153,310 +1153,322 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
}
}
-void CConnman::ThreadSocketHandler()
+void CConnman::DisconnectNodes()
{
- unsigned int nPrevNodeCount = 0;
- while (!interruptNet)
{
- //
- // Disconnect nodes
- //
- {
- LOCK(cs_vNodes);
+ LOCK(cs_vNodes);
- if (!fNetworkActive) {
- // Disconnect any connected nodes
- for (CNode* pnode : vNodes) {
- if (!pnode->fDisconnect) {
- LogPrint(BCLog::NET, "Network not active, dropping peer=%d\n", pnode->GetId());
- pnode->fDisconnect = true;
- }
+ if (!fNetworkActive) {
+ // Disconnect any connected nodes
+ for (CNode* pnode : vNodes) {
+ if (!pnode->fDisconnect) {
+ LogPrint(BCLog::NET, "Network not active, dropping peer=%d\n", pnode->GetId());
+ pnode->fDisconnect = true;
}
}
+ }
- // Disconnect unused nodes
- std::vector<CNode*> vNodesCopy = vNodes;
- for (CNode* pnode : vNodesCopy)
+ // Disconnect unused nodes
+ std::vector<CNode*> vNodesCopy = vNodes;
+ for (CNode* pnode : vNodesCopy)
+ {
+ if (pnode->fDisconnect)
{
- if (pnode->fDisconnect)
- {
- // remove from vNodes
- vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
+ // remove from vNodes
+ vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());
- // release outbound grant (if any)
- pnode->grantOutbound.Release();
+ // release outbound grant (if any)
+ pnode->grantOutbound.Release();
- // close socket and cleanup
- pnode->CloseSocketDisconnect();
+ // close socket and cleanup
+ pnode->CloseSocketDisconnect();
- // hold in disconnected pool until all refs are released
- pnode->Release();
- vNodesDisconnected.push_back(pnode);
- }
+ // hold in disconnected pool until all refs are released
+ pnode->Release();
+ vNodesDisconnected.push_back(pnode);
}
}
+ }
+ {
+ // Delete disconnected nodes
+ std::list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
+ for (CNode* pnode : vNodesDisconnectedCopy)
{
- // Delete disconnected nodes
- std::list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
- for (CNode* pnode : vNodesDisconnectedCopy)
- {
- // wait until threads are done using it
- if (pnode->GetRefCount() <= 0) {
- bool fDelete = false;
- {
- TRY_LOCK(pnode->cs_inventory, lockInv);
- if (lockInv) {
- TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend) {
- fDelete = true;
- }
+ // wait until threads are done using it
+ if (pnode->GetRefCount() <= 0) {
+ bool fDelete = false;
+ {
+ TRY_LOCK(pnode->cs_inventory, lockInv);
+ if (lockInv) {
+ TRY_LOCK(pnode->cs_vSend, lockSend);
+ if (lockSend) {
+ fDelete = true;
}
}
- if (fDelete) {
- vNodesDisconnected.remove(pnode);
- DeleteNode(pnode);
- }
+ }
+ if (fDelete) {
+ vNodesDisconnected.remove(pnode);
+ DeleteNode(pnode);
}
}
}
- size_t vNodesSize;
+ }
+}
+
+void CConnman::NotifyNumConnectionsChanged()
+{
+ size_t vNodesSize;
+ {
+ LOCK(cs_vNodes);
+ vNodesSize = vNodes.size();
+ }
+ if(vNodesSize != nPrevNodeCount) {
+ nPrevNodeCount = vNodesSize;
+ if(clientInterface)
+ clientInterface->NotifyNumConnectionsChanged(vNodesSize);
+ }
+}
+
+void CConnman::InactivityCheck(CNode *pnode)
+{
+ int64_t nTime = GetSystemTimeInSeconds();
+ if (nTime - pnode->nTimeConnected > 60)
+ {
+ if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
+ {
+ LogPrint(BCLog::NET, "socket no message in first 60 seconds, %d %d from %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->GetId());
+ pnode->fDisconnect = true;
+ }
+ else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)
{
- LOCK(cs_vNodes);
- vNodesSize = vNodes.size();
+ LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend);
+ pnode->fDisconnect = true;
+ }
+ else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60))
+ {
+ LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
+ pnode->fDisconnect = true;
+ }
+ else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros())
+ {
+ LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
+ pnode->fDisconnect = true;
}
- if(vNodesSize != nPrevNodeCount) {
- nPrevNodeCount = vNodesSize;
- if(clientInterface)
- clientInterface->NotifyNumConnectionsChanged(vNodesSize);
+ else if (!pnode->fSuccessfullyConnected)
+ {
+ LogPrint(BCLog::NET, "version handshake timeout from %d\n", pnode->GetId());
+ pnode->fDisconnect = true;
}
+ }
+}
- //
- // Find which sockets have data to receive
- //
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 50000; // frequency to poll pnode->vSend
-
- fd_set fdsetRecv;
- fd_set fdsetSend;
- fd_set fdsetError;
- FD_ZERO(&fdsetRecv);
- FD_ZERO(&fdsetSend);
- FD_ZERO(&fdsetError);
- SOCKET hSocketMax = 0;
- bool have_fds = false;
+void CConnman::SocketHandler()
+{
+ //
+ // Find which sockets have data to receive
+ //
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 50000; // frequency to poll pnode->vSend
- for (const ListenSocket& hListenSocket : vhListenSocket) {
- FD_SET(hListenSocket.socket, &fdsetRecv);
- hSocketMax = std::max(hSocketMax, hListenSocket.socket);
- have_fds = true;
- }
+ fd_set fdsetRecv;
+ fd_set fdsetSend;
+ fd_set fdsetError;
+ FD_ZERO(&fdsetRecv);
+ FD_ZERO(&fdsetSend);
+ FD_ZERO(&fdsetError);
+ SOCKET hSocketMax = 0;
+ bool have_fds = false;
+ for (const ListenSocket& hListenSocket : vhListenSocket) {
+ FD_SET(hListenSocket.socket, &fdsetRecv);
+ hSocketMax = std::max(hSocketMax, hListenSocket.socket);
+ have_fds = true;
+ }
+
+ {
+ LOCK(cs_vNodes);
+ for (CNode* pnode : vNodes)
{
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodes)
+ // Implement the following logic:
+ // * If there is data to send, select() for sending data. As this only
+ // happens when optimistic write failed, we choose to first drain the
+ // write buffer in this case before receiving more. This avoids
+ // needlessly queueing received data, if the remote peer is not themselves
+ // receiving data. This means properly utilizing TCP flow control signalling.
+ // * Otherwise, if there is space left in the receive buffer, select() for
+ // receiving data.
+ // * Hand off all complete messages to the processor, to be handled without
+ // blocking here.
+
+ bool select_recv = !pnode->fPauseRecv;
+ bool select_send;
{
- // Implement the following logic:
- // * If there is data to send, select() for sending data. As this only
- // happens when optimistic write failed, we choose to first drain the
- // write buffer in this case before receiving more. This avoids
- // needlessly queueing received data, if the remote peer is not themselves
- // receiving data. This means properly utilizing TCP flow control signalling.
- // * Otherwise, if there is space left in the receive buffer, select() for
- // receiving data.
- // * Hand off all complete messages to the processor, to be handled without
- // blocking here.
-
- bool select_recv = !pnode->fPauseRecv;
- bool select_send;
- {
- LOCK(pnode->cs_vSend);
- select_send = !pnode->vSendMsg.empty();
- }
+ LOCK(pnode->cs_vSend);
+ select_send = !pnode->vSendMsg.empty();
+ }
- LOCK(pnode->cs_hSocket);
- if (pnode->hSocket == INVALID_SOCKET)
- continue;
+ LOCK(pnode->cs_hSocket);
+ if (pnode->hSocket == INVALID_SOCKET)
+ continue;
- FD_SET(pnode->hSocket, &fdsetError);
- hSocketMax = std::max(hSocketMax, pnode->hSocket);
- have_fds = true;
+ FD_SET(pnode->hSocket, &fdsetError);
+ hSocketMax = std::max(hSocketMax, pnode->hSocket);
+ have_fds = true;
- if (select_send) {
- FD_SET(pnode->hSocket, &fdsetSend);
- continue;
- }
- if (select_recv) {
- FD_SET(pnode->hSocket, &fdsetRecv);
- }
+ if (select_send) {
+ FD_SET(pnode->hSocket, &fdsetSend);
+ continue;
+ }
+ if (select_recv) {
+ FD_SET(pnode->hSocket, &fdsetRecv);
}
}
+ }
- int nSelect = select(have_fds ? hSocketMax + 1 : 0,
- &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
- if (interruptNet)
- return;
+ int nSelect = select(have_fds ? hSocketMax + 1 : 0,
+ &fdsetRecv, &fdsetSend, &fdsetError, &timeout);
+ if (interruptNet)
+ return;
- if (nSelect == SOCKET_ERROR)
+ if (nSelect == SOCKET_ERROR)
+ {
+ if (have_fds)
{
- if (have_fds)
- {
- int nErr = WSAGetLastError();
- LogPrintf("socket select error %s\n", NetworkErrorString(nErr));
- for (unsigned int i = 0; i <= hSocketMax; i++)
- FD_SET(i, &fdsetRecv);
- }
- FD_ZERO(&fdsetSend);
- FD_ZERO(&fdsetError);
- if (!interruptNet.sleep_for(std::chrono::milliseconds(timeout.tv_usec/1000)))
- return;
+ int nErr = WSAGetLastError();
+ LogPrintf("socket select error %s\n", NetworkErrorString(nErr));
+ for (unsigned int i = 0; i <= hSocketMax; i++)
+ FD_SET(i, &fdsetRecv);
}
+ FD_ZERO(&fdsetSend);
+ FD_ZERO(&fdsetError);
+ if (!interruptNet.sleep_for(std::chrono::milliseconds(timeout.tv_usec/1000)))
+ return;
+ }
- //
- // Accept new connections
- //
- for (const ListenSocket& hListenSocket : vhListenSocket)
+ //
+ // Accept new connections
+ //
+ for (const ListenSocket& hListenSocket : vhListenSocket)
+ {
+ if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv))
{
- if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv))
- {
- AcceptConnection(hListenSocket);
- }
+ AcceptConnection(hListenSocket);
}
+ }
+
+ //
+ // Service each socket
+ //
+ std::vector<CNode*> vNodesCopy;
+ {
+ LOCK(cs_vNodes);
+ vNodesCopy = vNodes;
+ for (CNode* pnode : vNodesCopy)
+ pnode->AddRef();
+ }
+ for (CNode* pnode : vNodesCopy)
+ {
+ if (interruptNet)
+ return;
//
- // Service each socket
+ // Receive
//
- std::vector<CNode*> vNodesCopy;
+ bool recvSet = false;
+ bool sendSet = false;
+ bool errorSet = false;
{
- LOCK(cs_vNodes);
- vNodesCopy = vNodes;
- for (CNode* pnode : vNodesCopy)
- pnode->AddRef();
+ LOCK(pnode->cs_hSocket);
+ if (pnode->hSocket == INVALID_SOCKET)
+ continue;
+ recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv);
+ sendSet = FD_ISSET(pnode->hSocket, &fdsetSend);
+ errorSet = FD_ISSET(pnode->hSocket, &fdsetError);
}
- for (CNode* pnode : vNodesCopy)
+ if (recvSet || errorSet)
{
- if (interruptNet)
- return;
-
- //
- // Receive
- //
- bool recvSet = false;
- bool sendSet = false;
- bool errorSet = false;
+ // typical socket buffer is 8K-64K
+ char pchBuf[0x10000];
+ int nBytes = 0;
{
LOCK(pnode->cs_hSocket);
if (pnode->hSocket == INVALID_SOCKET)
continue;
- recvSet = FD_ISSET(pnode->hSocket, &fdsetRecv);
- sendSet = FD_ISSET(pnode->hSocket, &fdsetSend);
- errorSet = FD_ISSET(pnode->hSocket, &fdsetError);
+ nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
}
- if (recvSet || errorSet)
+ if (nBytes > 0)
{
- // typical socket buffer is 8K-64K
- char pchBuf[0x10000];
- int nBytes = 0;
- {
- LOCK(pnode->cs_hSocket);
- if (pnode->hSocket == INVALID_SOCKET)
- continue;
- nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
- }
- if (nBytes > 0)
- {
- bool notify = false;
- if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify))
- pnode->CloseSocketDisconnect();
- RecordBytesRecv(nBytes);
- if (notify) {
- size_t nSizeAdded = 0;
- auto it(pnode->vRecvMsg.begin());
- for (; it != pnode->vRecvMsg.end(); ++it) {
- if (!it->complete())
- break;
- nSizeAdded += it->vRecv.size() + CMessageHeader::HEADER_SIZE;
- }
- {
- LOCK(pnode->cs_vProcessMsg);
- pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it);
- pnode->nProcessQueueSize += nSizeAdded;
- pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize;
- }
- WakeMessageHandler();
- }
- }
- else if (nBytes == 0)
- {
- // socket closed gracefully
- if (!pnode->fDisconnect) {
- LogPrint(BCLog::NET, "socket closed\n");
- }
+ bool notify = false;
+ if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify))
pnode->CloseSocketDisconnect();
- }
- else if (nBytes < 0)
- {
- // error
- int nErr = WSAGetLastError();
- if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
+ RecordBytesRecv(nBytes);
+ if (notify) {
+ size_t nSizeAdded = 0;
+ auto it(pnode->vRecvMsg.begin());
+ for (; it != pnode->vRecvMsg.end(); ++it) {
+ if (!it->complete())
+ break;
+ nSizeAdded += it->vRecv.size() + CMessageHeader::HEADER_SIZE;
+ }
{
- if (!pnode->fDisconnect)
- LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
- pnode->CloseSocketDisconnect();
+ LOCK(pnode->cs_vProcessMsg);
+ pnode->vProcessMsg.splice(pnode->vProcessMsg.end(), pnode->vRecvMsg, pnode->vRecvMsg.begin(), it);
+ pnode->nProcessQueueSize += nSizeAdded;
+ pnode->fPauseRecv = pnode->nProcessQueueSize > nReceiveFloodSize;
}
+ WakeMessageHandler();
}
}
-
- //
- // Send
- //
- if (sendSet)
+ else if (nBytes == 0)
{
- LOCK(pnode->cs_vSend);
- size_t nBytes = SocketSendData(pnode);
- if (nBytes) {
- RecordBytesSent(nBytes);
+ // socket closed gracefully
+ if (!pnode->fDisconnect) {
+ LogPrint(BCLog::NET, "socket closed\n");
}
+ pnode->CloseSocketDisconnect();
}
-
- //
- // Inactivity checking
- //
- int64_t nTime = GetSystemTimeInSeconds();
- if (nTime - pnode->nTimeConnected > 60)
+ else if (nBytes < 0)
{
- if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
- {
- LogPrint(BCLog::NET, "socket no message in first 60 seconds, %d %d from %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->GetId());
- pnode->fDisconnect = true;
- }
- else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)
- {
- LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend);
- pnode->fDisconnect = true;
- }
- else if (nTime - pnode->nLastRecv > (pnode->nVersion > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60))
- {
- LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
- pnode->fDisconnect = true;
- }
- else if (pnode->nPingNonceSent && pnode->nPingUsecStart + TIMEOUT_INTERVAL * 1000000 < GetTimeMicros())
- {
- LogPrintf("ping timeout: %fs\n", 0.000001 * (GetTimeMicros() - pnode->nPingUsecStart));
- pnode->fDisconnect = true;
- }
- else if (!pnode->fSuccessfullyConnected)
+ // error
+ int nErr = WSAGetLastError();
+ if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
{
- LogPrint(BCLog::NET, "version handshake timeout from %d\n", pnode->GetId());
- pnode->fDisconnect = true;
+ if (!pnode->fDisconnect)
+ LogPrintf("socket recv error %s\n", NetworkErrorString(nErr));
+ pnode->CloseSocketDisconnect();
}
}
}
+
+ //
+ // Send
+ //
+ if (sendSet)
{
- LOCK(cs_vNodes);
- for (CNode* pnode : vNodesCopy)
- pnode->Release();
+ LOCK(pnode->cs_vSend);
+ size_t nBytes = SocketSendData(pnode);
+ if (nBytes) {
+ RecordBytesSent(nBytes);
+ }
}
+
+ InactivityCheck(pnode);
+ }
+ {
+ LOCK(cs_vNodes);
+ for (CNode* pnode : vNodesCopy)
+ pnode->Release();
+ }
+}
+
+void CConnman::ThreadSocketHandler()
+{
+ while (!interruptNet)
+ {
+ DisconnectNodes();
+ NotifyNumConnectionsChanged();
+ SocketHandler();
}
}
@@ -2217,6 +2229,7 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe
setBannedIsDirty = false;
fAddressesInitialized = false;
nLastNodeId = 0;
+ nPrevNodeCount = 0;
nSendBufferMaxSize = 0;
nReceiveFloodSize = 0;
flagInterruptMsgProc = false;
diff --git a/src/net.h b/src/net.h
index c43429c7f3..164ec9080c 100644
--- a/src/net.h
+++ b/src/net.h
@@ -11,6 +11,7 @@
#include <amount.h>
#include <bloom.h>
#include <compat.h>
+#include <crypto/siphash.h>
#include <hash.h>
#include <limitedmap.h>
#include <netaddress.h>
@@ -338,6 +339,10 @@ private:
void ThreadOpenConnections(std::vector<std::string> connect);
void ThreadMessageHandler();
void AcceptConnection(const ListenSocket& hListenSocket);
+ void DisconnectNodes();
+ void NotifyNumConnectionsChanged();
+ void InactivityCheck(CNode *pnode);
+ void SocketHandler();
void ThreadSocketHandler();
void ThreadDNSAddressSeed();
@@ -408,6 +413,7 @@ private:
std::list<CNode*> vNodesDisconnected;
mutable CCriticalSection cs_vNodes;
std::atomic<NodeId> nLastNodeId;
+ unsigned int nPrevNodeCount;
/** Services this instance offers */
ServiceFlags nLocalServices;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index a1b6e021ae..f4ab3aa153 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -25,9 +25,9 @@
#include <tinyformat.h>
#include <txmempool.h>
#include <ui_interface.h>
-#include <util.h>
-#include <utilmoneystr.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/moneystr.h>
+#include <util/strencodings.h>
#include <memory>
@@ -2357,6 +2357,23 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
for (const CTransactionRef& removedTx : lRemovedTxn)
AddToCompactExtraTransactions(removedTx);
+ // If a tx has been detected by recentRejects, we will have reached
+ // this point and the tx will have been ignored. Because we haven't run
+ // the tx through AcceptToMemoryPool, we won't have computed a DoS
+ // score for it or determined exactly why we consider it invalid.
+ //
+ // This means we won't penalize any peer subsequently relaying a DoSy
+ // tx (even if we penalized the first peer who gave it to us) because
+ // we have to account for recentRejects showing false positives. In
+ // other words, we shouldn't penalize a peer if we aren't *sure* they
+ // submitted a DoSy tx.
+ //
+ // Note that recentRejects doesn't just record DoSy or invalid
+ // transactions, but any tx not accepted by the mempool, which may be
+ // due to node policy (vs. consensus). So we can't blanket penalize a
+ // peer simply for relaying a tx that our recentRejects has caught,
+ // regardless of false positives.
+
int nDoS = 0;
if (state.IsInvalid(nDoS))
{
diff --git a/src/net_processing.h b/src/net_processing.h
index 88dbdf556d..0113e25f7e 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -71,7 +71,7 @@ public:
void EvictExtraOutboundPeers(int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
private:
- int64_t m_stale_tip_check_time; //! Next time to check for stale tip
+ int64_t m_stale_tip_check_time; //!< Next time to check for stale tip
/** Enable BIP61 (sending reject messages) */
const bool m_enable_bip61;
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 778c2700f9..e1af4eff62 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -5,7 +5,7 @@
#include <netaddress.h>
#include <hash.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <tinyformat.h>
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 093fd0bdb7..6a750d5141 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -10,8 +10,8 @@
#include <uint256.h>
#include <random.h>
#include <tinyformat.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <atomic>
@@ -191,10 +191,10 @@ enum SOCKSVersion: uint8_t {
/** Values defined for METHOD in RFC1928 */
enum SOCKS5Method: uint8_t {
- NOAUTH = 0x00, //! No authentication required
- GSSAPI = 0x01, //! GSSAPI
- USER_PASS = 0x02, //! Username/password
- NO_ACCEPTABLE = 0xff, //! No acceptable methods
+ NOAUTH = 0x00, //!< No authentication required
+ GSSAPI = 0x01, //!< GSSAPI
+ USER_PASS = 0x02, //!< Username/password
+ NO_ACCEPTABLE = 0xff, //!< No acceptable methods
};
/** Values defined for CMD in RFC1928 */
@@ -206,15 +206,15 @@ enum SOCKS5Command: uint8_t {
/** Values defined for REP in RFC1928 */
enum SOCKS5Reply: uint8_t {
- SUCCEEDED = 0x00, //! Succeeded
- GENFAILURE = 0x01, //! General failure
- NOTALLOWED = 0x02, //! Connection not allowed by ruleset
- NETUNREACHABLE = 0x03, //! Network unreachable
- HOSTUNREACHABLE = 0x04, //! Network unreachable
- CONNREFUSED = 0x05, //! Connection refused
- TTLEXPIRED = 0x06, //! TTL expired
- CMDUNSUPPORTED = 0x07, //! Command not supported
- ATYPEUNSUPPORTED = 0x08, //! Address type not supported
+ SUCCEEDED = 0x00, //!< Succeeded
+ GENFAILURE = 0x01, //!< General failure
+ NOTALLOWED = 0x02, //!< Connection not allowed by ruleset
+ NETUNREACHABLE = 0x03, //!< Network unreachable
+ HOSTUNREACHABLE = 0x04, //!< Network unreachable
+ CONNREFUSED = 0x05, //!< Connection refused
+ TTLEXPIRED = 0x06, //!< TTL expired
+ CMDUNSUPPORTED = 0x07, //!< Command not supported
+ ATYPEUNSUPPORTED = 0x08, //!< Address type not supported
};
/** Values defined for ATYPE in RFC1928 */
diff --git a/src/noui.cpp b/src/noui.cpp
index df4bfabb66..c7d8fee0ba 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -6,7 +6,7 @@
#include <noui.h>
#include <ui_interface.h>
-#include <util.h>
+#include <util/system.h>
#include <cstdio>
#include <stdint.h>
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index aee6fbee1a..3afe6fe1b7 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -10,7 +10,7 @@
#include <primitives/transaction.h>
#include <streams.h>
#include <txmempool.h>
-#include <util.h>
+#include <util/system.h>
static constexpr double INF_FEERATE = 1e99;
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 2733c5a7de..90f159b48c 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -50,9 +50,9 @@ std::string StringForFeeReason(FeeReason reason);
/* Used to determine type of fee estimation requested */
enum class FeeEstimateMode {
- UNSET, //! Use default settings based on other criteria
- ECONOMICAL, //! Force estimateSmartFee to use non-conservative estimates
- CONSERVATIVE, //! Force estimateSmartFee to use conservative estimates
+ UNSET, //!< Use default settings based on other criteria
+ ECONOMICAL, //!< Force estimateSmartFee to use non-conservative estimates
+ CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates
};
bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode);
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index ac1b75edb4..d4cc538492 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -11,8 +11,8 @@
#include <validation.h>
#include <coins.h>
#include <tinyformat.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 18f9c0c2a8..0dc130d104 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -7,7 +7,7 @@
bool SignalsOptInRBF(const CTransaction &tx)
{
for (const CTxIn &txin : tx.vin) {
- if (txin.nSequence < std::numeric_limits<unsigned int>::max()-1) {
+ if (txin.nSequence <= MAX_BIP125_RBF_SEQUENCE) {
return true;
}
}
diff --git a/src/prevector.h b/src/prevector.h
index 6ddb6f321f..aa77573746 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -10,6 +10,7 @@
#include <stdint.h>
#include <string.h>
+#include <algorithm>
#include <cstddef>
#include <iterator>
#include <type_traits>
@@ -198,22 +199,11 @@ private:
const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); }
void fill(T* dst, ptrdiff_t count) {
- if (IS_TRIVIALLY_CONSTRUCTIBLE<T>::value) {
- // The most common use of prevector is where T=unsigned char. For
- // trivially constructible types, we can use memset() to avoid
- // looping.
- ::memset(dst, 0, count * sizeof(T));
- } else {
- for (auto i = 0; i < count; ++i) {
- new(static_cast<void*>(dst + i)) T();
- }
- }
+ std::fill_n(dst, count, T{});
}
void fill(T* dst, ptrdiff_t count, const T& value) {
- for (auto i = 0; i < count; ++i) {
- new(static_cast<void*>(dst + i)) T(value);
- }
+ std::fill_n(dst, count, value);
}
template<typename InputIterator>
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index fb95a66bde..a0c2e3f125 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -7,7 +7,7 @@
#include <hash.h>
#include <tinyformat.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <crypto/common.h>
uint256 CBlockHeader::GetHash() const
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index bdb470470e..28c145f71d 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -7,7 +7,7 @@
#include <hash.h>
#include <tinyformat.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
std::string COutPoint::ToString() const
{
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index fb9db508d2..0f834eb8c1 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -64,7 +64,7 @@ public:
COutPoint prevout;
CScript scriptSig;
uint32_t nSequence;
- CScriptWitness scriptWitness; //! Only serialized through CTransaction
+ CScriptWitness scriptWitness; //!< Only serialized through CTransaction
/* Setting nSequence to this value for every input in a transaction
* disables nLockTime. */
@@ -73,7 +73,7 @@ public:
/* Below flags apply in the context of BIP 68*/
/* If this flag set, CTxIn::nSequence is NOT interpreted as a
* relative lock-time. */
- static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1 << 31);
+ static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1U << 31);
/* If CTxIn::nSequence encodes a relative lock-time and this flag
* is set, the relative lock-time has units of 512 seconds,
diff --git a/src/protocol.cpp b/src/protocol.cpp
index b4fc9def1f..bdf236c2c7 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -5,8 +5,8 @@
#include <protocol.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#ifndef WIN32
# include <arpa/inet.h>
diff --git a/src/qt/README.md b/src/qt/README.md
index 3ec538b4f4..0eb18f7cd5 100644
--- a/src/qt/README.md
+++ b/src/qt/README.md
@@ -64,8 +64,8 @@ Represents the view to a single wallet.
* `callback.h`
* `guiconstants.h`: UI colors, app name, etc
* `guiutil.h`: several helper functions
-* `macdockiconhandler.(h/cpp)`
-* `macdockiconhandler.(h/cpp)`: display notifications in macOS
+* `macdockiconhandler.(h/mm)`: macOS dock icon handler
+* `macnotificationhandler.(h/mm)`: display notifications in macOS
## Contribute
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index 97348aad2b..dcfe3dcc57 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -10,7 +10,7 @@
#include <interfaces/node.h>
#include <sync.h>
-#include <utiltime.h>
+#include <util/time.h>
#include <QDebug>
#include <QList>
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 1e950e2686..7508f596e6 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -32,7 +32,7 @@
#include <rpc/server.h>
#include <ui_interface.h>
#include <uint256.h>
-#include <util.h>
+#include <util/system.h>
#include <warnings.h>
#include <walletinitinterface.h>
@@ -51,7 +51,6 @@
#include <QThread>
#include <QTimer>
#include <QTranslator>
-#include <QSslConfiguration>
#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
@@ -440,8 +439,10 @@ void BitcoinApplication::addWallet(WalletModel* walletModel)
window->setCurrentWallet(walletModel->getWalletName());
}
+#ifdef ENABLE_BIP70
connect(walletModel, &WalletModel::coinsSent,
paymentServer, &PaymentServer::fetchPaymentACK);
+#endif
connect(walletModel, &WalletModel::unload, this, &BitcoinApplication::removeWallet);
m_wallet_models.push_back(walletModel);
@@ -468,7 +469,9 @@ void BitcoinApplication::initializeResult(bool success)
// Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
qWarning() << "Platform customization:" << platformStyle->getName();
#ifdef ENABLE_WALLET
+#ifdef ENABLE_BIP70
PaymentServer::LoadRootCAs();
+#endif
paymentServer->setOptionsModel(optionsModel);
#endif
@@ -537,7 +540,7 @@ WId BitcoinApplication::getMainWinId() const
static void SetupUIArgs()
{
-#ifdef ENABLE_WALLET
+#if defined(ENABLE_WALLET) && defined(ENABLE_BIP70)
gArgs.AddArg("-allowselfsignedrootcertificates", strprintf("Allow self signed root certificates (default: %u)", DEFAULT_SELFSIGNED_ROOTCERTS), true, OptionsCategory::GUI);
#endif
gArgs.AddArg("-choosedatadir", strprintf("Choose data directory on startup (default: %u)", DEFAULT_CHOOSE_DATADIR), false, OptionsCategory::GUI);
@@ -552,6 +555,10 @@ static void SetupUIArgs()
#ifndef BITCOIN_QT_TEST
int main(int argc, char *argv[])
{
+#ifdef WIN32
+ util::WinCmdLineArgs winArgs;
+ std::tie(argc, argv) = winArgs.get();
+#endif
SetupEnvironment();
std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();
@@ -573,13 +580,6 @@ int main(int argc, char *argv[])
#ifdef Q_OS_MAC
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
#endif
-#if QT_VERSION >= 0x050500
- // Because of the POODLE attack it is recommended to disable SSLv3 (https://disablessl3.com/),
- // so set SSL protocols to TLS1.0+.
- QSslConfiguration sslconf = QSslConfiguration::defaultConfiguration();
- sslconf.setProtocol(QSsl::TlsV1_0OrLater);
- QSslConfiguration::setDefaultConfiguration(sslconf);
-#endif
// Register meta types used for QMetaObject::invokeMethod
qRegisterMetaType< bool* >();
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 51aff08c42..ef82351551 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -33,7 +33,7 @@
#include <interfaces/node.h>
#include <noui.h>
#include <ui_interface.h>
-#include <util.h>
+#include <util/system.h>
#include <iostream>
@@ -92,12 +92,8 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
windowTitle += tr("Node");
}
windowTitle += " " + networkStyle->getTitleAddText();
-#ifndef Q_OS_MAC
QApplication::setWindowIcon(networkStyle->getTrayAndWindowIcon());
setWindowIcon(networkStyle->getTrayAndWindowIcon());
-#else
- MacDockIconHandler::instance()->setIcon(networkStyle->getAppIcon());
-#endif
setWindowTitle(windowTitle);
rpcConsole = new RPCConsole(node, _platformStyle, 0);
@@ -131,7 +127,9 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
createToolBars();
// Create system tray icon and notification
- createTrayIcon(networkStyle);
+ if (QSystemTrayIcon::isSystemTrayAvailable()) {
+ createTrayIcon(networkStyle);
+ }
// Create status bar
statusBar();
@@ -211,6 +209,10 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
connect(progressBar, &GUIUtil::ClickableProgressBar::clicked, this, &BitcoinGUI::showModalOverlay);
}
#endif
+
+#ifdef Q_OS_MAC
+ m_app_nap_inhibitor = new CAppNapInhibitor;
+#endif
}
BitcoinGUI::~BitcoinGUI()
@@ -223,6 +225,7 @@ BitcoinGUI::~BitcoinGUI()
if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
trayIcon->hide();
#ifdef Q_OS_MAC
+ delete m_app_nap_inhibitor;
delete appMenuBar;
MacDockIconHandler::cleanup();
#endif
@@ -273,17 +276,17 @@ void BitcoinGUI::createActions()
#ifdef ENABLE_WALLET
// These showNormalIfMinimized are needed because Send Coins and Receive Coins
// can be triggered from the tray menu, and need to show the GUI to be useful.
- connect(overviewAction, &QAction::triggered, this, static_cast<void (BitcoinGUI::*)()>(&BitcoinGUI::showNormalIfMinimized));
+ connect(overviewAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(overviewAction, &QAction::triggered, this, &BitcoinGUI::gotoOverviewPage);
- connect(sendCoinsAction, &QAction::triggered, this, static_cast<void (BitcoinGUI::*)()>(&BitcoinGUI::showNormalIfMinimized));
+ connect(sendCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(sendCoinsAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); });
- connect(sendCoinsMenuAction, &QAction::triggered, this, static_cast<void (BitcoinGUI::*)()>(&BitcoinGUI::showNormalIfMinimized));
+ connect(sendCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(sendCoinsMenuAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); });
- connect(receiveCoinsAction, &QAction::triggered, this, static_cast<void (BitcoinGUI::*)()>(&BitcoinGUI::showNormalIfMinimized));
+ connect(receiveCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage);
- connect(receiveCoinsMenuAction, &QAction::triggered, this, static_cast<void (BitcoinGUI::*)()>(&BitcoinGUI::showNormalIfMinimized));
+ connect(receiveCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(receiveCoinsMenuAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage);
- connect(historyAction, &QAction::triggered, this, static_cast<void (BitcoinGUI::*)()>(&BitcoinGUI::showNormalIfMinimized));
+ connect(historyAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage);
#endif // ENABLE_WALLET
@@ -350,7 +353,9 @@ void BitcoinGUI::createActions()
connect(encryptWalletAction, &QAction::triggered, walletFrame, &WalletFrame::encryptWallet);
connect(backupWalletAction, &QAction::triggered, walletFrame, &WalletFrame::backupWallet);
connect(changePassphraseAction, &QAction::triggered, walletFrame, &WalletFrame::changePassphrase);
+ connect(signMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(signMessageAction, &QAction::triggered, [this]{ gotoSignMessageTab(); });
+ connect(verifyMessageAction, &QAction::triggered, [this]{ showNormalIfMinimized(); });
connect(verifyMessageAction, &QAction::triggered, [this]{ gotoVerifyMessageTab(); });
connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses);
connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedReceivingAddresses);
@@ -585,6 +590,8 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled)
void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
{
+ assert(QSystemTrayIcon::isSystemTrayAvailable());
+
#ifndef Q_OS_MAC
trayIcon = new QSystemTrayIcon(this);
QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
@@ -599,7 +606,7 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
void BitcoinGUI::createTrayIconMenu()
{
#ifndef Q_OS_MAC
- // return if trayIcon is unset (only on non-Mac OSes)
+ // return if trayIcon is unset (only on non-macOSes)
if (!trayIcon)
return;
@@ -608,27 +615,31 @@ void BitcoinGUI::createTrayIconMenu()
connect(trayIcon, &QSystemTrayIcon::activated, this, &BitcoinGUI::trayIconActivated);
#else
- // Note: On Mac, the dock icon is used to provide the tray's functionality.
+ // Note: On macOS, the Dock icon is used to provide the tray's functionality.
MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance();
- dockIconHandler->setMainWindow(static_cast<QMainWindow*>(this));
- trayIconMenu = dockIconHandler->dockMenu();
+ connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this, &BitcoinGUI::macosDockIconActivated);
+
+ trayIconMenu = new QMenu(this);
+ trayIconMenu->setAsDockMenu();
#endif
- // Configuration of the tray icon (or dock icon) icon menu
+ // Configuration of the tray icon (or Dock icon) menu
#ifndef Q_OS_MAC
- // Note: On Mac, the dock icon's menu already has show / hide action.
+ // Note: On macOS, the Dock icon's menu already has Show / Hide action.
trayIconMenu->addAction(toggleHideAction);
trayIconMenu->addSeparator();
#endif
- trayIconMenu->addAction(sendCoinsMenuAction);
- trayIconMenu->addAction(receiveCoinsMenuAction);
- trayIconMenu->addSeparator();
- trayIconMenu->addAction(signMessageAction);
- trayIconMenu->addAction(verifyMessageAction);
- trayIconMenu->addSeparator();
+ if (enableWallet) {
+ trayIconMenu->addAction(sendCoinsMenuAction);
+ trayIconMenu->addAction(receiveCoinsMenuAction);
+ trayIconMenu->addSeparator();
+ trayIconMenu->addAction(signMessageAction);
+ trayIconMenu->addAction(verifyMessageAction);
+ trayIconMenu->addSeparator();
+ trayIconMenu->addAction(openRPCConsoleAction);
+ }
trayIconMenu->addAction(optionsAction);
- trayIconMenu->addAction(openRPCConsoleAction);
-#ifndef Q_OS_MAC // This is built-in on Mac
+#ifndef Q_OS_MAC // This is built-in on macOS
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
#endif
@@ -643,6 +654,12 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
toggleHidden();
}
}
+#else
+void BitcoinGUI::macosDockIconActivated()
+{
+ show();
+ activateWindow();
+}
#endif
void BitcoinGUI::optionsClicked()
@@ -661,10 +678,7 @@ void BitcoinGUI::aboutClicked()
void BitcoinGUI::showDebugWindow()
{
- rpcConsole->showNormal();
- rpcConsole->show();
- rpcConsole->raise();
- rpcConsole->activateWindow();
+ GUIUtil::bringToFront(rpcConsole);
}
void BitcoinGUI::showDebugWindowActivateConsole()
@@ -784,6 +798,11 @@ void BitcoinGUI::openOptionsDialogWithTab(OptionsDialog::Tab tab)
void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header)
{
+// Disabling macOS App Nap on initial sync, disk and reindex operations.
+#ifdef Q_OS_MAC
+ (m_node.isInitialBlockDownload() || m_node.getReindex() || m_node.getImporting()) ? m_app_nap_inhibitor->disableAppNap() : m_app_nap_inhibitor->enableAppNap();
+#endif
+
if (modalOverlay)
{
if (header)
@@ -1146,24 +1165,11 @@ void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
if(!clientModel)
return;
- // activateWindow() (sometimes) helps with keyboard focus on Windows
- if (isHidden())
- {
- show();
- activateWindow();
- }
- else if (isMinimized())
- {
- showNormal();
- activateWindow();
- }
- else if (GUIUtil::isObscured(this))
- {
- raise();
- activateWindow();
- }
- else if(fToggleHidden)
+ if (!isHidden() && !isMinimized() && !GUIUtil::isObscured(this) && fToggleHidden) {
hide();
+ } else {
+ GUIUtil::bringToFront(this);
+ }
}
void BitcoinGUI::toggleHidden()
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index dcaca10557..e8b857c17c 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -20,6 +20,10 @@
#include <QPoint>
#include <QSystemTrayIcon>
+#ifdef Q_OS_MAC
+#include <qt/macos_appnap.h>
+#endif
+
#include <memory>
class ClientModel;
@@ -143,6 +147,10 @@ private:
HelpMessageDialog* helpMessageDialog = nullptr;
ModalOverlay* modalOverlay = nullptr;
+#ifdef Q_OS_MAC
+ CAppNapInhibitor* m_app_nap_inhibitor = nullptr;
+#endif
+
/** Keep track of previous number of blocks, to detect progress */
int prevBlocks = 0;
int spinnerFrame = 0;
@@ -260,6 +268,9 @@ public Q_SLOTS:
#ifndef Q_OS_MAC
/** Handle tray icon clicked */
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
+#else
+ /** Handle macOS Dock icon clicked */
+ void macosDockIconActivated();
#endif
/** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */
diff --git a/src/qt/callback.h b/src/qt/callback.h
deleted file mode 100644
index da6b0c4c2e..0000000000
--- a/src/qt/callback.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef BITCOIN_QT_CALLBACK_H
-#define BITCOIN_QT_CALLBACK_H
-
-#include <QObject>
-
-class Callback : public QObject
-{
- Q_OBJECT
-public Q_SLOTS:
- virtual void call() = 0;
-};
-
-template <typename F>
-class FunctionCallback : public Callback
-{
- F f;
-
-public:
- explicit FunctionCallback(F f_) : f(std::move(f_)) {}
- ~FunctionCallback() override {}
- void call() override { f(this); }
-};
-
-template <typename F>
-FunctionCallback<F>* makeCallback(F f)
-{
- return new FunctionCallback<F>(std::move(f));
-}
-
-#endif // BITCOIN_QT_CALLBACK_H
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index b2cf4b6399..75012b279c 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -20,7 +20,7 @@
#include <netbase.h>
#include <txmempool.h>
#include <ui_interface.h>
-#include <util.h>
+#include <util/system.h>
#include <warnings.h>
#include <stdint.h>
@@ -177,6 +177,11 @@ QString ClientModel::dataDir() const
return GUIUtil::boostPathToQString(GetDataDir());
}
+QString ClientModel::blocksDir() const
+{
+ return GUIUtil::boostPathToQString(GetBlocksDir());
+}
+
void ClientModel::updateBanlist()
{
banTableModel->refresh();
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index ed7ecbf73b..79e7074cca 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -69,6 +69,7 @@ public:
bool isReleaseVersion() const;
QString formatClientStartupTime() const;
QString dataDir() const;
+ QString blocksDir() const;
bool getProxyInfo(std::string& ip_port) const;
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 68330c51fa..ea970c0bc9 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -2,10 +2,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
#include <qt/coincontroldialog.h>
#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>
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 695ed61228..dca16d6f78 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -127,6 +127,9 @@
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
+ <property name="toolTip">
+ <string>To specify a non-default location of the data directory use the '%1' option.</string>
+ </property>
<property name="text">
<string>N/A</string>
</property>
@@ -142,13 +145,42 @@
</widget>
</item>
<item row="5" column="0">
+ <widget class="QLabel" name="label_11">
+ <property name="text">
+ <string>Blocksdir</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" colspan="2">
+ <widget class="QLabel" name="blocksDir">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="toolTip">
+ <string>To specify a non-default location of the blocks directory use the '%1' option.</string>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Startup time</string>
</property>
</widget>
</item>
- <item row="5" column="1" colspan="2">
+ <item row="6" column="1" colspan="2">
<widget class="QLabel" name="startupTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -164,7 +196,7 @@
</property>
</widget>
</item>
- <item row="6" column="0">
+ <item row="7" column="0">
<widget class="QLabel" name="labelNetwork">
<property name="font">
<font>
@@ -177,14 +209,14 @@
</property>
</widget>
</item>
- <item row="7" column="0">
+ <item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
- <item row="7" column="1" colspan="2">
+ <item row="8" column="1" colspan="2">
<widget class="QLabel" name="networkName">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -200,14 +232,14 @@
</property>
</widget>
</item>
- <item row="8" column="0">
+ <item row="9" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Number of connections</string>
</property>
</widget>
</item>
- <item row="8" column="1" colspan="2">
+ <item row="9" column="1" colspan="2">
<widget class="QLabel" name="numberOfConnections">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -223,7 +255,7 @@
</property>
</widget>
</item>
- <item row="9" column="0">
+ <item row="10" column="0">
<widget class="QLabel" name="label_10">
<property name="font">
<font>
@@ -236,14 +268,14 @@
</property>
</widget>
</item>
- <item row="10" column="0">
+ <item row="11" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Current number of blocks</string>
</property>
</widget>
</item>
- <item row="10" column="1" colspan="2">
+ <item row="11" column="1" colspan="2">
<widget class="QLabel" name="numberOfBlocks">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -259,14 +291,14 @@
</property>
</widget>
</item>
- <item row="11" column="0">
+ <item row="12" column="0">
<widget class="QLabel" name="labelLastBlockTime">
<property name="text">
<string>Last block time</string>
</property>
</widget>
</item>
- <item row="11" column="1" colspan="2">
+ <item row="12" column="1" colspan="2">
<widget class="QLabel" name="lastBlockTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -282,7 +314,7 @@
</property>
</widget>
</item>
- <item row="12" column="0">
+ <item row="13" column="0">
<widget class="QLabel" name="labelMempoolTitle">
<property name="font">
<font>
@@ -295,14 +327,14 @@
</property>
</widget>
</item>
- <item row="13" column="0">
+ <item row="14" column="0">
<widget class="QLabel" name="labelNumberOfTransactions">
<property name="text">
<string>Current number of transactions</string>
</property>
</widget>
</item>
- <item row="13" column="1">
+ <item row="14" column="1">
<widget class="QLabel" name="mempoolNumberTxs">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -318,14 +350,14 @@
</property>
</widget>
</item>
- <item row="14" column="0">
+ <item row="15" column="0">
<widget class="QLabel" name="labelMemoryUsage">
<property name="text">
<string>Memory usage</string>
</property>
</widget>
</item>
- <item row="14" column="1">
+ <item row="15" column="1">
<widget class="QLabel" name="mempoolSize">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -341,7 +373,7 @@
</property>
</widget>
</item>
- <item row="12" column="2" rowspan="3">
+ <item row="13" column="2" rowspan="3">
<layout class="QVBoxLayout" name="verticalLayoutDebugButton">
<property name="spacing">
<number>3</number>
@@ -381,7 +413,7 @@
</item>
</layout>
</item>
- <item row="15" column="0">
+ <item row="16" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index b894fc8166..b1cd2f77d0 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -18,7 +18,7 @@
#include <protocol.h>
#include <script/script.h>
#include <script/standard.h>
-#include <util.h>
+#include <util/system.h>
#ifdef WIN32
#ifdef _WIN32_WINNT
@@ -60,6 +60,14 @@
#include <QFontDatabase>
#endif
+#if defined(Q_OS_MAC)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#include <objc/objc-runtime.h>
+#include <CoreServices/CoreServices.h>
+#endif
+
namespace GUIUtil {
QString dateTimeStr(const QDateTime &date)
@@ -353,6 +361,27 @@ bool isObscured(QWidget *w)
&& checkPoint(QPoint(w->width() / 2, w->height() / 2), w));
}
+void bringToFront(QWidget* w)
+{
+#ifdef Q_OS_MAC
+ // Force application activation on macOS. With Qt 5.4 this is required when
+ // an action in the dock menu is triggered.
+ id app = objc_msgSend((id) objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
+ objc_msgSend(app, sel_registerName("activateIgnoringOtherApps:"), YES);
+#endif
+
+ if (w) {
+ // activateWindow() (sometimes) helps with keyboard focus on Windows
+ if (w->isMinimized()) {
+ w->showNormal();
+ } else {
+ w->show();
+ }
+ w->activateWindow();
+ w->raise();
+ }
+}
+
void openDebugLogfile()
{
fs::path pathDebug = GetDataDir() / "debug.log";
@@ -367,7 +396,7 @@ bool openBitcoinConf()
fs::path pathConfig = GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
/* Create the file */
- fs::ofstream configFile(pathConfig, std::ios_base::app);
+ fsbridge::ofstream configFile(pathConfig, std::ios_base::app);
if (!configFile.good())
return false;
@@ -611,7 +640,7 @@ fs::path static GetAutostartFilePath()
bool GetStartOnSystemStartup()
{
- fs::ifstream optionFile(GetAutostartFilePath());
+ fsbridge::ifstream optionFile(GetAutostartFilePath());
if (!optionFile.good())
return false;
// Scan through file for "Hidden=true":
@@ -642,7 +671,7 @@ bool SetStartOnSystemStartup(bool fAutoStart)
fs::create_directories(GetAutostartDir());
- fs::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
+ fsbridge::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc);
if (!optionFile.good())
return false;
std::string chain = gArgs.GetChainName();
@@ -663,13 +692,8 @@ bool SetStartOnSystemStartup(bool fAutoStart)
#elif defined(Q_OS_MAC)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
// based on: https://github.com/Mozketo/LaunchAtLoginController/blob/master/LaunchAtLoginController.m
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreServices/CoreServices.h>
-
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl);
LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl)
{
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 011827e134..f1d0aa48ef 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -115,6 +115,9 @@ namespace GUIUtil
// Determine whether a widget is hidden behind other windows
bool isObscured(QWidget *w);
+ // Activate, show and raise the widget
+ void bringToFront(QWidget* w);
+
// Open debug.log
void openDebugLogfile();
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index b19cc17a4d..0b61b05318 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -13,7 +13,7 @@
#include <qt/guiutil.h>
#include <interfaces/node.h>
-#include <util.h>
+#include <util/system.h>
#include <QFileDialog>
#include <QSettings>
diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h
index 1c28593d4a..ff867e21a7 100644
--- a/src/qt/macdockiconhandler.h
+++ b/src/qt/macdockiconhandler.h
@@ -1,44 +1,27 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// Copyright (c) 2011-2018 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_QT_MACDOCKICONHANDLER_H
#define BITCOIN_QT_MACDOCKICONHANDLER_H
-#include <QMainWindow>
#include <QObject>
-QT_BEGIN_NAMESPACE
-class QIcon;
-class QMenu;
-class QWidget;
-QT_END_NAMESPACE
-
-/** Macintosh-specific dock icon handler.
+/** macOS-specific Dock icon handler.
*/
class MacDockIconHandler : public QObject
{
Q_OBJECT
public:
- ~MacDockIconHandler();
-
- QMenu *dockMenu();
- void setIcon(const QIcon &icon);
- void setMainWindow(QMainWindow *window);
static MacDockIconHandler *instance();
static void cleanup();
- void handleDockIconClickEvent();
Q_SIGNALS:
void dockIconClicked();
private:
MacDockIconHandler();
-
- QWidget *m_dummyWidget;
- QMenu *m_dockMenu;
- QMainWindow *mainWindow;
};
#endif // BITCOIN_QT_MACDOCKICONHANDLER_H
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index b9ad191da7..102adce6c5 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -1,107 +1,36 @@
-// Copyright (c) 2011-2013 The Bitcoin Core developers
+// Copyright (c) 2011-2018 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 "macdockiconhandler.h"
-#include <QImageWriter>
-#include <QMenu>
-#include <QBuffer>
-#include <QWidget>
-
#undef slots
-#include <Cocoa/Cocoa.h>
#include <objc/objc.h>
#include <objc/message.h>
static MacDockIconHandler *s_instance = nullptr;
-bool dockClickHandler(id self,SEL _cmd,...) {
+bool dockClickHandler(id self, SEL _cmd, ...) {
Q_UNUSED(self)
Q_UNUSED(_cmd)
- s_instance->handleDockIconClickEvent();
+ Q_EMIT s_instance->dockIconClicked();
- // Return NO (false) to suppress the default OS X actions
+ // Return NO (false) to suppress the default macOS actions
return false;
}
void setupDockClickHandler() {
- Class cls = objc_getClass("NSApplication");
- id appInst = objc_msgSend((id)cls, sel_registerName("sharedApplication"));
-
- if (appInst != nullptr) {
- id delegate = objc_msgSend(appInst, sel_registerName("delegate"));
- Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
- SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
- if (class_getInstanceMethod(delClass, shouldHandle))
- class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:");
- else
- class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler,"B@:");
- }
+ id app = objc_msgSend((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
+ id delegate = objc_msgSend(app, sel_registerName("delegate"));
+ Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
+ SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
+ class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:");
}
-
MacDockIconHandler::MacDockIconHandler() : QObject()
{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
setupDockClickHandler();
- this->m_dummyWidget = new QWidget();
- this->m_dockMenu = new QMenu(this->m_dummyWidget);
- this->setMainWindow(nullptr);
-#if QT_VERSION >= 0x050200
- this->m_dockMenu->setAsDockMenu();
-#endif
- [pool release];
-}
-
-void MacDockIconHandler::setMainWindow(QMainWindow *window) {
- this->mainWindow = window;
-}
-
-MacDockIconHandler::~MacDockIconHandler()
-{
- delete this->m_dummyWidget;
- this->setMainWindow(nullptr);
-}
-
-QMenu *MacDockIconHandler::dockMenu()
-{
- return this->m_dockMenu;
-}
-
-void MacDockIconHandler::setIcon(const QIcon &icon)
-{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- NSImage *image = nil;
- if (icon.isNull())
- image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
- else {
- // generate NSImage from QIcon and use this as dock icon.
- QSize size = icon.actualSize(QSize(128, 128));
- QPixmap pixmap = icon.pixmap(size);
-
- // Write image into a R/W buffer from raw pixmap, then save the image.
- QBuffer notificationBuffer;
- if (!pixmap.isNull() && notificationBuffer.open(QIODevice::ReadWrite)) {
- QImageWriter writer(&notificationBuffer, "PNG");
- if (writer.write(pixmap.toImage())) {
- NSData* macImgData = [NSData dataWithBytes:notificationBuffer.buffer().data()
- length:notificationBuffer.buffer().size()];
- image = [[NSImage alloc] initWithData:macImgData];
- }
- }
-
- if(!image) {
- // if testnet image could not be created, load std. app icon
- image = [[NSImage imageNamed:@"NSApplicationIcon"] retain];
- }
- }
-
- [NSApp setApplicationIconImage:image];
- [image release];
- [pool release];
}
MacDockIconHandler *MacDockIconHandler::instance()
@@ -115,14 +44,3 @@ void MacDockIconHandler::cleanup()
{
delete s_instance;
}
-
-void MacDockIconHandler::handleDockIconClickEvent()
-{
- if (this->mainWindow)
- {
- this->mainWindow->activateWindow();
- this->mainWindow->show();
- }
-
- Q_EMIT this->dockIconClicked();
-}
diff --git a/src/qt/macos_appnap.h b/src/qt/macos_appnap.h
new file mode 100644
index 0000000000..8c2cd840b0
--- /dev/null
+++ b/src/qt/macos_appnap.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2011-2018 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_QT_MACOS_APPNAP_H
+#define BITCOIN_QT_MACOS_APPNAP_H
+
+#include <memory>
+
+class CAppNapInhibitor final
+{
+public:
+ explicit CAppNapInhibitor();
+ ~CAppNapInhibitor();
+
+ void disableAppNap();
+ void enableAppNap();
+
+private:
+ class CAppNapImpl;
+ std::unique_ptr<CAppNapImpl> impl;
+};
+
+#endif // BITCOIN_QT_MACOS_APPNAP_H
diff --git a/src/qt/macos_appnap.mm b/src/qt/macos_appnap.mm
new file mode 100644
index 0000000000..22a88782ab
--- /dev/null
+++ b/src/qt/macos_appnap.mm
@@ -0,0 +1,71 @@
+// Copyright (c) 2011-2018 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 "macos_appnap.h"
+
+#include <AvailabilityMacros.h>
+#include <Foundation/NSProcessInfo.h>
+#include <Foundation/Foundation.h>
+
+class CAppNapInhibitor::CAppNapImpl
+{
+public:
+ ~CAppNapImpl()
+ {
+ if(activityId)
+ enableAppNap();
+ }
+
+ void disableAppNap()
+ {
+ if (!activityId)
+ {
+ @autoreleasepool {
+ const NSActivityOptions activityOptions =
+ NSActivityUserInitiatedAllowingIdleSystemSleep &
+ ~(NSActivitySuddenTerminationDisabled |
+ NSActivityAutomaticTerminationDisabled);
+
+ id processInfo = [NSProcessInfo processInfo];
+ if ([processInfo respondsToSelector:@selector(beginActivityWithOptions:reason:)])
+ {
+ activityId = [processInfo beginActivityWithOptions: activityOptions reason:@"Temporarily disable App Nap for bitcoin-qt."];
+ [activityId retain];
+ }
+ }
+ }
+ }
+
+ void enableAppNap()
+ {
+ if(activityId)
+ {
+ @autoreleasepool {
+ id processInfo = [NSProcessInfo processInfo];
+ if ([processInfo respondsToSelector:@selector(endActivity:)])
+ [processInfo endActivity:activityId];
+
+ [activityId release];
+ activityId = nil;
+ }
+ }
+ }
+
+private:
+ NSObject* activityId;
+};
+
+CAppNapInhibitor::CAppNapInhibitor() : impl(new CAppNapImpl()) {}
+
+CAppNapInhibitor::~CAppNapInhibitor() = default;
+
+void CAppNapInhibitor::disableAppNap()
+{
+ impl->disableAppNap();
+}
+
+void CAppNapInhibitor::enableAppNap()
+{
+ impl->enableAppNap();
+}
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index b51322394f..c9871f6c66 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -23,6 +23,7 @@
#include <QIntValidator>
#include <QLocale>
#include <QMessageBox>
+#include <QSystemTrayIcon>
#include <QTimer>
OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
@@ -126,6 +127,13 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
connect(ui->proxyIpTor, &QValidatedLineEdit::validationDidChange, this, &OptionsDialog::updateProxyValidationState);
connect(ui->proxyPort, &QLineEdit::textChanged, this, &OptionsDialog::updateProxyValidationState);
connect(ui->proxyPortTor, &QLineEdit::textChanged, this, &OptionsDialog::updateProxyValidationState);
+
+ if (!QSystemTrayIcon::isSystemTrayAvailable()) {
+ ui->hideTrayIcon->setChecked(true);
+ ui->hideTrayIcon->setEnabled(false);
+ ui->minimizeToTray->setChecked(false);
+ ui->minimizeToTray->setEnabled(false);
+ }
}
OptionsDialog::~OptionsDialog()
@@ -211,8 +219,10 @@ void OptionsDialog::setMapper()
/* Window */
#ifndef Q_OS_MAC
- mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon);
- mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
+ if (QSystemTrayIcon::isSystemTrayAvailable()) {
+ mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon);
+ mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
+ }
mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
#endif
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index a989988c45..b962ab1ef2 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -9,7 +9,7 @@
#include <qt/paymentrequestplus.h>
-#include <util.h>
+#include <util/system.h>
#include <stdexcept>
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index bcafc8f859..8148986b51 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -2,6 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
#include <qt/paymentserver.h>
#include <qt/bitcoinunits.h>
@@ -13,7 +17,7 @@
#include <policy/policy.h>
#include <key_io.h>
#include <ui_interface.h>
-#include <util.h>
+#include <util/system.h>
#include <wallet/wallet.h>
#include <cstdlib>
@@ -45,6 +49,7 @@
const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
const QString BITCOIN_IPC_PREFIX("bitcoin:");
+#ifdef ENABLE_BIP70
// BIP70 payment protocol messages
const char* BIP70_MESSAGE_PAYMENTACK = "PaymentACK";
const char* BIP70_MESSAGE_PAYMENTREQUEST = "PaymentRequest";
@@ -52,21 +57,7 @@ const char* BIP70_MESSAGE_PAYMENTREQUEST = "PaymentRequest";
const char* BIP71_MIMETYPE_PAYMENT = "application/bitcoin-payment";
const char* BIP71_MIMETYPE_PAYMENTACK = "application/bitcoin-paymentack";
const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest";
-
-struct X509StoreDeleter {
- void operator()(X509_STORE* b) {
- X509_STORE_free(b);
- }
-};
-
-struct X509Deleter {
- void operator()(X509* b) { X509_free(b); }
-};
-
-namespace // Anon namespace
-{
- std::unique_ptr<X509_STORE, X509StoreDeleter> certStore;
-}
+#endif
//
// Create a name that is unique for:
@@ -93,94 +84,6 @@ static QString ipcServerName()
static QList<QString> savedPaymentRequests;
-static void ReportInvalidCertificate(const QSslCertificate& cert)
-{
- qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
-}
-
-//
-// Load OpenSSL's list of root certificate authorities
-//
-void PaymentServer::LoadRootCAs(X509_STORE* _store)
-{
- // Unit tests mostly use this, to pass in fake root CAs:
- if (_store)
- {
- certStore.reset(_store);
- return;
- }
-
- // Normal execution, use either -rootcertificates or system certs:
- certStore.reset(X509_STORE_new());
-
- // Note: use "-system-" default here so that users can pass -rootcertificates=""
- // and get 'I don't like X.509 certificates, don't trust anybody' behavior:
- QString certFile = QString::fromStdString(gArgs.GetArg("-rootcertificates", "-system-"));
-
- // Empty store
- if (certFile.isEmpty()) {
- qDebug() << QString("PaymentServer::%1: Payment request authentication via X.509 certificates disabled.").arg(__func__);
- return;
- }
-
- QList<QSslCertificate> certList;
-
- if (certFile != "-system-") {
- qDebug() << QString("PaymentServer::%1: Using \"%2\" as trusted root certificate.").arg(__func__).arg(certFile);
-
- certList = QSslCertificate::fromPath(certFile);
- // Use those certificates when fetching payment requests, too:
- QSslSocket::setDefaultCaCertificates(certList);
- } else
- certList = QSslSocket::systemCaCertificates();
-
- int nRootCerts = 0;
- const QDateTime currentTime = QDateTime::currentDateTime();
-
- for (const QSslCertificate& cert : certList) {
- // Don't log NULL certificates
- if (cert.isNull())
- continue;
-
- // Not yet active/valid, or expired certificate
- if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) {
- ReportInvalidCertificate(cert);
- continue;
- }
-
- // Blacklisted certificate
- if (cert.isBlacklisted()) {
- ReportInvalidCertificate(cert);
- continue;
- }
- QByteArray certData = cert.toDer();
- const unsigned char *data = (const unsigned char *)certData.data();
-
- std::unique_ptr<X509, X509Deleter> x509(d2i_X509(0, &data, certData.size()));
- if (x509 && X509_STORE_add_cert(certStore.get(), x509.get()))
- {
- // Note: X509_STORE increases the reference count to the X509 object,
- // we still have to release our reference to it.
- ++nRootCerts;
- }
- else
- {
- ReportInvalidCertificate(cert);
- continue;
- }
- }
- qWarning() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
-
- // Project for another day:
- // Fetch certificate revocation lists, and add them to certStore.
- // Issues to consider:
- // performance (start a thread to fetch in background?)
- // privacy (fetch through tor/proxy so IP address isn't revealed)
- // would it be easier to just use a compiled-in blacklist?
- // or use Qt's blacklist?
- // "certificate stapling" with server-side caching is more efficient
-}
-
//
// Sending to the server is done synchronously, at startup.
// If the server isn't already running, startup continues,
@@ -221,6 +124,7 @@ void PaymentServer::ipcParseCommandLine(interfaces::Node& node, int argc, char*
}
}
}
+#ifdef ENABLE_BIP70
else if (QFile::exists(arg)) // Filename
{
savedPaymentRequests.append(arg);
@@ -244,6 +148,7 @@ void PaymentServer::ipcParseCommandLine(interfaces::Node& node, int argc, char*
// GUI hasn't started yet so we can't pop up a message box.
qWarning() << "PaymentServer::ipcSendCommandLine: Payment request file does not exist: " << arg;
}
+#endif
}
}
@@ -290,12 +195,16 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
QObject(parent),
saveURIs(true),
uriServer(0),
- netManager(0),
optionsModel(0)
+#ifdef ENABLE_BIP70
+ ,netManager(0)
+#endif
{
+#ifdef ENABLE_BIP70
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
+#endif
// Install global event filter to catch QFileOpenEvents
// on Mac: sent when you click bitcoin: links
@@ -319,14 +228,18 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
}
else {
connect(uriServer, &QLocalServer::newConnection, this, &PaymentServer::handleURIConnection);
+#ifdef ENABLE_BIP70
connect(this, &PaymentServer::receivedPaymentACK, this, &PaymentServer::handlePaymentACK);
+#endif
}
}
}
PaymentServer::~PaymentServer()
{
+#ifdef ENABLE_BIP70
google::protobuf::ShutdownProtobufLibrary();
+#endif
}
//
@@ -349,33 +262,11 @@ bool PaymentServer::eventFilter(QObject *object, QEvent *event)
return QObject::eventFilter(object, event);
}
-void PaymentServer::initNetManager()
-{
- if (!optionsModel)
- return;
- delete netManager;
-
- // netManager is used to fetch paymentrequests given in bitcoin: URIs
- netManager = new QNetworkAccessManager(this);
-
- QNetworkProxy proxy;
-
- // Query active SOCKS5 proxy
- if (optionsModel->getProxySettings(proxy)) {
- netManager->setProxy(proxy);
-
- qDebug() << "PaymentServer::initNetManager: Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
- }
- else
- qDebug() << "PaymentServer::initNetManager: No active proxy server found.";
-
- connect(netManager, &QNetworkAccessManager::finished, this, &PaymentServer::netRequestFinished);
- connect(netManager, &QNetworkAccessManager::sslErrors, this, &PaymentServer::reportSslErrors);
-}
-
void PaymentServer::uiReady()
{
+#ifdef ENABLE_BIP70
initNetManager();
+#endif
saveURIs = false;
for (const QString& s : savedPaymentRequests)
@@ -403,6 +294,10 @@ void PaymentServer::handleURIOrFile(const QString& s)
QUrlQuery uri((QUrl(s)));
if (uri.hasQueryItem("r")) // payment request URI
{
+#ifdef ENABLE_BIP70
+ Q_EMIT message(tr("URI handling"),
+ tr("You are using a BIP70 URL which will be unsupported in the future."),
+ CClientUIInterface::ICON_WARNING);
QByteArray temp;
temp.append(uri.queryItemValue("r"));
QString decoded = QUrl::fromPercentEncoding(temp);
@@ -420,7 +315,11 @@ void PaymentServer::handleURIOrFile(const QString& s)
tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()),
CClientUIInterface::ICON_WARNING);
}
-
+#else
+ Q_EMIT message(tr("URI handling"),
+ tr("Cannot process payment request because BIP70 support was not compiled in."),
+ CClientUIInterface::ICON_WARNING);
+#endif
return;
}
else // normal URI
@@ -444,6 +343,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
}
}
+#ifdef ENABLE_BIP70
if (QFile::exists(s)) // payment request file
{
PaymentRequestPlus request;
@@ -459,6 +359,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
return;
}
+#endif
}
void PaymentServer::handleURIConnection()
@@ -481,6 +382,140 @@ void PaymentServer::handleURIConnection()
handleURIOrFile(msg);
}
+void PaymentServer::setOptionsModel(OptionsModel *_optionsModel)
+{
+ this->optionsModel = _optionsModel;
+}
+
+#ifdef ENABLE_BIP70
+struct X509StoreDeleter {
+ void operator()(X509_STORE* b) {
+ X509_STORE_free(b);
+ }
+};
+
+struct X509Deleter {
+ void operator()(X509* b) { X509_free(b); }
+};
+
+namespace // Anon namespace
+{
+ std::unique_ptr<X509_STORE, X509StoreDeleter> certStore;
+}
+
+static void ReportInvalidCertificate(const QSslCertificate& cert)
+{
+ qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
+}
+
+//
+// Load OpenSSL's list of root certificate authorities
+//
+void PaymentServer::LoadRootCAs(X509_STORE* _store)
+{
+ // Unit tests mostly use this, to pass in fake root CAs:
+ if (_store)
+ {
+ certStore.reset(_store);
+ return;
+ }
+
+ // Normal execution, use either -rootcertificates or system certs:
+ certStore.reset(X509_STORE_new());
+
+ // Note: use "-system-" default here so that users can pass -rootcertificates=""
+ // and get 'I don't like X.509 certificates, don't trust anybody' behavior:
+ QString certFile = QString::fromStdString(gArgs.GetArg("-rootcertificates", "-system-"));
+
+ // Empty store
+ if (certFile.isEmpty()) {
+ qDebug() << QString("PaymentServer::%1: Payment request authentication via X.509 certificates disabled.").arg(__func__);
+ return;
+ }
+
+ QList<QSslCertificate> certList;
+
+ if (certFile != "-system-") {
+ qDebug() << QString("PaymentServer::%1: Using \"%2\" as trusted root certificate.").arg(__func__).arg(certFile);
+
+ certList = QSslCertificate::fromPath(certFile);
+ // Use those certificates when fetching payment requests, too:
+ QSslSocket::setDefaultCaCertificates(certList);
+ } else
+ certList = QSslSocket::systemCaCertificates();
+
+ int nRootCerts = 0;
+ const QDateTime currentTime = QDateTime::currentDateTime();
+
+ for (const QSslCertificate& cert : certList) {
+ // Don't log NULL certificates
+ if (cert.isNull())
+ continue;
+
+ // Not yet active/valid, or expired certificate
+ if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) {
+ ReportInvalidCertificate(cert);
+ continue;
+ }
+
+ // Blacklisted certificate
+ if (cert.isBlacklisted()) {
+ ReportInvalidCertificate(cert);
+ continue;
+ }
+
+ QByteArray certData = cert.toDer();
+ const unsigned char *data = (const unsigned char *)certData.data();
+
+ std::unique_ptr<X509, X509Deleter> x509(d2i_X509(0, &data, certData.size()));
+ if (x509 && X509_STORE_add_cert(certStore.get(), x509.get()))
+ {
+ // Note: X509_STORE increases the reference count to the X509 object,
+ // we still have to release our reference to it.
+ ++nRootCerts;
+ }
+ else
+ {
+ ReportInvalidCertificate(cert);
+ continue;
+ }
+ }
+ qWarning() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
+
+ // Project for another day:
+ // Fetch certificate revocation lists, and add them to certStore.
+ // Issues to consider:
+ // performance (start a thread to fetch in background?)
+ // privacy (fetch through tor/proxy so IP address isn't revealed)
+ // would it be easier to just use a compiled-in blacklist?
+ // or use Qt's blacklist?
+ // "certificate stapling" with server-side caching is more efficient
+}
+
+void PaymentServer::initNetManager()
+{
+ if (!optionsModel)
+ return;
+ delete netManager;
+
+ // netManager is used to fetch paymentrequests given in bitcoin: URIs
+ netManager = new QNetworkAccessManager(this);
+
+ QNetworkProxy proxy;
+
+ // Query active SOCKS5 proxy
+ if (optionsModel->getProxySettings(proxy)) {
+ netManager->setProxy(proxy);
+
+ qDebug() << "PaymentServer::initNetManager: Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
+ }
+ else
+ qDebug() << "PaymentServer::initNetManager: No active proxy server found.";
+
+ connect(netManager, &QNetworkAccessManager::finished, this, &PaymentServer::netRequestFinished);
+ connect(netManager, &QNetworkAccessManager::sslErrors, this, &PaymentServer::reportSslErrors);
+}
+
//
// Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine()
// so don't use "Q_EMIT message()", but "QMessageBox::"!
@@ -731,11 +766,6 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError>
Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
}
-void PaymentServer::setOptionsModel(OptionsModel *_optionsModel)
-{
- this->optionsModel = _optionsModel;
-}
-
void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
{
// currently we don't further process or store the paymentACK message
@@ -794,3 +824,4 @@ X509_STORE* PaymentServer::getCertStore()
{
return certStore.get();
}
+#endif
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index d335db9c85..30b5bc3b6d 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -32,7 +32,13 @@
// sends them to the server.
//
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#ifdef ENABLE_BIP70
#include <qt/paymentrequestplus.h>
+#endif
#include <qt/walletmodel.h>
#include <QObject>
@@ -73,6 +79,10 @@ public:
explicit PaymentServer(QObject* parent, bool startLocalServer = true);
~PaymentServer();
+ // OptionsModel is used for getting proxy settings and display unit
+ void setOptionsModel(OptionsModel *optionsModel);
+
+#ifdef ENABLE_BIP70
// Load root certificate authorities. Pass nullptr (default)
// to read from the file specified in the -rootcertificates setting,
// or, if that's not set, to use the system default root certificates.
@@ -83,9 +93,6 @@ public:
// Return certificate store
static X509_STORE* getCertStore();
- // OptionsModel is used for getting proxy settings and display unit
- void setOptionsModel(OptionsModel *optionsModel);
-
// Verify that the payment request network matches the client network
static bool verifyNetwork(interfaces::Node& node, const payments::PaymentDetails& requestDetails);
// Verify if the payment request is expired
@@ -94,33 +101,40 @@ public:
static bool verifySize(qint64 requestSize);
// Verify the payment request amount is valid
static bool verifyAmount(const CAmount& requestAmount);
+#endif
Q_SIGNALS:
// Fired when a valid payment request is received
void receivedPaymentRequest(SendCoinsRecipient);
- // Fired when a valid PaymentACK is received
- void receivedPaymentACK(const QString &paymentACKMsg);
-
// Fired when a message should be reported to the user
void message(const QString &title, const QString &message, unsigned int style);
+#ifdef ENABLE_BIP70
+ // Fired when a valid PaymentACK is received
+ void receivedPaymentACK(const QString &paymentACKMsg);
+#endif
+
public Q_SLOTS:
// Signal this when the main window's UI is ready
// to display payment requests to the user
void uiReady();
- // Submit Payment message to a merchant, get back PaymentACK:
- void fetchPaymentACK(WalletModel* walletModel, const SendCoinsRecipient& recipient, QByteArray transaction);
-
// Handle an incoming URI, URI with local file scheme or file
void handleURIOrFile(const QString& s);
+#ifdef ENABLE_BIP70
+ // Submit Payment message to a merchant, get back PaymentACK:
+ void fetchPaymentACK(WalletModel* walletModel, const SendCoinsRecipient& recipient, QByteArray transaction);
+#endif
+
private Q_SLOTS:
void handleURIConnection();
+#ifdef ENABLE_BIP70
void netRequestFinished(QNetworkReply*);
void reportSslErrors(QNetworkReply*, const QList<QSslError> &);
void handlePaymentACK(const QString& paymentACKMsg);
+#endif
protected:
// Constructor registers this on the parent QApplication to
@@ -128,19 +142,19 @@ protected:
bool eventFilter(QObject *object, QEvent *event);
private:
+ bool saveURIs; // true during startup
+ QLocalServer* uriServer;
+ OptionsModel *optionsModel;
+
+#ifdef ENABLE_BIP70
static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request);
bool processPaymentRequest(const PaymentRequestPlus& request, SendCoinsRecipient& recipient);
void fetchRequest(const QUrl& url);
// Setup networking
void initNetManager();
-
- bool saveURIs; // true during startup
- QLocalServer* uriServer;
-
QNetworkAccessManager* netManager; // Used to fetch payment requests
-
- OptionsModel *optionsModel;
+#endif
};
#endif // BITCOIN_QT_PAYMENTSERVER_H
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 3857befdf2..606f1d2910 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -18,7 +18,7 @@
#include <netbase.h>
#include <rpc/server.h>
#include <rpc/client.h>
-#include <util.h>
+#include <util/system.h>
#include <openssl/crypto.h>
@@ -459,6 +459,9 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
}
+ 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)));
if (platformStyle->getImagesOnButtons()) {
@@ -536,6 +539,7 @@ bool RPCConsole::eventFilter(QObject* obj, QEvent *event)
// forward these events to lineEdit
if(obj == autoCompleter->popup()) {
QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt));
+ autoCompleter->popup()->hide();
return true;
}
break;
@@ -661,6 +665,7 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->clientVersion->setText(model->formatFullVersion());
ui->clientUserAgent->setText(model->formatSubVersion());
ui->dataDir->setText(model->dataDir());
+ ui->blocksDir->setText(model->blocksDir());
ui->startupTime->setText(model->formatClientStartupTime());
ui->networkName->setText(QString::fromStdString(Params().NetworkIDString()));
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 6f66bc19e1..858128f9f9 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -2,6 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
#include <qt/sendcoinsdialog.h>
#include <qt/forms/ui_sendcoinsdialog.h>
@@ -290,7 +294,9 @@ void SendCoinsDialog::on_sendButton_clicked()
QString recipientElement;
recipientElement = "<br />";
+#ifdef ENABLE_BIP70
if (!rcp.paymentRequest.IsInitialized()) // normal payment
+#endif
{
if(rcp.label.length() > 0) // label with address
{
@@ -302,6 +308,7 @@ void SendCoinsDialog::on_sendButton_clicked()
recipientElement.append(tr("%1 to %2").arg(amount, address));
}
}
+#ifdef ENABLE_BIP70
else if(!rcp.authenticatedMerchant.isEmpty()) // authenticated payment request
{
recipientElement.append(tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.authenticatedMerchant)));
@@ -310,6 +317,7 @@ void SendCoinsDialog::on_sendButton_clicked()
{
recipientElement.append(tr("%1 to %2").arg(amount, address));
}
+#endif
formatted.append(recipientElement);
}
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index b394ff3150..76c942c8b9 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -2,6 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
#include <qt/sendcoinsentry.h>
#include <qt/forms/ui_sendcoinsentry.h>
@@ -133,9 +137,11 @@ bool SendCoinsEntry::validate(interfaces::Node& node)
// Check input validity
bool retval = true;
+#ifdef ENABLE_BIP70
// Skip checks for payment request
if (recipient.paymentRequest.IsInitialized())
return retval;
+#endif
if (!model->validateAddress(ui->payTo->text()))
{
@@ -166,9 +172,11 @@ bool SendCoinsEntry::validate(interfaces::Node& node)
SendCoinsRecipient SendCoinsEntry::getValue()
{
+#ifdef ENABLE_BIP70
// Payment request
if (recipient.paymentRequest.IsInitialized())
return recipient;
+#endif
// Normal payment
recipient.address = ui->payTo->text();
@@ -196,6 +204,7 @@ void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
{
recipient = value;
+#ifdef ENABLE_BIP70
if (recipient.paymentRequest.IsInitialized()) // payment request
{
if (recipient.authenticatedMerchant.isEmpty()) // unauthenticated
@@ -216,6 +225,7 @@ void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
}
}
else // normal payment
+#endif
{
// message
ui->messageTextLabel->setText(recipient.message);
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 1eff4f6b65..b6235e91f7 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -15,7 +15,7 @@
#include <interfaces/node.h>
#include <interfaces/wallet.h>
#include <ui_interface.h>
-#include <util.h>
+#include <util/system.h>
#include <version.h>
#include <QApplication>
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index c3d33c76d4..3e414df1f0 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -2,21 +2,22 @@
#include <qt/test/util.h>
#include <test/test_bitcoin.h>
+#include <interfaces/chain.h>
#include <interfaces/node.h>
#include <qt/addressbookpage.h>
#include <qt/addresstablemodel.h>
#include <qt/editaddressdialog.h>
-#include <qt/callback.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/qvalidatedlineedit.h>
#include <qt/walletmodel.h>
#include <key.h>
-#include <pubkey.h>
#include <key_io.h>
+#include <pubkey.h>
#include <wallet/wallet.h>
+#include <QApplication>
#include <QTimer>
#include <QMessageBox>
@@ -56,7 +57,8 @@ void EditAddressAndSubmit(
void TestAddAddressesToSendBook()
{
TestChain100Setup test;
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("mock", WalletDatabase::CreateMock());
+ auto chain = interfaces::MakeChain();
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateMock());
bool firstRun;
wallet->LoadWallet(firstRun);
@@ -139,5 +141,16 @@ void TestAddAddressesToSendBook()
void AddressBookTests::addressBookTests()
{
+#ifdef Q_OS_MAC
+ if (QApplication::platformName() == "minimal") {
+ // Disable for mac on "minimal" platform to avoid crashes inside the Qt
+ // framework when it tries to look up unimplemented cocoa functions,
+ // and fails to handle returned nulls
+ // (https://bugreports.qt.io/browse/QTBUG-49686).
+ QWARN("Skipping AddressBookTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
+ "with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build.");
+ return;
+ }
+#endif
TestAddAddressesToSendBook();
}
diff --git a/src/qt/test/compattests.cpp b/src/qt/test/compattests.cpp
index af5c69ea9a..6750c543da 100644
--- a/src/qt/test/compattests.cpp
+++ b/src/qt/test/compattests.cpp
@@ -2,7 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#if defined(ENABLE_WALLET) && defined(ENABLE_BIP70)
#include <qt/paymentrequestplus.h> // this includes protobuf's port.h which defines its own bswap macos
+#endif
#include <qt/test/compattests.h>
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index 5384b9e8b0..94907595f5 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -13,8 +13,8 @@
#include <random.h>
#include <script/script.h>
#include <script/standard.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index 2e321c1ba1..ed453336da 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -14,7 +14,7 @@
#include <qt/rpcconsole.h>
#include <test/test_bitcoin.h>
#include <univalue.h>
-#include <util.h>
+#include <util/system.h>
#include <QDir>
#include <QtGlobal>
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index df65a85fb5..b6523604fd 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -8,15 +8,17 @@
#include <chainparams.h>
#include <qt/test/rpcnestedtests.h>
-#include <util.h>
+#include <util/system.h>
#include <qt/test/uritests.h>
#include <qt/test/compattests.h>
#ifdef ENABLE_WALLET
#include <qt/test/addressbooktests.h>
+#ifdef ENABLE_BIP70
#include <qt/test/paymentservertests.h>
+#endif // ENABLE_BIP70
#include <qt/test/wallettests.h>
-#endif
+#endif // ENABLE_WALLET
#include <QApplication>
#include <QObject>
@@ -74,7 +76,7 @@ int main(int argc, char *argv[])
if (QTest::qExec(&test1) != 0) {
fInvalid = true;
}
-#ifdef ENABLE_WALLET
+#if defined(ENABLE_WALLET) && defined(ENABLE_BIP70)
PaymentServerTests test2;
if (QTest::qExec(&test2) != 0) {
fInvalid = true;
diff --git a/src/qt/test/util.cpp b/src/qt/test/util.cpp
index 0bd719326e..ae2fb93bf7 100644
--- a/src/qt/test/util.cpp
+++ b/src/qt/test/util.cpp
@@ -1,15 +1,13 @@
-#include <qt/callback.h>
-
#include <QApplication>
#include <QMessageBox>
-#include <QTimer>
-#include <QString>
#include <QPushButton>
+#include <QString>
+#include <QTimer>
#include <QWidget>
void ConfirmMessage(QString* text, int msec)
{
- QTimer::singleShot(msec, makeCallback([text](Callback* callback) {
+ QTimer::singleShot(msec, [text]() {
for (QWidget* widget : QApplication::topLevelWidgets()) {
if (widget->inherits("QMessageBox")) {
QMessageBox* messageBox = qobject_cast<QMessageBox*>(widget);
@@ -17,6 +15,5 @@ void ConfirmMessage(QString* text, int msec)
messageBox->defaultButton()->click();
}
}
- delete callback;
- }), &Callback::call);
+ });
}
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index a0cfe8ae87..f02fd8aea7 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -1,9 +1,10 @@
#include <qt/test/wallettests.h>
#include <qt/test/util.h>
+#include <interfaces/chain.h>
#include <interfaces/node.h>
+#include <base58.h>
#include <qt/bitcoinamountfield.h>
-#include <qt/callback.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/qvalidatedlineedit.h>
@@ -39,7 +40,7 @@ namespace
//! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
void ConfirmSend(QString* text = nullptr, bool cancel = false)
{
- QTimer::singleShot(0, makeCallback([text, cancel](Callback* callback) {
+ QTimer::singleShot(0, [text, cancel]() {
for (QWidget* widget : QApplication::topLevelWidgets()) {
if (widget->inherits("SendConfirmationDialog")) {
SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
@@ -49,8 +50,7 @@ void ConfirmSend(QString* text = nullptr, bool cancel = false)
button->click();
}
}
- delete callback;
- }), &Callback::call);
+ });
}
//! Send coins to address and return txid.
@@ -133,7 +133,8 @@ void TestGUI()
for (int i = 0; i < 5; ++i) {
test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
}
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("mock", WalletDatabase::CreateMock());
+ auto chain = interfaces::MakeChain();
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateMock());
bool firstRun;
wallet->LoadWallet(firstRun);
{
@@ -142,7 +143,7 @@ void TestGUI()
wallet->AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
}
{
- LOCK(cs_main);
+ auto locked_chain = wallet->chain().lock();
WalletRescanReserver reserver(wallet.get());
reserver.reserve();
wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, true);
@@ -243,5 +244,16 @@ void TestGUI()
void WalletTests::walletTests()
{
+#ifdef Q_OS_MAC
+ if (QApplication::platformName() == "minimal") {
+ // Disable for mac on "minimal" platform to avoid crashes inside the Qt
+ // framework when it tries to look up unimplemented cocoa functions,
+ // and fails to handle returned nulls
+ // (https://bugreports.qt.io/browse/QTBUG-49686).
+ QWARN("Skipping WalletTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
+ "with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build.");
+ return;
+ }
+#endif
TestGUI();
}
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 59332be754..0d070d9e87 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -2,6 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifdef HAVE_CONFIG_H
+#include <config/bitcoin-config.h>
+#endif
+
#include <qt/transactiondesc.h>
#include <qt/bitcoinunits.h>
@@ -15,7 +19,7 @@
#include <validation.h>
#include <script/script.h>
#include <timedata.h>
-#include <util.h>
+#include <util/system.h>
#include <wallet/db.h>
#include <wallet/wallet.h>
#include <policy/policy.h>
@@ -23,7 +27,7 @@
#include <stdint.h>
#include <string>
-QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks, int64_t adjustedTime)
+QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks)
{
if (!status.is_final)
{
@@ -49,11 +53,10 @@ QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const i
QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit)
{
int numBlocks;
- int64_t adjustedTime;
interfaces::WalletTxStatus status;
interfaces::WalletOrderForm orderForm;
bool inMempool;
- interfaces::WalletTx wtx = wallet.getWalletTxDetails(rec->hash, status, orderForm, inMempool, numBlocks, adjustedTime);
+ interfaces::WalletTx wtx = wallet.getWalletTxDetails(rec->hash, status, orderForm, inMempool, numBlocks);
QString strHTML;
@@ -65,7 +68,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
CAmount nDebit = wtx.debit;
CAmount nNet = nCredit - nDebit;
- strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx, status, inMempool, numBlocks, adjustedTime);
+ strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx, status, inMempool, numBlocks);
strHTML += "<br>";
strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
@@ -257,6 +260,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
if (r.first == "Message")
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
+#ifdef ENABLE_BIP70
//
// PaymentRequest info:
//
@@ -271,6 +275,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
strHTML += "<b>" + tr("Merchant") + ":</b> " + GUIUtil::HtmlEscape(merchant) + "<br>";
}
}
+#endif
if (wtx.is_coinbase)
{
diff --git a/src/qt/transactiondesc.h b/src/qt/transactiondesc.h
index 80eca7b97c..cf955a433c 100644
--- a/src/qt/transactiondesc.h
+++ b/src/qt/transactiondesc.h
@@ -29,7 +29,7 @@ public:
private:
TransactionDesc() {}
- static QString FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks, int64_t adjustedTime);
+ static QString FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks);
};
#endif // BITCOIN_QT_TRANSACTIONDESC_H
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index d1a7527ac7..d88cfe52ed 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -158,7 +158,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface
return parts;
}
-void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t adjustedTime)
+void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks)
{
// Determine transaction status
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index e187309d3f..470f70e2ab 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -138,7 +138,7 @@ public:
/** Update status from core wallet tx.
*/
- void updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks, int64_t adjustedTime);
+ void updateStatus(const interfaces::WalletTxStatus& wtx, int numBlocks);
/** Return whether a status update is needed.
*/
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index b4be068904..1983c3bc92 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -18,7 +18,7 @@
#include <interfaces/node.h>
#include <sync.h>
#include <uint256.h>
-#include <util.h>
+#include <util/system.h>
#include <validation.h>
#include <QColor>
@@ -193,9 +193,8 @@ public:
// simply re-use the cached status.
interfaces::WalletTxStatus wtx;
int numBlocks;
- int64_t adjustedTime;
- if (wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, adjustedTime) && rec->statusUpdateNeeded(numBlocks)) {
- rec->updateStatus(wtx, numBlocks, adjustedTime);
+ if (wallet.tryGetTxStatus(rec->hash, wtx, numBlocks) && rec->statusUpdateNeeded(numBlocks)) {
+ rec->updateStatus(wtx, numBlocks);
}
return rec;
}
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 6d08a3b0fb..68410c8bd6 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -106,7 +106,11 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
} else {
amountWidget->setFixedWidth(100);
}
- amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
+ QDoubleValidator *amountValidator = new QDoubleValidator(0, 1e20, 8, this);
+ QLocale amountLocale(QLocale::C);
+ amountLocale.setNumberOptions(QLocale::RejectGroupSeparator);
+ amountValidator->setLocale(amountLocale);
+ amountWidget->setValidator(amountValidator);
hlayout->addWidget(amountWidget);
// Delay before filtering transactions in ms
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 7d903b3b1c..ebf7bad795 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -14,13 +14,15 @@
#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.h>
+#include <util/system.h>
#include <stdio.h>
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index f7cc94ae32..353da0c9b4 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -2,6 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
#include <qt/walletmodel.h>
#include <qt/addresstablemodel.h>
@@ -16,7 +20,7 @@
#include <interfaces/node.h>
#include <key_io.h>
#include <ui_interface.h>
-#include <util.h> // for GetBoolArg
+#include <util/system.h> // for GetBoolArg
#include <wallet/coincontrol.h>
#include <wallet/wallet.h>
@@ -142,6 +146,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
if (rcp.fSubtractFeeFromAmount)
fSubtractFeeFromAmount = true;
+#ifdef ENABLE_BIP70
if (rcp.paymentRequest.IsInitialized())
{ // PaymentRequest...
CAmount subtotal = 0;
@@ -164,6 +169,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
total += subtotal;
}
else
+#endif
{ // User-entered bitcoin address / amount:
if(!validateAddress(rcp.address))
{
@@ -235,6 +241,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
std::vector<std::pair<std::string, std::string>> vOrderForm;
for (const SendCoinsRecipient &rcp : transaction.getRecipients())
{
+#ifdef ENABLE_BIP70
if (rcp.paymentRequest.IsInitialized())
{
// Make sure any payment requests involved are still valid.
@@ -247,7 +254,9 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
rcp.paymentRequest.SerializeToString(&value);
vOrderForm.emplace_back("PaymentRequest", std::move(value));
}
- else if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
+ else
+#endif
+ if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example)
vOrderForm.emplace_back("Message", rcp.message.toStdString());
}
@@ -266,7 +275,9 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
for (const SendCoinsRecipient &rcp : transaction.getRecipients())
{
// Don't touch the address book when we have a payment request
+#ifdef ENABLE_BIP70
if (!rcp.paymentRequest.IsInitialized())
+#endif
{
std::string strAddress = rcp.address.toStdString();
CTxDestination dest = DecodeDestination(strAddress);
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index b22728c69b..ec4c5a2a6c 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -10,7 +10,13 @@
#include <serialize.h>
#include <script/standard.h>
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#ifdef ENABLE_BIP70
#include <qt/paymentrequestplus.h>
+#endif
#include <qt/walletmodeltransaction.h>
#include <interfaces/wallet.h>
@@ -63,8 +69,14 @@ public:
// If from a payment request, this is used for storing the memo
QString message;
+#ifdef ENABLE_BIP70
// If from a payment request, paymentRequest.IsInitialized() will be true
PaymentRequestPlus paymentRequest;
+#else
+ // If building with BIP70 is disabled, keep the payment request around as
+ // serialized string to ensure load/store is lossless
+ std::string sPaymentRequest;
+#endif
// Empty if no authentication or invalid signature/cert/etc.
QString authenticatedMerchant;
@@ -80,9 +92,11 @@ public:
std::string sAddress = address.toStdString();
std::string sLabel = label.toStdString();
std::string sMessage = message.toStdString();
+#ifdef ENABLE_BIP70
std::string sPaymentRequest;
if (!ser_action.ForRead() && paymentRequest.IsInitialized())
paymentRequest.SerializeToString(&sPaymentRequest);
+#endif
std::string sAuthenticatedMerchant = authenticatedMerchant.toStdString();
READWRITE(this->nVersion);
@@ -98,8 +112,10 @@ public:
address = QString::fromStdString(sAddress);
label = QString::fromStdString(sLabel);
message = QString::fromStdString(sMessage);
+#ifdef ENABLE_BIP70
if (!sPaymentRequest.empty())
paymentRequest.parse(QByteArray::fromRawData(sPaymentRequest.data(), sPaymentRequest.size()));
+#endif
authenticatedMerchant = QString::fromStdString(sAuthenticatedMerchant);
}
}
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index de50616499..eb3b0baf08 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -2,6 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifdef HAVE_CONFIG_H
+#include <config/bitcoin-config.h>
+#endif
+
#include <qt/walletmodeltransaction.h>
#include <interfaces/node.h>
@@ -46,6 +50,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
{
SendCoinsRecipient& rcp = (*it);
+#ifdef ENABLE_BIP70
if (rcp.paymentRequest.IsInitialized())
{
CAmount subtotal = 0;
@@ -62,6 +67,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
rcp.amount = subtotal;
}
else // normal recipient (no payment request)
+#endif
{
if (i == nChangePosRet)
i++;
diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h
index 75ede2e2a1..289aee847b 100644
--- a/src/qt/walletmodeltransaction.h
+++ b/src/qt/walletmodeltransaction.h
@@ -8,6 +8,7 @@
#include <qt/walletmodel.h>
#include <memory>
+#include <amount.h>
#include <QObject>
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 053e951921..a619992344 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -292,9 +292,7 @@ void WalletView::usedSendingAddresses()
if(!walletModel)
return;
- usedSendingAddressesPage->show();
- usedSendingAddressesPage->raise();
- usedSendingAddressesPage->activateWindow();
+ GUIUtil::bringToFront(usedSendingAddressesPage);
}
void WalletView::usedReceivingAddresses()
@@ -302,9 +300,7 @@ void WalletView::usedReceivingAddresses()
if(!walletModel)
return;
- usedReceivingAddressesPage->show();
- usedReceivingAddressesPage->raise();
- usedReceivingAddressesPage->activateWindow();
+ GUIUtil::bringToFront(usedReceivingAddressesPage);
}
void WalletView::showProgress(const QString &title, int nProgress)
diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp
index d732326b33..08cae76add 100644
--- a/src/qt/winshutdownmonitor.cpp
+++ b/src/qt/winshutdownmonitor.cpp
@@ -6,7 +6,7 @@
#if defined(Q_OS_WIN)
#include <shutdown.h>
-#include <util.h>
+#include <util/system.h>
#include <windows.h>
diff --git a/src/random.cpp b/src/random.cpp
index 503d5b3636..a34c70e1d5 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -13,7 +13,7 @@
#endif
#include <logging.h> // for LogPrint()
#include <sync.h> // for WAIT_LOCK
-#include <utiltime.h> // for GetTime()
+#include <util/time.h> // for GetTime()
#include <stdlib.h>
#include <chrono>
@@ -35,7 +35,7 @@
#include <sys/random.h>
#endif
#ifdef HAVE_SYSCTL_ARND
-#include <utilstrencodings.h> // for ARRAYLEN
+#include <util/strencodings.h> // for ARRAYLEN
#include <sys/sysctl.h>
#endif
diff --git a/src/rest.cpp b/src/rest.cpp
index 1850c0b7a6..6c7e0384cb 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -16,7 +16,7 @@
#include <streams.h>
#include <sync.h>
#include <txmempool.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <version.h>
#include <boost/algorithm/string.hpp>
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 1eca0277b0..92f6f0fe11 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -26,8 +26,8 @@
#include <sync.h>
#include <txdb.h>
#include <txmempool.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <hash.h>
#include <validationinterface.h>
#include <versionbitsinfo.h>
@@ -182,7 +182,7 @@ static UniValue getbestblockhash(const JSONRPCRequest& request)
"getbestblockhash\n"
"\nReturns the hash of the best (tip) block in the longest blockchain.\n"
"\nResult:\n"
- "\"hex\" (string) the block hash hex encoded\n"
+ "\"hex\" (string) the block hash, hex-encoded\n"
"\nExamples:\n"
+ HelpExampleCli("getbestblockhash", "")
+ HelpExampleRpc("getbestblockhash", "")
@@ -509,17 +509,17 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw std::runtime_error(
- "getmempoolancestors txid (verbose)\n"
+ "getmempoolancestors txid ( verbose )\n"
"\nIf txid is in the mempool, returns all in-mempool ancestors.\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
"2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
- "\nResult (for verbose=false):\n"
+ "\nResult (for verbose = false):\n"
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool ancestor transaction\n"
" ,...\n"
"]\n"
- "\nResult (for verbose=true):\n"
+ "\nResult (for verbose = true):\n"
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
+ EntryDescriptionString()
@@ -573,17 +573,17 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw std::runtime_error(
- "getmempooldescendants txid (verbose)\n"
+ "getmempooldescendants txid ( verbose )\n"
"\nIf txid is in the mempool, returns all in-mempool descendants.\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id (must be in mempool)\n"
"2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n"
- "\nResult (for verbose=false):\n"
+ "\nResult (for verbose = false):\n"
"[ (json array of strings)\n"
" \"transactionid\" (string) The transaction id of an in-mempool descendant transaction\n"
" ,...\n"
"]\n"
- "\nResult (for verbose=true):\n"
+ "\nResult (for verbose = true):\n"
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
+ EntryDescriptionString()
@@ -700,7 +700,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
"If verbose is true, returns an Object with information about blockheader <hash>.\n"
"\nArguments:\n"
"1. \"hash\" (string, required) The block hash\n"
- "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"
+ "2. verbose (boolean, optional, default=true) true for a json object, false for the hex-encoded data\n"
"\nResult (for verbose = true):\n"
"{\n"
" \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
@@ -779,7 +779,7 @@ static UniValue getblock(const JSONRPCRequest& request)
"If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n"
"\nArguments:\n"
"1. \"blockhash\" (string, required) The block hash\n"
- "2. verbosity (numeric, optional, default=1) 0 for hex encoded data, 1 for a json object, and 2 for json object with transaction data\n"
+ "2. verbosity (numeric, optional, default=1) 0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data\n"
"\nResult (for verbosity = 0):\n"
"\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
"\nResult (for verbosity = 1):\n"
@@ -1046,7 +1046,7 @@ UniValue gettxout(const JSONRPCRequest& request)
+ HelpExampleCli("listunspent", "") +
"\nView the details\n"
+ HelpExampleCli("gettxout", "\"txid\" 1") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("gettxout", "\"txid\", 1")
);
@@ -1798,6 +1798,10 @@ static UniValue getblockstats(const JSONRPCRequest& request)
const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate");
const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight");
+ if (loop_inputs && !g_txindex) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more of the selected stats requires -txindex enabled");
+ }
+
CAmount maxfee = 0;
CAmount maxfeerate = 0;
CAmount minfee = MAX_MONEY;
@@ -1861,10 +1865,6 @@ static UniValue getblockstats(const JSONRPCRequest& request)
}
if (loop_inputs) {
-
- if (!g_txindex) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more of the selected stats requires -txindex enabled");
- }
CAmount tx_total_in = 0;
for (const CTxIn& in : tx->vin) {
CTransactionRef tx_in;
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 649e222c39..2b99808c07 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -5,7 +5,7 @@
#include <rpc/client.h>
#include <rpc/protocol.h>
-#include <util.h>
+#include <util/system.h>
#include <set>
#include <stdint.h>
@@ -45,7 +45,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listreceivedbyaddress", 0, "minconf" },
{ "listreceivedbyaddress", 1, "include_empty" },
{ "listreceivedbyaddress", 2, "include_watchonly" },
- { "listreceivedbyaddress", 3, "address_filter" },
{ "listreceivedbylabel", 0, "minconf" },
{ "listreceivedbylabel", 1, "include_empty" },
{ "listreceivedbylabel", 2, "include_watchonly" },
@@ -148,7 +147,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "logging", 0, "include" },
{ "logging", 1, "exclude" },
{ "disconnectnode", 1, "nodeid" },
- { "addwitnessaddress", 1, "p2sh" },
// Echo with conversion (For testing only)
{ "echojson", 0, "arg0" },
{ "echojson", 1, "arg1" },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 1b2fc2c156..58b54c66de 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -20,8 +20,8 @@
#include <rpc/server.h>
#include <shutdown.h>
#include <txmempool.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <validation.h>
#include <validationinterface.h>
#include <versionbitsinfo.h>
@@ -167,6 +167,8 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
"\nExamples:\n"
"\nGenerate 11 blocks to myaddress\n"
+ HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
+ + "If you are running the bitcoin core wallet, you can get a new address to send the newly generated bitcoin to with:\n"
+ + HelpExampleCli("getnewaddress", "")
);
int nGenerate = request.params[0].get_int();
@@ -362,8 +364,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
"}\n"
"\nExamples:\n"
- + HelpExampleCli("getblocktemplate", "")
- + HelpExampleRpc("getblocktemplate", "")
+ + HelpExampleCli("getblocktemplate", "{\"rules\": [\"segwit\"]}")
+ + HelpExampleRpc("getblocktemplate", "{\"rules\": [\"segwit\"]}")
);
LOCK(cs_main);
@@ -813,7 +815,7 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request)
" higher feerate and is more likely to be sufficient for the desired\n"
" target, but is not as responsive to short term drops in the\n"
" prevailing fee market. Must be one of:\n"
- " \"UNSET\" (defaults to CONSERVATIVE)\n"
+ " \"UNSET\"\n"
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\"\n"
"\nResult:\n"
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 0f3b601414..cebf12bb34 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -17,8 +17,8 @@
#include <rpc/server.h>
#include <rpc/util.h>
#include <timedata.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <warnings.h>
#include <stdint.h>
@@ -44,7 +44,7 @@ static UniValue validateaddress(const JSONRPCRequest& request)
"{\n"
" \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
" \"address\" : \"address\", (string) The bitcoin address validated\n"
- " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
+ " \"scriptPubKey\" : \"hex\", (string) The hex-encoded scriptPubKey generated by the address\n"
" \"isscript\" : true|false, (boolean) If the key is a script\n"
" \"iswitness\" : true|false, (boolean) If the address is a witness address\n"
" \"witness_version\" : version (numeric, optional) The version number of the witness program\n"
@@ -99,7 +99,7 @@ static UniValue createmultisig(const JSONRPCRequest& request)
"\nExamples:\n"
"\nCreate a multisig address from 2 public keys\n"
+ HelpExampleCli("createmultisig", "2 \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("createmultisig", "2, \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"")
;
throw std::runtime_error(msg);
@@ -157,7 +157,7 @@ static UniValue verifymessage(const JSONRPCRequest& request)
+ HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
"\nVerify the signature\n"
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
- "\nAs json rpc\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
);
@@ -210,7 +210,7 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
+ HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
"\nVerify the signature\n"
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
- "\nAs json rpc\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
);
@@ -446,7 +446,7 @@ static const CRPCCommand commands[] =
{ "control", "getmemoryinfo", &getmemoryinfo, {"mode"} },
{ "control", "logging", &logging, {"include", "exclude"}},
{ "util", "validateaddress", &validateaddress, {"address"} },
- { "util", "createmultisig", &createmultisig, {"nrequired","keys"} },
+ { "util", "createmultisig", &createmultisig, {"nrequired","keys","address_type"} },
{ "util", "verifymessage", &verifymessage, {"address","signature","message"} },
{ "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 846d90cd0a..4d893bb838 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -16,8 +16,8 @@
#include <sync.h>
#include <timedata.h>
#include <ui_interface.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <version.h>
#include <warnings.h>
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index 55bebb5662..23999b305a 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -7,13 +7,11 @@
#include <random.h>
#include <tinyformat.h>
-#include <util.h>
-#include <utilstrencodings.h>
-#include <utiltime.h>
+#include <util/system.h>
+#include <util/strencodings.h>
+#include <util/time.h>
#include <version.h>
-#include <fstream>
-
/**
* JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
* but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
@@ -85,9 +83,9 @@ bool GenerateAuthCookie(std::string *cookie_out)
/** the umask determines what permissions are used to create this file -
* these are set to 077 in init.cpp unless overridden with -sysperms.
*/
- std::ofstream file;
+ fsbridge::ofstream file;
fs::path filepath_tmp = GetAuthCookieFile(true);
- file.open(filepath_tmp.string().c_str());
+ file.open(filepath_tmp);
if (!file.is_open()) {
LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string());
return false;
@@ -109,10 +107,10 @@ bool GenerateAuthCookie(std::string *cookie_out)
bool GetAuthCookie(std::string *cookie_out)
{
- std::ifstream file;
+ fsbridge::ifstream file;
std::string cookie;
fs::path filepath = GetAuthCookieFile();
- file.open(filepath.string().c_str());
+ file.open(filepath);
if (!file.is_open())
return false;
std::getline(file, cookie);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index e13a551388..c27d5d142b 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -9,6 +9,7 @@
#include <consensus/validation.h>
#include <core_io.h>
#include <index/txindex.h>
+#include <init.h>
#include <keystore.h>
#include <validation.h>
#include <validationinterface.h>
@@ -20,13 +21,14 @@
#include <primitives/transaction.h>
#include <rpc/rawtransaction.h>
#include <rpc/server.h>
+#include <rpc/util.h>
#include <script/script.h>
#include <script/script_error.h>
#include <script/sign.h>
#include <script/standard.h>
#include <txmempool.h>
#include <uint256.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <future>
#include <stdint.h>
@@ -346,7 +348,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
if (!locktime.isNull()) {
int64_t nLockTime = locktime.get_int64();
- if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
+ if (nLockTime < 0 || nLockTime > LOCKTIME_MAX)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
rawTx.nLockTime = nLockTime;
}
@@ -368,18 +370,18 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
uint32_t nSequence;
if (rbfOptIn) {
- nSequence = MAX_BIP125_RBF_SEQUENCE;
+ nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */
} else if (rawTx.nLockTime) {
- nSequence = std::numeric_limits<uint32_t>::max() - 1;
+ nSequence = CTxIn::SEQUENCE_FINAL - 1;
} else {
- nSequence = std::numeric_limits<uint32_t>::max();
+ nSequence = CTxIn::SEQUENCE_FINAL;
}
// set the sequence number if passed in the parameters object
const UniValue& sequenceObj = find_value(o, "sequence");
if (sequenceObj.isNum()) {
int64_t seqNr64 = sequenceObj.get_int64();
- if (seqNr64 < 0 || seqNr64 > std::numeric_limits<uint32_t>::max()) {
+ if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range");
} else {
nSequence = (uint32_t)seqNr64;
@@ -466,13 +468,13 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
" \"address\": x.xxx, (obj, optional) A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + "\n"
" },\n"
" {\n"
- " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex encoded data\n"
+ " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex-encoded data\n"
" }\n"
" ,... More key-value pairs of the above form. For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
" accepted as second parameter.\n"
" ]\n"
"3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n"
- "4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n"
+ "4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125-replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n"
"\nResult:\n"
"\"transaction\" (string) hex string of the transaction\n"
@@ -581,11 +583,11 @@ static UniValue decodescript(const JSONRPCRequest& request)
"decodescript \"hexstring\"\n"
"\nDecode a hex-encoded script.\n"
"\nArguments:\n"
- "1. \"hexstring\" (string) the hex encoded script\n"
+ "1. \"hexstring\" (string) the hex-encoded script\n"
"\nResult:\n"
"{\n"
" \"asm\":\"asm\", (string) Script public key\n"
- " \"hex\":\"hex\", (string) hex encoded public key\n"
+ " \"hex\":\"hex\", (string) hex-encoded public key\n"
" \"type\":\"type\", (string) The output type\n"
" \"reqSigs\": n, (numeric) The required signatures\n"
" \"addresses\": [ (json array of string)\n"
@@ -754,7 +756,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
return EncodeHexTx(mergedTx);
}
-UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType)
+UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType)
{
// Fetch previous transactions (inputs):
CCoinsView viewDummy;
@@ -922,7 +924,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
" }\n"
" ,...\n"
" ]\n"
- "4. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of\n"
+ "4. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of:\n"
" \"ALL\"\n"
" \"NONE\"\n"
" \"SINGLE\"\n"
@@ -969,7 +971,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
keystore.AddKey(key);
}
- return SignTransaction(mtx, request.params[2], &keystore, true, request.params[3]);
+ return SignTransaction(*g_rpc_interfaces->chain, mtx, request.params[2], &keystore, true, request.params[3]);
}
UniValue signrawtransaction(const JSONRPCRequest& request)
@@ -999,7 +1001,7 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
+ HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
"\nSend the transaction (signed hex)\n"
+ HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
);
@@ -1104,7 +1106,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
+ HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
"\nTest acceptance of the transaction (signed hex)\n"
+ HelpExampleCli("testmempoolaccept", "\"signedhex\"") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
// clang-format on
);
@@ -1536,12 +1538,13 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
- // Get all of the previous transactions
+ // Finalize input signatures -- in case we have partial signatures that add up to a complete
+ // signature, but have not combined them yet (e.g. because the combiner that created this
+ // PartiallySignedTransaction did not understand them), this will combine them into a final
+ // script.
bool complete = true;
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
- PSBTInput& input = psbtx.inputs.at(i);
-
- complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, i, 1);
+ complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, SIGHASH_ALL);
}
UniValue result(UniValue::VOBJ);
@@ -1554,10 +1557,10 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
mtx.vin[i].scriptWitness = psbtx.inputs[i].final_script_witness;
}
ssTx << mtx;
- result.pushKV("hex", HexStr(ssTx.begin(), ssTx.end()));
+ result.pushKV("hex", HexStr(ssTx.str()));
} else {
ssTx << psbtx;
- result.pushKV("psbt", EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()));
+ result.pushKV("psbt", EncodeBase64(ssTx.str()));
}
result.pushKV("complete", complete);
@@ -1587,7 +1590,7 @@ UniValue createpsbt(const JSONRPCRequest& request)
" \"address\": x.xxx, (obj, optional) A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + "\n"
" },\n"
" {\n"
- " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex encoded data\n"
+ " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex-encoded data\n"
" }\n"
" ,... More key-value pairs of the above form. For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
" accepted as second parameter.\n"
diff --git a/src/rpc/rawtransaction.h b/src/rpc/rawtransaction.h
index 924611ed5a..52d701d1c3 100644
--- a/src/rpc/rawtransaction.h
+++ b/src/rpc/rawtransaction.h
@@ -9,8 +9,12 @@ class CBasicKeyStore;
struct CMutableTransaction;
class UniValue;
+namespace interfaces {
+class Chain;
+} // namespace interfaces
+
/** Sign a transaction with the given keystore and previous transactions */
-UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore *keystore, bool tempKeystore, const UniValue& hashType);
+UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore *keystore, bool tempKeystore, const UniValue& hashType);
/** Create a transaction from univalue parameters */
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf);
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 60bf3c28c0..78abd7b610 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -11,8 +11,8 @@
#include <shutdown.h>
#include <sync.h>
#include <ui_interface.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <boost/bind.hpp>
#include <boost/signals2/signal.hpp>
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index ba414bf3f5..ef2d14b90e 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -7,7 +7,9 @@
#include <rpc/protocol.h>
#include <rpc/util.h>
#include <tinyformat.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
+
+InitInterfaces* g_rpc_interfaces = nullptr;
// Converts a hex string to a public key if possible
CPubKey HexToPubKey(const std::string& hex_in)
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 0a3a156e45..e21b5ba22a 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -17,6 +17,12 @@
class CKeyStore;
class CPubKey;
class CScript;
+struct InitInterfaces;
+
+//! Pointers to interfaces that need to be accessible from RPC methods. Due to
+//! limitations of the RPC framework, there's currently no direct way to pass in
+//! state to RPC method implementations.
+extern InitInterfaces* g_rpc_interfaces;
CPubKey HexToPubKey(const std::string& hex_in);
CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in);
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 45b097dde6..90c4ddcc11 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -10,8 +10,8 @@
#include <script/standard.h>
#include <span.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <memory>
#include <string>
@@ -41,7 +41,7 @@ struct PubkeyProvider
virtual ~PubkeyProvider() = default;
/** Derive a public key. */
- virtual bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& out) const = 0;
+ virtual bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const = 0;
/** Whether this represent multiple public keys at different positions. */
virtual bool IsRange() const = 0;
@@ -56,6 +56,37 @@ struct PubkeyProvider
virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;
};
+class OriginPubkeyProvider final : public PubkeyProvider
+{
+ KeyOriginInfo m_origin;
+ std::unique_ptr<PubkeyProvider> m_provider;
+
+ std::string OriginString() const
+ {
+ return HexStr(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint)) + FormatKeyPath(m_origin.path);
+ }
+
+public:
+ OriginPubkeyProvider(KeyOriginInfo info, std::unique_ptr<PubkeyProvider> provider) : m_origin(std::move(info)), m_provider(std::move(provider)) {}
+ bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const override
+ {
+ if (!m_provider->GetPubKey(pos, arg, key, info)) return false;
+ std::copy(std::begin(m_origin.fingerprint), std::end(m_origin.fingerprint), info.fingerprint);
+ info.path.insert(info.path.begin(), m_origin.path.begin(), m_origin.path.end());
+ return true;
+ }
+ bool IsRange() const override { return m_provider->IsRange(); }
+ size_t GetSize() const override { return m_provider->GetSize(); }
+ std::string ToString() const override { return "[" + OriginString() + "]" + m_provider->ToString(); }
+ bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override
+ {
+ std::string sub;
+ if (!m_provider->ToPrivateString(arg, sub)) return false;
+ ret = "[" + OriginString() + "]" + std::move(sub);
+ return true;
+ }
+};
+
/** An object representing a parsed constant public key in a descriptor. */
class ConstPubkeyProvider final : public PubkeyProvider
{
@@ -63,9 +94,12 @@ class ConstPubkeyProvider final : public PubkeyProvider
public:
ConstPubkeyProvider(const CPubKey& pubkey) : m_pubkey(pubkey) {}
- bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& out) const override
+ bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const override
{
- out = m_pubkey;
+ key = m_pubkey;
+ info.path.clear();
+ CKeyID keyid = m_pubkey.GetID();
+ std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
return true;
}
bool IsRange() const override { return false; }
@@ -98,7 +132,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
CKey key;
if (!arg.GetKey(m_extkey.pubkey.GetID(), key)) return false;
ret.nDepth = m_extkey.nDepth;
- std::copy(m_extkey.vchFingerprint, m_extkey.vchFingerprint + 4, ret.vchFingerprint);
+ std::copy(m_extkey.vchFingerprint, m_extkey.vchFingerprint + sizeof(ret.vchFingerprint), ret.vchFingerprint);
ret.nChild = m_extkey.nChild;
ret.chaincode = m_extkey.chaincode;
ret.key = key;
@@ -118,27 +152,32 @@ public:
BIP32PubkeyProvider(const CExtPubKey& extkey, KeyPath path, DeriveType derive) : m_extkey(extkey), m_path(std::move(path)), m_derive(derive) {}
bool IsRange() const override { return m_derive != DeriveType::NO; }
size_t GetSize() const override { return 33; }
- bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& out) const override
+ bool GetPubKey(int pos, const SigningProvider& arg, CPubKey& key, KeyOriginInfo& info) const override
{
if (IsHardened()) {
- CExtKey key;
- if (!GetExtKey(arg, key)) return false;
+ CExtKey extkey;
+ if (!GetExtKey(arg, extkey)) return false;
for (auto entry : m_path) {
- key.Derive(key, entry);
+ extkey.Derive(extkey, entry);
}
- if (m_derive == DeriveType::UNHARDENED) key.Derive(key, pos);
- if (m_derive == DeriveType::HARDENED) key.Derive(key, pos | 0x80000000UL);
- out = key.Neuter().pubkey;
+ if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
+ if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL);
+ key = extkey.Neuter().pubkey;
} else {
// TODO: optimize by caching
- CExtPubKey key = m_extkey;
+ CExtPubKey extkey = m_extkey;
for (auto entry : m_path) {
- key.Derive(key, entry);
+ extkey.Derive(extkey, entry);
}
- if (m_derive == DeriveType::UNHARDENED) key.Derive(key, pos);
+ if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
assert(m_derive != DeriveType::HARDENED);
- out = key.pubkey;
+ key = extkey.pubkey;
}
+ CKeyID keyid = m_extkey.pubkey.GetID();
+ std::copy(keyid.begin(), keyid.begin() + sizeof(info.fingerprint), info.fingerprint);
+ info.path = m_path;
+ if (m_derive == DeriveType::UNHARDENED) info.path.push_back((uint32_t)pos);
+ if (m_derive == DeriveType::HARDENED) info.path.push_back(((uint32_t)pos) | 0x80000000L);
return true;
}
std::string ToString() const override
@@ -221,9 +260,11 @@ public:
bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override
{
CPubKey key;
- if (!m_provider->GetPubKey(pos, arg, key)) return false;
+ KeyOriginInfo info;
+ if (!m_provider->GetPubKey(pos, arg, key, info)) return false;
output_scripts = std::vector<CScript>{m_script_fn(key)};
- out.pubkeys.emplace(key.GetID(), std::move(key));
+ out.origins.emplace(key.GetID(), std::move(info));
+ out.pubkeys.emplace(key.GetID(), key);
return true;
}
};
@@ -272,15 +313,19 @@ public:
bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override
{
- std::vector<CPubKey> pubkeys;
- pubkeys.reserve(m_providers.size());
+ std::vector<std::pair<CPubKey, KeyOriginInfo>> entries;
+ entries.reserve(m_providers.size());
+ // Construct temporary data in `entries`, to avoid producing output in case of failure.
for (const auto& p : m_providers) {
- CPubKey key;
- if (!p->GetPubKey(pos, arg, key)) return false;
- pubkeys.push_back(key);
+ entries.emplace_back();
+ if (!p->GetPubKey(pos, arg, entries.back().first, entries.back().second)) return false;
}
- for (const CPubKey& key : pubkeys) {
- out.pubkeys.emplace(key.GetID(), std::move(key));
+ std::vector<CPubKey> pubkeys;
+ pubkeys.reserve(entries.size());
+ for (auto& entry : entries) {
+ pubkeys.push_back(entry.first);
+ out.origins.emplace(entry.first.GetID(), std::move(entry.second));
+ out.pubkeys.emplace(entry.first.GetID(), entry.first);
}
output_scripts = std::vector<CScript>{GetScriptForMultisig(m_threshold, pubkeys)};
return true;
@@ -343,13 +388,15 @@ public:
bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override
{
CPubKey key;
- if (!m_provider->GetPubKey(pos, arg, key)) return false;
+ KeyOriginInfo info;
+ if (!m_provider->GetPubKey(pos, arg, key, info)) return false;
CKeyID keyid = key.GetID();
{
CScript p2pk = GetScriptForRawPubKey(key);
CScript p2pkh = GetScriptForDestination(keyid);
output_scripts = std::vector<CScript>{std::move(p2pk), std::move(p2pkh)};
out.pubkeys.emplace(keyid, key);
+ out.origins.emplace(keyid, std::move(info));
}
if (key.IsCompressed()) {
CScript p2wpkh = GetScriptForDestination(WitnessV0KeyHash(keyid));
@@ -447,7 +494,8 @@ bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out)
return true;
}
-std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out)
+/** Parse a public key that excludes origin information. */
+std::unique_ptr<PubkeyProvider> ParsePubkeyInner(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out)
{
auto split = Split(sp, '/');
std::string str(split[0].begin(), split[0].end());
@@ -484,6 +532,28 @@ std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool per
return MakeUnique<BIP32PubkeyProvider>(extpubkey, std::move(path), type);
}
+/** Parse a public key including origin information (if enabled). */
+std::unique_ptr<PubkeyProvider> ParsePubkey(const Span<const char>& sp, bool permit_uncompressed, FlatSigningProvider& out)
+{
+ auto origin_split = Split(sp, ']');
+ if (origin_split.size() > 2) return nullptr;
+ if (origin_split.size() == 1) return ParsePubkeyInner(origin_split[0], permit_uncompressed, out);
+ if (origin_split[0].size() < 1 || origin_split[0][0] != '[') return nullptr;
+ auto slash_split = Split(origin_split[0].subspan(1), '/');
+ if (slash_split[0].size() != 8) return nullptr;
+ std::string fpr_hex = std::string(slash_split[0].begin(), slash_split[0].end());
+ if (!IsHex(fpr_hex)) return nullptr;
+ auto fpr_bytes = ParseHex(fpr_hex);
+ KeyOriginInfo info;
+ static_assert(sizeof(info.fingerprint) == 4, "Fingerprint must be 4 bytes");
+ assert(fpr_bytes.size() == 4);
+ std::copy(fpr_bytes.begin(), fpr_bytes.end(), info.fingerprint);
+ if (!ParseKeyPath(slash_split, info.path)) return nullptr;
+ auto provider = ParsePubkeyInner(origin_split[1], permit_uncompressed, out);
+ if (!provider) return nullptr;
+ return MakeUnique<OriginPubkeyProvider>(std::move(info), std::move(provider));
+}
+
/** Parse a script in a particular context. */
std::unique_ptr<Descriptor> ParseScript(Span<const char>& sp, ParseScriptContext ctx, FlatSigningProvider& out)
{
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 1433ebf42f..51bd2d6e9f 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -23,9 +23,9 @@ namespace {
*/
enum class IsMineSigVersion
{
- TOP = 0, //! scriptPubKey execution
- P2SH = 1, //! P2SH redeemScript
- WITNESS_V0 = 2 //! P2WSH witness script execution
+ TOP = 0, //!< scriptPubKey execution
+ P2SH = 1, //!< P2SH redeemScript
+ WITNESS_V0 = 2, //!< P2WSH witness script execution
};
/**
@@ -35,10 +35,10 @@ enum class IsMineSigVersion
*/
enum class IsMineResult
{
- NO = 0, //! Not ours
- WATCH_ONLY = 1, //! Included in watch-only balance
- SPENDABLE = 2, //! Included in all balances
- INVALID = 3, //! Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness)
+ NO = 0, //!< Not ours
+ WATCH_ONLY = 1, //!< Included in watch-only balance
+ SPENDABLE = 2, //!< Included in all balances
+ INVALID = 3, //!< Not spendable by anyone (uncompressed pubkey in segwit, P2SH inside P2SH or witness, witness inside witness)
};
bool PermitsUncompressed(IsMineSigVersion sigversion)
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 9bdf3ed808..982aa241e7 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -6,7 +6,7 @@
#include <script/script.h>
#include <tinyformat.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
const char* GetOpName(opcodetype opcode)
{
diff --git a/src/script/script.h b/src/script/script.h
index 00065a24be..1d8ddba2f2 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -38,6 +38,12 @@ static const int MAX_STACK_SIZE = 1000;
// otherwise as UNIX timestamp.
static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
+// Maximum nLockTime. Since a lock time indicates the last invalid timestamp, a
+// transaction with this lock time will never be valid unless lock time
+// checking is disabled (by setting all input sequence numbers to
+// SEQUENCE_FINAL).
+static const uint32_t LOCKTIME_MAX = 0xFFFFFFFFU;
+
template <typename T>
std::vector<unsigned char> ToByteVector(const T& in)
{
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 68f0542294..94005cf6f3 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -9,7 +9,7 @@
#include <pubkey.h>
#include <random.h>
#include <uint256.h>
-#include <util.h>
+#include <util/system.h>
#include <cuckoocache.h>
#include <boost/thread.hpp>
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index d779910425..2795dc96d3 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -73,15 +73,18 @@ static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, c
return false;
}
-static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const CKeyID& keyid, const CScript& scriptcode, SigVersion sigversion)
+static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& sig_out, const CPubKey& pubkey, const CScript& scriptcode, SigVersion sigversion)
{
+ CKeyID keyid = pubkey.GetID();
const auto it = sigdata.signatures.find(keyid);
if (it != sigdata.signatures.end()) {
sig_out = it->second.second;
return true;
}
- CPubKey pubkey;
- GetPubKey(provider, sigdata, keyid, pubkey);
+ KeyOriginInfo info;
+ if (provider.GetKeyOrigin(keyid, info)) {
+ sigdata.misc_pubkeys.emplace(keyid, std::make_pair(pubkey, std::move(info)));
+ }
if (creator.CreateSig(provider, sig_out, keyid, scriptcode, sigversion)) {
auto i = sigdata.signatures.emplace(keyid, SigPair(pubkey, sig_out));
assert(i.second);
@@ -114,15 +117,15 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
case TX_WITNESS_UNKNOWN:
return false;
case TX_PUBKEY:
- if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]).GetID(), scriptPubKey, sigversion)) return false;
+ if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false;
ret.push_back(std::move(sig));
return true;
case TX_PUBKEYHASH: {
CKeyID keyID = CKeyID(uint160(vSolutions[0]));
- if (!CreateSig(creator, sigdata, provider, sig, keyID, scriptPubKey, sigversion)) return false;
- ret.push_back(std::move(sig));
CPubKey pubkey;
- GetPubKey(provider, sigdata, keyID, pubkey);
+ if (!GetPubKey(provider, sigdata, keyID, pubkey)) return false;
+ if (!CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) return false;
+ ret.push_back(std::move(sig));
ret.push_back(ToByteVector(pubkey));
return true;
}
@@ -138,7 +141,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
for (size_t i = 1; i < vSolutions.size() - 1; ++i) {
CPubKey pubkey = CPubKey(vSolutions[i]);
- if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey.GetID(), scriptPubKey, sigversion)) {
+ if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) {
ret.push_back(std::move(sig));
}
}
@@ -236,10 +239,17 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
return sigdata.complete;
}
-bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash)
+bool PSBTInputSigned(PSBTInput& input)
{
- // if this input has a final scriptsig or scriptwitness, don't do anything with it
- if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) {
+ return !input.final_script_sig.empty() || !input.final_script_witness.IsNull();
+}
+
+bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash)
+{
+ PSBTInput& input = psbt.inputs.at(index);
+ const CMutableTransaction& tx = *psbt.tx;
+
+ if (PSBTInputSigned(input)) {
return true;
}
@@ -250,15 +260,19 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
// Get UTXO
bool require_witness_sig = false;
CTxOut utxo;
+
+ // Verify input sanity, which checks that at most one of witness or non-witness utxos is provided.
+ if (!input.IsSane()) {
+ return false;
+ }
+
if (input.non_witness_utxo) {
// If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
- if (input.non_witness_utxo->GetHash() != tx.vin[index].prevout.hash) return false;
- // If both witness and non-witness UTXO are provided, verify that they match. This check shouldn't
- // matter, as the PSBT deserializer enforces only one of both is provided, and the only way both
- // can be present is when they're added simultaneously by FillPSBT (in which case they always match).
- // Still, check in order to not rely on callers to enforce this.
- if (!input.witness_utxo.IsNull() && input.non_witness_utxo->vout[tx.vin[index].prevout.n] != input.witness_utxo) return false;
- utxo = input.non_witness_utxo->vout[tx.vin[index].prevout.n];
+ COutPoint prevout = tx.vin[index].prevout;
+ if (input.non_witness_utxo->GetHash() != prevout.hash) {
+ return false;
+ }
+ utxo = input.non_witness_utxo->vout[prevout.n];
} else if (!input.witness_utxo.IsNull()) {
utxo = input.witness_utxo;
// When we're taking our information from a witness UTXO, we can't verify it is actually data from
@@ -277,13 +291,10 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
if (require_witness_sig && !sigdata.witness) return false;
input.FromSignatureData(sigdata);
- // If both UTXO types are present, drop the unnecessary one.
- if (input.non_witness_utxo && !input.witness_utxo.IsNull()) {
- if (sigdata.witness) {
- input.non_witness_utxo = nullptr;
- } else {
- input.witness_utxo.SetNull();
- }
+ // If we have a witness signature, use the smaller witness UTXO.
+ if (sigdata.witness) {
+ input.witness_utxo = utxo;
+ input.non_witness_utxo = nullptr;
}
return sig_complete;
@@ -505,6 +516,12 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script)
return false;
}
+PartiallySignedTransaction::PartiallySignedTransaction(const CTransaction& tx) : tx(tx)
+{
+ inputs.resize(tx.vin.size());
+ outputs.resize(tx.vout.size());
+}
+
bool PartiallySignedTransaction::IsNull() const
{
return !tx && inputs.empty() && outputs.empty() && unknown.empty();
@@ -683,6 +700,7 @@ bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& inf
bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); }
bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); }
+bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return LookupHelper(origins, keyid, info); }
bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); }
FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b)
diff --git a/src/script/sign.h b/src/script/sign.h
index 2fc4575e59..e71f43f96d 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -34,7 +34,7 @@ public:
virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; }
virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; }
- virtual bool GetKeyOrigin(const CKeyID& id, KeyOriginInfo& info) const { return false; }
+ virtual bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return false; }
};
extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
@@ -58,10 +58,12 @@ struct FlatSigningProvider final : public SigningProvider
{
std::map<CScriptID, CScript> scripts;
std::map<CKeyID, CPubKey> pubkeys;
+ std::map<CKeyID, KeyOriginInfo> origins;
std::map<CKeyID, CKey> keys;
bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
+ bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
bool GetKey(const CKeyID& keyid, CKey& key) const override;
};
@@ -300,6 +302,7 @@ struct PSBTInput
template <typename Stream>
inline void Unserialize(Stream& s) {
// Read loop
+ bool found_sep = false;
while(!s.empty()) {
// Read
std::vector<unsigned char> key;
@@ -307,7 +310,10 @@ struct PSBTInput
// the key is empty if that was actually a separator byte
// This is a special case for key lengths 0 as those are not allowed (except for separator)
- if (key.empty()) return;
+ if (key.empty()) {
+ found_sep = true;
+ break;
+ }
// First byte of key is the type
unsigned char type = key[0];
@@ -422,6 +428,10 @@ struct PSBTInput
break;
}
}
+
+ if (!found_sep) {
+ throw std::ios_base::failure("Separator is missing at the end of an input map");
+ }
}
template <typename Stream>
@@ -475,6 +485,7 @@ struct PSBTOutput
template <typename Stream>
inline void Unserialize(Stream& s) {
// Read loop
+ bool found_sep = false;
while(!s.empty()) {
// Read
std::vector<unsigned char> key;
@@ -482,7 +493,10 @@ struct PSBTOutput
// the key is empty if that was actually a separator byte
// This is a special case for key lengths 0 as those are not allowed (except for separator)
- if (key.empty()) return;
+ if (key.empty()) {
+ found_sep = true;
+ break;
+ }
// First byte of key is the type
unsigned char type = key[0];
@@ -527,6 +541,10 @@ struct PSBTOutput
}
}
}
+
+ if (!found_sep) {
+ throw std::ios_base::failure("Separator is missing at the end of an output map");
+ }
}
template <typename Stream>
@@ -548,6 +566,7 @@ struct PartiallySignedTransaction
bool IsSane() const;
PartiallySignedTransaction() {}
PartiallySignedTransaction(const PartiallySignedTransaction& psbt_in) : tx(psbt_in.tx), inputs(psbt_in.inputs), outputs(psbt_in.outputs), unknown(psbt_in.unknown) {}
+ explicit PartiallySignedTransaction(const CTransaction& tx);
// Only checks if they refer to the same transaction
friend bool operator==(const PartiallySignedTransaction& a, const PartiallySignedTransaction &b)
@@ -602,6 +621,7 @@ struct PartiallySignedTransaction
}
// Read global data
+ bool found_sep = false;
while(!s.empty()) {
// Read
std::vector<unsigned char> key;
@@ -609,7 +629,10 @@ struct PartiallySignedTransaction
// the key is empty if that was actually a separator byte
// This is a special case for key lengths 0 as those are not allowed (except for separator)
- if (key.empty()) break;
+ if (key.empty()) {
+ found_sep = true;
+ break;
+ }
// First byte of key is the type
unsigned char type = key[0];
@@ -649,6 +672,10 @@ struct PartiallySignedTransaction
}
}
+ if (!found_sep) {
+ throw std::ios_base::failure("Separator is missing at the end of the global map");
+ }
+
// Make sure that we got an unsigned tx
if (!tx) {
throw std::ios_base::failure("No unsigned transcation was provided");
@@ -703,8 +730,11 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType);
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
+/** Checks whether a PSBTInput is already signed. */
+bool PSBTInputSigned(PSBTInput& input);
+
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
-bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash = SIGHASH_ALL);
+bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash = SIGHASH_ALL);
/** Extract signature data from a transaction input, and insert it. */
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 08ba1b1e0f..31bfd04b0f 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -8,8 +8,8 @@
#include <crypto/sha256.h>
#include <pubkey.h>
#include <script/script.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
typedef std::vector<unsigned char> valtype;
diff --git a/src/sync.cpp b/src/sync.cpp
index c9aa98dcd6..30811f5f89 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -5,7 +5,7 @@
#include <sync.h>
#include <logging.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <stdio.h>
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index f57d0c6d79..8c2873d916 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -40,22 +40,26 @@ public:
CAddrInfo* Find(const CNetAddr& addr, int* pnId = nullptr)
{
+ LOCK(cs);
return CAddrMan::Find(addr, pnId);
}
CAddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId = nullptr)
{
+ LOCK(cs);
return CAddrMan::Create(addr, addrSource, pnId);
}
void Delete(int nId)
{
+ LOCK(cs);
CAddrMan::Delete(nId);
}
// Simulates connection failure so that we can test eviction of offline nodes
void SimConnFail(CService& addr)
{
+ LOCK(cs);
int64_t nLastSuccess = 1;
Good_(addr, true, nLastSuccess); // Set last good connection in the deep past.
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index c72c062b81..5a108dcdad 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util.h>
+#include <util/system.h>
#include <support/allocators/secure.h>
#include <test/test_bitcoin.h>
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
index adffcfeef5..1ff040b077 100644
--- a/src/test/amount_tests.cpp
+++ b/src/test/amount_tests.cpp
@@ -13,8 +13,10 @@ BOOST_FIXTURE_TEST_SUITE(amount_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(MoneyRangeTest)
{
BOOST_CHECK_EQUAL(MoneyRange(CAmount(-1)), false);
- BOOST_CHECK_EQUAL(MoneyRange(MAX_MONEY + CAmount(1)), false);
+ BOOST_CHECK_EQUAL(MoneyRange(CAmount(0)), true);
BOOST_CHECK_EQUAL(MoneyRange(CAmount(1)), true);
+ BOOST_CHECK_EQUAL(MoneyRange(MAX_MONEY), true);
+ BOOST_CHECK_EQUAL(MoneyRange(MAX_MONEY + CAmount(1)), false);
}
BOOST_AUTO_TEST_CASE(GetFeeTest)
@@ -23,43 +25,43 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
feeRate = CFeeRate(0);
// Must always return 0
- BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
- BOOST_CHECK_EQUAL(feeRate.GetFee(1e5), 0);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), CAmount(0));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e5), CAmount(0));
feeRate = CFeeRate(1000);
// Must always just return the arg
- BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
- BOOST_CHECK_EQUAL(feeRate.GetFee(1), 1);
- BOOST_CHECK_EQUAL(feeRate.GetFee(121), 121);
- BOOST_CHECK_EQUAL(feeRate.GetFee(999), 999);
- BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 1e3);
- BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 9e3);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), CAmount(0));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1), CAmount(1));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(121), CAmount(121));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(999), CAmount(999));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), CAmount(1e3));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), CAmount(9e3));
feeRate = CFeeRate(-1000);
// Must always just return -1 * arg
- BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
- BOOST_CHECK_EQUAL(feeRate.GetFee(1), -1);
- BOOST_CHECK_EQUAL(feeRate.GetFee(121), -121);
- BOOST_CHECK_EQUAL(feeRate.GetFee(999), -999);
- BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), -1e3);
- BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), -9e3);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), CAmount(0));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1), CAmount(-1));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(121), CAmount(-121));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(999), CAmount(-999));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), CAmount(-1e3));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), CAmount(-9e3));
feeRate = CFeeRate(123);
// Truncates the result, if not integer
- BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
- BOOST_CHECK_EQUAL(feeRate.GetFee(8), 1); // Special case: returns 1 instead of 0
- BOOST_CHECK_EQUAL(feeRate.GetFee(9), 1);
- BOOST_CHECK_EQUAL(feeRate.GetFee(121), 14);
- BOOST_CHECK_EQUAL(feeRate.GetFee(122), 15);
- BOOST_CHECK_EQUAL(feeRate.GetFee(999), 122);
- BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 123);
- BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 1107);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), CAmount(0));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(8), CAmount(1)); // Special case: returns 1 instead of 0
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9), CAmount(1));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(121), CAmount(14));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(122), CAmount(15));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(999), CAmount(122));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), CAmount(123));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), CAmount(1107));
feeRate = CFeeRate(-123);
// Truncates the result, if not integer
- BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0);
- BOOST_CHECK_EQUAL(feeRate.GetFee(8), -1); // Special case: returns -1 instead of 0
- BOOST_CHECK_EQUAL(feeRate.GetFee(9), -1);
+ BOOST_CHECK_EQUAL(feeRate.GetFee(0), CAmount(0));
+ BOOST_CHECK_EQUAL(feeRate.GetFee(8), CAmount(-1)); // Special case: returns -1 instead of 0
+ BOOST_CHECK_EQUAL(feeRate.GetFee(9), CAmount(-1));
// check alternate constructor
feeRate = CFeeRate(1000);
@@ -67,6 +69,9 @@ BOOST_AUTO_TEST_CASE(GetFeeTest)
BOOST_CHECK_EQUAL(feeRate.GetFee(100), altFeeRate.GetFee(100));
// Check full constructor
+ BOOST_CHECK(CFeeRate(CAmount(-1), 0) == CFeeRate(0));
+ BOOST_CHECK(CFeeRate(CAmount(0), 0) == CFeeRate(0));
+ BOOST_CHECK(CFeeRate(CAmount(1), 0) == CFeeRate(0));
// default value
BOOST_CHECK(CFeeRate(CAmount(-1), 1000) == CFeeRate(-1));
BOOST_CHECK(CFeeRate(CAmount(0), 1000) == CFeeRate(0));
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
index 6b06d2e1b6..32af843bf6 100644
--- a/src/test/base32_tests.cpp
+++ b/src/test/base32_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 5fc4abaf3d..f8f9b3c1a7 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -6,7 +6,7 @@
#include <base58.h>
#include <test/test_bitcoin.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <univalue.h>
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
index daceea262c..0abbb682a7 100644
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 2cdbaca7ba..c9951f4b7e 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -7,8 +7,8 @@
#include <key.h>
#include <key_io.h>
#include <uint256.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <string>
diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp
index 4941ebd483..2144202b8d 100644
--- a/src/test/blockfilter_tests.cpp
+++ b/src/test/blockfilter_tests.cpp
@@ -10,7 +10,7 @@
#include <serialize.h>
#include <streams.h>
#include <univalue.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 8a8e8bfdc3..c900bee199 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -13,8 +13,8 @@
#include <serialize.h>
#include <streams.h>
#include <uint256.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index f4b416c4ca..a757e06a9d 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_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 <util.h>
-#include <utiltime.h>
+#include <util/system.h>
+#include <util/time.h>
#include <validation.h>
#include <test/test_bitcoin.h>
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 6f4b5ecd26..521312f1b7 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -6,7 +6,7 @@
#include <script/standard.h>
#include <uint256.h>
#include <undo.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <validation.h>
#include <consensus/validation.h>
diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp
index a4e99d438f..e686c05165 100644
--- a/src/test/compress_tests.cpp
+++ b/src/test/compress_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <compressor.h>
-#include <util.h>
+#include <util/system.h>
#include <test/test_bitcoin.h>
#include <stdint.h>
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 713e3e2ded..f3fd83a0cc 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -11,7 +11,7 @@
#include <crypto/hmac_sha256.h>
#include <crypto/hmac_sha512.h>
#include <random.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 52bbe96b96..97cf5ed345 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -11,7 +11,7 @@
#include <pow.h>
#include <script/sign.h>
#include <serialize.h>
-#include <util.h>
+#include <util/system.h>
#include <validation.h>
#include <test/test_bitcoin.h>
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index e739b84a48..57e4b067c0 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -9,7 +9,7 @@
#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
#include <script/descriptor.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
namespace {
@@ -43,9 +43,12 @@ std::string MaybeUseHInsteadOfApostrophy(std::string ret)
return ret;
}
-void Check(const std::string& prv, const std::string& pub, int flags, const std::vector<std::vector<std::string>>& scripts)
+const std::set<std::vector<uint32_t>> ONLY_EMPTY{{}};
+
+void Check(const std::string& prv, const std::string& pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY)
{
FlatSigningProvider keys_priv, keys_pub;
+ std::set<std::vector<uint32_t>> left_paths = paths;
// Check that parsing succeeds.
auto parse_priv = Parse(MaybeUseHInsteadOfApostrophy(prv), keys_priv);
@@ -84,7 +87,7 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std:
for (size_t i = 0; i < max; ++i) {
const auto& ref = scripts[(flags & RANGE) ? i : 0];
for (int t = 0; t < 2; ++t) {
- FlatSigningProvider key_provider = (flags & HARDENED) ? keys_priv : keys_pub;
+ const FlatSigningProvider& key_provider = (flags & HARDENED) ? keys_priv : keys_pub;
FlatSigningProvider script_provider;
std::vector<CScript> spks;
BOOST_CHECK((t ? parse_priv : parse_pub)->Expand(i, key_provider, spks, script_provider));
@@ -100,9 +103,16 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std:
BOOST_CHECK_MESSAGE(SignSignature(Merge(keys_priv, script_provider), spks[n], spend, 0, 1, SIGHASH_ALL), prv);
}
}
-
+ // Test whether the observed key path is present in the 'paths' variable (which contains expected, unobserved paths),
+ // and then remove it from that set.
+ for (const auto& origin : script_provider.origins) {
+ BOOST_CHECK_MESSAGE(paths.count(origin.second.path), "Unexpected key path: " + prv);
+ left_paths.erase(origin.second.path);
+ }
}
}
+ // Verify no expected paths remain that were not observed.
+ BOOST_CHECK_MESSAGE(left_paths.empty(), "Not all expected key paths found: " + prv);
}
}
@@ -114,7 +124,7 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
// Basic single-key compressed
Check("combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "combo(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac","76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac","00149a1c78a507689f6f54b847ad1cef1e614ee23f1e","a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}});
Check("pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pk(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"}});
- Check("pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}});
+ Check("pkh([deadbeef/1/2'/3/4']L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "pkh([deadbeef/1/2'/3/4']03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"76a9149a1c78a507689f6f54b847ad1cef1e614ee23f1e88ac"}}, {{1,0x80000002UL,3,0x80000004UL}});
Check("wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", SIGNABLE, {{"00149a1c78a507689f6f54b847ad1cef1e614ee23f1e"}});
Check("sh(wpkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))", "sh(wpkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", SIGNABLE, {{"a91484ab21b1b2fd065d4504ff693d832434b6108d7b87"}});
@@ -135,20 +145,26 @@ BOOST_AUTO_TEST_CASE(descriptor_test)
Check("sh(wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)))", "sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)))", SIGNABLE, {{"a914b61b92e2ca21bac1e72a3ab859a742982bea960a87"}});
// Versions with BIP32 derivations
- Check("combo(xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", SIGNABLE, {{"2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac","76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac","001431a507b815593dfc51ffc7245ae7e5aee304246e","a9142aafb926eb247cb18240a7f4c07983ad1f37922687"}});
- Check("pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", DEFAULT, {{"210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac"}});
- Check("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}});
- Check("wpkh(xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh(xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", RANGE, {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}});
- Check("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", RANGE | HARDENED, {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}});
- Check("combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", RANGE, {{"2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac","76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac","0014f90e3178ca25f2c808dc76624032d352fdbdfaf2","a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087"},{"21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac","76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac","0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7","a91473e39884cb71ae4e5ac9739e9225026c99763e6687"}});
+ Check("combo([01234567]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", SIGNABLE, {{"2102d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0ac","76a91431a507b815593dfc51ffc7245ae7e5aee304246e88ac","001431a507b815593dfc51ffc7245ae7e5aee304246e","a9142aafb926eb247cb18240a7f4c07983ad1f37922687"}});
+ Check("pk(xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0)", "pk(xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0)", DEFAULT, {{"210379e45b3cf75f9c5f9befd8e9506fb962f6a9d185ac87001ec44a8d3df8d4a9e3ac"}}, {{0}});
+ Check("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)", HARDENED, {{"76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac"}}, {{0xFFFFFFFFUL,0}});
+ Check("wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", RANGE, {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}}, {{0x8000000DUL, 1, 2, 0}, {0x8000000DUL, 1, 2, 1}, {0x8000000DUL, 1, 2, 2}});
+ Check("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", RANGE | HARDENED, {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}}, {{10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
+ Check("combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", RANGE, {{"2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac","76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac","0014f90e3178ca25f2c808dc76624032d352fdbdfaf2","a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087"},{"21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac","76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac","0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7","a91473e39884cb71ae4e5ac9739e9225026c99763e6687"}}, {{0}, {1}});
+ CheckUnparsable("combo([012345678]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([012345678]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)"); // Too long key fingerprint
CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483648)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483648)"); // BIP 32 path element overflow
// Multisig constructions
Check("multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss)", "multi(1,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,04a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea235)", SIGNABLE, {{"512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd4104a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd5b8dec5235a0fa8722476c7709c02559e3aa73aa03918ba2d492eea75abea23552ae"}});
- Check("sh(multi(2,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}});
- Check("wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", HARDENED | RANGE, {{"0020b92623201f3bb7c3771d45b2ad1d0351ea8fbf8cfe0a0e570264e1075fa1948f"},{"002036a08bbe4923af41cf4316817c93b8d37e2f635dd25cfff06bd50df6ae7ea203"},{"0020a96e7ab4607ca6b261bfe3245ffda9c746b28d3f59e83d34820ec0e2b36c139c"}});
+ Check("sh(multi(2,[00000000/111'/222]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc,xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L/0))", "sh(multi(2,[00000000/111'/222]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0))", DEFAULT, {{"a91445a9a622a8b0a1269944be477640eedc447bbd8487"}}, {{0x8000006FUL,222},{0}});
+ Check("wsh(multi(2,xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", HARDENED | RANGE, {{"0020b92623201f3bb7c3771d45b2ad1d0351ea8fbf8cfe0a0e570264e1075fa1948f"},{"002036a08bbe4923af41cf4316817c93b8d37e2f635dd25cfff06bd50df6ae7ea203"},{"0020a96e7ab4607ca6b261bfe3245ffda9c746b28d3f59e83d34820ec0e2b36c139c"}}, {{0xFFFFFFFFUL,0}, {1,2,0}, {1,2,1}, {1,2,2}, {10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}});
Check("sh(wsh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9)))","sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))", SIGNABLE, {{"a9147fc63e13dc25e8a95a3cee3d9a714ac3afd96f1e87"}});
CheckUnparsable("sh(multi(16,KzoAz5CanayRKex3fSLQ2BwJpN7U52gZvxMyk78nDMHuqrUxuSJy,KwGNz6YCCQtYvFzMtrC6D3tKTKdBBboMrLTsjr2NYVBwapCkn7Mr,KxogYhiNfwxuswvXV66eFyKcCpm7dZ7TqHVqujHAVUjJxyivxQ9X,L2BUNduTSyZwZjwNHynQTF14mv2uz2NRq5n5sYWTb4FkkmqgEE9f,L1okJGHGn1kFjdXHKxXjwVVtmCMR2JA5QsbKCSpSb7ReQjezKeoD,KxDCNSST75HFPaW5QKpzHtAyaCQC7p9Vo3FYfi2u4dXD1vgMiboK,L5edQjFtnkcf5UWURn6UuuoFrabgDQUHdheKCziwN42aLwS3KizU,KzF8UWFcEC7BYTq8Go1xVimMkDmyNYVmXV5PV7RuDicvAocoPB8i,L3nHUboKG2w4VSJ5jYZ5CBM97oeK6YuKvfZxrefdShECcjEYKMWZ,KyjHo36dWkYhimKmVVmQTq3gERv3pnqA4xFCpvUgbGDJad7eS8WE,KwsfyHKRUTZPQtysN7M3tZ4GXTnuov5XRgjdF2XCG8faAPmFruRF,KzCUbGhN9LJhdeFfL9zQgTJMjqxdBKEekRGZX24hXdgCNCijkkap,KzgpMBwwsDLwkaC5UrmBgCYaBD2WgZ7PBoGYXR8KT7gCA9UTN5a3,KyBXTPy4T7YG4q9tcAM3LkvfRpD1ybHMvcJ2ehaWXaSqeGUxEdkP,KzJDe9iwJRPtKP2F2AoN6zBgzS7uiuAwhWCfGdNeYJ3PC1HNJ8M8,L1xbHrxynrqLKkoYc4qtoQPx6uy5qYXR5ZDYVYBSRmCV5piU3JG9))","sh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232))"); // P2SH does not fit 16 compressed pubkeys in a redeemscript
+ CheckUnparsable("wsh(multi(2,[aaaaaaaa][aaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaa][aaaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))"); // Double key origin descriptor
+ CheckUnparsable("wsh(multi(2,[aaaagaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaagaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))"); // Non hex fingerprint
+ CheckUnparsable("wsh(multi(2,[aaaaaaaa],xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaa],xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))"); // No public key with origin
+ CheckUnparsable("wsh(multi(2,[aaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))"); // Too short fingerprint
+ CheckUnparsable("wsh(multi(2,[aaaaaaaaa]xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483647'/0,xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*,xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "wsh(multi(2,[aaaaaaaaa]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*,xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))"); // Too long fingerprint
// Check for invalid nesting of structures
CheckUnparsable("sh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)", "sh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)"); // P2SH needs a script, not a key
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
new file mode 100644
index 0000000000..93aee10bb7
--- /dev/null
+++ b/src/test/fs_tests.cpp
@@ -0,0 +1,56 @@
+// Copyright (c) 2011-2018 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 <fs.h>
+#include <test/test_bitcoin.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(fsbridge_fstream)
+{
+ fs::path tmpfolder = SetDataDir("fsbridge_fstream");
+ // tmpfile1 should be the same as tmpfile2
+ fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃";
+ fs::path tmpfile2 = tmpfolder / L"fs_tests_₿_🏃";
+ {
+ fsbridge::ofstream file(tmpfile1);
+ file << "bitcoin";
+ }
+ {
+ fsbridge::ifstream file(tmpfile2);
+ std::string input_buffer;
+ file >> input_buffer;
+ BOOST_CHECK_EQUAL(input_buffer, "bitcoin");
+ }
+ {
+ fsbridge::ifstream file(tmpfile1, std::ios_base::in | std::ios_base::ate);
+ std::string input_buffer;
+ file >> input_buffer;
+ BOOST_CHECK_EQUAL(input_buffer, "");
+ }
+ {
+ fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::app);
+ file << "tests";
+ }
+ {
+ fsbridge::ifstream file(tmpfile1);
+ std::string input_buffer;
+ file >> input_buffer;
+ BOOST_CHECK_EQUAL(input_buffer, "bitcointests");
+ }
+ {
+ fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::trunc);
+ file << "bitcoin";
+ }
+ {
+ fsbridge::ifstream file(tmpfile1);
+ std::string input_buffer;
+ file >> input_buffer;
+ BOOST_CHECK_EQUAL(input_buffer, "bitcoin");
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 7592330b10..0432ede3e0 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util.h>
+#include <util/system.h>
#include <test/test_bitcoin.h>
#include <string>
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index 6ed0209895..e8e5040855 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -2,8 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <crypto/siphash.h>
#include <hash.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp
index a0c10d8ddd..5db62f4bba 100644
--- a/src/test/key_io_tests.cpp
+++ b/src/test/key_io_tests.cpp
@@ -8,7 +8,7 @@
#include <key.h>
#include <key_io.h>
#include <script/script.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/key_properties.cpp b/src/test/key_properties.cpp
index 14e3c85359..c564b4eab8 100644
--- a/src/test/key_properties.cpp
+++ b/src/test/key_properties.cpp
@@ -6,8 +6,8 @@
#include <base58.h>
#include <script/script.h>
#include <uint256.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <string>
#include <vector>
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 61db70decb..91cafd05d9 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -7,8 +7,8 @@
#include <key_io.h>
#include <script/script.h>
#include <uint256.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <string>
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 0e15464fd9..db38c9623c 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -4,7 +4,7 @@
#include <policy/policy.h>
#include <txmempool.h>
-#include <util.h>
+#include <util/system.h>
#include <test/test_bitcoin.h>
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 3eb8aa14fd..a7074a5e43 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -15,8 +15,8 @@
#include <script/standard.h>
#include <txmempool.h>
#include <uint256.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
@@ -92,8 +92,8 @@ static CBlockIndex CreateBlockIndex(int nHeight)
static bool TestSequenceLocks(const CTransaction &tx, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- LOCK(mempool.cs);
- return CheckSequenceLocks(tx, flags);
+ LOCK(::mempool.cs);
+ return CheckSequenceLocks(::mempool, tx, flags);
}
// Test suite for ancestor feerate transaction selection.
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 35a143957e..213afed730 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -11,7 +11,7 @@
#include <net.h>
#include <netbase.h>
#include <chainparams.h>
-#include <util.h>
+#include <util/system.h>
#include <memory>
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 8072eb922d..0d557cff13 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -4,7 +4,7 @@
#include <netbase.h>
#include <test/test_bitcoin.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <string>
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 2022ed6659..51668cbe64 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -6,7 +6,7 @@
#include <policy/fees.h>
#include <txmempool.h>
#include <uint256.h>
-#include <util.h>
+#include <util/system.h>
#include <test/test_bitcoin.h>
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index 1ac9adc740..26cdc9bc5c 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -1,12 +1,12 @@
// Copyright (c) 2015-2018 The Bitcoin Core developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chain.h>
#include <chainparams.h>
#include <pow.h>
#include <random.h>
-#include <util.h>
+#include <util/system.h>
#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index a49796d6f4..121b72a5f7 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -4,8 +4,11 @@
#include <rpc/server.h>
#include <rpc/client.h>
+#include <rpc/util.h>
#include <core_io.h>
+#include <init.h>
+#include <interfaces/chain.h>
#include <key_io.h>
#include <netbase.h>
@@ -112,10 +115,14 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign)
std::string notsigned = r.get_str();
std::string privkey1 = "\"KzsXybp9jX64P5ekX1KUxRQ79Jht9uzW7LorgwE65i5rWACL6LQe\"";
std::string privkey2 = "\"Kyhdf5LuKTRx4ge69ybABsiUAWjVRK4XGxAKk2FQLp2HjGMy87Z4\"";
+ InitInterfaces interfaces;
+ interfaces.chain = interfaces::MakeChain();
+ g_rpc_interfaces = &interfaces;
r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" [] "+prevout);
BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false);
r = CallRPC(std::string("signrawtransactionwithkey ")+notsigned+" ["+privkey1+","+privkey2+"] "+prevout);
BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true);
+ g_rpc_interfaces = nullptr;
}
BOOST_AUTO_TEST_CASE(rpc_createraw_op_return)
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 67c377778f..1c70fdcce6 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -10,8 +10,8 @@
#include <script/script.h>
#include <script/script_error.h>
#include <script/sign.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <test/test_bitcoin.h>
#include <rpc/server.h>
@@ -1013,21 +1013,21 @@ BOOST_AUTO_TEST_CASE(script_PushData)
ScriptError err;
std::vector<std::vector<unsigned char> > directStack;
- BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));
+ BOOST_CHECK(EvalScript(directStack, CScript(direct, direct + sizeof(direct)), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
std::vector<std::vector<unsigned char> > pushdata1Stack;
- BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));
+ BOOST_CHECK(EvalScript(pushdata1Stack, CScript(pushdata1, pushdata1 + sizeof(pushdata1)), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));
BOOST_CHECK(pushdata1Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
std::vector<std::vector<unsigned char> > pushdata2Stack;
- BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));
+ BOOST_CHECK(EvalScript(pushdata2Stack, CScript(pushdata2, pushdata2 + sizeof(pushdata2)), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));
BOOST_CHECK(pushdata2Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
std::vector<std::vector<unsigned char> > pushdata4Stack;
- BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));
+ BOOST_CHECK(EvalScript(pushdata4Stack, CScript(pushdata4, pushdata4 + sizeof(pushdata4)), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SigVersion::BASE, &err));
BOOST_CHECK(pushdata4Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index e6905457bb..c329844341 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -11,8 +11,8 @@
#include <serialize.h>
#include <streams.h>
#include <test/test_bitcoin.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <version.h>
#include <iostream>
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index c0754618fb..5c46976ace 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chain.h>
-#include <util.h>
+#include <util/system.h>
#include <test/test_bitcoin.h>
#include <vector>
@@ -170,7 +170,6 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_edge_test)
BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-1)->nHeight, 0);
BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::min())->nHeight, 0);
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(std::numeric_limits<unsigned int>::min())->nHeight, 0);
BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-int64_t(std::numeric_limits<unsigned int>::max()) - 1)->nHeight, 0);
BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::max()));
BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<unsigned int>::max()));
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index c527ad448c..9978c71661 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -19,7 +19,7 @@
#include <script/sign.h>
#include <script/script_error.h>
#include <script/standard.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <map>
#include <string>
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index 2a160b9988..43e025c58f 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -5,8 +5,8 @@
#include <index/txindex.h>
#include <script/standard.h>
#include <test/test_bitcoin.h>
-#include <util.h>
-#include <utiltime.h>
+#include <util/system.h>
+#include <util/time.h>
#include <validation.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 2bf835a756..506a60d173 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -12,7 +12,7 @@
#include <script/standard.h>
#include <script/sign.h>
#include <test/test_bitcoin.h>
-#include <utiltime.h>
+#include <util/time.h>
#include <core_io.h>
#include <keystore.h>
#include <policy/policy.h>
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index c74eb7531a..ff19b12a9c 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util.h>
+#include <util/system.h>
#include <clientversion.h>
#include <primitives/transaction.h>
#include <sync.h>
-#include <utilstrencodings.h>
-#include <utilmoneystr.h>
+#include <util/strencodings.h>
+#include <util/moneystr.h>
#include <test/test_bitcoin.h>
#include <stdint.h>
diff --git a/src/threadsafety.h b/src/threadsafety.h
index 47e6b2ea38..33acddc65c 100644
--- a/src/threadsafety.h
+++ b/src/threadsafety.h
@@ -54,4 +54,15 @@
#define ASSERT_EXCLUSIVE_LOCK(...)
#endif // __GNUC__
+// Utility class for indicating to compiler thread analysis that a mutex is
+// locked (when it couldn't be determined otherwise).
+struct SCOPED_LOCKABLE LockAnnotation
+{
+ template <typename Mutex>
+ explicit LockAnnotation(Mutex& mutex) EXCLUSIVE_LOCK_FUNCTION(mutex)
+ {
+ }
+ ~LockAnnotation() UNLOCK_FUNCTION() {}
+};
+
#endif // BITCOIN_THREADSAFETY_H
diff --git a/src/timedata.cpp b/src/timedata.cpp
index 291111feb2..9c022c9ad1 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -11,8 +11,8 @@
#include <netaddress.h>
#include <sync.h>
#include <ui_interface.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/strencodings.h>
#include <warnings.h>
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index c88f61f1ec..229cc7d553 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -4,10 +4,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <torcontrol.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <netbase.h>
#include <net.h>
-#include <util.h>
+#include <util/system.h>
#include <crypto/hmac_sha256.h>
#include <vector>
diff --git a/src/txdb.cpp b/src/txdb.cpp
index cbea550739..8447352c54 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -11,7 +11,7 @@
#include <pow.h>
#include <shutdown.h>
#include <uint256.h>
-#include <util.h>
+#include <util/system.h>
#include <ui_interface.h>
#include <stdint.h>
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 3ad93342c4..68f47d5cce 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -14,9 +14,9 @@
#include <reverse_iterator.h>
#include <streams.h>
#include <timedata.h>
-#include <util.h>
-#include <utilmoneystr.h>
-#include <utiltime.h>
+#include <util/system.h>
+#include <util/moneystr.h>
+#include <util/time.h>
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, unsigned int _entryHeight,
@@ -498,7 +498,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
const CTransaction& tx = it->GetTx();
LockPoints lp = it->GetLockPoints();
bool validLP = TestLockPointValidity(&lp);
- if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(tx, flags, &lp, validLP)) {
+ if (!CheckFinalTx(tx, flags) || !CheckSequenceLocks(*this, tx, flags, &lp, validLP)) {
// Note if CheckSequenceLocks fails the LockPoints may still be invalid
// So it's critical that we remove the tx and not depend on the LockPoints.
txToRemove.insert(it);
diff --git a/src/txmempool.h b/src/txmempool.h
index 913501fd66..fadb554723 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -15,6 +15,7 @@
#include <amount.h>
#include <coins.h>
+#include <crypto/siphash.h>
#include <indirectmap.h>
#include <policy/feerate.h>
#include <primitives/transaction.h>
@@ -343,13 +344,13 @@ struct TxMempoolInfo
* this is passed to the notification signal.
*/
enum class MemPoolRemovalReason {
- UNKNOWN = 0, //! Manually removed or unknown reason
- EXPIRY, //! Expired from mempool
- SIZELIMIT, //! Removed in size limiting
- REORG, //! Removed for reorganization
- BLOCK, //! Removed for block
- CONFLICT, //! Removed for conflict with in-block transaction
- REPLACED //! Removed for replacement
+ UNKNOWN = 0, //!< Manually removed or unknown reason
+ EXPIRY, //!< Expired from mempool
+ SIZELIMIT, //!< Removed in size limiting
+ REORG, //!< Removed for reorganization
+ BLOCK, //!< Removed for block
+ CONFLICT, //!< Removed for conflict with in-block transaction
+ REPLACED, //!< Removed for replacement
};
class SaltedTxidHasher
diff --git a/src/ui_interface.cpp b/src/ui_interface.cpp
index 22b4768059..947d7e2308 100644
--- a/src/ui_interface.cpp
+++ b/src/ui_interface.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <ui_interface.h>
-#include <util.h>
+#include <util/system.h>
#include <boost/signals2/last_value.hpp>
#include <boost/signals2/signal.hpp>
diff --git a/src/uint256.cpp b/src/uint256.cpp
index e513dc1de7..d9da668036 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -5,7 +5,7 @@
#include <uint256.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <stdio.h>
#include <string.h>
@@ -29,7 +29,7 @@ void base_blob<BITS>::SetHex(const char* psz)
memset(data, 0, sizeof(data));
// skip leading spaces
- while (isspace(*psz))
+ while (IsSpace(*psz))
psz++;
// skip 0x
diff --git a/src/undo.h b/src/undo.h
index 4ed3dc4ca0..3f50f4caad 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -11,6 +11,7 @@
#include <consensus/consensus.h>
#include <primitives/transaction.h>
#include <serialize.h>
+#include <version.h>
/** Undo information for a CTxIn
*
diff --git a/src/util/bytevectorhash.cpp b/src/util/bytevectorhash.cpp
new file mode 100644
index 0000000000..f87d0e04b3
--- /dev/null
+++ b/src/util/bytevectorhash.cpp
@@ -0,0 +1,18 @@
+// Copyright (c) 2018 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 <crypto/siphash.h>
+#include <random.h>
+#include <util/bytevectorhash.h>
+
+ByteVectorHash::ByteVectorHash()
+{
+ GetRandBytes(reinterpret_cast<unsigned char*>(&m_k0), sizeof(m_k0));
+ GetRandBytes(reinterpret_cast<unsigned char*>(&m_k1), sizeof(m_k1));
+}
+
+size_t ByteVectorHash::operator()(const std::vector<unsigned char>& input) const
+{
+ return CSipHasher(m_k0, m_k1).Write(input.data(), input.size()).Finalize();
+}
diff --git a/src/util/bytevectorhash.h b/src/util/bytevectorhash.h
new file mode 100644
index 0000000000..b88c17460b
--- /dev/null
+++ b/src/util/bytevectorhash.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2018 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_UTIL_BYTEVECTORHASH_H
+#define BITCOIN_UTIL_BYTEVECTORHASH_H
+
+#include <stdint.h>
+#include <vector>
+
+/**
+ * Implementation of Hash named requirement for types that internally store a byte array. This may
+ * be used as the hash function in std::unordered_set or std::unordered_map over such types.
+ * Internally, this uses a random instance of SipHash-2-4.
+ */
+class ByteVectorHash final
+{
+private:
+ uint64_t m_k0, m_k1;
+
+public:
+ ByteVectorHash();
+ size_t operator()(const std::vector<unsigned char>& input) const;
+};
+
+#endif // BITCOIN_UTIL_BYTEVECTORHASH_H
diff --git a/src/utilmemory.h b/src/util/memory.h
index e71fe92284..15ecf8f80d 100644
--- a/src/utilmemory.h
+++ b/src/util/memory.h
@@ -3,8 +3,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_UTILMEMORY_H
-#define BITCOIN_UTILMEMORY_H
+#ifndef BITCOIN_UTIL_MEMORY_H
+#define BITCOIN_UTIL_MEMORY_H
#include <memory>
#include <utility>
diff --git a/src/utilmoneystr.cpp b/src/util/moneystr.cpp
index 326ef9b27a..4c4de7b729 100644
--- a/src/utilmoneystr.cpp
+++ b/src/util/moneystr.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <utilmoneystr.h>
+#include <util/moneystr.h>
#include <primitives/transaction.h>
#include <tinyformat.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
std::string FormatMoney(const CAmount& n)
{
@@ -41,7 +41,7 @@ bool ParseMoney(const char* pszIn, CAmount& nRet)
std::string strWhole;
int64_t nUnits = 0;
const char* p = pszIn;
- while (isspace(*p))
+ while (IsSpace(*p))
p++;
for (; *p; p++)
{
@@ -56,14 +56,14 @@ bool ParseMoney(const char* pszIn, CAmount& nRet)
}
break;
}
- if (isspace(*p))
+ if (IsSpace(*p))
break;
if (!isdigit(*p))
return false;
strWhole.insert(strWhole.end(), *p);
}
for (; *p; p++)
- if (!isspace(*p))
+ if (!IsSpace(*p))
return false;
if (strWhole.size() > 10) // guard against 63 bit overflow
return false;
diff --git a/src/utilmoneystr.h b/src/util/moneystr.h
index 67579adb77..9133f46d5d 100644
--- a/src/utilmoneystr.h
+++ b/src/util/moneystr.h
@@ -6,8 +6,8 @@
/**
* Money parsing/formatting utilities.
*/
-#ifndef BITCOIN_UTILMONEYSTR_H
-#define BITCOIN_UTILMONEYSTR_H
+#ifndef BITCOIN_UTIL_MONEYSTR_H
+#define BITCOIN_UTIL_MONEYSTR_H
#include <stdint.h>
#include <string>
@@ -21,4 +21,4 @@ std::string FormatMoney(const CAmount& n);
bool ParseMoney(const std::string& str, CAmount& nRet);
bool ParseMoney(const char* pszIn, CAmount& nRet);
-#endif // BITCOIN_UTILMONEYSTR_H
+#endif // BITCOIN_UTIL_MONEYSTR_H
diff --git a/src/utilstrencodings.cpp b/src/util/strencodings.cpp
index 4940267bae..2a2df43337 100644
--- a/src/utilstrencodings.cpp
+++ b/src/util/strencodings.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <tinyformat.h>
@@ -20,6 +20,7 @@ static const std::string SAFE_CHARS[] =
CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
+ CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%", // SAFE_CHARS_URI
};
std::string SanitizeString(const std::string& str, int rule)
@@ -85,7 +86,7 @@ std::vector<unsigned char> ParseHex(const char* psz)
std::vector<unsigned char> vch;
while (true)
{
- while (isspace(*psz))
+ while (IsSpace(*psz))
psz++;
signed char c = HexDigit(*psz++);
if (c == (signed char)-1)
@@ -266,7 +267,7 @@ static bool ParsePrechecks(const std::string& str)
{
if (str.empty()) // No empty string allowed
return false;
- if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed
+ if (str.size() >= 1 && (IsSpace(str[0]) || IsSpace(str[str.size()-1]))) // No padding allowed
return false;
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
return false;
diff --git a/src/utilstrencodings.h b/src/util/strencodings.h
index 846a3917a2..87ccf40a1b 100644
--- a/src/utilstrencodings.h
+++ b/src/util/strencodings.h
@@ -6,8 +6,8 @@
/**
* Utilities for converting data from/to strings.
*/
-#ifndef BITCOIN_UTILSTRENCODINGS_H
-#define BITCOIN_UTILSTRENCODINGS_H
+#ifndef BITCOIN_UTIL_STRENCODINGS_H
+#define BITCOIN_UTIL_STRENCODINGS_H
#include <stdint.h>
#include <string>
@@ -25,6 +25,7 @@ enum SafeChars
SAFE_CHARS_DEFAULT, //!< The full set of allowed chars
SAFE_CHARS_UA_COMMENT, //!< BIP-0014 subset
SAFE_CHARS_FILENAME, //!< Chars allowed in filenames
+ SAFE_CHARS_URI, //!< Chars allowed in URIs (RFC 3986)
};
/**
@@ -72,6 +73,21 @@ constexpr bool IsDigit(char c)
}
/**
+ * Tests if the given character is a whitespace character. The whitespace characters
+ * are: space, form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal
+ * tab ('\t'), and vertical tab ('\v').
+ *
+ * This function is locale independent. Under the C locale this function gives the
+ * same result as std::isspace.
+ *
+ * @param[in] c character to test
+ * @return true if the argument is a whitespace character; otherwise false
+ */
+constexpr inline bool IsSpace(char c) noexcept {
+ return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v';
+}
+
+/**
* Convert string to signed 32-bit integer with strict parse error feedback.
* @returns true if the entire string could be parsed as valid integer,
* false if not the entire string could be parsed or when overflow or underflow occurred.
@@ -230,4 +246,4 @@ constexpr unsigned char ToUpper(unsigned char c)
*/
std::string Capitalize(std::string str);
-#endif // BITCOIN_UTILSTRENCODINGS_H
+#endif // BITCOIN_UTIL_STRENCODINGS_H
diff --git a/src/util.cpp b/src/util/system.cpp
index fa624aee90..f6f36c2238 100644
--- a/src/util.cpp
+++ b/src/util/system.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <util.h>
+#include <util/system.h>
#include <chainparamsbase.h>
#include <random.h>
#include <serialize.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <stdarg.h>
@@ -61,6 +61,7 @@
#include <codecvt>
#include <io.h> /* for _commit */
+#include <shellapi.h>
#include <shlobj.h>
#endif
@@ -825,8 +826,10 @@ static bool GetConfigOptions(std::istream& stream, std::string& error, std::vect
std::string::size_type pos;
int linenr = 1;
while (std::getline(stream, str)) {
+ bool used_hash = false;
if ((pos = str.find('#')) != std::string::npos) {
str = str.substr(0, pos);
+ used_hash = true;
}
const static std::string pattern = " \t\r\n";
str = TrimString(str, pattern);
@@ -839,6 +842,10 @@ static bool GetConfigOptions(std::istream& stream, std::string& error, std::vect
} else if ((pos = str.find('=')) != std::string::npos) {
std::string name = prefix + TrimString(str.substr(0, pos), pattern);
std::string value = TrimString(str.substr(pos + 1), pattern);
+ if (used_hash && name == "rpcpassword") {
+ error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr);
+ return false;
+ }
options.emplace_back(name, value);
} else {
error = strprintf("parse error on line %i: %s", linenr, str);
@@ -891,7 +898,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
}
const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME);
- fs::ifstream stream(GetConfigFile(confPath));
+ fsbridge::ifstream stream(GetConfigFile(confPath));
// ok to not have a config file
if (stream.good()) {
@@ -924,7 +931,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
}
for (const std::string& to_include : includeconf) {
- fs::ifstream include_config(GetConfigFile(to_include));
+ fsbridge::ifstream include_config(GetConfigFile(to_include));
if (include_config.good()) {
if (!ReadConfigStream(include_config, error, ignore_invalid_keys)) {
return false;
@@ -1200,6 +1207,10 @@ void SetupEnvironment()
} catch (const std::runtime_error&) {
setenv("LC_ALL", "C", 1);
}
+#elif defined(WIN32)
+ // Set the default input/output charset is utf-8
+ SetConsoleCP(CP_UTF8);
+ SetConsoleOutputCP(CP_UTF8);
#endif
// The path locale is lazy initialized and to avoid deinitialization errors
// in multithreading environments, it is set explicitly by the main thread.
@@ -1265,3 +1276,30 @@ int ScheduleBatchPriority()
return 1;
#endif
}
+
+namespace util {
+#ifdef WIN32
+WinCmdLineArgs::WinCmdLineArgs()
+{
+ wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
+ std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt;
+ argv = new char*[argc];
+ args.resize(argc);
+ for (int i = 0; i < argc; i++) {
+ args[i] = utf8_cvt.to_bytes(wargv[i]);
+ argv[i] = &*args[i].begin();
+ }
+ LocalFree(wargv);
+}
+
+WinCmdLineArgs::~WinCmdLineArgs()
+{
+ delete[] argv;
+}
+
+std::pair<int, char**> WinCmdLineArgs::get()
+{
+ return std::make_pair(argc, argv);
+}
+#endif
+} // namespace util
diff --git a/src/util.h b/src/util/system.h
index f119385e48..5634b8dd61 100644
--- a/src/util.h
+++ b/src/util/system.h
@@ -7,8 +7,8 @@
* Server/client environment: argument handling, config file parsing,
* thread wrappers, startup time
*/
-#ifndef BITCOIN_UTIL_H
-#define BITCOIN_UTIL_H
+#ifndef BITCOIN_UTIL_SYSTEM_H
+#define BITCOIN_UTIL_SYSTEM_H
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
@@ -19,8 +19,8 @@
#include <logging.h>
#include <sync.h>
#include <tinyformat.h>
-#include <utilmemory.h>
-#include <utiltime.h>
+#include <util/memory.h>
+#include <util/time.h>
#include <atomic>
#include <exception>
@@ -29,6 +29,7 @@
#include <stdint.h>
#include <string>
#include <unordered_set>
+#include <utility>
#include <vector>
#include <boost/thread/condition_variable.hpp> // for boost::thread_interrupted
@@ -361,6 +362,21 @@ inline void insert(std::set<TsetT>& dst, const Tsrc& src) {
dst.insert(src.begin(), src.end());
}
+#ifdef WIN32
+class WinCmdLineArgs
+{
+public:
+ WinCmdLineArgs();
+ ~WinCmdLineArgs();
+ std::pair<int, char**> get();
+
+private:
+ int argc;
+ char** argv;
+ std::vector<std::string> args;
+};
+#endif
+
} // namespace util
-#endif // BITCOIN_UTIL_H
+#endif // BITCOIN_UTIL_SYSTEM_H
diff --git a/src/utiltime.cpp b/src/util/time.cpp
index 908791da48..83a7937d8f 100644
--- a/src/utiltime.cpp
+++ b/src/util/time.cpp
@@ -7,7 +7,7 @@
#include <config/bitcoin-config.h>
#endif
-#include <utiltime.h>
+#include <util/time.h>
#include <atomic>
#include <boost/date_time/posix_time/posix_time.hpp>
diff --git a/src/utiltime.h b/src/util/time.h
index c3e3da3014..f2e2747434 100644
--- a/src/utiltime.h
+++ b/src/util/time.h
@@ -3,8 +3,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_UTILTIME_H
-#define BITCOIN_UTILTIME_H
+#ifndef BITCOIN_UTIL_TIME_H
+#define BITCOIN_UTIL_TIME_H
#include <stdint.h>
#include <string>
@@ -35,4 +35,4 @@ std::string FormatISO8601DateTime(int64_t nTime);
std::string FormatISO8601Date(int64_t nTime);
std::string FormatISO8601Time(int64_t nTime);
-#endif // BITCOIN_UTILTIME_H
+#endif // BITCOIN_UTIL_TIME_H
diff --git a/src/validation.cpp b/src/validation.cpp
index 458458d85d..241957878e 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -35,9 +35,9 @@
#include <txmempool.h>
#include <ui_interface.h>
#include <undo.h>
-#include <util.h>
-#include <utilmoneystr.h>
-#include <utilstrencodings.h>
+#include <util/system.h>
+#include <util/moneystr.h>
+#include <util/strencodings.h>
#include <validationinterface.h>
#include <warnings.h>
@@ -361,10 +361,10 @@ bool TestLockPointValidity(const LockPoints* lp)
return true;
}
-bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints)
+bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp, bool useExistingLockPoints)
{
AssertLockHeld(cs_main);
- AssertLockHeld(mempool.cs);
+ AssertLockHeld(pool.cs);
CBlockIndex* tip = chainActive.Tip();
assert(tip != nullptr);
@@ -387,7 +387,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
}
else {
// pcoinsTip contains the UTXO set for chainActive.Tip()
- CCoinsViewMemPool viewMemPool(pcoinsTip.get(), mempool);
+ CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
std::vector<int> prevheights;
prevheights.resize(tx.vin.size());
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
@@ -679,7 +679,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// be mined yet.
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a
// CoinsViewCache instead of create its own
- if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
+ if (!CheckSequenceLocks(pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final");
CAmount nFees = 0;
@@ -918,7 +918,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks (using TestBlockValidity), however allowing such
// transactions into the mempool can be exploited as a DoS attack.
- unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(chainActive.Tip(), Params().GetConsensus());
+ unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(chainActive.Tip(), chainparams.GetConsensus());
if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, currentBlockScriptVerifyFlags, true, txdata)) {
return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s",
__func__, hash.ToString(), FormatStateMessage(state));
@@ -4766,6 +4766,9 @@ bool DumpMempool()
std::map<uint256, CAmount> mapDeltas;
std::vector<TxMempoolInfo> vinfo;
+ static Mutex dump_mutex;
+ LOCK(dump_mutex);
+
{
LOCK(mempool.cs);
for (const auto &i : mempool.mapDeltas) {
diff --git a/src/validation.h b/src/validation.h
index 1034ba4665..3e98ebc866 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -257,7 +257,7 @@ bool LoadGenesisBlock(const CChainParams& chainparams);
* initializing state if we're running with -reindex. */
bool LoadBlockIndex(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Update the chain tip based on database information. */
-bool LoadChainTip(const CChainParams& chainparams);
+bool LoadChainTip(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Unload database information */
void UnloadBlockIndex();
/** Run an instance of the script checking thread */
@@ -347,7 +347,7 @@ bool TestLockPointValidity(const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_mai
*
* See consensus/consensus.h for flag definitions.
*/
-bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Closure representing one script verification
@@ -436,7 +436,7 @@ inline CBlockIndex* LookupBlockIndex(const uint256& hash)
}
/** Find the last common block between the parameter chain and a locator. */
-CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator);
+CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Mark a block as precious and reorganize.
*
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index e25eca2368..214a9ffba9 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -8,7 +8,7 @@
#include <primitives/block.h>
#include <scheduler.h>
#include <txmempool.h>
-#include <util.h>
+#include <util/system.h>
#include <validation.h>
#include <list>
diff --git a/src/wallet/coincontrol.cpp b/src/wallet/coincontrol.cpp
index 645981faa4..87d2c4f06e 100644
--- a/src/wallet/coincontrol.cpp
+++ b/src/wallet/coincontrol.cpp
@@ -4,7 +4,7 @@
#include <wallet/coincontrol.h>
-#include <util.h>
+#include <util/system.h>
void CCoinControl::SetNull()
{
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index fdeb89553b..5e955b8495 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -4,8 +4,8 @@
#include <wallet/coinselection.h>
-#include <util.h>
-#include <utilmoneystr.h>
+#include <util/system.h>
+#include <util/moneystr.h>
#include <boost/optional.hpp>
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index 729e4e39b0..de320b4e9e 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -8,7 +8,7 @@
#include <crypto/sha512.h>
#include <script/script.h>
#include <script/standard.h>
-#include <util.h>
+#include <util/system.h>
#include <string>
#include <vector>
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index a7bf89c572..74787eb5d2 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -8,7 +8,7 @@
#include <addrman.h>
#include <hash.h>
#include <protocol.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <wallet/walletutil.h>
#include <stdint.h>
@@ -20,6 +20,7 @@
#include <boost/thread.hpp>
namespace {
+
//! Make sure database has a unique fileid within the environment. If it
//! doesn't, throw an error. BDB caches do not work properly when more than one
//! open database has the same fileid (values written to one database may show
@@ -29,25 +30,19 @@ namespace {
//! (https://docs.oracle.com/cd/E17275_01/html/programmer_reference/program_copy.html),
//! so bitcoin should never create different databases with the same fileid, but
//! this error can be triggered if users manually copy database files.
-void CheckUniqueFileid(const BerkeleyEnvironment& env, const std::string& filename, Db& db)
+void CheckUniqueFileid(const BerkeleyEnvironment& env, const std::string& filename, Db& db, WalletDatabaseFileId& fileid)
{
if (env.IsMock()) return;
- u_int8_t fileid[DB_FILE_ID_LEN];
- int ret = db.get_mpf()->get_fileid(fileid);
+ int ret = db.get_mpf()->get_fileid(fileid.value);
if (ret != 0) {
throw std::runtime_error(strprintf("BerkeleyBatch: Can't open database %s (get_fileid failed with %d)", filename, ret));
}
- for (const auto& item : env.mapDb) {
- u_int8_t item_fileid[DB_FILE_ID_LEN];
- if (item.second && item.second->get_mpf()->get_fileid(item_fileid) == 0 &&
- memcmp(fileid, item_fileid, sizeof(fileid)) == 0) {
- const char* item_filename = nullptr;
- item.second->get_dbname(&item_filename, nullptr);
+ for (const auto& item : env.m_fileids) {
+ if (fileid == item.second && &fileid != &item.second) {
throw std::runtime_error(strprintf("BerkeleyBatch: Can't open database %s (duplicates fileid %s from %s)", filename,
- HexStr(std::begin(item_fileid), std::end(item_fileid)),
- item_filename ? item_filename : "(unknown database)"));
+ HexStr(std::begin(item.second.value), std::end(item.second.value)), item.first));
}
}
}
@@ -56,6 +51,11 @@ CCriticalSection cs_db;
std::map<std::string, BerkeleyEnvironment> g_dbenvs GUARDED_BY(cs_db); //!< Map from directory name to open db environment.
} // namespace
+bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const
+{
+ return memcmp(value, &rhs.value, sizeof(value)) == 0;
+}
+
BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename)
{
fs::path env_directory;
@@ -504,7 +504,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo
// versions of BDB have an set_lk_exclusive method for this
// purpose, but the older version we use does not.)
for (const auto& env : g_dbenvs) {
- CheckUniqueFileid(env.second, strFilename, *pdb_temp);
+ CheckUniqueFileid(env.second, strFilename, *pdb_temp, this->env->m_fileids[strFilename]);
}
pdb = pdb_temp.release();
@@ -826,6 +826,13 @@ void BerkeleyDatabase::Flush(bool shutdown)
LOCK(cs_db);
g_dbenvs.erase(env->Directory().string());
env = nullptr;
+ } else {
+ // TODO: To avoid g_dbenvs.erase erasing the environment prematurely after the
+ // first database shutdown when multiple databases are open in the same
+ // environment, should replace raw database `env` pointers with shared or weak
+ // pointers, or else separate the database and environment shutdowns so
+ // environments can be shut down after databases.
+ env->m_fileids.erase(strFile);
}
}
}
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 467ed13b45..8f96483a18 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -11,13 +11,14 @@
#include <serialize.h>
#include <streams.h>
#include <sync.h>
-#include <util.h>
+#include <util/system.h>
#include <version.h>
#include <atomic>
#include <map>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
#include <db_cxx.h>
@@ -25,6 +26,11 @@
static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
static const bool DEFAULT_WALLET_PRIVDB = true;
+struct WalletDatabaseFileId {
+ u_int8_t value[DB_FILE_ID_LEN];
+ bool operator==(const WalletDatabaseFileId& rhs) const;
+};
+
class BerkeleyEnvironment
{
private:
@@ -38,6 +44,7 @@ public:
std::unique_ptr<DbEnv> dbenv;
std::map<std::string, int> mapFileUseCount;
std::map<std::string, Db*> mapDb;
+ std::unordered_map<std::string, WalletDatabaseFileId> m_fileids;
std::condition_variable_any m_db_in_use;
BerkeleyEnvironment(const fs::path& env_directory);
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 677bf74b5d..7a71aea715 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/validation.h>
+#include <interfaces/chain.h>
#include <wallet/coincontrol.h>
#include <wallet/feebumper.h>
#include <wallet/fees.h>
@@ -12,13 +13,13 @@
#include <policy/rbf.h>
#include <validation.h> //for mempool access
#include <txmempool.h>
-#include <utilmoneystr.h>
-#include <util.h>
+#include <util/moneystr.h>
+#include <util/system.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.
-static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors) EXCLUSIVE_LOCKS_REQUIRED(cs_main, wallet->cs_wallet)
+static feebumper::Result PreconditionChecks(interfaces::Chain::Lock& locked_chain, const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet)
{
if (wallet->HasWalletSpend(wtx.GetHash())) {
errors.push_back("Transaction has descendants in the wallet");
@@ -34,7 +35,7 @@ static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWallet
}
}
- if (wtx.GetDepthInMainChain() != 0) {
+ if (wtx.GetDepthInMainChain(locked_chain) != 0) {
errors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
return feebumper::Result::WALLET_ERROR;
}
@@ -64,19 +65,21 @@ namespace feebumper {
bool TransactionCanBeBumped(const CWallet* wallet, const uint256& txid)
{
- LOCK2(cs_main, wallet->cs_wallet);
+ auto locked_chain = wallet->chain().lock();
+ LOCK(wallet->cs_wallet);
const CWalletTx* wtx = wallet->GetWalletTx(txid);
if (wtx == nullptr) return false;
std::vector<std::string> errors_dummy;
- feebumper::Result res = PreconditionChecks(wallet, *wtx, errors_dummy);
+ feebumper::Result res = PreconditionChecks(*locked_chain, wallet, *wtx, errors_dummy);
return res == feebumper::Result::OK;
}
Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoinControl& coin_control, CAmount total_fee, std::vector<std::string>& errors,
CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
{
- LOCK2(cs_main, wallet->cs_wallet);
+ auto locked_chain = wallet->chain().lock();
+ LOCK(wallet->cs_wallet);
errors.clear();
auto it = wallet->mapWallet.find(txid);
if (it == wallet->mapWallet.end()) {
@@ -85,7 +88,7 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin
}
const CWalletTx& wtx = it->second;
- Result result = PreconditionChecks(wallet, wtx, errors);
+ Result result = PreconditionChecks(*locked_chain, wallet, wtx, errors);
if (result != Result::OK) {
return result;
}
@@ -212,13 +215,15 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin
}
bool SignTransaction(CWallet* wallet, CMutableTransaction& mtx) {
- LOCK2(cs_main, wallet->cs_wallet);
+ auto locked_chain = wallet->chain().lock();
+ LOCK(wallet->cs_wallet);
return wallet->SignTransaction(mtx);
}
Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<std::string>& errors, uint256& bumped_txid)
{
- LOCK2(cs_main, wallet->cs_wallet);
+ auto locked_chain = wallet->chain().lock();
+ LOCK(wallet->cs_wallet);
if (!errors.empty()) {
return Result::MISC_ERROR;
}
@@ -230,7 +235,7 @@ Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransacti
CWalletTx& oldWtx = it->second;
// make sure the transaction still has no descendants and hasn't been mined in the meantime
- Result result = PreconditionChecks(wallet, oldWtx, errors);
+ Result result = PreconditionChecks(*locked_chain, wallet, oldWtx, errors);
if (result != Result::OK) {
return result;
}
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
index d620e25f2b..9e2984ff05 100644
--- a/src/wallet/fees.cpp
+++ b/src/wallet/fees.cpp
@@ -7,7 +7,7 @@
#include <policy/policy.h>
#include <txmempool.h>
-#include <util.h>
+#include <util/system.h>
#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/wallet.h>
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index a299a4ee44..14d811c6cd 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -5,11 +5,12 @@
#include <chainparams.h>
#include <init.h>
+#include <interfaces/chain.h>
#include <net.h>
#include <scheduler.h>
#include <outputtype.h>
-#include <util.h>
-#include <utilmoneystr.h>
+#include <util/system.h>
+#include <util/moneystr.h>
#include <validation.h>
#include <walletinitinterface.h>
#include <wallet/rpcwallet.h>
@@ -28,28 +29,8 @@ public:
//! Wallets parameter interaction
bool ParameterInteraction() const override;
- //! Register wallet RPCs.
- void RegisterRPC(CRPCTable &tableRPC) const override;
-
- //! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
- // This function will perform salvage on the wallet if requested, as long as only one wallet is
- // being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
- bool Verify() const override;
-
- //! Load wallet databases.
- bool Open() const override;
-
- //! Complete startup of wallets.
- void Start(CScheduler& scheduler) const override;
-
- //! Flush all wallets in preparation for shutdown.
- void Flush() const override;
-
- //! Stop all wallets. Wallets will be flushed first.
- void Stop() const override;
-
- //! Close all wallets.
- void Close() const override;
+ //! Add wallets that should be opened to list of init interfaces.
+ void Construct(InitInterfaces& interfaces) const override;
};
const WalletInitInterface& g_wallet_init_interface = WalletInit();
@@ -57,7 +38,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)", 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). "
@@ -99,7 +80,6 @@ bool WalletInit::ParameterInteraction() const
return true;
}
- gArgs.SoftSetArg("-wallet", "");
const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
@@ -165,38 +145,28 @@ bool WalletInit::ParameterInteraction() const
return true;
}
-void WalletInit::RegisterRPC(CRPCTable &t) const
-{
- if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
- return;
- }
-
- RegisterWalletRPCCommands(t);
-}
-
-bool WalletInit::Verify() const
+bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
{
- if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
- return true;
- }
-
if (gArgs.IsArgSet("-walletdir")) {
fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
- if (!fs::exists(wallet_dir)) {
+ boost::system::error_code error;
+ // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
+ fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
+ if (error || !fs::exists(wallet_dir)) {
return InitError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
} else if (!fs::is_directory(wallet_dir)) {
return InitError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
+ // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
} else if (!wallet_dir.is_absolute()) {
return InitError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
}
+ gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string());
}
LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
uiInterface.InitMessage(_("Verifying wallet(s)..."));
- std::vector<std::string> wallet_files = gArgs.GetArgs("-wallet");
-
// Parameter interaction code should have thrown an error if -salvagewallet
// was enabled with more than wallet file, so the wallet_files size check
// here should have no effect.
@@ -206,15 +176,15 @@ bool WalletInit::Verify() const
std::set<fs::path> wallet_paths;
for (const auto& wallet_file : wallet_files) {
- fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir());
+ WalletLocation location(wallet_file);
- if (!wallet_paths.insert(wallet_path).second) {
+ if (!wallet_paths.insert(location.GetPath()).second) {
return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
}
std::string error_string;
std::string warning_string;
- bool verify_success = CWallet::Verify(wallet_file, salvage_wallet, error_string, warning_string);
+ bool verify_success = CWallet::Verify(chain, location, salvage_wallet, error_string, warning_string);
if (!error_string.empty()) InitError(error_string);
if (!warning_string.empty()) InitWarning(warning_string);
if (!verify_success) return false;
@@ -223,15 +193,20 @@ bool WalletInit::Verify() const
return true;
}
-bool WalletInit::Open() const
+void WalletInit::Construct(InitInterfaces& interfaces) const
{
if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
LogPrintf("Wallet disabled!\n");
- return true;
+ return;
}
+ gArgs.SoftSetArg("-wallet", "");
+ interfaces.chain_clients.emplace_back(interfaces::MakeWalletClient(*interfaces.chain, gArgs.GetArgs("-wallet")));
+}
- for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
- std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(walletFile, fs::absolute(walletFile, GetWalletDir()));
+bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
+{
+ for (const std::string& walletFile : wallet_files) {
+ std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile));
if (!pwallet) {
return false;
}
@@ -241,7 +216,7 @@ bool WalletInit::Open() const
return true;
}
-void WalletInit::Start(CScheduler& scheduler) const
+void StartWallets(CScheduler& scheduler)
{
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
pwallet->postInitProcess();
@@ -251,21 +226,21 @@ void WalletInit::Start(CScheduler& scheduler) const
scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
}
-void WalletInit::Flush() const
+void FlushWallets()
{
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
pwallet->Flush(false);
}
}
-void WalletInit::Stop() const
+void StopWallets()
{
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
pwallet->Flush(true);
}
}
-void WalletInit::Close() const
+void UnloadWallets()
{
for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
RemoveWallet(pwallet);
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index c97bc38e6f..e1e4fc51fe 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -3,21 +3,21 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chain.h>
+#include <interfaces/chain.h>
#include <key_io.h>
#include <rpc/server.h>
#include <validation.h>
#include <script/script.h>
#include <script/standard.h>
#include <sync.h>
-#include <util.h>
-#include <utiltime.h>
+#include <util/system.h>
+#include <util/time.h>
#include <wallet/wallet.h>
#include <merkleblock.h>
#include <core_io.h>
#include <wallet/rpcwallet.h>
-#include <fstream>
#include <stdint.h>
#include <boost/algorithm/string.hpp>
@@ -134,7 +134,8 @@ UniValue importprivkey(const JSONRPCRequest& request)
WalletRescanReserver reserver(pwallet);
bool fRescan = true;
{
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
@@ -306,7 +307,8 @@ UniValue importaddress(const JSONRPCRequest& request)
fP2SH = request.params[3].get_bool();
{
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (IsValidDestination(dest)) {
@@ -363,7 +365,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
unsigned int txnIndex = 0;
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {
- LOCK(cs_main);
+ auto locked_chain = pwallet->chain().lock();
const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash());
if (!pindex || !chainActive.Contains(pindex)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
@@ -383,7 +385,8 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
wtx.nIndex = txnIndex;
wtx.hashBlock = merkleBlock.header.GetHash();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
if (pwallet->IsMine(*wtx.tx)) {
pwallet->AddToWallet(wtx, false);
@@ -413,7 +416,8 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
+ HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
);
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
uint256 hash(ParseHashV(request.params[0], "txid"));
std::vector<uint256> vHash;
@@ -484,7 +488,8 @@ UniValue importpubkey(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
{
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
for (const auto& dest : GetAllDestinationsForKey(pubKey)) {
ImportAddress(pwallet, dest, strLabel);
@@ -536,12 +541,13 @@ UniValue importwallet(const JSONRPCRequest& request)
int64_t nTimeBegin = 0;
bool fGood = true;
{
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
- std::ifstream file;
- file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate);
+ fsbridge::ifstream file;
+ file.open(request.params[0].get_str(), std::ios::in | std::ios::ate);
if (!file.is_open()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
}
@@ -654,7 +660,8 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"")
);
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
@@ -701,7 +708,8 @@ UniValue dumpwallet(const JSONRPCRequest& request)
+ HelpExampleRpc("dumpwallet", "\"test\"")
);
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
@@ -717,14 +725,14 @@ UniValue dumpwallet(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.string() + " already exists. If you are sure this is what you want, move it out of the way first");
}
- std::ofstream file;
- file.open(filepath.string().c_str());
+ fsbridge::ofstream file;
+ file.open(filepath);
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
std::map<CTxDestination, int64_t> mapKeyBirth;
const std::map<CKeyID, int64_t>& mapKeyPool = pwallet->GetAllReserveKeys();
- pwallet->GetKeyBirthTimes(mapKeyBirth);
+ pwallet->GetKeyBirthTimes(*locked_chain, mapKeyBirth);
std::set<CScriptID> scripts = pwallet->GetCScripts();
// TODO: include scripts in GetKeyBirthTimes() output instead of separate
@@ -809,29 +817,24 @@ UniValue dumpwallet(const JSONRPCRequest& request)
static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
try {
- bool success = false;
-
- // Required fields.
+ // First ensure scriptPubKey has either a script or JSON with "address" string
const UniValue& scriptPubKey = data["scriptPubKey"];
-
- // Should have script or JSON with "address".
- if (!(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address")) && !(scriptPubKey.getType() == UniValue::VSTR)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid scriptPubKey");
+ bool isScript = scriptPubKey.getType() == UniValue::VSTR;
+ if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address"))) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "scriptPubKey must be string with script or JSON with address string");
}
+ const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
// Optional fields.
const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
+ const std::string& witness_script_hex = data.exists("witnessscript") ? data["witnessscript"].get_str() : "";
const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
- const std::string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
-
- bool isScript = scriptPubKey.getType() == UniValue::VSTR;
- bool isP2SH = strRedeemScript.length() > 0;
- const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
+ const std::string& label = data.exists("label") ? data["label"].get_str() : "";
- // Parse the output.
+ // Generate the script and destination for the scriptPubKey provided
CScript script;
CTxDestination dest;
@@ -855,35 +858,38 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
// Watchonly and private keys
if (watchOnly && keys.size()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between watchonly and keys");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Watch-only addresses should not include private keys");
}
- // Internal + Label
+ // Internal addresses should not have a label
if (internal && data.exists("label")) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between internal and label");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label");
}
- // Keys / PubKeys size check.
- if (!isP2SH && (keys.size() > 1 || pubKeys.size() > 1)) { // Address / scriptPubKey
- throw JSONRPCError(RPC_INVALID_PARAMETER, "More than private key given for one address");
+ // Force users to provide the witness script in its field rather than redeemscript
+ if (!strRedeemScript.empty() && script.IsPayToWitnessScriptHash()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "P2WSH addresses have an empty redeemscript. Please provide the witnessscript instead.");
}
- // Invalid P2SH redeemScript
- if (isP2SH && !IsHex(strRedeemScript)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script");
- }
-
- // Process. //
+ CScript scriptpubkey_script = script;
+ CTxDestination scriptpubkey_dest = dest;
+ bool allow_p2wpkh = true;
// P2SH
- if (isP2SH) {
+ if (!strRedeemScript.empty() && script.IsPayToScriptHash()) {
+ // Check the redeemScript is valid
+ if (!IsHex(strRedeemScript)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script: must be hex string");
+ }
+
// Import redeem script.
std::vector<unsigned char> vData(ParseHex(strRedeemScript));
CScript redeemScript = CScript(vData.begin(), vData.end());
+ CScriptID redeem_id(redeemScript);
- // Invalid P2SH address
- if (!script.IsPayToScriptHash()) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid P2SH address / script");
+ // Check that the redeemScript and scriptPubKey match
+ if (GetScriptForDestination(redeem_id) != script) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The redeemScript does not match the scriptPubKey");
}
pwallet->MarkDirty();
@@ -892,103 +898,83 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
- CScriptID redeem_id(redeemScript);
if (!pwallet->HaveCScript(redeem_id) && !pwallet->AddCScript(redeemScript)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}
- CScript redeemDestination = GetScriptForDestination(redeem_id);
+ // Now set script to the redeemScript so we parse the inner script as P2WSH or P2WPKH below
+ script = redeemScript;
+ ExtractDestination(script, dest);
+ }
- if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) {
- throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ // (P2SH-)P2WSH
+ if (!witness_script_hex.empty() && script.IsPayToWitnessScriptHash()) {
+ if (!IsHex(witness_script_hex)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script: must be hex string");
}
- pwallet->MarkDirty();
+ // Generate the scripts
+ std::vector<unsigned char> witness_script_parsed(ParseHex(witness_script_hex));
+ CScript witness_script = CScript(witness_script_parsed.begin(), witness_script_parsed.end());
+ CScriptID witness_id(witness_script);
- if (!pwallet->AddWatchOnly(redeemDestination, timestamp)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ // Check that the witnessScript and scriptPubKey match
+ if (GetScriptForDestination(WitnessV0ScriptHash(witness_script)) != script) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The witnessScript does not match the scriptPubKey or redeemScript");
}
- // add to address book or update label
- if (IsValidDestination(dest)) {
- pwallet->SetAddressBook(dest, label, "receive");
+ // Add the witness script as watch only only if it is not for P2SH-P2WSH
+ if (!scriptpubkey_script.IsPayToScriptHash() && !pwallet->AddWatchOnly(witness_script, timestamp)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
- // Import private keys.
- if (keys.size()) {
- for (size_t i = 0; i < keys.size(); i++) {
- const std::string& privkey = keys[i].get_str();
-
- CKey key = DecodeSecret(privkey);
-
- if (!key.IsValid()) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
- }
-
- CPubKey pubkey = key.GetPubKey();
- assert(key.VerifyPubKey(pubkey));
-
- CKeyID vchAddress = pubkey.GetID();
- pwallet->MarkDirty();
- pwallet->SetAddressBook(vchAddress, label, "receive");
-
- if (pwallet->HaveKey(vchAddress)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key");
- }
-
- pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
+ if (!pwallet->HaveCScript(witness_id) && !pwallet->AddCScript(witness_script)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2wsh witnessScript to wallet");
+ }
- if (!pwallet->AddKeyPubKey(key, pubkey)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
- }
+ // Now set script to the witnessScript so we parse the inner script as P2PK or P2PKH below
+ script = witness_script;
+ ExtractDestination(script, dest);
+ allow_p2wpkh = false; // P2WPKH cannot be embedded in P2WSH
+ }
- pwallet->UpdateTimeFirstKey(timestamp);
- }
+ // (P2SH-)P2PK/P2PKH/P2WPKH
+ if (dest.type() == typeid(CKeyID) || dest.type() == typeid(WitnessV0KeyHash)) {
+ if (!allow_p2wpkh && dest.type() == typeid(WitnessV0KeyHash)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "P2WPKH cannot be embedded in P2WSH");
}
-
- success = true;
- } else {
- // Import public keys.
- if (pubKeys.size() && keys.size() == 0) {
+ if (keys.size() > 1 || pubKeys.size() > 1) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "More than one key given for one single-key address");
+ }
+ CPubKey pubkey;
+ if (keys.size()) {
+ pubkey = DecodeSecret(keys[0].get_str()).GetPubKey();
+ }
+ if (pubKeys.size()) {
const std::string& strPubKey = pubKeys[0].get_str();
-
if (!IsHex(strPubKey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
}
-
- std::vector<unsigned char> vData(ParseHex(strPubKey));
- CPubKey pubKey(vData.begin(), vData.end());
-
- if (!pubKey.IsFullyValid()) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
- }
-
- CTxDestination pubkey_dest = pubKey.GetID();
-
- // Consistency check.
- if (!(pubkey_dest == dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
- }
-
- CScript pubKeyScript = GetScriptForDestination(pubkey_dest);
-
- if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) {
- throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ std::vector<unsigned char> vData(ParseHex(pubKeys[0].get_str()));
+ CPubKey pubkey_temp(vData.begin(), vData.end());
+ if (pubkey.size() && pubkey_temp != pubkey) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key does not match public key for address");
}
-
- pwallet->MarkDirty();
-
- if (!pwallet->AddWatchOnly(pubKeyScript, timestamp)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ pubkey = pubkey_temp;
+ }
+ if (pubkey.size() > 0) {
+ if (!pubkey.IsFullyValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
}
- // add to address book or update label
- if (IsValidDestination(pubkey_dest)) {
- pwallet->SetAddressBook(pubkey_dest, label, "receive");
+ // Check the key corresponds to the destination given
+ std::vector<CTxDestination> destinations = GetAllDestinationsForKey(pubkey);
+ if (std::find(destinations.begin(), destinations.end(), dest) == destinations.end()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Key does not match address destination");
}
- // TODO Is this necessary?
- CScript scriptRawPubKey = GetScriptForRawPubKey(pubKey);
+ // This is necessary to force the wallet to import the pubKey
+ CScript scriptRawPubKey = GetScriptForRawPubKey(pubkey);
if (::IsMine(*pwallet, scriptRawPubKey) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
@@ -999,73 +985,61 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
if (!pwallet->AddWatchOnly(scriptRawPubKey, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
-
- success = true;
}
+ }
- // Import private keys.
- if (keys.size()) {
- const std::string& strPrivkey = keys[0].get_str();
-
- // Checks.
- CKey key = DecodeSecret(strPrivkey);
-
- if (!key.IsValid()) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
- }
-
- CPubKey pubKey = key.GetPubKey();
- assert(key.VerifyPubKey(pubKey));
-
- CTxDestination pubkey_dest = pubKey.GetID();
+ // Import the address
+ if (::IsMine(*pwallet, scriptpubkey_script) == ISMINE_SPENDABLE) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ }
- // Consistency check.
- if (!(pubkey_dest == dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
- }
+ pwallet->MarkDirty();
- CKeyID vchAddress = pubKey.GetID();
- pwallet->MarkDirty();
- pwallet->SetAddressBook(vchAddress, label, "receive");
+ if (!pwallet->AddWatchOnly(scriptpubkey_script, timestamp)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ }
- if (pwallet->HaveKey(vchAddress)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
- }
+ if (!watchOnly && !pwallet->HaveCScript(CScriptID(scriptpubkey_script)) && !pwallet->AddCScript(scriptpubkey_script)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding scriptPubKey script to wallet");
+ }
- pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
+ // add to address book or update label
+ if (IsValidDestination(scriptpubkey_dest)) {
+ pwallet->SetAddressBook(scriptpubkey_dest, label, "receive");
+ }
- if (!pwallet->AddKeyPubKey(key, pubKey)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
- }
+ // Import private keys.
+ for (size_t i = 0; i < keys.size(); i++) {
+ const std::string& strPrivkey = keys[i].get_str();
- pwallet->UpdateTimeFirstKey(timestamp);
+ // Checks.
+ CKey key = DecodeSecret(strPrivkey);
- success = true;
+ if (!key.IsValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
}
- // Import scriptPubKey only.
- if (pubKeys.size() == 0 && keys.size() == 0) {
- if (::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
- throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
- }
+ CPubKey pubKey = key.GetPubKey();
+ assert(key.VerifyPubKey(pubKey));
- pwallet->MarkDirty();
+ CKeyID vchAddress = pubKey.GetID();
+ pwallet->MarkDirty();
- if (!pwallet->AddWatchOnly(script, timestamp)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
- }
+ if (pwallet->HaveKey(vchAddress)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key");
+ }
- // add to address book or update label
- if (IsValidDestination(dest)) {
- pwallet->SetAddressBook(dest, label, "receive");
- }
+ pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
- success = true;
+ if (!pwallet->AddKeyPubKey(key, pubKey)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
}
+
+ pwallet->UpdateTimeFirstKey(timestamp);
}
UniValue result = UniValue(UniValue::VOBJ);
- result.pushKV("success", UniValue(success));
+ result.pushKV("success", UniValue(true));
return result;
} catch (const UniValue& e) {
UniValue result = UniValue(UniValue::VOBJ);
@@ -1118,7 +1092,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
" \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
" 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n"
" creation time of all keys being imported by the importmulti call will be scanned.\n"
- " \"redeemscript\": \"<script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH address or a P2SH scriptPubKey\n"
+ " \"redeemscript\": \"<script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey\n"
+ " \"witnessscript\": \"<script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey\n"
" \"pubkeys\": [\"<pubKey>\", ... ] , (array, optional) Array of strings giving pubkeys that must occur in the output or redeemscript\n"
" \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n"
" \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be treated as not incoming payments\n"
@@ -1168,7 +1143,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
int64_t nLowestTimestamp = 0;
UniValue response(UniValue::VARR);
{
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
// Verify all timestamps are present before importing any keys.
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 7d0219201e..bfac990639 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -8,6 +8,8 @@
#include <consensus/validation.h>
#include <core_io.h>
#include <httpserver.h>
+#include <init.h>
+#include <interfaces/chain.h>
#include <validation.h>
#include <key_io.h>
#include <net.h>
@@ -23,8 +25,8 @@
#include <script/sign.h>
#include <shutdown.h>
#include <timedata.h>
-#include <util.h>
-#include <utilmoneystr.h>
+#include <util/system.h>
+#include <util/moneystr.h>
#include <wallet/coincontrol.h>
#include <wallet/feebumper.h>
#include <wallet/rpcwallet.h>
@@ -89,9 +91,9 @@ void EnsureWalletIsUnlocked(CWallet * const pwallet)
}
}
-static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static void WalletTxToJSON(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx, UniValue& entry)
{
- int confirms = wtx.GetDepthInMainChain();
+ int confirms = wtx.GetDepthInMainChain(locked_chain);
entry.pushKV("confirmations", confirms);
if (wtx.IsCoinBase())
entry.pushKV("generated", true);
@@ -101,7 +103,7 @@ static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) EXCLUSIVE_LOCK
entry.pushKV("blockindex", wtx.nIndex);
entry.pushKV("blocktime", LookupBlockIndex(wtx.hashBlock)->GetBlockTime());
} else {
- entry.pushKV("trusted", wtx.IsTrusted());
+ entry.pushKV("trusted", wtx.IsTrusted(locked_chain));
}
uint256 hash = wtx.GetHash();
entry.pushKV("txid", hash.GetHex());
@@ -290,7 +292,7 @@ static UniValue setlabel(const JSONRPCRequest& request)
}
-static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue)
+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();
@@ -317,7 +319,7 @@ static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
CTransactionRef tx;
- if (!pwallet->CreateTransaction(vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
+ if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
@@ -373,7 +375,8 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (!IsValidDestination(dest)) {
@@ -415,7 +418,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue));
+ CTransactionRef tx = SendMoney(*locked_chain, pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue));
return tx->GetHash().GetHex();
}
@@ -455,10 +458,11 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
UniValue jsonGroupings(UniValue::VARR);
- std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();
+ std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances(*locked_chain);
for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) {
UniValue jsonGrouping(UniValue::VARR);
for (const CTxDestination& address : grouping)
@@ -504,11 +508,12 @@ static UniValue signmessage(const JSONRPCRequest& request)
+ HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
"\nVerify the signature\n"
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
- "\nAs json rpc\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")
);
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
@@ -566,7 +571,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 0") +
"\nThe amount with at least 6 confirmations\n"
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 6") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6")
);
@@ -574,7 +579,9 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ LockAnnotation lock(::cs_main); // Temporary, for CheckFinalTx below. Removed in upcoming commit.
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
// Bitcoin address
CTxDestination dest = DecodeDestination(request.params[0].get_str());
@@ -600,7 +607,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
for (const CTxOut& txout : wtx.tx->vout)
if (txout.scriptPubKey == scriptPubKey)
- if (wtx.GetDepthInMainChain() >= nMinDepth)
+ if (wtx.GetDepthInMainChain(*locked_chain) >= nMinDepth)
nAmount += txout.nValue;
}
@@ -633,7 +640,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
+ HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") +
"\nThe amount with at least 6 confirmations\n"
+ HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6")
);
@@ -641,7 +648,9 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ LockAnnotation lock(::cs_main); // Temporary, for CheckFinalTx below. Removed in upcoming commit.
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
// Minimum confirmations
int nMinDepth = 1;
@@ -663,7 +672,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
{
CTxDestination address;
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwallet, address) && setAddress.count(address)) {
- if (wtx.GetDepthInMainChain() >= nMinDepth)
+ if (wtx.GetDepthInMainChain(*locked_chain) >= nMinDepth)
nAmount += txout.nValue;
}
}
@@ -699,7 +708,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
+ HelpExampleCli("getbalance", "") +
"\nThe total amount in the wallet at least 6 blocks confirmed\n"
+ HelpExampleCli("getbalance", "\"*\" 6") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("getbalance", "\"*\", 6")
);
@@ -707,7 +716,8 @@ static UniValue getbalance(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
const UniValue& dummy_value = request.params[0];
if (!dummy_value.isNull() && dummy_value.get_str() != "*") {
@@ -745,7 +755,8 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
return ValueFromAmount(pwallet->GetUnconfirmedBalance());
}
@@ -798,7 +809,7 @@ static UniValue sendmany(const JSONRPCRequest& request)
+ HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
"\nSend two amounts to two different addresses, subtract fee from amount:\n"
+ HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"")
);
@@ -806,7 +817,8 @@ static UniValue sendmany(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
if (pwallet->GetBroadcastTransactions() && !g_connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -892,7 +904,7 @@ static UniValue sendmany(const JSONRPCRequest& request)
int nChangePosRet = -1;
std::string strFailReason;
CTransactionRef tx;
- bool fCreated = pwallet->CreateTransaction(vecSend, tx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
+ bool fCreated = pwallet->CreateTransaction(*locked_chain, vecSend, tx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state;
@@ -939,13 +951,14 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
"\nExamples:\n"
"\nAdd a multisig address from 2 addresses\n"
+ HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
- "\nAs json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
;
throw std::runtime_error(msg);
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
std::string label;
if (!request.params[2].isNull())
@@ -982,131 +995,6 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
return result;
}
-class Witnessifier : public boost::static_visitor<bool>
-{
-public:
- CWallet * const pwallet;
- CTxDestination result;
- bool already_witness;
-
- explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet), already_witness(false) {}
-
- bool operator()(const CKeyID &keyID) {
- if (pwallet) {
- CScript basescript = GetScriptForDestination(keyID);
- CScript witscript = GetScriptForWitness(basescript);
- if (!IsSolvable(*pwallet, witscript)) {
- return false;
- }
- return ExtractDestination(witscript, result);
- }
- return false;
- }
-
- bool operator()(const CScriptID &scriptID) {
- CScript subscript;
- if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
- int witnessversion;
- std::vector<unsigned char> witprog;
- if (subscript.IsWitnessProgram(witnessversion, witprog)) {
- ExtractDestination(subscript, result);
- already_witness = true;
- return true;
- }
- CScript witscript = GetScriptForWitness(subscript);
- if (!IsSolvable(*pwallet, witscript)) {
- return false;
- }
- return ExtractDestination(witscript, result);
- }
- return false;
- }
-
- bool operator()(const WitnessV0KeyHash& id)
- {
- already_witness = true;
- result = id;
- return true;
- }
-
- bool operator()(const WitnessV0ScriptHash& id)
- {
- already_witness = true;
- result = id;
- return true;
- }
-
- template<typename T>
- bool operator()(const T& dest) { return false; }
-};
-
-static UniValue addwitnessaddress(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 msg = "addwitnessaddress \"address\" ( p2sh )\n"
- "\nDEPRECATED: set the address_type argument of getnewaddress, or option -addresstype=[bech32|p2sh-segwit] instead.\n"
- "Add a witness address for a script (with pubkey or redeemscript known). Requires a new wallet backup.\n"
- "It returns the witness script.\n"
-
- "\nArguments:\n"
- "1. \"address\" (string, required) An address known to the wallet\n"
- "2. p2sh (bool, optional, default=true) Embed inside P2SH\n"
-
- "\nResult:\n"
- "\"witnessaddress\", (string) The value of the new address (P2SH or BIP173).\n"
- "}\n"
- ;
- throw std::runtime_error(msg);
- }
-
- if (!IsDeprecatedRPCEnabled("addwitnessaddress")) {
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "addwitnessaddress is deprecated and will be fully removed in v0.17. "
- "To use addwitnessaddress in v0.16, restart bitcoind with -deprecatedrpc=addwitnessaddress.\n"
- "Projects should transition to using the address_type argument of getnewaddress, or option -addresstype=[bech32|p2sh-segwit] instead.\n");
- }
-
- CTxDestination dest = DecodeDestination(request.params[0].get_str());
- if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- }
-
- bool p2sh = true;
- if (!request.params[1].isNull()) {
- p2sh = request.params[1].get_bool();
- }
-
- Witnessifier w(pwallet);
- bool ret = boost::apply_visitor(w, dest);
- if (!ret) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed");
- }
-
- CScript witprogram = GetScriptForDestination(w.result);
-
- if (p2sh) {
- w.result = CScriptID(witprogram);
- }
-
- if (w.already_witness) {
- if (!(dest == w.result)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Cannot convert between witness address types");
- }
- } else {
- pwallet->AddCScript(witprogram); // Implicit for single-key now, but necessary for multisig and for compatibility with older software
- pwallet->SetAddressBook(w.result, "", "receive");
- }
-
- return EncodeDestination(w.result);
-}
-
struct tallyitem
{
CAmount nAmount;
@@ -1121,8 +1009,10 @@ struct tallyitem
}
};
-static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, CWallet * const pwallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
+ LockAnnotation lock(::cs_main); // Temporary, for CheckFinalTx below. Removed in upcoming commit.
+
// Minimum confirmations
int nMinDepth = 1;
if (!params[0].isNull())
@@ -1156,7 +1046,7 @@ static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bo
if (wtx.IsCoinBase() || !CheckFinalTx(*wtx.tx))
continue;
- int nDepth = wtx.GetDepthInMainChain();
+ int nDepth = wtx.GetDepthInMainChain(locked_chain);
if (nDepth < nMinDepth)
continue;
@@ -1310,9 +1200,10 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
- return ListReceived(pwallet, request.params, false);
+ return ListReceived(*locked_chain, pwallet, request.params, false);
}
static UniValue listreceivedbylabel(const JSONRPCRequest& request)
@@ -1354,9 +1245,10 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
- return ListReceived(pwallet, request.params, true);
+ return ListReceived(*locked_chain, pwallet, request.params, true);
}
static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
@@ -1376,7 +1268,7 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
* @param ret The UniValue into which the result is stored.
* @param filter The "is mine" filter bool.
*/
-static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
{
CAmount nFee;
std::list<COutputEntry> listReceived;
@@ -1404,14 +1296,14 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int n
entry.pushKV("vout", s.vout);
entry.pushKV("fee", ValueFromAmount(-nFee));
if (fLong)
- WalletTxToJSON(wtx, entry);
+ WalletTxToJSON(pwallet->chain(), locked_chain, wtx, entry);
entry.pushKV("abandoned", wtx.isAbandoned());
ret.push_back(entry);
}
}
// Received
- if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
+ if (listReceived.size() > 0 && wtx.GetDepthInMainChain(locked_chain) >= nMinDepth)
{
for (const COutputEntry& r : listReceived)
{
@@ -1426,9 +1318,9 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int n
MaybePushAddress(entry, r.destination);
if (wtx.IsCoinBase())
{
- if (wtx.GetDepthInMainChain() < 1)
+ if (wtx.GetDepthInMainChain(locked_chain) < 1)
entry.pushKV("category", "orphan");
- else if (wtx.IsImmatureCoinBase())
+ else if (wtx.IsImmatureCoinBase(locked_chain))
entry.pushKV("category", "immature");
else
entry.pushKV("category", "generate");
@@ -1443,7 +1335,7 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int n
}
entry.pushKV("vout", r.vout);
if (fLong)
- WalletTxToJSON(wtx, entry);
+ WalletTxToJSON(pwallet->chain(), locked_chain, wtx, entry);
ret.push_back(entry);
}
}
@@ -1500,7 +1392,7 @@ UniValue listtransactions(const JSONRPCRequest& request)
+ HelpExampleCli("listtransactions", "") +
"\nList transactions 100 to 120\n"
+ HelpExampleCli("listtransactions", "\"*\" 20 100") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
);
@@ -1530,7 +1422,8 @@ UniValue listtransactions(const JSONRPCRequest& request)
UniValue ret(UniValue::VARR);
{
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
@@ -1538,7 +1431,7 @@ UniValue listtransactions(const JSONRPCRequest& request)
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
CWalletTx *const pwtx = (*it).second;
- ListTransactions(pwallet, *pwtx, 0, true, ret, filter);
+ ListTransactions(*locked_chain, pwallet, *pwtx, 0, true, ret, filter);
if ((int)ret.size() >= (nCount+nFrom)) break;
}
}
@@ -1630,7 +1523,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
const CBlockIndex* pindex = nullptr; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain.
const CBlockIndex* paltindex = nullptr; // Block index of the specified block, even if it's in a deactivated chain.
@@ -1673,8 +1567,8 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
CWalletTx tx = pairWtx.second;
- if (depth == -1 || tx.GetDepthInMainChain() < depth) {
- ListTransactions(pwallet, tx, 0, true, transactions, filter);
+ if (depth == -1 || tx.GetDepthInMainChain(*locked_chain) < depth) {
+ ListTransactions(*locked_chain, pwallet, tx, 0, true, transactions, filter);
}
}
@@ -1691,7 +1585,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
if (it != pwallet->mapWallet.end()) {
// We want all transactions regardless of confirmation count to appear here,
// even negative confirmation ones, hence the big negative.
- ListTransactions(pwallet, it->second, -100000000, true, removed, filter);
+ ListTransactions(*locked_chain, pwallet, it->second, -100000000, true, removed, filter);
}
}
paltindex = paltindex->pprev;
@@ -1765,7 +1659,8 @@ static UniValue gettransaction(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
uint256 hash(ParseHashV(request.params[0], "txid"));
@@ -1781,7 +1676,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
}
const CWalletTx& wtx = it->second;
- CAmount nCredit = wtx.GetCredit(filter);
+ CAmount nCredit = wtx.GetCredit(*locked_chain, filter);
CAmount nDebit = wtx.GetDebit(filter);
CAmount nNet = nCredit - nDebit;
CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
@@ -1790,10 +1685,10 @@ static UniValue gettransaction(const JSONRPCRequest& request)
if (wtx.IsFromMe(filter))
entry.pushKV("fee", ValueFromAmount(nFee));
- WalletTxToJSON(wtx, entry);
+ WalletTxToJSON(pwallet->chain(), *locked_chain, wtx, entry);
UniValue details(UniValue::VARR);
- ListTransactions(pwallet, wtx, 0, false, details, filter);
+ ListTransactions(*locked_chain, pwallet, wtx, 0, false, details, filter);
entry.pushKV("details", details);
std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags());
@@ -1832,14 +1727,15 @@ static UniValue abandontransaction(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
uint256 hash(ParseHashV(request.params[0], "txid"));
if (!pwallet->mapWallet.count(hash)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
}
- if (!pwallet->AbandonTransaction(hash)) {
+ if (!pwallet->AbandonTransaction(*locked_chain, hash)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
}
@@ -1871,7 +1767,8 @@ static UniValue backupwallet(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
std::string strDest = request.params[0].get_str();
if (!pwallet->BackupWallet(strDest)) {
@@ -1907,7 +1804,8 @@ static UniValue keypoolrefill(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
// 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
unsigned int kpSize = 0;
@@ -1928,13 +1826,6 @@ static UniValue keypoolrefill(const JSONRPCRequest& request)
}
-static void LockWallet(CWallet* pWallet)
-{
- LOCK(pWallet->cs_wallet);
- pWallet->nRelockTime = 0;
- pWallet->Lock();
-}
-
static UniValue walletpassphrase(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -1960,12 +1851,13 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
+ HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
"\nLock the wallet again (before 60 seconds)\n"
+ HelpExampleCli("walletlock", "") +
- "\nAs json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
);
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
@@ -2004,7 +1896,18 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
pwallet->TopUpKeyPool();
pwallet->nRelockTime = GetTime() + nSleepTime;
- RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), std::bind(LockWallet, pwallet), nSleepTime);
+
+ // Keep a weak pointer to the wallet so that it is possible to unload the
+ // wallet before the following callback is called. If a valid shared pointer
+ // is acquired in the callback then the wallet is still loaded.
+ std::weak_ptr<CWallet> weak_wallet = wallet;
+ RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet] {
+ if (auto shared_wallet = weak_wallet.lock()) {
+ LOCK(shared_wallet->cs_wallet);
+ shared_wallet->Lock();
+ shared_wallet->nRelockTime = 0;
+ }
+ }, nSleepTime);
return NullUniValue;
}
@@ -2032,7 +1935,8 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request)
);
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
@@ -2083,12 +1987,13 @@ static UniValue walletlock(const JSONRPCRequest& request)
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
"\nClear the passphrase since we are done before 2 minutes is up\n"
+ HelpExampleCli("walletlock", "") +
- "\nAs json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("walletlock", "")
);
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
@@ -2129,12 +2034,13 @@ static UniValue encryptwallet(const JSONRPCRequest& request)
+ HelpExampleCli("signmessage", "\"address\" \"test message\"") +
"\nNow lock the wallet again by removing the passphrase\n"
+ HelpExampleCli("walletlock", "") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
);
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
if (pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
@@ -2200,7 +2106,7 @@ static UniValue lockunspent(const JSONRPCRequest& request)
+ HelpExampleCli("listlockunspent", "") +
"\nUnlock the transaction again\n"
+ HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
);
@@ -2208,7 +2114,8 @@ static UniValue lockunspent(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
@@ -2257,7 +2164,7 @@ static UniValue lockunspent(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
}
- if (pwallet->IsSpent(outpt.hash, outpt.n)) {
+ if (pwallet->IsSpent(*locked_chain, outpt.hash, outpt.n)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
}
@@ -2314,11 +2221,12 @@ static UniValue listlockunspent(const JSONRPCRequest& request)
+ HelpExampleCli("listlockunspent", "") +
"\nUnlock the transaction again\n"
+ HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
- "\nAs a json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("listlockunspent", "")
);
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
std::vector<COutPoint> vOutpts;
pwallet->ListLockedCoins(vOutpts);
@@ -2359,7 +2267,8 @@ static UniValue settxfee(const JSONRPCRequest& request)
);
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
CAmount nAmount = AmountFromValue(request.params[0]);
CFeeRate tx_fee_rate(nAmount, 1000);
@@ -2414,7 +2323,8 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
UniValue obj(UniValue::VOBJ);
@@ -2443,6 +2353,38 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
return obj;
}
+static UniValue listwalletdir(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 0) {
+ throw std::runtime_error(
+ "listwalletdir\n"
+ "Returns a list of wallets in the wallet directory.\n"
+ "{\n"
+ " \"wallets\" : [ (json array of objects)\n"
+ " {\n"
+ " \"name\" : \"name\" (string) The wallet name\n"
+ " }\n"
+ " ,...\n"
+ " ]\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("listwalletdir", "")
+ + HelpExampleRpc("listwalletdir", "")
+ );
+ }
+
+ UniValue wallets(UniValue::VARR);
+ for (const auto& path : ListWalletDir()) {
+ UniValue wallet(UniValue::VOBJ);
+ wallet.pushKV("name", path.string());
+ wallets.push_back(wallet);
+ }
+
+ UniValue result(UniValue::VOBJ);
+ result.pushKV("wallets", wallets);
+ return result;
+}
+
static UniValue listwallets(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
@@ -2494,26 +2436,26 @@ static UniValue loadwallet(const JSONRPCRequest& request)
+ HelpExampleCli("loadwallet", "\"test.dat\"")
+ HelpExampleRpc("loadwallet", "\"test.dat\"")
);
- std::string wallet_file = request.params[0].get_str();
+
+ WalletLocation location(request.params[0].get_str());
std::string error;
- fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir());
- if (fs::symlink_status(wallet_path).type() == fs::file_not_found) {
- throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + wallet_file + " not found.");
- } else if (fs::is_directory(wallet_path)) {
+ if (!location.Exists()) {
+ throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + location.GetName() + " not found.");
+ } else if (fs::is_directory(location.GetPath())) {
// The given filename is a directory. Check that there's a wallet.dat file.
- fs::path wallet_dat_file = wallet_path / "wallet.dat";
+ fs::path wallet_dat_file = location.GetPath() / "wallet.dat";
if (fs::symlink_status(wallet_dat_file).type() == fs::file_not_found) {
- throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Directory " + wallet_file + " does not contain a wallet.dat file.");
+ throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Directory " + location.GetName() + " does not contain a wallet.dat file.");
}
}
std::string warning;
- if (!CWallet::Verify(wallet_file, false, error, warning)) {
+ if (!CWallet::Verify(*g_rpc_interfaces->chain, location, false, error, warning)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
}
- std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(wallet_file, fs::absolute(wallet_file, GetWalletDir()));
+ std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location);
if (!wallet) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet loading failed.");
}
@@ -2547,7 +2489,6 @@ static UniValue createwallet(const JSONRPCRequest& request)
+ HelpExampleRpc("createwallet", "\"testwallet\"")
);
}
- std::string wallet_name = request.params[0].get_str();
std::string error;
std::string warning;
@@ -2556,17 +2497,17 @@ static UniValue createwallet(const JSONRPCRequest& request)
disable_privatekeys = request.params[1].get_bool();
}
- fs::path wallet_path = fs::absolute(wallet_name, GetWalletDir());
- if (fs::symlink_status(wallet_path).type() != fs::file_not_found) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Wallet " + wallet_name + " already exists.");
+ WalletLocation location(request.params[0].get_str());
+ if (location.Exists()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Wallet " + location.GetName() + " already exists.");
}
// Wallet::Verify will check if we're trying to create a wallet with a duplication name.
- if (!CWallet::Verify(wallet_name, false, error, warning)) {
+ if (!CWallet::Verify(*g_rpc_interfaces->chain, location, false, error, warning)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
}
- std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(wallet_name, fs::absolute(wallet_name, GetWalletDir()), (disable_privatekeys ? (uint64_t)WALLET_FLAG_DISABLE_PRIVATE_KEYS : 0));
+ std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location, (disable_privatekeys ? (uint64_t)WALLET_FLAG_DISABLE_PRIVATE_KEYS : 0));
if (!wallet) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed.");
}
@@ -2652,13 +2593,14 @@ static UniValue resendwallettransactions(const JSONRPCRequest& request)
if (!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
if (!pwallet->GetBroadcastTransactions()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast");
}
- std::vector<uint256> txids = pwallet->ResendWalletTransactionsBefore(GetTime(), g_connman.get());
+ std::vector<uint256> txids = pwallet->ResendWalletTransactionsBefore(*locked_chain, GetTime(), g_connman.get());
UniValue result(UniValue::VARR);
for (const uint256& txid : txids)
{
@@ -2789,8 +2731,9 @@ static UniValue listunspent(const JSONRPCRequest& request)
UniValue results(UniValue::VARR);
std::vector<COutput> vecOutputs;
{
- LOCK2(cs_main, pwallet->cs_wallet);
- pwallet->AvailableCoins(vecOutputs, !include_unsafe, nullptr, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
+ pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, nullptr, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
}
LOCK(pwallet->cs_wallet);
@@ -3108,10 +3051,11 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
}
// Sign the transaction
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
- return SignTransaction(mtx, request.params[1], pwallet, false, request.params[2]);
+ return SignTransaction(pwallet->chain(), mtx, request.params[1], pwallet, false, request.params[2]);
}
static UniValue bumpfee(const JSONRPCRequest& request)
@@ -3213,7 +3157,8 @@ static UniValue bumpfee(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
@@ -3289,6 +3234,12 @@ UniValue generate(const JSONRPCRequest& request)
);
}
+ if (!IsDeprecatedRPCEnabled("generate")) {
+ throw JSONRPCError(RPC_METHOD_DEPRECATED, "The wallet generate rpc method is deprecated and will be fully removed in v0.19. "
+ "To use generate in v0.18, restart bitcoind with -deprecatedrpc=generate.\n"
+ "Clients should transition to using the node rpc method generatetoaddress\n");
+ }
+
int num_generate = request.params[0].get_int();
uint64_t max_tries = 1000000;
if (!request.params[1].isNull()) {
@@ -3347,7 +3298,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
CBlockIndex *pindexStop = nullptr;
CBlockIndex *pChainTip = nullptr;
{
- LOCK(cs_main);
+ auto locked_chain = pwallet->chain().lock();
pindexStart = chainActive.Genesis();
pChainTip = chainActive.Tip();
@@ -3371,7 +3322,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
// We can't rescan beyond non-pruned blocks, stop and throw an error
if (fPruneMode) {
- LOCK(cs_main);
+ auto locked_chain = pwallet->chain().lock();
CBlockIndex *block = pindexStop ? pindexStop : pChainTip;
while (block && block->nHeight >= pindexStart->nHeight) {
if (!(block->nStatus & BLOCK_HAVE_DATA)) {
@@ -3536,10 +3487,12 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
"\nResult:\n"
"{\n"
" \"address\" : \"address\", (string) The bitcoin address validated\n"
- " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
+ " \"scriptPubKey\" : \"hex\", (string) The hex-encoded scriptPubKey generated by the address\n"
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
+ " \"solvable\" : true|false, (boolean) If the address is solvable by the wallet\n"
" \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
" \"isscript\" : true|false, (boolean) If the key is a script\n"
+ " \"ischange\" : true|false, (boolean) If the address was used for change output\n"
" \"iswitness\" : true|false, (boolean) If the address is a witness address\n"
" \"witness_version\" : version (numeric, optional) The version number of the witness program\n"
" \"witness_program\" : \"hex\" (string, optional) The hex value of the witness program\n"
@@ -3592,11 +3545,13 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
isminetype mine = IsMine(*pwallet, dest);
ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
+ ret.pushKV("solvable", IsSolvable(*pwallet, scriptPubKey));
UniValue detail = DescribeWalletAddress(pwallet, dest);
ret.pushKVs(detail);
if (pwallet->mapAddressBook.count(dest)) {
ret.pushKV("label", pwallet->mapAddressBook[dest].name);
}
+ ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
const CKeyMetadata* meta = nullptr;
CKeyID key_id = GetKeyForDestination(*pwallet, dest);
if (!key_id.IsNull()) {
@@ -3705,7 +3660,7 @@ static UniValue listlabels(const JSONRPCRequest& request)
+ HelpExampleCli("listlabels", "receive") +
"\nList labels that have sending addresses\n"
+ HelpExampleCli("listlabels", "send") +
- "\nAs json rpc call\n"
+ "\nAs a JSON-RPC call\n"
+ HelpExampleRpc("listlabels", "receive")
);
@@ -3767,7 +3722,8 @@ UniValue sethdseed(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download");
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
// Do not do anything to non-HD wallets
if (!pwallet->IsHDEnabled()) {
@@ -3816,24 +3772,34 @@ void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubK
hd_keypaths.emplace(vchPubKey, std::move(info));
}
-bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type, bool sign, bool bip32derivs)
+bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, int sighash_type, bool sign, bool bip32derivs)
{
LOCK(pwallet->cs_wallet);
// Get all of the previous transactions
bool complete = true;
- for (unsigned int i = 0; i < txConst->vin.size(); ++i) {
- const CTxIn& txin = txConst->vin[i];
+ for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
+ const CTxIn& txin = psbtx.tx->vin[i];
PSBTInput& input = psbtx.inputs.at(i);
- // If we don't know about this input, skip it and let someone else deal with it
- const uint256& txhash = txin.prevout.hash;
- const auto it = pwallet->mapWallet.find(txhash);
- if (it != pwallet->mapWallet.end()) {
- const CWalletTx& wtx = it->second;
- CTxOut utxo = wtx.tx->vout[txin.prevout.n];
- // Update both UTXOs from the wallet.
- input.non_witness_utxo = wtx.tx;
- input.witness_utxo = utxo;
+ if (PSBTInputSigned(input)) {
+ continue;
+ }
+
+ // Verify input looks sane. This will check that we have at most one uxto, witness or non-witness.
+ if (!input.IsSane()) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "PSBT input is not sane.");
+ }
+
+ // If we have no utxo, grab it from the wallet.
+ if (!input.non_witness_utxo && input.witness_utxo.IsNull()) {
+ const uint256& txhash = txin.prevout.hash;
+ const auto it = pwallet->mapWallet.find(txhash);
+ if (it != pwallet->mapWallet.end()) {
+ const CWalletTx& wtx = it->second;
+ // We only need the non_witness_utxo, which is a superset of the witness_utxo.
+ // The signing code will switch to the smaller witness_utxo if this is ok.
+ input.non_witness_utxo = wtx.tx;
+ }
}
// Get the Sighash type
@@ -3841,12 +3807,12 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Specified Sighash and sighash in PSBT do not match.");
}
- complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), *psbtx.tx, input, i, sighash_type);
+ complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), psbtx, i, sighash_type);
}
// Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
- for (unsigned int i = 0; i < txConst->vout.size(); ++i) {
- const CTxOut& out = txConst->vout.at(i);
+ 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
@@ -3911,19 +3877,15 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
// Get the sighash type
int nHashType = ParseSighashString(request.params[2]);
- // Use CTransaction for the constant parts of the
- // transaction to avoid rehashing.
- const CTransaction txConst(*psbtx.tx);
-
// Fill transaction with our data and also sign
bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
bool bip32derivs = request.params[3].isNull() ? false : request.params[3].get_bool();
- bool complete = FillPSBT(pwallet, psbtx, &txConst, nHashType, sign, bip32derivs);
+ bool complete = FillPSBT(pwallet, psbtx, nHashType, sign, bip32derivs);
UniValue result(UniValue::VOBJ);
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
- result.pushKV("psbt", EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()));
+ result.pushKV("psbt", EncodeBase64(ssTx.str()));
result.pushKV("complete", complete);
return result;
@@ -3959,7 +3921,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
" \"address\": x.xxx, (obj, optional) A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + "\n"
" },\n"
" {\n"
- " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex encoded data\n"
+ " \"data\": \"hex\" (obj, optional) A key-value pair. The key must be \"data\", the value is hex-encoded data\n"
" }\n"
" ,... More key-value pairs of the above form. For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
" accepted as second parameter.\n"
@@ -4015,29 +3977,18 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
FundTransaction(pwallet, rawTx, fee, change_position, request.params[3]);
// Make a blank psbt
- PartiallySignedTransaction psbtx;
- psbtx.tx = rawTx;
- for (unsigned int i = 0; i < rawTx.vin.size(); ++i) {
- psbtx.inputs.push_back(PSBTInput());
- }
- for (unsigned int i = 0; i < rawTx.vout.size(); ++i) {
- psbtx.outputs.push_back(PSBTOutput());
- }
-
- // Use CTransaction for the constant parts of the
- // transaction to avoid rehashing.
- const CTransaction txConst(*psbtx.tx);
+ PartiallySignedTransaction psbtx(rawTx);
// Fill transaction with out data but don't sign
bool bip32derivs = request.params[4].isNull() ? false : request.params[4].get_bool();
- FillPSBT(pwallet, psbtx, &txConst, 1, false, bip32derivs);
+ FillPSBT(pwallet, psbtx, 1, false, bip32derivs);
// Serialize the PSBT
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
UniValue result(UniValue::VOBJ);
- result.pushKV("psbt", EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()));
+ result.pushKV("psbt", EncodeBase64(ssTx.str()));
result.pushKV("fee", ValueFromAmount(fee));
result.pushKV("changepos", change_position);
return result;
@@ -4059,7 +4010,6 @@ static const CRPCCommand commands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
{ "generating", "generate", &generate, {"nblocks","maxtries"} },
- { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} },
{ "hidden", "resendwallettransactions", &resendwallettransactions, {} },
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} },
{ "wallet", "abandontransaction", &abandontransaction, {"txid"} },
@@ -4096,6 +4046,7 @@ static const CRPCCommand commands[] =
{ "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
{ "wallet", "listtransactions", &listtransactions, {"dummy","count","skip","include_watchonly"} },
{ "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
+ { "wallet", "listwalletdir", &listwalletdir, {} },
{ "wallet", "listwallets", &listwallets, {} },
{ "wallet", "loadwallet", &loadwallet, {"filename"} },
{ "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index 9b9a159b86..abd7750874 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -30,5 +30,5 @@ bool EnsureWalletIsAvailable(CWallet *, bool avoidException);
UniValue getaddressinfo(const JSONRPCRequest& request);
UniValue signrawtransactionwithwallet(const JSONRPCRequest& request);
-bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type = 1, bool sign = true, bool bip32derivs = false);
+bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false);
#endif //BITCOIN_WALLET_RPCWALLET_H
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 21857df081..5c65acf601 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -28,7 +28,8 @@ std::vector<std::unique_ptr<CWalletTx>> wtxn;
typedef std::set<CInputCoin> CoinSet;
static std::vector<COutput> vCoins;
-static CWallet testWallet("dummy", WalletDatabase::CreateDummy());
+static auto testChain = interfaces::MakeChain();
+static CWallet testWallet(*testChain, WalletLocation(), WalletDatabase::CreateDummy());
static CAmount balance = 0;
CoinEligibilityFilter filter_standard(1, 6, 0);
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
new file mode 100644
index 0000000000..3b828d57f9
--- /dev/null
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -0,0 +1,44 @@
+// Copyright (c) 2018 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 <fs.h>
+
+#include <wallet/test/init_test_fixture.h>
+
+InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainName): BasicTestingSetup(chainName)
+{
+ m_chain_client = MakeWalletClient(*m_chain, {});
+
+ std::string sep;
+ sep += fs::path::preferred_separator;
+
+ m_datadir = SetDataDir("tempdir");
+ m_cwd = fs::current_path();
+
+ m_walletdir_path_cases["default"] = m_datadir / "wallets";
+ m_walletdir_path_cases["custom"] = m_datadir / "my_wallets";
+ m_walletdir_path_cases["nonexistent"] = m_datadir / "path_does_not_exist";
+ m_walletdir_path_cases["file"] = m_datadir / "not_a_directory.dat";
+ m_walletdir_path_cases["trailing"] = m_datadir / "wallets" / sep;
+ m_walletdir_path_cases["trailing2"] = m_datadir / "wallets" / sep / sep;
+
+ fs::current_path(m_datadir);
+ m_walletdir_path_cases["relative"] = "wallets";
+
+ fs::create_directories(m_walletdir_path_cases["default"]);
+ fs::create_directories(m_walletdir_path_cases["custom"]);
+ fs::create_directories(m_walletdir_path_cases["relative"]);
+ std::ofstream f(m_walletdir_path_cases["file"].BOOST_FILESYSTEM_C_STR);
+ f.close();
+}
+
+InitWalletDirTestingSetup::~InitWalletDirTestingSetup()
+{
+ fs::current_path(m_cwd);
+}
+
+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_test_fixture.h b/src/wallet/test/init_test_fixture.h
new file mode 100644
index 0000000000..cd47b31da1
--- /dev/null
+++ b/src/wallet/test/init_test_fixture.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2018 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_WALLET_TEST_INIT_TEST_FIXTURE_H
+#define BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H
+
+#include <interfaces/chain.h>
+#include <test/test_bitcoin.h>
+
+
+struct InitWalletDirTestingSetup: public BasicTestingSetup {
+ explicit InitWalletDirTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ ~InitWalletDirTestingSetup();
+ void SetWalletDir(const fs::path& walletdir_path);
+
+ fs::path m_datadir;
+ fs::path m_cwd;
+ std::map<std::string, fs::path> m_walletdir_path_cases;
+ std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
+ std::unique_ptr<interfaces::ChainClient> m_chain_client;
+};
+
+#endif // BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
new file mode 100644
index 0000000000..5852d3ef84
--- /dev/null
+++ b/src/wallet/test/init_tests.cpp
@@ -0,0 +1,78 @@
+// Copyright (c) 2018 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 <boost/test/unit_test.hpp>
+
+#include <test/test_bitcoin.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)
+{
+ SetWalletDir(m_walletdir_path_cases["default"]);
+ bool result = m_chain_client->verify();
+ BOOST_CHECK(result == true);
+ fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
+ BOOST_CHECK(walletdir == expected_path);
+}
+
+BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom)
+{
+ SetWalletDir(m_walletdir_path_cases["custom"]);
+ bool result = m_chain_client->verify();
+ BOOST_CHECK(result == true);
+ fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]);
+ BOOST_CHECK(walletdir == expected_path);
+}
+
+BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_does_not_exist)
+{
+ SetWalletDir(m_walletdir_path_cases["nonexistent"]);
+ bool result = m_chain_client->verify();
+ BOOST_CHECK(result == false);
+}
+
+BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_directory)
+{
+ SetWalletDir(m_walletdir_path_cases["file"]);
+ bool result = m_chain_client->verify();
+ BOOST_CHECK(result == false);
+}
+
+BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_relative)
+{
+ SetWalletDir(m_walletdir_path_cases["relative"]);
+ bool result = m_chain_client->verify();
+ BOOST_CHECK(result == false);
+}
+
+BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing)
+{
+ SetWalletDir(m_walletdir_path_cases["trailing"]);
+ bool result = m_chain_client->verify();
+ BOOST_CHECK(result == true);
+ fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
+ BOOST_CHECK(walletdir == expected_path);
+}
+
+BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2)
+{
+ SetWalletDir(m_walletdir_path_cases["trailing2"]);
+ bool result = m_chain_client->verify();
+ BOOST_CHECK(result == true);
+ fs::path walletdir = gArgs.GetArg("-walletdir", "");
+ fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]);
+ BOOST_CHECK(walletdir == expected_path);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index 526f2d983f..9918eeb89f 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -4,7 +4,7 @@
#include <key_io.h>
#include <script/sign.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
#include <univalue.h>
@@ -17,6 +17,8 @@ BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup)
BOOST_AUTO_TEST_CASE(psbt_updater_test)
{
+ LOCK(m_wallet.cs_wallet);
+
// Create prevtxs and add to wallet
CDataStream s_prev_tx1(ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx1;
@@ -57,12 +59,8 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
CDataStream ssData(ParseHex("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000"), SER_NETWORK, PROTOCOL_VERSION);
ssData >> psbtx;
- // Use CTransaction for the constant parts of the
- // transaction to avoid rehashing.
- const CTransaction txConst(*psbtx.tx);
-
// Fill transaction with our data
- FillPSBT(&m_wallet, psbtx, &txConst, 1, false, true);
+ FillPSBT(&m_wallet, psbtx, SIGHASH_ALL, false, true);
// Get the final tx
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp
index f193d5c41d..ae7092fa89 100644
--- a/src/wallet/test/wallet_crypto_tests.cpp
+++ b/src/wallet/test/wallet_crypto_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <test/test_bitcoin.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <wallet/crypter.h>
#include <vector>
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index de59b60349..a5fb1db86c 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -6,9 +6,10 @@
#include <rpc/server.h>
#include <wallet/db.h>
+#include <wallet/rpcwallet.h>
WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
- TestingSetup(chainName), m_wallet("mock", WalletDatabase::CreateMock())
+ TestingSetup(chainName), m_wallet(*m_chain, WalletLocation(), WalletDatabase::CreateMock())
{
bool fFirstRun;
m_wallet.LoadWallet(fFirstRun);
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index ff8ec32b03..e6fe8c9473 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -7,6 +7,8 @@
#include <test/test_bitcoin.h>
+#include <interfaces/chain.h>
+#include <interfaces/wallet.h>
#include <wallet/wallet.h>
#include <memory>
@@ -17,6 +19,7 @@ struct WalletTestingSetup: public TestingSetup {
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~WalletTestingSetup();
+ std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
CWallet m_wallet;
};
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 3a8e6f751a..c6aac8aad5 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -11,6 +11,7 @@
#include <vector>
#include <consensus/validation.h>
+#include <interfaces/chain.h>
#include <rpc/server.h>
#include <test/test_bitcoin.h>
#include <validation.h>
@@ -34,6 +35,8 @@ static void AddKey(CWallet& wallet, const CKey& key)
BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{
+ auto chain = interfaces::MakeChain();
+
// Cap last block file size, and mine new block in a new block file.
CBlockIndex* const nullBlock = nullptr;
CBlockIndex* oldTip = chainActive.Tip();
@@ -41,12 +44,12 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
CBlockIndex* newTip = chainActive.Tip();
- LOCK(cs_main);
+ auto locked_chain = chain->lock();
// Verify ScanForWalletTransactions picks up transactions in both the old
// and new block files.
{
- CWallet wallet("dummy", WalletDatabase::CreateDummy());
+ CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
@@ -61,7 +64,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// Verify ScanForWalletTransactions only picks transactions in the new block
// file.
{
- CWallet wallet("dummy", WalletDatabase::CreateDummy());
+ CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
@@ -73,7 +76,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// before the missing block, and success for a key whose creation time is
// after.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateDummy());
AddWallet(wallet);
UniValue keys;
keys.setArray();
@@ -115,6 +118,8 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// than or equal to key birthday.
BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
{
+ auto chain = interfaces::MakeChain();
+
// Create two blocks with same timestamp to verify that importwallet rescan
// will pick up both blocks, not just the first.
const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;
@@ -128,13 +133,13 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
SetMockTime(KEY_TIME);
m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
- LOCK(cs_main);
+ auto locked_chain = chain->lock();
std::string backup_file = (SetDataDir("importwallet_rescan") / "wallet.backup").string();
// Import key into wallet and call dumpwallet to create backup file.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateDummy());
LOCK(wallet->cs_wallet);
wallet->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
@@ -150,7 +155,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
// were scanned, and no prior blocks were scanned.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateDummy());
JSONRPCRequest request;
request.params.setArray();
@@ -180,21 +185,23 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// debit functions.
BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{
- CWallet wallet("dummy", WalletDatabase::CreateDummy());
+ auto chain = interfaces::MakeChain();
+ CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
CWalletTx wtx(&wallet, m_coinbase_txns.back());
- LOCK2(cs_main, wallet.cs_wallet);
+ auto locked_chain = chain->lock();
+ LOCK(wallet.cs_wallet);
wtx.hashBlock = chainActive.Tip()->GetBlockHash();
wtx.nIndex = 0;
// Call GetImmatureCredit() once before adding the key to the wallet to
// cache the current immature credit amount, which is 0.
- BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 0);
+ BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(*locked_chain), 0);
// Invalidate the cached value, add the key, and make sure a new immature
// credit amount is calculated.
wtx.MarkDirty();
wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
- BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 50*COIN);
+ BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(*locked_chain), 50*COIN);
}
static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
@@ -204,7 +211,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
SetMockTime(mockTime);
CBlockIndex* block = nullptr;
if (blockTime > 0) {
- LOCK(cs_main);
+ auto locked_chain = wallet.chain().lock();
auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
assert(inserted.second);
const uint256& hash = inserted.first->first;
@@ -273,7 +280,7 @@ public:
ListCoinsTestingSetup()
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- wallet = MakeUnique<CWallet>("mock", WalletDatabase::CreateMock());
+ wallet = MakeUnique<CWallet>(*m_chain, WalletLocation(), WalletDatabase::CreateMock());
bool firstRun;
wallet->LoadWallet(firstRun);
AddKey(*wallet, coinbaseKey);
@@ -295,7 +302,7 @@ public:
int changePos = -1;
std::string error;
CCoinControl dummy;
- BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, reservekey, fee, changePos, error, dummy));
+ BOOST_CHECK(wallet->CreateTransaction(*m_locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy));
CValidationState state;
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, nullptr, state));
CMutableTransaction blocktx;
@@ -311,6 +318,8 @@ public:
return it->second;
}
+ std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
+ std::unique_ptr<interfaces::Chain::Lock> m_locked_chain = m_chain->assumeLocked(); // Temporary. Removed in upcoming lock cleanup
std::unique_ptr<CWallet> wallet;
};
@@ -323,7 +332,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
std::map<CTxDestination, std::vector<COutput>> list;
{
LOCK2(cs_main, wallet->cs_wallet);
- list = wallet->ListCoins();
+ list = wallet->ListCoins(*m_locked_chain);
}
BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
@@ -339,7 +348,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */});
{
LOCK2(cs_main, wallet->cs_wallet);
- list = wallet->ListCoins();
+ list = wallet->ListCoins(*m_locked_chain);
}
BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
@@ -349,7 +358,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
{
LOCK2(cs_main, wallet->cs_wallet);
std::vector<COutput> available;
- wallet->AvailableCoins(available);
+ wallet->AvailableCoins(*m_locked_chain, available);
BOOST_CHECK_EQUAL(available.size(), 2U);
}
for (const auto& group : list) {
@@ -361,14 +370,14 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
{
LOCK2(cs_main, wallet->cs_wallet);
std::vector<COutput> available;
- wallet->AvailableCoins(available);
+ wallet->AvailableCoins(*m_locked_chain, available);
BOOST_CHECK_EQUAL(available.size(), 0U);
}
// Confirm ListCoins still returns same result as before, despite coins
// being locked.
{
LOCK2(cs_main, wallet->cs_wallet);
- list = wallet->ListCoins();
+ list = wallet->ListCoins(*m_locked_chain);
}
BOOST_CHECK_EQUAL(list.size(), 1U);
BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
@@ -377,7 +386,8 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("dummy", WalletDatabase::CreateDummy());
+ auto chain = interfaces::MakeChain();
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateDummy());
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
BOOST_CHECK(!wallet->TopUpKeyPool(1000));
CPubKey pubkey;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index afe47d986e..8ea4c5c495 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -11,6 +11,7 @@
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <fs.h>
+#include <interfaces/chain.h>
#include <key.h>
#include <key_io.h>
#include <keystore.h>
@@ -25,9 +26,8 @@
#include <shutdown.h>
#include <timedata.h>
#include <txmempool.h>
-#include <utilmoneystr.h>
+#include <util/moneystr.h>
#include <wallet/fees.h>
-#include <wallet/walletutil.h>
#include <algorithm>
#include <assert.h>
@@ -594,7 +594,7 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
* Outpoint is spent if any non-conflicted transaction
* spends it:
*/
-bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
+bool CWallet::IsSpent(interfaces::Chain::Lock& locked_chain, const uint256& hash, unsigned int n) const
{
const COutPoint outpoint(hash, n);
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
@@ -605,7 +605,7 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
const uint256& wtxid = it->second;
std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
if (mit != mapWallet.end()) {
- int depth = mit->second.GetDepthInMainChain();
+ int depth = mit->second.GetDepthInMainChain(locked_chain);
if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
return true; // Spent
}
@@ -1006,9 +1006,10 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockI
bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
const CWalletTx* wtx = GetWalletTx(hashTx);
- return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain() == 0 && !wtx->InMempool();
+ return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain(*locked_chain) == 0 && !wtx->InMempool();
}
void CWallet::MarkInputsDirty(const CTransactionRef& tx)
@@ -1021,9 +1022,10 @@ void CWallet::MarkInputsDirty(const CTransactionRef& tx)
}
}
-bool CWallet::AbandonTransaction(const uint256& hashTx)
+bool CWallet::AbandonTransaction(interfaces::Chain::Lock& locked_chain, const uint256& hashTx)
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain_recursive = chain().lock(); // Temporary. Removed in upcoming lock cleanup
+ LOCK(cs_wallet);
WalletBatch batch(*database, "r+");
@@ -1034,7 +1036,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
auto it = mapWallet.find(hashTx);
assert(it != mapWallet.end());
CWalletTx& origtx = it->second;
- if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool()) {
+ if (origtx.GetDepthInMainChain(locked_chain) != 0 || origtx.InMempool()) {
return false;
}
@@ -1047,7 +1049,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
auto it = mapWallet.find(now);
assert(it != mapWallet.end());
CWalletTx& wtx = it->second;
- int currentconfirm = wtx.GetDepthInMainChain();
+ int currentconfirm = wtx.GetDepthInMainChain(locked_chain);
// If the orig tx was not in block, none of its spends can be
assert(currentconfirm <= 0);
// if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
@@ -1078,7 +1080,8 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
int conflictconfirms = 0;
CBlockIndex* pindex = LookupBlockIndex(hashBlock);
@@ -1107,7 +1110,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
auto it = mapWallet.find(now);
assert(it != mapWallet.end());
CWalletTx& wtx = it->second;
- int currentconfirm = wtx.GetDepthInMainChain();
+ int currentconfirm = wtx.GetDepthInMainChain(*locked_chain);
if (conflictconfirms < currentconfirm) {
// Block is 'more conflicted' than current confirm; update.
// Mark transaction as conflicted with this block.
@@ -1141,7 +1144,8 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pin
}
void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
SyncTransaction(ptx);
auto it = mapWallet.find(ptx->GetHash());
@@ -1159,7 +1163,8 @@ void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
}
void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
// TODO: Temporarily ensure that mempool removals are notified before
// connected transactions. This shouldn't matter, but the abandoned
// state of transactions in our wallet is currently cleared when we
@@ -1181,7 +1186,8 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
}
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
for (const CTransactionRef& ptx : pblock->vtx) {
SyncTransaction(ptx);
@@ -1200,7 +1206,7 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
// We could also take cs_wallet here, and call m_last_block_processed
// protected by cs_wallet instead of cs_main, but as long as we need
// cs_main here anyway, it's easier to just call it cs_main-protected.
- LOCK(cs_main);
+ auto locked_chain = chain().lock();
const CBlockIndex* initialChainTip = chainActive.Tip();
if (m_last_block_processed && m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
@@ -1262,6 +1268,11 @@ CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) cons
bool CWallet::IsChange(const CTxOut& txout) const
{
+ return IsChange(txout.scriptPubKey);
+}
+
+bool CWallet::IsChange(const CScript& script) const
+{
// TODO: fix handling of 'change' outputs. The assumption is that any
// payment to a script that is ours, but is not in the address book
// is change. That assumption is likely to break when we implement multisignature
@@ -1269,10 +1280,10 @@ bool CWallet::IsChange(const CTxOut& txout) const
// a better way of identifying which outputs are 'the send' and which are
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
// which output, if any, was change).
- if (::IsMine(*this, txout.scriptPubKey))
+ if (::IsMine(*this, script))
{
CTxDestination address;
- if (!ExtractDestination(txout.scriptPubKey, address))
+ if (!ExtractDestination(script, address))
return true;
LOCK(cs_wallet);
@@ -1596,7 +1607,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
// to be scanned.
CBlockIndex* startBlock = nullptr;
{
- LOCK(cs_main);
+ auto locked_chain = chain().lock();
startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW);
WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
}
@@ -1648,7 +1659,7 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
double progress_begin;
double progress_end;
{
- LOCK(cs_main);
+ auto locked_chain = chain().lock();
progress_begin = GuessVerificationProgress(chainParams.TxData(), pindex);
if (pindexStop == nullptr) {
tip = chainActive.Tip();
@@ -1670,7 +1681,8 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
CBlock block;
if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) {
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
if (pindex && !chainActive.Contains(pindex)) {
// Abort scan if current block is no longer active, to prevent
// marking transactions as coming from the wrong block.
@@ -1687,7 +1699,7 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlock
break;
}
{
- LOCK(cs_main);
+ auto locked_chain = chain().lock();
pindex = chainActive.Next(pindex);
progress_current = GuessVerificationProgress(chainParams.TxData(), pindex);
if (pindexStop == nullptr && tip != chainActive.Tip()) {
@@ -1712,7 +1724,8 @@ void CWallet::ReacceptWalletTransactions()
// If transactions aren't being broadcasted, don't let them into local mempool either
if (!fBroadcastTransactions)
return;
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
std::map<int64_t, CWalletTx*> mapSorted;
// Sort pending wallet transactions based on their initial wallet insertion order
@@ -1722,7 +1735,7 @@ void CWallet::ReacceptWalletTransactions()
CWalletTx& wtx = item.second;
assert(wtx.GetHash() == wtxid);
- int nDepth = wtx.GetDepthInMainChain();
+ int nDepth = wtx.GetDepthInMainChain(*locked_chain);
if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
@@ -1733,18 +1746,18 @@ void CWallet::ReacceptWalletTransactions()
for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
CWalletTx& wtx = *(item.second);
CValidationState state;
- wtx.AcceptToMemoryPool(maxTxFee, state);
+ wtx.AcceptToMemoryPool(*locked_chain, maxTxFee, state);
}
}
-bool CWalletTx::RelayWalletTransaction(CConnman* connman)
+bool CWalletTx::RelayWalletTransaction(interfaces::Chain::Lock& locked_chain, CConnman* connman)
{
assert(pwallet->GetBroadcastTransactions());
- if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain() == 0)
+ if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain(locked_chain) == 0)
{
CValidationState state;
/* GetDepthInMainChain already catches known conflicts. */
- if (InMempool() || AcceptToMemoryPool(maxTxFee, state)) {
+ if (InMempool() || AcceptToMemoryPool(locked_chain, maxTxFee, state)) {
pwallet->WalletLogPrintf("Relaying wtx %s\n", GetHash().ToString());
if (connman) {
CInv inv(MSG_TX, GetHash());
@@ -1802,10 +1815,10 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const
return debit;
}
-CAmount CWalletTx::GetCredit(const isminefilter& filter) const
+CAmount CWalletTx::GetCredit(interfaces::Chain::Lock& locked_chain, const isminefilter& filter) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
- if (IsImmatureCoinBase())
+ if (IsImmatureCoinBase(locked_chain))
return 0;
CAmount credit = 0;
@@ -1835,9 +1848,9 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const
return credit;
}
-CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
+CAmount CWalletTx::GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache) const
{
- if (IsImmatureCoinBase() && IsInMainChain()) {
+ if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) {
if (fUseCache && fImmatureCreditCached)
return nImmatureCreditCached;
nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
@@ -1848,13 +1861,13 @@ CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
return 0;
}
-CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter) const
+CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache, const isminefilter& filter) const
{
if (pwallet == nullptr)
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
- if (IsImmatureCoinBase())
+ if (IsImmatureCoinBase(locked_chain))
return 0;
CAmount* cache = nullptr;
@@ -1876,7 +1889,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter
uint256 hashTx = GetHash();
for (unsigned int i = 0; i < tx->vout.size(); i++)
{
- if (!pwallet->IsSpent(hashTx, i))
+ if (!pwallet->IsSpent(locked_chain, hashTx, i))
{
const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, filter);
@@ -1893,9 +1906,9 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter
return nCredit;
}
-CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const
+CAmount CWalletTx::GetImmatureWatchOnlyCredit(interfaces::Chain::Lock& locked_chain, const bool fUseCache) const
{
- if (IsImmatureCoinBase() && IsInMainChain()) {
+ if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) {
if (fUseCache && fImmatureWatchCreditCached)
return nImmatureWatchCreditCached;
nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
@@ -1920,12 +1933,14 @@ bool CWalletTx::InMempool() const
return fInMempool;
}
-bool CWalletTx::IsTrusted() const
+bool CWalletTx::IsTrusted(interfaces::Chain::Lock& locked_chain) const
{
+ LockAnnotation lock(::cs_main); // Temporary, for CheckFinalTx below. Removed in upcoming commit.
+
// Quick answer in most cases
if (!CheckFinalTx(*tx))
return false;
- int nDepth = GetDepthInMainChain();
+ int nDepth = GetDepthInMainChain(locked_chain);
if (nDepth >= 1)
return true;
if (nDepth < 0)
@@ -1960,7 +1975,7 @@ bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
return CTransaction(tx1) == CTransaction(tx2);
}
-std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman)
+std::vector<uint256> CWallet::ResendWalletTransactionsBefore(interfaces::Chain::Lock& locked_chain, int64_t nTime, CConnman* connman)
{
std::vector<uint256> result;
@@ -1979,7 +1994,7 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CCon
for (const std::pair<const unsigned int, CWalletTx*>& item : mapSorted)
{
CWalletTx& wtx = *item.second;
- if (wtx.RelayWalletTransaction(connman))
+ if (wtx.RelayWalletTransaction(locked_chain, connman))
result.push_back(wtx.GetHash());
}
return result;
@@ -2003,7 +2018,8 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman
// Rebroadcast unconfirmed txes older than 5 minutes before the last
// block was found:
- std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60, connman);
+ auto locked_chain = chain().assumeLocked(); // Temporary. Removed in upcoming lock cleanup
+ std::vector<uint256> relayed = ResendWalletTransactionsBefore(*locked_chain, nBestBlockTime-5*60, connman);
if (!relayed.empty())
WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
}
@@ -2023,12 +2039,13 @@ CAmount CWallet::GetBalance(const isminefilter& filter, const int min_depth) con
{
CAmount nTotal = 0;
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
for (const auto& entry : mapWallet)
{
const CWalletTx* pcoin = &entry.second;
- if (pcoin->IsTrusted() && pcoin->GetDepthInMainChain() >= min_depth) {
- nTotal += pcoin->GetAvailableCredit(true, filter);
+ if (pcoin->IsTrusted(*locked_chain) && pcoin->GetDepthInMainChain(*locked_chain) >= min_depth) {
+ nTotal += pcoin->GetAvailableCredit(*locked_chain, true, filter);
}
}
}
@@ -2040,12 +2057,13 @@ CAmount CWallet::GetUnconfirmedBalance() const
{
CAmount nTotal = 0;
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
for (const auto& entry : mapWallet)
{
const CWalletTx* pcoin = &entry.second;
- if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
- nTotal += pcoin->GetAvailableCredit();
+ if (!pcoin->IsTrusted(*locked_chain) && pcoin->GetDepthInMainChain(*locked_chain) == 0 && pcoin->InMempool())
+ nTotal += pcoin->GetAvailableCredit(*locked_chain);
}
}
return nTotal;
@@ -2055,11 +2073,12 @@ CAmount CWallet::GetImmatureBalance() const
{
CAmount nTotal = 0;
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
for (const auto& entry : mapWallet)
{
const CWalletTx* pcoin = &entry.second;
- nTotal += pcoin->GetImmatureCredit();
+ nTotal += pcoin->GetImmatureCredit(*locked_chain);
}
}
return nTotal;
@@ -2069,12 +2088,13 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
{
CAmount nTotal = 0;
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
for (const auto& entry : mapWallet)
{
const CWalletTx* pcoin = &entry.second;
- if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
- nTotal += pcoin->GetAvailableCredit(true, ISMINE_WATCH_ONLY);
+ if (!pcoin->IsTrusted(*locked_chain) && pcoin->GetDepthInMainChain(*locked_chain) == 0 && pcoin->InMempool())
+ nTotal += pcoin->GetAvailableCredit(*locked_chain, true, ISMINE_WATCH_ONLY);
}
}
return nTotal;
@@ -2084,11 +2104,12 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
{
CAmount nTotal = 0;
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
for (const auto& entry : mapWallet)
{
const CWalletTx* pcoin = &entry.second;
- nTotal += pcoin->GetImmatureWatchOnlyCredit();
+ nTotal += pcoin->GetImmatureWatchOnlyCredit(*locked_chain);
}
}
return nTotal;
@@ -2102,13 +2123,15 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
// trusted.
CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth) const
{
- LOCK2(cs_main, cs_wallet);
+ LockAnnotation lock(::cs_main); // Temporary, for CheckFinalTx below. Removed in upcoming commit.
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
CAmount balance = 0;
for (const auto& entry : mapWallet) {
const CWalletTx& wtx = entry.second;
- const int depth = wtx.GetDepthInMainChain();
- if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.IsImmatureCoinBase()) {
+ const int depth = wtx.GetDepthInMainChain(*locked_chain);
+ if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.IsImmatureCoinBase(*locked_chain)) {
continue;
}
@@ -2135,11 +2158,12 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth) cons
CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
CAmount balance = 0;
std::vector<COutput> vCoins;
- AvailableCoins(vCoins, true, coinControl);
+ AvailableCoins(*locked_chain, vCoins, true, coinControl);
for (const COutput& out : vCoins) {
if (out.fSpendable) {
balance += out.tx->tx->vout[out.i].nValue;
@@ -2148,7 +2172,7 @@ CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const
return balance;
}
-void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const int nMinDepth, const int nMaxDepth) const
+void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const int nMinDepth, const int nMaxDepth) const
{
AssertLockHeld(cs_main);
AssertLockHeld(cs_wallet);
@@ -2164,10 +2188,10 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
if (!CheckFinalTx(*pcoin->tx))
continue;
- if (pcoin->IsImmatureCoinBase())
+ if (pcoin->IsImmatureCoinBase(locked_chain))
continue;
- int nDepth = pcoin->GetDepthInMainChain();
+ int nDepth = pcoin->GetDepthInMainChain(locked_chain);
if (nDepth < 0)
continue;
@@ -2176,7 +2200,7 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
if (nDepth == 0 && !pcoin->InMempool())
continue;
- bool safeTx = pcoin->IsTrusted();
+ bool safeTx = pcoin->IsTrusted(locked_chain);
// We should not consider coins from transactions that are replacing
// other transactions.
@@ -2226,7 +2250,7 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
if (IsLockedCoin(entry.first, i))
continue;
- if (IsSpent(wtxid, i))
+ if (IsSpent(locked_chain, wtxid, i))
continue;
isminetype mine = IsMine(pcoin->tx->vout[i]);
@@ -2257,7 +2281,7 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
}
}
-std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const
+std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins(interfaces::Chain::Lock& locked_chain) const
{
AssertLockHeld(cs_main);
AssertLockHeld(cs_wallet);
@@ -2265,7 +2289,7 @@ std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const
std::map<CTxDestination, std::vector<COutput>> result;
std::vector<COutput> availableCoins;
- AvailableCoins(availableCoins);
+ AvailableCoins(locked_chain, availableCoins);
for (const COutput& coin : availableCoins) {
CTxDestination address;
@@ -2280,7 +2304,7 @@ std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins() const
for (const COutPoint& output : lockedCoins) {
auto it = mapWallet.find(output.hash);
if (it != mapWallet.end()) {
- int depth = it->second.GetDepthInMainChain();
+ int depth = it->second.GetDepthInMainChain(locked_chain);
if (depth >= 0 && output.n < it->second.tx->vout.size() &&
IsMine(it->second.tx->vout[output.n]) == ISMINE_SPENDABLE) {
CTxDestination address;
@@ -2495,11 +2519,12 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
// Acquire the locks to prevent races to the new locked unspents between the
// CreateTransaction call and LockCoin calls (when lockUnspents is true).
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
CReserveKey reservekey(this);
CTransactionRef tx_new;
- if (!CreateTransaction(vecSend, tx_new, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
+ if (!CreateTransaction(*locked_chain, vecSend, tx_new, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
return false;
}
@@ -2558,7 +2583,7 @@ OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vec
return m_default_address_type;
}
-bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet,
+bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet,
int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
{
CAmount nValue = 0;
@@ -2620,10 +2645,11 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
int nBytes;
{
std::set<CInputCoin> setCoins;
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
{
std::vector<COutput> vAvailableCoins;
- AvailableCoins(vAvailableCoins, true, &coin_control);
+ AvailableCoins(*locked_chain, vAvailableCoins, true, &coin_control);
CoinSelectionParams coin_selection_params; // Parameters for coin selection, init with dummy
// Create change script that will be used if we need change
@@ -2958,7 +2984,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac
bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CReserveKey& reservekey, CConnman* connman, CValidationState& state)
{
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
CWalletTx wtxNew(this, std::move(tx));
wtxNew.mapValue = std::move(mapValue);
@@ -2991,11 +3018,11 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
if (fBroadcastTransactions)
{
// Broadcast
- if (!wtx.AcceptToMemoryPool(maxTxFee, state)) {
+ if (!wtx.AcceptToMemoryPool(*locked_chain, maxTxFee, state)) {
WalletLogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", FormatStateMessage(state));
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
} else {
- wtx.RelayWalletTransaction(connman);
+ wtx.RelayWalletTransaction(*locked_chain, connman);
}
}
}
@@ -3004,7 +3031,8 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{
- LOCK2(cs_main, cs_wallet);
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
fFirstRunRet = false;
DBErrors nLoadWalletRet = WalletBatch(*database,"cr+").LoadWallet(this);
@@ -3388,7 +3416,7 @@ int64_t CWallet::GetOldestKeyPoolTime()
return oldestKey;
}
-std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
+std::map<CTxDestination, CAmount> CWallet::GetAddressBalances(interfaces::Chain::Lock& locked_chain)
{
std::map<CTxDestination, CAmount> balances;
@@ -3398,13 +3426,13 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
const CWalletTx *pcoin = &walletEntry.second;
- if (!pcoin->IsTrusted())
+ if (!pcoin->IsTrusted(locked_chain))
continue;
- if (pcoin->IsImmatureCoinBase())
+ if (pcoin->IsImmatureCoinBase(locked_chain))
continue;
- int nDepth = pcoin->GetDepthInMainChain();
+ int nDepth = pcoin->GetDepthInMainChain(locked_chain);
if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
continue;
@@ -3416,7 +3444,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr))
continue;
- CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue;
+ CAmount n = IsSpent(locked_chain, walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue;
if (!balances.count(addr))
balances[addr] = 0;
@@ -3641,7 +3669,7 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const
/** @} */ // end of Actions
-void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const {
+void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CTxDestination, int64_t> &mapKeyBirth) const {
AssertLockHeld(cs_wallet); // mapKeyMetadata
mapKeyBirth.clear();
@@ -3821,7 +3849,7 @@ void CWallet::MarkPreSplitKeys()
}
}
-bool CWallet::Verify(std::string wallet_file, bool salvage_wallet, std::string& error_string, std::string& warning_string)
+bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, std::string& error_string, std::string& warning_string)
{
// Do some checking on wallet path. It should be either a:
//
@@ -3830,23 +3858,23 @@ bool CWallet::Verify(std::string wallet_file, bool salvage_wallet, std::string&
// 3. Path to a symlink to a directory.
// 4. For backwards compatibility, the name of a data file in -walletdir.
LOCK(cs_wallets);
- fs::path wallet_path = fs::absolute(wallet_file, GetWalletDir());
+ const fs::path& wallet_path = location.GetPath();
fs::file_type path_type = fs::symlink_status(wallet_path).type();
if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
(path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
- (path_type == fs::regular_file && fs::path(wallet_file).filename() == wallet_file))) {
+ (path_type == fs::regular_file && fs::path(location.GetName()).filename() == location.GetName()))) {
error_string = strprintf(
"Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
"database/log.?????????? files can be stored, a location where such a directory could be created, "
"or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
- wallet_file, GetWalletDir());
+ location.GetName(), GetWalletDir());
return false;
}
// Make sure that the wallet path doesn't clash with an existing wallet path
for (auto wallet : GetWallets()) {
- if (fs::absolute(wallet->GetName(), GetWalletDir()) == wallet_path) {
- error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", wallet_file);
+ if (wallet->GetLocation().GetPath() == wallet_path) {
+ error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName());
return false;
}
}
@@ -3856,13 +3884,13 @@ bool CWallet::Verify(std::string wallet_file, bool salvage_wallet, std::string&
return false;
}
} catch (const fs::filesystem_error& e) {
- error_string = strprintf("Error loading wallet %s. %s", wallet_file, fsbridge::get_filesystem_error_message(e));
+ error_string = strprintf("Error loading wallet %s. %s", location.GetName(), fsbridge::get_filesystem_error_message(e));
return false;
}
if (salvage_wallet) {
// Recover readable keypairs:
- CWallet dummyWallet("dummy", WalletDatabase::CreateDummy());
+ CWallet dummyWallet(chain, WalletLocation(), WalletDatabase::CreateDummy());
std::string backup_filename;
if (!WalletBatch::Recover(wallet_path, (void *)&dummyWallet, WalletBatch::RecoverKeysOnlyFilter, backup_filename)) {
return false;
@@ -3872,9 +3900,9 @@ bool CWallet::Verify(std::string wallet_file, bool salvage_wallet, std::string&
return WalletBatch::VerifyDatabaseFile(wallet_path, warning_string, error_string);
}
-std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name, const fs::path& path, uint64_t wallet_creation_flags)
+std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, uint64_t wallet_creation_flags)
{
- const std::string& walletFile = name;
+ const std::string& walletFile = location.GetName();
// needed to restore wallet transaction meta data after -zapwallettxes
std::vector<CWalletTx> vWtx;
@@ -3882,7 +3910,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name,
if (gArgs.GetBoolArg("-zapwallettxes", false)) {
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
- std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(name, WalletDatabase::Create(path));
+ std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(chain, location, WalletDatabase::Create(location.GetPath()));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DBErrors::LOAD_OK) {
InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
@@ -3896,7 +3924,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name,
bool fFirstRun = true;
// TODO: Can't use std::make_shared because we need a custom deleter but
// should be possible to use std::allocate_shared.
- std::shared_ptr<CWallet> walletInstance(new CWallet(name, WalletDatabase::Create(path)), ReleaseWallet);
+ std::shared_ptr<CWallet> walletInstance(new CWallet(chain, location, WalletDatabase::Create(location.GetPath())), ReleaseWallet);
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DBErrors::LOAD_OK)
{
@@ -4006,6 +4034,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name,
return nullptr;
}
+ auto locked_chain = chain.assumeLocked(); // Temporary. Removed in upcoming lock cleanup
walletInstance->ChainStateFlushed(chainActive.GetLocator());
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
// Make it impossible to disable private keys after creation
@@ -4093,7 +4122,9 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name,
// Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool();
- LOCK(cs_main);
+ LockAnnotation lock(::cs_main); // Temporary, for FindForkInGlobalIndex below. Removed in upcoming commit.
+ auto locked_chain = chain.lock();
+ LOCK(walletInstance->cs_wallet);
CBlockIndex *pindexRescan = chainActive.Genesis();
if (!gArgs.GetBoolArg("-rescan", false))
@@ -4178,7 +4209,6 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name,
walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
{
- LOCK(walletInstance->cs_wallet);
walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size());
walletInstance->WalletLogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size());
@@ -4229,7 +4259,7 @@ void CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
nIndex = posInBlock;
}
-int CMerkleTx::GetDepthInMainChain() const
+int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
{
if (hashUnset())
return 0;
@@ -4244,23 +4274,25 @@ int CMerkleTx::GetDepthInMainChain() const
return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1);
}
-int CMerkleTx::GetBlocksToMaturity() const
+int CMerkleTx::GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const
{
if (!IsCoinBase())
return 0;
- int chain_depth = GetDepthInMainChain();
+ int chain_depth = GetDepthInMainChain(locked_chain);
assert(chain_depth >= 0); // coinbase tx should not be conflicted
return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
}
-bool CMerkleTx::IsImmatureCoinBase() const
+bool CMerkleTx::IsImmatureCoinBase(interfaces::Chain::Lock& locked_chain) const
{
// note GetBlocksToMaturity is 0 for non-coinbase tx
- return GetBlocksToMaturity() > 0;
+ return GetBlocksToMaturity(locked_chain) > 0;
}
-bool CWalletTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
+bool CWalletTx::AcceptToMemoryPool(interfaces::Chain::Lock& locked_chain, const CAmount& nAbsurdFee, CValidationState& state)
{
+ LockAnnotation lock(::cs_main); // Temporary, for AcceptToMemoryPool below. Removed in upcoming commit.
+
// We must set fInMempool here - while it will be re-set to true by the
// entered-mempool callback, if we did not there would be a race where a
// user could call sendmoney in a loop and hit spurious out of funds errors
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index da326517c0..f96798201f 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -7,20 +7,21 @@
#define BITCOIN_WALLET_WALLET_H
#include <amount.h>
+#include <interfaces/chain.h>
#include <outputtype.h>
#include <policy/feerate.h>
#include <streams.h>
#include <tinyformat.h>
#include <ui_interface.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
#include <validationinterface.h>
#include <script/ismine.h>
#include <script/sign.h>
-#include <util.h>
+#include <util/system.h>
#include <wallet/crypter.h>
#include <wallet/coinselection.h>
#include <wallet/walletdb.h>
-#include <wallet/rpcwallet.h>
+#include <wallet/walletutil.h>
#include <algorithm>
#include <atomic>
@@ -33,6 +34,26 @@
#include <utility>
#include <vector>
+//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
+// This function will perform salvage on the wallet if requested, as long as only one wallet is
+// being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
+bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
+
+//! Load wallet databases.
+bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
+
+//! Complete startup of wallets.
+void StartWallets(CScheduler& scheduler);
+
+//! Flush all wallets in preparation for shutdown.
+void FlushWallets();
+
+//! Stop all wallets. Wallets will be flushed first.
+void StopWallets();
+
+//! Close all wallets.
+void UnloadWallets();
+
bool AddWallet(const std::shared_ptr<CWallet>& wallet);
bool RemoveWallet(const std::shared_ptr<CWallet>& wallet);
bool HasWallets();
@@ -264,22 +285,22 @@ public:
* 0 : in memory pool, waiting to be included in a block
* >=1 : this many blocks deep in the main chain
*/
- int GetDepthInMainChain() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- bool IsInMainChain() const EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return GetDepthInMainChain() > 0; }
+ int GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const;
+ bool IsInMainChain(interfaces::Chain::Lock& locked_chain) const { return GetDepthInMainChain(locked_chain) > 0; }
/**
* @return number of blocks to maturity for this transaction:
* 0 : is not a coinbase transaction, or is a mature coinbase transaction
* >0 : is a coinbase transaction which matures in this many blocks
*/
- int GetBlocksToMaturity() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ int GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const;
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
const uint256& GetHash() const { return tx->GetHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
- bool IsImmatureCoinBase() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool IsImmatureCoinBase(interfaces::Chain::Lock& locked_chain) const;
};
//Get the marginal bytes of spending the specified output
@@ -458,10 +479,14 @@ public:
//! filter decides which addresses will count towards the debit
CAmount GetDebit(const isminefilter& filter) const;
- CAmount GetCredit(const isminefilter& filter) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- CAmount GetImmatureCredit(bool fUseCache=true) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- CAmount GetAvailableCredit(bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- CAmount GetImmatureWatchOnlyCredit(const bool fUseCache=true) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CAmount GetCredit(interfaces::Chain::Lock& locked_chain, const isminefilter& filter) const;
+ CAmount GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true) const;
+ // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
+ // annotation "EXCLUSIVE_LOCKS_REQUIRED(cs_main, pwallet->cs_wallet)". The
+ // annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
+ // having to resolve the issue of member access into incomplete type CWallet.
+ CAmount GetAvailableCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS;
+ CAmount GetImmatureWatchOnlyCredit(interfaces::Chain::Lock& locked_chain, const bool fUseCache=true) const;
CAmount GetChange() const;
// Get the marginal bytes if spending the specified output from this transaction
@@ -482,17 +507,23 @@ public:
bool IsEquivalentTo(const CWalletTx& tx) const;
bool InMempool() const;
- bool IsTrusted() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool IsTrusted(interfaces::Chain::Lock& locked_chain) const;
int64_t GetTxTime() const;
// RelayWalletTransaction may only be called if fBroadcastTransactions!
- bool RelayWalletTransaction(CConnman* connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool RelayWalletTransaction(interfaces::Chain::Lock& locked_chain, CConnman* connman);
/** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
- bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- std::set<uint256> GetConflicts() const;
+ bool AcceptToMemoryPool(interfaces::Chain::Lock& locked_chain, const CAmount& nAbsurdFee, CValidationState& state);
+
+ // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
+ // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation
+ // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to
+ // resolve the issue of member access into incomplete type CWallet. Note
+ // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)"
+ // in place.
+ std::set<uint256> GetConflicts() const NO_THREAD_SAFETY_ANALYSIS;
};
class COutput
@@ -591,13 +622,13 @@ private:
std::mutex mutexScanning;
friend class WalletRescanReserver;
- WalletBatch *encrypted_batch = nullptr;
+ WalletBatch *encrypted_batch GUARDED_BY(cs_wallet) = nullptr;
//! the current wallet version: clients below this version are not able to load the wallet
int nWalletVersion = FEATURE_BASE;
//! the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded
- int nWalletMaxVersion = FEATURE_BASE;
+ int nWalletMaxVersion GUARDED_BY(cs_wallet) = FEATURE_BASE;
int64_t nNextResend = 0;
int64_t nLastResend = 0;
@@ -609,9 +640,9 @@ private:
* mutated transactions where the mutant gets mined).
*/
typedef std::multimap<COutPoint, uint256> TxSpends;
- TxSpends mapTxSpends;
- void AddToSpends(const COutPoint& outpoint, const uint256& wtxid);
- void AddToSpends(const uint256& wtxid);
+ TxSpends mapTxSpends GUARDED_BY(cs_wallet);
+ void AddToSpends(const COutPoint& outpoint, const uint256& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void AddToSpends(const uint256& wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Add a transaction to the wallet, or update it. pIndex and posInBlock should
@@ -632,9 +663,9 @@ private:
void MarkConflicted(const uint256& hashBlock, const uint256& hashTx);
/* Mark a transaction's inputs dirty, thus forcing the outputs to be recomputed */
- void MarkInputsDirty(const CTransactionRef& tx);
+ void MarkInputsDirty(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>);
+ void SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator>) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions.
* Should be called with pindexBlock and posInBlock if this is for a transaction that is included in a block. */
@@ -647,13 +678,13 @@ private:
void DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
std::set<int64_t> setInternalKeyPool;
- std::set<int64_t> setExternalKeyPool;
+ std::set<int64_t> setExternalKeyPool GUARDED_BY(cs_wallet);
std::set<int64_t> set_pre_split_keypool;
- int64_t m_max_keypool_index = 0;
+ int64_t m_max_keypool_index GUARDED_BY(cs_wallet) = 0;
std::map<CKeyID, int64_t> m_pool_key_to_index;
std::atomic<uint64_t> m_wallet_flags{0};
- int64_t nTimeFirstKey = 0;
+ int64_t nTimeFirstKey GUARDED_BY(cs_wallet) = 0;
/**
* Private version of AddWatchOnly method which does not accept a
@@ -666,12 +697,11 @@ private:
*/
bool AddWatchOnly(const CScript& dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- /**
- * Wallet filename from wallet=<path> command line or config option.
- * Used in debug logs and to send RPCs to the right wallet instance when
- * more than one wallet is loaded.
- */
- std::string m_name;
+ /** Interface for accessing chain state. */
+ interfaces::Chain& m_chain;
+
+ /** Wallet location which includes wallet name (see WalletLocation). */
+ WalletLocation m_location;
/** Internal database handle. */
std::unique_ptr<WalletDatabase> database;
@@ -709,27 +739,29 @@ public:
* if they are not ours
*/
bool SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet,
- const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const;
+ const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ const WalletLocation& GetLocation() const { return m_location; }
/** Get a name for this wallet for logging/debugging purposes.
*/
- const std::string& GetName() const { return m_name; }
+ const std::string& GetName() const { return m_location.GetName(); }
void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- void MarkPreSplitKeys();
+ void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
// Map from Key ID to key metadata.
- std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
+ std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_wallet);
// Map from Script ID to key metadata (for watch-only keys).
- std::map<CScriptID, CKeyMetadata> m_script_metadata;
+ std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_wallet);
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID = 0;
/** Construct wallet with specified name and database implementation. */
- CWallet(std::string name, std::unique_ptr<WalletDatabase> database) : m_name(std::move(name)), database(std::move(database))
+ CWallet(interfaces::Chain& chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database) : m_chain(chain), m_location(location), database(std::move(database))
{
}
@@ -739,17 +771,20 @@ public:
encrypted_batch = nullptr;
}
- std::map<uint256, CWalletTx> mapWallet;
+ std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet);
typedef std::multimap<int64_t, CWalletTx*> TxItems;
TxItems wtxOrdered;
- int64_t nOrderPosNext = 0;
+ int64_t nOrderPosNext GUARDED_BY(cs_wallet) = 0;
uint64_t nAccountingEntryNumber = 0;
std::map<CTxDestination, CAddressBookData> mapAddressBook;
- std::set<COutPoint> setLockedCoins;
+ std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet);
+
+ /** Interface for accessing chain state. */
+ interfaces::Chain& chain() const { return m_chain; }
const CWalletTx* GetWalletTx(const uint256& hash) const;
@@ -759,17 +794,17 @@ public:
/**
* populate vCoins with vector of available COutputs.
*/
- void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0, const int nMinDepth = 0, const int nMaxDepth = 9999999) const EXCLUSIVE_LOCKS_REQUIRED(cs_main, cs_wallet);
+ void AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0, const int nMinDepth = 0, const int nMaxDepth = 9999999) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Return list of available coins and locked coins grouped by non-change output address.
*/
- std::map<CTxDestination, std::vector<COutput>> ListCoins() const EXCLUSIVE_LOCKS_REQUIRED(cs_main, cs_wallet);
+ std::map<CTxDestination, std::vector<COutput>> ListCoins(interfaces::Chain::Lock& locked_chain) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Find non-change parent output.
*/
- const CTxOut& FindNonChangeParentOutput(const CTransaction& tx, int output) const;
+ const CTxOut& FindNonChangeParentOutput(const CTransaction& tx, int output) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Shuffle and select coins until nTargetValue is reached while avoiding
@@ -780,7 +815,7 @@ public:
bool SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<OutputGroup> groups,
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const;
- bool IsSpent(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool IsSpent(interfaces::Chain::Lock& locked_chain, const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
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);
@@ -844,7 +879,7 @@ public:
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
- void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CTxDestination, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
unsigned int ComputeTimeSmart(const CWalletTx& wtx) const;
/**
@@ -856,7 +891,7 @@ public:
void MarkDirty();
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
- void LoadToWallet(const CWalletTx& wtxIn);
+ void LoadToWallet(const CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void TransactionAddedToMempool(const CTransactionRef& tx) override;
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
@@ -866,7 +901,7 @@ public:
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
- std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ std::vector<uint256> ResendWalletTransactionsBefore(interfaces::Chain::Lock& locked_chain, int64_t nTime, CConnman* connman);
CAmount GetBalance(const isminefilter& filter=ISMINE_SPENDABLE, const int min_depth=0) const;
CAmount GetUnconfirmedBalance() const;
CAmount GetImmatureBalance() const;
@@ -889,7 +924,7 @@ public:
* selected by SelectCoins(); Also create the change output, when needed
* @note passing nChangePosInOut as -1 will result in setting a random position
*/
- bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
+ bool CreateTransaction(interfaces::Chain::Lock& locked_chain, const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
std::string& strFailReason, const CCoinControl& coin_control, bool sign = true);
bool CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CReserveKey& reservekey, CConnman* connman, CValidationState& state);
@@ -948,7 +983,7 @@ public:
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
std::set<std::set<CTxDestination>> GetAddressGroupings() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- std::map<CTxDestination, CAmount> GetAddressBalances() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ std::map<CTxDestination, CAmount> GetAddressBalances(interfaces::Chain::Lock& locked_chain);
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
@@ -961,6 +996,7 @@ public:
isminetype IsMine(const CTxOut& txout) const;
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
bool IsChange(const CTxOut& txout) const;
+ bool IsChange(const CScript& script) const;
CAmount GetChange(const CTxOut& txout) const;
bool IsMine(const CTransaction& tx) const;
/** should probably be renamed to IsRelevantToMe */
@@ -1000,7 +1036,7 @@ public:
int GetVersion() { LOCK(cs_wallet); return nWalletVersion; }
//! Get wallet transactions that conflict with given transaction (spend same outputs)
- std::set<uint256> GetConflicts(const uint256& txid) const;
+ std::set<uint256> GetConflicts(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Check if a given transaction has any of its outputs spent by another transaction in the wallet
bool HasWalletSpend(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -1042,16 +1078,16 @@ public:
bool TransactionCanBeAbandoned(const uint256& hashTx) const;
/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
- bool AbandonTransaction(const uint256& hashTx);
+ bool AbandonTransaction(interfaces::Chain::Lock& locked_chain, const uint256& hashTx);
/** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
//! Verify wallet naming and perform salvage on the wallet if required
- static bool Verify(std::string wallet_file, bool salvage_wallet, std::string& error_string, std::string& warning_string);
+ static bool Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, std::string& error_string, std::string& warning_string);
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
- static std::shared_ptr<CWallet> CreateWalletFromFile(const std::string& name, const fs::path& path, uint64_t wallet_creation_flags = 0);
+ static std::shared_ptr<CWallet> CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, uint64_t wallet_creation_flags = 0);
/**
* Wallet post-init setup
@@ -1198,6 +1234,6 @@ public:
// Use DummySignatureCreator, which inserts 71 byte signatures everywhere.
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
// be IsAllFromMe).
-int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig = false);
+int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig = false) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet);
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, bool use_max_sig = false);
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 5e85151358..09a33f252c 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -12,8 +12,8 @@
#include <protocol.h>
#include <serialize.h>
#include <sync.h>
-#include <util.h>
-#include <utiltime.h>
+#include <util/system.h>
+#include <util/time.h>
#include <wallet/wallet.h>
#include <atomic>
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index 34c76ec4c4..6db4c63acb 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -4,6 +4,8 @@
#include <wallet/walletutil.h>
+#include <util/system.h>
+
fs::path GetWalletDir()
{
fs::path path;
@@ -25,3 +27,67 @@ fs::path GetWalletDir()
return path;
}
+
+static bool IsBerkeleyBtree(const fs::path& path)
+{
+ // A Berkeley DB Btree file has at least 4K.
+ // This check also prevents opening lock files.
+ boost::system::error_code ec;
+ if (fs::file_size(path, ec) < 4096) return false;
+
+ fs::ifstream file(path.string(), std::ios::binary);
+ if (!file.is_open()) return false;
+
+ file.seekg(12, std::ios::beg); // Magic bytes start at offset 12
+ uint32_t data = 0;
+ file.read((char*) &data, sizeof(data)); // Read 4 bytes of file to compare against magic
+
+ // Berkeley DB Btree magic bytes, from:
+ // https://github.com/file/file/blob/5824af38469ec1ca9ac3ffd251e7afe9dc11e227/magic/Magdir/database#L74-L75
+ // - big endian systems - 00 05 31 62
+ // - little endian systems - 62 31 05 00
+ return data == 0x00053162 || data == 0x62310500;
+}
+
+std::vector<fs::path> ListWalletDir()
+{
+ const fs::path wallet_dir = GetWalletDir();
+ const size_t offset = wallet_dir.string().size() + 1;
+ std::vector<fs::path> paths;
+
+ for (auto it = fs::recursive_directory_iterator(wallet_dir); it != fs::recursive_directory_iterator(); ++it) {
+ // Get wallet path relative to walletdir by removing walletdir from the wallet path.
+ // This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60.
+ const fs::path path = it->path().string().substr(offset);
+
+ if (it->status().type() == fs::directory_file && IsBerkeleyBtree(it->path() / "wallet.dat")) {
+ // Found a directory which contains wallet.dat btree file, add it as a wallet.
+ paths.emplace_back(path);
+ } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && IsBerkeleyBtree(it->path())) {
+ if (it->path().filename() == "wallet.dat") {
+ // Found top-level wallet.dat btree file, add top level directory ""
+ // as a wallet.
+ paths.emplace_back();
+ } else {
+ // Found top-level btree file not called wallet.dat. Current bitcoin
+ // software will never create these files but will allow them to be
+ // opened in a shared database environment for backwards compatibility.
+ // Add it to the list of available wallets.
+ paths.emplace_back(path);
+ }
+ }
+ }
+
+ return paths;
+}
+
+WalletLocation::WalletLocation(const std::string& name)
+ : m_name(name)
+ , m_path(fs::absolute(name, GetWalletDir()))
+{
+}
+
+bool WalletLocation::Exists() const
+{
+ return fs::symlink_status(m_path).type() != fs::file_not_found;
+}
diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h
index 7c42954616..ba2f913841 100644
--- a/src/wallet/walletutil.h
+++ b/src/wallet/walletutil.h
@@ -5,10 +5,34 @@
#ifndef BITCOIN_WALLET_WALLETUTIL_H
#define BITCOIN_WALLET_WALLETUTIL_H
-#include <chainparamsbase.h>
-#include <util.h>
+#include <fs.h>
+
+#include <vector>
//! Get the path of the wallet directory.
fs::path GetWalletDir();
+//! Get wallets in wallet directory.
+std::vector<fs::path> ListWalletDir();
+
+//! The WalletLocation class provides wallet information.
+class WalletLocation final
+{
+ std::string m_name;
+ fs::path m_path;
+
+public:
+ explicit WalletLocation() {}
+ explicit WalletLocation(const std::string& name);
+
+ //! Get wallet name.
+ const std::string& GetName() const { return m_name; }
+
+ //! Get wallet absolute path.
+ const fs::path& GetPath() const { return m_path; }
+
+ //! Return whether the wallet exists.
+ bool Exists() const;
+};
+
#endif // BITCOIN_WALLET_WALLETUTIL_H
diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h
index 6f12551273..22aca65990 100644
--- a/src/walletinitinterface.h
+++ b/src/walletinitinterface.h
@@ -9,6 +9,7 @@
class CScheduler;
class CRPCTable;
+struct InitInterfaces;
class WalletInitInterface {
public:
@@ -18,20 +19,8 @@ public:
virtual void AddWalletOptions() const = 0;
/** Check wallet parameter interaction */
virtual bool ParameterInteraction() const = 0;
- /** Register wallet RPC*/
- virtual void RegisterRPC(CRPCTable &) const = 0;
- /** Verify wallets */
- virtual bool Verify() const = 0;
- /** Open wallets*/
- virtual bool Open() const = 0;
- /** Start wallets*/
- virtual void Start(CScheduler& scheduler) const = 0;
- /** Flush Wallets*/
- virtual void Flush() const = 0;
- /** Stop Wallets*/
- virtual void Stop() const = 0;
- /** Close wallets */
- virtual void Close() const = 0;
+ /** Add wallets that should be opened to list of init interfaces. */
+ virtual void Construct(InitInterfaces& interfaces) const = 0;
virtual ~WalletInitInterface() {}
};
diff --git a/src/warnings.cpp b/src/warnings.cpp
index 9f10c48eef..1c6ba13f60 100644
--- a/src/warnings.cpp
+++ b/src/warnings.cpp
@@ -5,7 +5,7 @@
#include <sync.h>
#include <clientversion.h>
-#include <util.h>
+#include <util/system.h>
#include <warnings.h>
CCriticalSection cs_warnings;
diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp
index 39cc8968d2..6a9661e3e8 100644
--- a/src/zmq/zmqabstractnotifier.cpp
+++ b/src/zmq/zmqabstractnotifier.cpp
@@ -3,8 +3,9 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <zmq/zmqabstractnotifier.h>
-#include <util.h>
+#include <util/system.h>
+const int CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM;
CZMQAbstractNotifier::~CZMQAbstractNotifier()
{
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
index 5081c6cd02..887dde7b27 100644
--- a/src/zmq/zmqabstractnotifier.h
+++ b/src/zmq/zmqabstractnotifier.h
@@ -15,7 +15,9 @@ typedef CZMQAbstractNotifier* (*CZMQNotifierFactory)();
class CZMQAbstractNotifier
{
public:
- CZMQAbstractNotifier() : psocket(nullptr) { }
+ static const int DEFAULT_ZMQ_SNDHWM {1000};
+
+ CZMQAbstractNotifier() : psocket(nullptr), outbound_message_high_water_mark(DEFAULT_ZMQ_SNDHWM) { }
virtual ~CZMQAbstractNotifier();
template <typename T>
@@ -28,6 +30,12 @@ public:
void SetType(const std::string &t) { type = t; }
std::string GetAddress() const { return address; }
void SetAddress(const std::string &a) { address = a; }
+ int GetOutboundMessageHighWaterMark() const { return outbound_message_high_water_mark; }
+ void SetOutboundMessageHighWaterMark(const int sndhwm) {
+ if (sndhwm >= 0) {
+ outbound_message_high_water_mark = sndhwm;
+ }
+ }
virtual bool Initialize(void *pcontext) = 0;
virtual void Shutdown() = 0;
@@ -39,6 +47,7 @@ protected:
void *psocket;
std::string type;
std::string address;
+ int outbound_message_high_water_mark; // aka SNDHWM
};
#endif // BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index 1d9f86d450..6826cf62d6 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -8,7 +8,7 @@
#include <version.h>
#include <validation.h>
#include <streams.h>
-#include <util.h>
+#include <util/system.h>
void zmqError(const char *str)
{
@@ -59,6 +59,7 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create()
CZMQAbstractNotifier *notifier = factory();
notifier->SetType(entry.first);
notifier->SetAddress(address);
+ notifier->SetOutboundMessageHighWaterMark(static_cast<int>(gArgs.GetArg(arg + "hwm", CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM)));
notifiers.push_back(notifier);
}
}
@@ -102,11 +103,11 @@ bool CZMQNotificationInterface::Initialize()
CZMQAbstractNotifier *notifier = *i;
if (notifier->Initialize(pcontext))
{
- LogPrint(BCLog::ZMQ, " Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress());
+ LogPrint(BCLog::ZMQ, "zmq: Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress());
}
else
{
- LogPrint(BCLog::ZMQ, " Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress());
+ LogPrint(BCLog::ZMQ, "zmq: Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress());
break;
}
}
@@ -128,7 +129,7 @@ void CZMQNotificationInterface::Shutdown()
for (std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin(); i!=notifiers.end(); ++i)
{
CZMQAbstractNotifier *notifier = *i;
- LogPrint(BCLog::ZMQ, " Shutdown notifier %s at %s\n", notifier->GetType(), notifier->GetAddress());
+ LogPrint(BCLog::ZMQ, "zmq: Shutdown notifier %s at %s\n", notifier->GetType(), notifier->GetAddress());
notifier->Shutdown();
}
zmq_ctx_term(pcontext);
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index 36a6458f67..15d4ac1b89 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -7,7 +7,7 @@
#include <streams.h>
#include <zmq/zmqpublishnotifier.h>
#include <validation.h>
-#include <util.h>
+#include <util/system.h>
#include <rpc/server.h>
static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;
@@ -76,8 +76,18 @@ bool CZMQAbstractPublishNotifier::Initialize(void *pcontext)
return false;
}
- int rc = zmq_bind(psocket, address.c_str());
- if (rc!=0)
+ LogPrint(BCLog::ZMQ, "zmq: Outbound message high water mark for %s at %s is %d\n", type, address, outbound_message_high_water_mark);
+
+ int rc = zmq_setsockopt(psocket, ZMQ_SNDHWM, &outbound_message_high_water_mark, sizeof(outbound_message_high_water_mark));
+ if (rc != 0)
+ {
+ zmqError("Failed to set outbound message high water mark");
+ zmq_close(psocket);
+ return false;
+ }
+
+ rc = zmq_bind(psocket, address.c_str());
+ if (rc != 0)
{
zmqError("Failed to bind address");
zmq_close(psocket);
@@ -120,7 +130,7 @@ void CZMQAbstractPublishNotifier::Shutdown()
if (count == 1)
{
- LogPrint(BCLog::ZMQ, "Close socket at address %s\n", address);
+ LogPrint(BCLog::ZMQ, "zmq: Close socket at address %s\n", address);
int linger = 0;
zmq_setsockopt(psocket, ZMQ_LINGER, &linger, sizeof(linger));
zmq_close(psocket);
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index 0f5b43d726..278fdb94d2 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -12,7 +12,7 @@ class CBlockIndex;
class CZMQAbstractPublishNotifier : public CZMQAbstractNotifier
{
private:
- uint32_t nSequence; //!< upcounting per message sequence number
+ uint32_t nSequence {0U}; //!< upcounting per message sequence number
public:
diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp
index 4f88bf4eb9..0e0b745375 100644
--- a/src/zmq/zmqrpc.cpp
+++ b/src/zmq/zmqrpc.cpp
@@ -22,7 +22,8 @@ UniValue getzmqnotifications(const JSONRPCRequest& request)
"[\n"
" { (json object)\n"
" \"type\": \"pubhashtx\", (string) Type of notification\n"
- " \"address\": \"...\" (string) Address of the publisher\n"
+ " \"address\": \"...\", (string) Address of the publisher\n"
+ " \"hwm\": n (numeric) Outbound message high water mark\n"
" },\n"
" ...\n"
"]\n"
@@ -38,6 +39,7 @@ UniValue getzmqnotifications(const JSONRPCRequest& request)
UniValue obj(UniValue::VOBJ);
obj.pushKV("type", n->GetType());
obj.pushKV("address", n->GetAddress());
+ obj.pushKV("hwm", n->GetOutboundMessageHighWaterMark());
result.push_back(obj);
}
}