diff options
Diffstat (limited to 'src')
178 files changed, 1135 insertions, 945 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 7a2e9fa5e8..703304cebd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -183,10 +183,10 @@ BITCOIN_CORE_H = \ txmempool.h \ ui_interface.h \ undo.h \ - util.h \ - utilmemory.h \ - utilmoneystr.h \ - utiltime.h \ + util/system.h \ + util/memory.h \ + util/moneystr.h \ + util/time.h \ validation.h \ validationinterface.h \ versionbits.h \ @@ -377,8 +377,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 +427,10 @@ libbitcoin_util_a_SOURCES = \ support/cleanse.cpp \ sync.cpp \ threadinterrupt.cpp \ - util.cpp \ - utilmoneystr.cpp \ - utilstrencodings.cpp \ - utiltime.cpp \ + util/system.cpp \ + util/moneystr.cpp \ + util/strencodings.cpp \ + util/time.cpp \ $(BITCOIN_CORE_H) if GLIBC_BACK_COMPAT @@ -587,9 +587,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..3ca2a7451d 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 \ @@ -168,7 +167,6 @@ BITCOIN_MM = \ QT_MOC = \ qt/bitcoin.moc \ qt/bitcoinamountfield.moc \ - qt/callback.moc \ qt/intro.moc \ qt/overviewpage.moc \ qt/rpcconsole.moc @@ -178,9 +176,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 +195,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 \ @@ -330,7 +333,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 +351,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 +417,12 @@ 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) +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/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 6d5780afa8..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> diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 791dad7a60..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> 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..ac2299374c 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -13,7 +13,7 @@ #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/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..decdadfb26 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -33,7 +33,7 @@ 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()); + const CWallet wallet(WalletLocation(), WalletDatabase::CreateDummy()); LOCK(wallet.cs_wallet); // Add coins. @@ -57,7 +57,7 @@ static void CoinSelection(benchmark::State& state) } typedef std::set<CInputCoin> CoinSet; -static const CWallet testWallet("dummy", WalletDatabase::CreateDummy()); +static const CWallet testWallet(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..d7499a3767 100644 --- a/src/bench/crypto_hash.cpp +++ b/src/bench/crypto_hash.cpp @@ -9,7 +9,7 @@ #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> 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 f466505114..dc1b46faf1 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -12,8 +12,8 @@ #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> diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index a3fcb87675..bdc064b9fb 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> @@ -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 18fcd9bc2a..c6e2a7c20a 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -15,10 +15,10 @@ #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> diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index 4c57965bec..a06bced11b 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -11,7 +11,7 @@ #include <streams.h> #include <txmempool.h> #include <validation.h> -#include <util.h> +#include <util/system.h> #include <unordered_map> 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/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/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 3eb77354c1..2a9b297029 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; diff --git a/src/fs.cpp b/src/fs.cpp index a146107c4c..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; } 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 06f9ace7ec..d54d4a8782 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -41,8 +41,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> diff --git a/src/init.h b/src/init.h index c58ba5cfd3..b106353d08 100644 --- a/src/init.h +++ b/src/init.h @@ -8,7 +8,7 @@ #include <memory> #include <string> -#include <util.h> +#include <util/system.h> class CScheduler; class CWallet; 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 2b19e11f08..490c456e6e 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -25,7 +25,7 @@ #include <sync.h> #include <txmempool.h> #include <ui_interface.h> -#include <util.h> +#include <util/system.h> #include <validation.h> #include <warnings.h> diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 566ae37509..14c6bd0330 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -103,7 +103,7 @@ static WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx) EXCLUSIVE_LOCKS_R } //! Construct wallet TxOut struct. -static WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth) EXCLUSIVE_LOCKS_REQUIRED(cs_main, wallet.cs_wallet) { WalletTxOut result; result.txout = wtx.tx->vout[n]; @@ -290,8 +290,7 @@ public: } 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); if (!locked_chain) { @@ -306,7 +305,6 @@ public: return false; } num_blocks = ::chainActive.Height(); - adjusted_time = GetAdjustedTime(); tx_status = MakeWalletTxStatus(mi->second); return true; } @@ -314,14 +312,12 @@ public: 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 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); 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 c8d3efceed..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> diff --git a/src/net_processing.cpp b/src/net_processing.cpp index a1b6e021ae..f37312d155 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> 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 04d5eb12c8..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> 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/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/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 6d8b530f69..0f834eb8c1 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -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/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 a014ad4b28..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> @@ -439,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); @@ -467,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 @@ -536,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); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 311841017f..072334ebb0 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> 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 183444efab..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> 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/guiutil.cpp b/src/qt/guiutil.cpp index 5f6af61a70..a68140ccf9 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 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/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 c004c783f2..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> 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..0cabb5f0be 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -6,17 +6,17 @@ #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 +56,7 @@ void EditAddressAndSubmit( void TestAddAddressesToSendBook() { TestChain100Setup test; - std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>("mock", WalletDatabase::CreateMock()); + std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(WalletLocation(), WalletDatabase::CreateMock()); bool firstRun; wallet->LoadWallet(firstRun); @@ -139,5 +139,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..12dbf922f1 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -2,8 +2,8 @@ #include <qt/test/util.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 +39,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 +49,7 @@ void ConfirmSend(QString* text = nullptr, bool cancel = false) button->click(); } } - delete callback; - }), &Callback::call); + }); } //! Send coins to address and return txid. @@ -133,7 +132,7 @@ 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()); + std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(WalletLocation(), WalletDatabase::CreateMock()); bool firstRun; wallet->LoadWallet(firstRun); { @@ -243,5 +242,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/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/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 ff71b19250..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> @@ -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 c565b9b4f9..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(); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 6a66998d37..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> @@ -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 ee178f34ce..23999b305a 100644 --- a/src/rpc/protocol.cpp +++ b/src/rpc/protocol.cpp @@ -7,9 +7,9 @@ #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> /** diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index a2d990b51d..0f87646b08 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -26,7 +26,7 @@ #include <script/standard.h> #include <txmempool.h> #include <uint256.h> -#include <utilstrencodings.h> +#include <util/strencodings.h> #include <future> #include <stdint.h> 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..8a66191a6a 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -7,7 +7,7 @@ #include <rpc/protocol.h> #include <rpc/util.h> #include <tinyformat.h> -#include <utilstrencodings.h> +#include <util/strencodings.h> // Converts a hex string to a public key if possible CPubKey HexToPubKey(const std::string& hex_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/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/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 0042f35e2e..89cc7c808c 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -280,6 +280,11 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t if (require_witness_sig && !sigdata.witness) return false; input.FromSignatureData(sigdata); + if (sigdata.witness) { + assert(!utxo.IsNull()); + input.witness_utxo = utxo; + } + // If both UTXO types are present, drop the unnecessary one. if (input.non_witness_utxo && !input.witness_utxo.IsNull()) { if (sigdata.witness) { @@ -686,6 +691,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..d47aada17d 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> @@ -602,6 +620,7 @@ struct PartiallySignedTransaction } // Read global data + bool found_sep = false; while(!s.empty()) { // Read std::vector<unsigned char> key; @@ -609,7 +628,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 +671,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"); 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/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/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..fd3a6b0dec 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -3,7 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #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..f788c34e05 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -6,7 +6,7 @@ #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/script_tests.cpp b/src/test/script_tests.cpp index 7fbf37e7fb..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> 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..552bd1ab03 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> 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/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/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/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 6479b9b9ce..4f5dd2d6e9 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> diff --git a/src/util.h b/src/util/system.h index fa6d2cd489..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> @@ -379,4 +379,4 @@ private: } // 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..5eb70cd7a5 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -12,8 +12,8 @@ #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 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 46983642f0..220780c96c 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -8,8 +8,8 @@ #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> @@ -211,15 +211,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(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; @@ -236,7 +236,7 @@ bool WalletInit::Open() const } for (const std::string& walletFile : gArgs.GetArgs("-wallet")) { - std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(walletFile, fs::absolute(walletFile, GetWalletDir())); + std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(WalletLocation(walletFile)); if (!pwallet) { return false; } diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 92457c4644..2a4cf0147e 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -9,8 +9,8 @@ #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> @@ -808,29 +808,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; @@ -854,35 +849,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(); @@ -891,103 +889,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"); @@ -998,73 +976,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); @@ -1117,7 +1083,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" diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a3f5f8b211..45d4b5bceb 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -23,8 +23,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> @@ -982,131 +982,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,7 +996,7 @@ struct tallyitem } }; -static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pwallet->cs_wallet) { // Minimum confirmations int nMinDepth = 1; @@ -1928,13 +1803,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); @@ -2004,7 +1872,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; } @@ -2526,26 +2405,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(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(location); if (!wallet) { throw JSONRPCError(RPC_WALLET_ERROR, "Wallet loading failed."); } @@ -2579,7 +2458,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; @@ -2588,17 +2466,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(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(location, (disable_privatekeys ? (uint64_t)WALLET_FLAG_DISABLE_PRIVATE_KEYS : 0)); if (!wallet) { throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed."); } @@ -3321,6 +3199,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()) { @@ -3570,8 +3454,10 @@ UniValue getaddressinfo(const JSONRPCRequest& request) " \"address\" : \"address\", (string) The bitcoin address validated\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" @@ -3624,11 +3510,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()) { @@ -4091,7 +3979,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"} }, diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index 21857df081..a9464870ea 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -28,7 +28,7 @@ std::vector<std::unique_ptr<CWalletTx>> wtxn; typedef std::set<CInputCoin> CoinSet; static std::vector<COutput> vCoins; -static CWallet testWallet("dummy", WalletDatabase::CreateDummy()); +static CWallet testWallet(WalletLocation(), WalletDatabase::CreateDummy()); static CAmount balance = 0; CoinEligibilityFilter filter_standard(1, 6, 0); diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp index 526f2d983f..cb1ad25461 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; 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..d42209ab15 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(WalletLocation(), WalletDatabase::CreateMock()) { bool fFirstRun; m_wallet.LoadWallet(fFirstRun); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 3a8e6f751a..269a916829 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -46,7 +46,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) // Verify ScanForWalletTransactions picks up transactions in both the old // and new block files. { - CWallet wallet("dummy", WalletDatabase::CreateDummy()); + CWallet wallet(WalletLocation(), WalletDatabase::CreateDummy()); AddKey(wallet, coinbaseKey); WalletRescanReserver reserver(&wallet); reserver.reserve(); @@ -61,7 +61,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup) // Verify ScanForWalletTransactions only picks transactions in the new block // file. { - CWallet wallet("dummy", WalletDatabase::CreateDummy()); + CWallet wallet(WalletLocation(), WalletDatabase::CreateDummy()); AddKey(wallet, coinbaseKey); WalletRescanReserver reserver(&wallet); reserver.reserve(); @@ -73,7 +73,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>(WalletLocation(), WalletDatabase::CreateDummy()); AddWallet(wallet); UniValue keys; keys.setArray(); @@ -134,7 +134,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) // 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>(WalletLocation(), WalletDatabase::CreateDummy()); LOCK(wallet->cs_wallet); wallet->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME; wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()); @@ -150,7 +150,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>(WalletLocation(), WalletDatabase::CreateDummy()); JSONRPCRequest request; request.params.setArray(); @@ -180,7 +180,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) // debit functions. BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup) { - CWallet wallet("dummy", WalletDatabase::CreateDummy()); + CWallet wallet(WalletLocation(), WalletDatabase::CreateDummy()); CWalletTx wtx(&wallet, m_coinbase_txns.back()); LOCK2(cs_main, wallet.cs_wallet); wtx.hashBlock = chainActive.Tip()->GetBlockHash(); @@ -273,7 +273,7 @@ public: ListCoinsTestingSetup() { CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); - wallet = MakeUnique<CWallet>("mock", WalletDatabase::CreateMock()); + wallet = MakeUnique<CWallet>(WalletLocation(), WalletDatabase::CreateMock()); bool firstRun; wallet->LoadWallet(firstRun); AddKey(*wallet, coinbaseKey); @@ -377,7 +377,7 @@ 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()); + std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(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..2ea9f45462 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -25,9 +25,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> @@ -1262,6 +1261,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 +1273,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); @@ -3821,7 +3825,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(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 +3834,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 +3860,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(WalletLocation(), WalletDatabase::CreateDummy()); std::string backup_filename; if (!WalletBatch::Recover(wallet_path, (void *)&dummyWallet, WalletBatch::RecoverKeysOnlyFilter, backup_filename)) { return false; @@ -3872,9 +3876,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(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 +3886,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>(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 +3900,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(location, WalletDatabase::Create(location.GetPath())), ReleaseWallet); DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun); if (nLoadWalletRet != DBErrors::LOAD_OK) { @@ -4093,7 +4097,7 @@ 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); + LOCK2(cs_main, walletInstance->cs_wallet); CBlockIndex *pindexRescan = chainActive.Genesis(); if (!gArgs.GetBoolArg("-rescan", false)) @@ -4178,7 +4182,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()); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index da326517c0..74eaa09506 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -12,15 +12,15 @@ #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> @@ -460,7 +460,11 @@ public: 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); + // 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(bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS; CAmount GetImmatureWatchOnlyCredit(const bool fUseCache=true) const EXCLUSIVE_LOCKS_REQUIRED(cs_main); CAmount GetChange() const; @@ -492,7 +496,13 @@ public: /** 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; + // 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 +601,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 +619,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 +642,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 +657,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 +676,8 @@ 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; + /** Wallet location which includes wallet name (see WalletLocation). */ + WalletLocation m_location; /** Internal database handle. */ std::unique_ptr<WalletDatabase> database; @@ -709,27 +715,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(const WalletLocation& location, std::unique_ptr<WalletDatabase> database) : m_location(location), database(std::move(database)) { } @@ -739,17 +747,17 @@ 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); const CWalletTx* GetWalletTx(const uint256& hash) const; @@ -769,7 +777,7 @@ public: /** * 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 +788,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(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_main, 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); @@ -856,7 +864,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; @@ -961,6 +969,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 +1009,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); @@ -1048,10 +1057,10 @@ public: 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(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(const WalletLocation& location, uint64_t wallet_creation_flags = 0); /** * Wallet post-init setup @@ -1198,6 +1207,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 c0c9afe13e..6db4c63acb 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -4,7 +4,7 @@ #include <wallet/walletutil.h> -#include <util.h> +#include <util/system.h> fs::path GetWalletDir() { @@ -52,12 +52,17 @@ static bool IsBerkeleyBtree(const fs::path& path) 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 != end(it); ++it) { + 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(fs::relative(it->path(), wallet_dir)); + 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 "" @@ -68,10 +73,21 @@ std::vector<fs::path> ListWalletDir() // 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(fs::relative(it->path(), wallet_dir)); + 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 77f5ca428d..ba2f913841 100644 --- a/src/wallet/walletutil.h +++ b/src/wallet/walletutil.h @@ -15,4 +15,24 @@ 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/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 0eeef8cf1d..6a9661e3e8 100644 --- a/src/zmq/zmqabstractnotifier.cpp +++ b/src/zmq/zmqabstractnotifier.cpp @@ -3,7 +3,7 @@ // 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; diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 680e38bd77..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) { diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 280cd1642e..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; |