aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am14
-rw-r--r--src/Makefile.bench.include2
-rw-r--r--src/Makefile.qt.include2
-rw-r--r--src/bench/ccoins_caching.cpp6
-rw-r--r--src/bench/chacha_poly_aead.cpp123
-rw-r--r--src/bench/rpc_blockchain.cpp33
-rw-r--r--src/bitcoin-cli.cpp1
-rw-r--r--src/bitcoin-tx.cpp6
-rw-r--r--src/chainparams.cpp8
-rw-r--r--src/chainparams.h8
-rw-r--r--src/crypto/chacha_poly_aead.cpp126
-rw-r--r--src/crypto/chacha_poly_aead.h146
-rw-r--r--src/index/blockfilterindex.cpp4
-rw-r--r--src/init.cpp18
-rw-r--r--src/interfaces/chain.cpp2
-rw-r--r--src/interfaces/wallet.cpp15
-rw-r--r--src/interfaces/wallet.h4
-rw-r--r--src/keystore.h83
-rw-r--r--src/net.cpp2
-rw-r--r--src/net_processing.h1
-rw-r--r--src/netbase.cpp224
-rw-r--r--src/outputtype.cpp6
-rw-r--r--src/outputtype.h4
-rw-r--r--src/protocol.h5
-rw-r--r--src/psbt.h1
-rw-r--r--src/qt/addresstablemodel.cpp16
-rw-r--r--src/qt/bitcoin.cpp13
-rw-r--r--src/qt/bitcoingui.cpp15
-rw-r--r--src/qt/bitcoinstrings.cpp17
-rw-r--r--src/qt/clientmodel.cpp18
-rw-r--r--src/qt/coincontroldialog.cpp6
-rw-r--r--src/qt/guiutil.cpp11
-rw-r--r--src/qt/intro.cpp12
-rw-r--r--src/qt/locale/bitcoin_en.ts455
-rw-r--r--src/qt/optionsdialog.cpp8
-rw-r--r--src/qt/paymentserver.cpp8
-rw-r--r--src/qt/rpcconsole.cpp4
-rw-r--r--src/qt/splashscreen.cpp5
-rw-r--r--src/qt/test/wallettests.cpp3
-rw-r--r--src/qt/transactiontablemodel.cpp15
-rw-r--r--src/qt/utilitydialog.cpp6
-rw-r--r--src/qt/walletcontroller.cpp3
-rw-r--r--src/qt/walletmodel.cpp28
-rw-r--r--src/rest.cpp1
-rw-r--r--src/rpc/blockchain.cpp136
-rw-r--r--src/rpc/mining.cpp41
-rw-r--r--src/rpc/misc.cpp47
-rw-r--r--src/rpc/net.cpp47
-rw-r--r--src/rpc/protocol.h23
-rw-r--r--src/rpc/rawtransaction.cpp106
-rw-r--r--src/rpc/rawtransaction_util.cpp7
-rw-r--r--src/rpc/rawtransaction_util.h4
-rw-r--r--src/rpc/request.cpp (renamed from src/rpc/protocol.cpp)42
-rw-r--r--src/rpc/request.h42
-rw-r--r--src/rpc/server.cpp43
-rw-r--r--src/rpc/server.h18
-rw-r--r--src/rpc/util.cpp8
-rw-r--r--src/rpc/util.h18
-rw-r--r--src/script/descriptor.h1
-rw-r--r--src/script/interpreter.cpp4
-rw-r--r--src/script/keyorigin.h37
-rw-r--r--src/script/script.h4
-rw-r--r--src/script/sign.cpp60
-rw-r--r--src/script/sign.h70
-rw-r--r--src/script/signingprovider.cpp (renamed from src/keystore.cpp)158
-rw-r--r--src/script/signingprovider.h92
-rw-r--r--src/script/standard.cpp1
-rw-r--r--src/test/addrman_tests.cpp9
-rw-r--r--src/test/crypto_tests.cpp126
-rw-r--r--src/test/denialofservice_tests.cpp5
-rw-r--r--src/test/multisig_tests.cpp4
-rw-r--r--src/test/script_p2sh_tests.cpp8
-rw-r--r--src/test/script_standard_tests.cpp2
-rw-r--r--src/test/script_tests.cpp4
-rw-r--r--src/test/transaction_tests.cpp14
-rw-r--r--src/test/txvalidationcache_tests.cpp4
-rw-r--r--src/test/util.cpp11
-rw-r--r--src/timedata.cpp2
-rw-r--r--src/torcontrol.cpp4
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/util/system.cpp7
-rw-r--r--src/validation.cpp223
-rw-r--r--src/validation.h158
-rw-r--r--src/wallet/crypter.cpp192
-rw-r--r--src/wallet/crypter.h54
-rw-r--r--src/wallet/feebumper.cpp9
-rw-r--r--src/wallet/ismine.cpp1
-rw-r--r--src/wallet/rpcdump.cpp42
-rw-r--r--src/wallet/rpcwallet.cpp339
-rw-r--r--src/wallet/test/wallet_tests.cpp14
-rw-r--r--src/wallet/wallet.cpp449
-rw-r--r--src/wallet/wallet.h140
-rw-r--r--src/zmq/zmqrpc.cpp5
93 files changed, 2468 insertions, 1857 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 39e8d3d689..0ed412295f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -143,7 +143,6 @@ BITCOIN_CORE_H = \
interfaces/wallet.h \
key.h \
key_io.h \
- keystore.h \
dbwrapper.h \
limitedmap.h \
logging.h \
@@ -175,14 +174,17 @@ BITCOIN_CORE_H = \
rpc/blockchain.h \
rpc/client.h \
rpc/protocol.h \
- rpc/server.h \
rpc/rawtransaction_util.h \
rpc/register.h \
+ rpc/request.h \
+ rpc/server.h \
rpc/util.h \
scheduler.h \
script/descriptor.h \
+ script/keyorigin.h \
script/sigcache.h \
script/sign.h \
+ script/signingprovider.h \
script/standard.h \
shutdown.h \
streams.h \
@@ -351,6 +353,8 @@ crypto_libbitcoin_crypto_base_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_base_a_SOURCES = \
crypto/aes.cpp \
crypto/aes.h \
+ crypto/chacha_poly_aead.h \
+ crypto/chacha_poly_aead.cpp \
crypto/chacha20.h \
crypto/chacha20.cpp \
crypto/common.h \
@@ -446,7 +450,6 @@ libbitcoin_common_a_SOURCES = \
core_write.cpp \
key.cpp \
key_io.cpp \
- keystore.cpp \
merkleblock.cpp \
netaddress.cpp \
netbase.cpp \
@@ -460,6 +463,7 @@ libbitcoin_common_a_SOURCES = \
scheduler.cpp \
script/descriptor.cpp \
script/sign.cpp \
+ script/signingprovider.cpp \
script/standard.cpp \
versionbitsinfo.cpp \
warnings.cpp \
@@ -481,7 +485,7 @@ libbitcoin_util_a_SOURCES = \
interfaces/handler.cpp \
logging.cpp \
random.cpp \
- rpc/protocol.cpp \
+ rpc/request.cpp \
support/cleanse.cpp \
sync.cpp \
threadinterrupt.cpp \
@@ -613,7 +617,7 @@ bitcoin_wallet_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(CRYPTO_LIBS) $(EVENT_PTHREAD
# bitcoinconsensus library #
if BUILD_BITCOIN_LIBS
include_HEADERS = script/bitcoinconsensus.h
-libbitcoinconsensus_la_SOURCES = $(crypto_libbitcoin_crypto_base_a_SOURCES) $(libbitcoin_consensus_a_SOURCES)
+libbitcoinconsensus_la_SOURCES = support/cleanse.cpp $(crypto_libbitcoin_crypto_base_a_SOURCES) $(libbitcoin_consensus_a_SOURCES)
if GLIBC_BACK_COMPAT
libbitcoinconsensus_la_SOURCES += compat/glibc_compat.cpp
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 1b01b50b07..e421b377a0 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -24,11 +24,13 @@ bench_bench_bitcoin_SOURCES = \
bench/examples.cpp \
bench/rollingbloom.cpp \
bench/chacha20.cpp \
+ bench/chacha_poly_aead.cpp \
bench/crypto_hash.cpp \
bench/ccoins_caching.cpp \
bench/gcs_filter.cpp \
bench/merkle_root.cpp \
bench/mempool_eviction.cpp \
+ bench/rpc_blockchain.cpp \
bench/rpc_mempool.cpp \
bench/util_time.cpp \
bench/verify_script.cpp \
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index c4c08487f3..3ae8498a87 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -447,7 +447,7 @@ SECONDARY: $(QT_QM)
$(srcdir)/qt/bitcoinstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_zmq_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) $(libbitcoin_util_a_SOURCES)
@test -n $(XGETTEXT) || echo "xgettext is required for updating translations"
- $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" COPYRIGHT_HOLDERS_SUBSTITUTION="$(COPYRIGHT_HOLDERS_SUBSTITUTION)" $(PYTHON) ../share/qt/extract_strings_qt.py $^
+ $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" $(PYTHON) ../share/qt/extract_strings_qt.py $^
translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) qt/bitcoin.cpp $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM)
@test -n $(LUPDATE) || echo "lupdate is required for updating translations"
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
index 1041a22303..39cab092cf 100644
--- a/src/bench/ccoins_caching.cpp
+++ b/src/bench/ccoins_caching.cpp
@@ -5,7 +5,7 @@
#include <bench/bench.h>
#include <coins.h>
#include <policy/policy.h>
-#include <wallet/crypter.h>
+#include <script/signingprovider.h>
#include <vector>
@@ -17,7 +17,7 @@
// paid to a TX_PUBKEYHASH.
//
static std::vector<CMutableTransaction>
-SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
+SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet)
{
std::vector<CMutableTransaction> dummyTransactions;
dummyTransactions.resize(2);
@@ -55,7 +55,7 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
static void CCoinsCaching(benchmark::State& state)
{
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
diff --git a/src/bench/chacha_poly_aead.cpp b/src/bench/chacha_poly_aead.cpp
new file mode 100644
index 0000000000..f5f7297490
--- /dev/null
+++ b/src/bench/chacha_poly_aead.cpp
@@ -0,0 +1,123 @@
+// Copyright (c) 2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <iostream>
+
+#include <bench/bench.h>
+#include <crypto/chacha_poly_aead.h>
+#include <crypto/poly1305.h> // for the POLY1305_TAGLEN constant
+#include <hash.h>
+
+#include <limits>
+#include <assert.h>
+
+/* Number of bytes to process per iteration */
+static constexpr uint64_t BUFFER_SIZE_TINY = 64;
+static constexpr uint64_t BUFFER_SIZE_SMALL = 256;
+static constexpr uint64_t BUFFER_SIZE_LARGE = 1024 * 1024;
+
+static const unsigned char k1[32] = {0};
+static const unsigned char k2[32] = {0};
+
+static ChaCha20Poly1305AEAD aead(k1, 32, k2, 32);
+
+static void CHACHA20_POLY1305_AEAD(benchmark::State& state, size_t buffersize, bool include_decryption)
+{
+ std::vector<unsigned char> in(buffersize + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
+ std::vector<unsigned char> out(buffersize + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
+ uint64_t seqnr_payload = 0;
+ uint64_t seqnr_aad = 0;
+ int aad_pos = 0;
+ uint32_t len = 0;
+ while (state.KeepRunning()) {
+ // encrypt or decrypt the buffer with a static key
+ assert(aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true));
+
+ if (include_decryption) {
+ // if we decrypt, include the GetLength
+ assert(aead.GetLength(&len, seqnr_aad, aad_pos, in.data()));
+ assert(aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true));
+ }
+
+ // increase main sequence number
+ seqnr_payload++;
+ // increase aad position (position in AAD keystream)
+ aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
+ if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
+ aad_pos = 0;
+ seqnr_aad++;
+ }
+ if (seqnr_payload + 1 == std::numeric_limits<uint64_t>::max()) {
+ // reuse of nonce+key is okay while benchmarking.
+ seqnr_payload = 0;
+ seqnr_aad = 0;
+ aad_pos = 0;
+ }
+ }
+}
+
+static void CHACHA20_POLY1305_AEAD_64BYTES_ONLY_ENCRYPT(benchmark::State& state)
+{
+ CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_TINY, false);
+}
+
+static void CHACHA20_POLY1305_AEAD_256BYTES_ONLY_ENCRYPT(benchmark::State& state)
+{
+ CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_SMALL, false);
+}
+
+static void CHACHA20_POLY1305_AEAD_1MB_ONLY_ENCRYPT(benchmark::State& state)
+{
+ CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_LARGE, false);
+}
+
+static void CHACHA20_POLY1305_AEAD_64BYTES_ENCRYPT_DECRYPT(benchmark::State& state)
+{
+ CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_TINY, true);
+}
+
+static void CHACHA20_POLY1305_AEAD_256BYTES_ENCRYPT_DECRYPT(benchmark::State& state)
+{
+ CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_SMALL, true);
+}
+
+static void CHACHA20_POLY1305_AEAD_1MB_ENCRYPT_DECRYPT(benchmark::State& state)
+{
+ CHACHA20_POLY1305_AEAD(state, BUFFER_SIZE_LARGE, true);
+}
+
+// Add Hash() (dbl-sha256) bench for comparison
+
+static void HASH(benchmark::State& state, size_t buffersize)
+{
+ uint8_t hash[CHash256::OUTPUT_SIZE];
+ std::vector<uint8_t> in(buffersize,0);
+ while (state.KeepRunning())
+ CHash256().Write(in.data(), in.size()).Finalize(hash);
+}
+
+static void HASH_64BYTES(benchmark::State& state)
+{
+ HASH(state, BUFFER_SIZE_TINY);
+}
+
+static void HASH_256BYTES(benchmark::State& state)
+{
+ HASH(state, BUFFER_SIZE_SMALL);
+}
+
+static void HASH_1MB(benchmark::State& state)
+{
+ HASH(state, BUFFER_SIZE_LARGE);
+}
+
+BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ONLY_ENCRYPT, 500000);
+BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ONLY_ENCRYPT, 250000);
+BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ONLY_ENCRYPT, 340);
+BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ENCRYPT_DECRYPT, 500000);
+BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ENCRYPT_DECRYPT, 250000);
+BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ENCRYPT_DECRYPT, 340);
+BENCHMARK(HASH_64BYTES, 500000);
+BENCHMARK(HASH_256BYTES, 250000);
+BENCHMARK(HASH_1MB, 340);
diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp
new file mode 100644
index 0000000000..29e448fc43
--- /dev/null
+++ b/src/bench/rpc_blockchain.cpp
@@ -0,0 +1,33 @@
+// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <bench/bench.h>
+#include <bench/data.h>
+
+#include <validation.h>
+#include <streams.h>
+#include <consensus/validation.h>
+#include <rpc/blockchain.h>
+
+#include <univalue.h>
+
+static void BlockToJsonVerbose(benchmark::State& state) {
+ CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
+ char a = '\0';
+ stream.write(&a, 1); // Prevent compaction
+
+ CBlock block;
+ stream >> block;
+
+ CBlockIndex blockindex;
+ const uint256 blockHash = block.GetHash();
+ blockindex.phashBlock = &blockHash;
+ blockindex.nBits = 403014710;
+
+ while (state.KeepRunning()) {
+ (void)blockToJSON(block, &blockindex, &blockindex, /*verbose*/ true);
+ }
+}
+
+BENCHMARK(BlockToJsonVerbose, 10);
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 38010c461e..d3419520a7 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -12,6 +12,7 @@
#include <fs.h>
#include <rpc/client.h>
#include <rpc/protocol.h>
+#include <rpc/request.h>
#include <util/system.h>
#include <util/strencodings.h>
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 933b34744d..4d513deed8 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -11,12 +11,12 @@
#include <consensus/consensus.h>
#include <core_io.h>
#include <key_io.h>
-#include <keystore.h>
#include <policy/policy.h>
#include <policy/rbf.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <univalue.h>
#include <util/rbf.h>
#include <util/system.h>
@@ -557,7 +557,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
if (!registers.count("privatekeys"))
throw std::runtime_error("privatekeys register variable must be set.");
- CBasicKeyStore tempKeystore;
+ FillableSigningProvider tempKeystore;
UniValue keysObj = registers["privatekeys"];
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
@@ -631,7 +631,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
}
}
- const CKeyStore& keystore = tempKeystore;
+ const FillableSigningProvider& keystore = tempKeystore;
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index b8e0ea23dd..f937e2754b 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -141,7 +141,7 @@ public:
fDefaultConsistencyChecks = false;
fRequireStandard = true;
- fMineBlocksOnDemand = false;
+ m_is_test_chain = false;
checkpointData = {
{
@@ -247,7 +247,7 @@ public:
fDefaultConsistencyChecks = false;
fRequireStandard = false;
- fMineBlocksOnDemand = false;
+ m_is_test_chain = true;
checkpointData = {
@@ -324,8 +324,8 @@ public:
vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds.
fDefaultConsistencyChecks = true;
- fRequireStandard = false;
- fMineBlocksOnDemand = true;
+ fRequireStandard = true;
+ m_is_test_chain = true;
checkpointData = {
{
diff --git a/src/chainparams.h b/src/chainparams.h
index 6ff3dbb7e5..b3fcd77cea 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -66,13 +66,15 @@ public:
bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
/** Policy: Filter transactions that do not match well-defined patterns */
bool RequireStandard() const { return fRequireStandard; }
+ /** If this is a test chain */
+ bool IsTestChain() const { return m_is_test_chain; }
uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }
/** Minimum free space (in GB) needed for data directory */
uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; }
/** Minimum free space (in GB) needed for data directory when pruned; Does not include prune target*/
uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; }
- /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */
- bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
+ /** Whether it is possible to mine blocks on demand (no retargeting) */
+ bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; }
/** Return the BIP70 network string (main, test or regtest) */
std::string NetworkIDString() const { return strNetworkID; }
/** Return true if the fallback fee is by default enabled for this network */
@@ -101,7 +103,7 @@ protected:
std::vector<SeedSpec6> vFixedSeeds;
bool fDefaultConsistencyChecks;
bool fRequireStandard;
- bool fMineBlocksOnDemand;
+ bool m_is_test_chain;
CCheckpointData checkpointData;
ChainTxData chainTxData;
bool m_fallback_fee_enabled;
diff --git a/src/crypto/chacha_poly_aead.cpp b/src/crypto/chacha_poly_aead.cpp
new file mode 100644
index 0000000000..6a3d43deb1
--- /dev/null
+++ b/src/crypto/chacha_poly_aead.cpp
@@ -0,0 +1,126 @@
+// Copyright (c) 2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <crypto/chacha_poly_aead.h>
+
+#include <crypto/common.h>
+#include <crypto/poly1305.h>
+#include <support/cleanse.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <cstdio>
+#include <limits>
+
+#ifndef HAVE_TIMINGSAFE_BCMP
+
+int timingsafe_bcmp(const unsigned char* b1, const unsigned char* b2, size_t n)
+{
+ const unsigned char *p1 = b1, *p2 = b2;
+ int ret = 0;
+
+ for (; n > 0; n--)
+ ret |= *p1++ ^ *p2++;
+ return (ret != 0);
+}
+
+#endif // TIMINGSAFE_BCMP
+
+ChaCha20Poly1305AEAD::ChaCha20Poly1305AEAD(const unsigned char* K_1, size_t K_1_len, const unsigned char* K_2, size_t K_2_len)
+{
+ assert(K_1_len == CHACHA20_POLY1305_AEAD_KEY_LEN);
+ assert(K_2_len == CHACHA20_POLY1305_AEAD_KEY_LEN);
+ m_chacha_main.SetKey(K_1, CHACHA20_POLY1305_AEAD_KEY_LEN);
+ m_chacha_header.SetKey(K_2, CHACHA20_POLY1305_AEAD_KEY_LEN);
+
+ // set the cached sequence number to uint64 max which hints for an unset cache.
+ // we can't hit uint64 max since the rekey rule (which resets the sequence number) is 1GB
+ m_cached_aad_seqnr = std::numeric_limits<uint64_t>::max();
+}
+
+bool ChaCha20Poly1305AEAD::Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos, unsigned char* dest, size_t dest_len /* length of the output buffer for sanity checks */, const unsigned char* src, size_t src_len, bool is_encrypt)
+{
+ // check buffer boundaries
+ if (
+ // if we encrypt, make sure the source contains at least the expected AAD and the destination has at least space for the source + MAC
+ (is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN || dest_len < src_len + POLY1305_TAGLEN)) ||
+ // if we decrypt, make sure the source contains at least the expected AAD+MAC and the destination has at least space for the source - MAC
+ (!is_encrypt && (src_len < CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN || dest_len < src_len - POLY1305_TAGLEN))) {
+ return false;
+ }
+
+ unsigned char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
+ memset(poly_key, 0, sizeof(poly_key));
+ m_chacha_main.SetIV(seqnr_payload);
+
+ // block counter 0 for the poly1305 key
+ // use lower 32bytes for the poly1305 key
+ // (throws away 32 unused bytes (upper 32) from this ChaCha20 round)
+ m_chacha_main.Seek(0);
+ m_chacha_main.Crypt(poly_key, poly_key, sizeof(poly_key));
+
+ // if decrypting, verify the tag prior to decryption
+ if (!is_encrypt) {
+ const unsigned char* tag = src + src_len - POLY1305_TAGLEN;
+ poly1305_auth(expected_tag, src, src_len - POLY1305_TAGLEN, poly_key);
+
+ // constant time compare the calculated MAC with the provided MAC
+ if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) {
+ memory_cleanse(expected_tag, sizeof(expected_tag));
+ memory_cleanse(poly_key, sizeof(poly_key));
+ return false;
+ }
+ memory_cleanse(expected_tag, sizeof(expected_tag));
+ // MAC has been successfully verified, make sure we don't covert it in decryption
+ src_len -= POLY1305_TAGLEN;
+ }
+
+ // calculate and cache the next 64byte keystream block if requested sequence number is not yet the cache
+ if (m_cached_aad_seqnr != seqnr_aad) {
+ m_cached_aad_seqnr = seqnr_aad;
+ m_chacha_header.SetIV(seqnr_aad);
+ m_chacha_header.Seek(0);
+ m_chacha_header.Keystream(m_aad_keystream_buffer, CHACHA20_ROUND_OUTPUT);
+ }
+ // crypt the AAD (3 bytes message length) with given position in AAD cipher instance keystream
+ dest[0] = src[0] ^ m_aad_keystream_buffer[aad_pos];
+ dest[1] = src[1] ^ m_aad_keystream_buffer[aad_pos + 1];
+ dest[2] = src[2] ^ m_aad_keystream_buffer[aad_pos + 2];
+
+ // Set the playload ChaCha instance block counter to 1 and crypt the payload
+ m_chacha_main.Seek(1);
+ m_chacha_main.Crypt(src + CHACHA20_POLY1305_AEAD_AAD_LEN, dest + CHACHA20_POLY1305_AEAD_AAD_LEN, src_len - CHACHA20_POLY1305_AEAD_AAD_LEN);
+
+ // If encrypting, calculate and append tag
+ if (is_encrypt) {
+ // the poly1305 tag expands over the AAD (3 bytes length) & encrypted payload
+ poly1305_auth(dest + src_len, dest, src_len, poly_key);
+ }
+
+ // cleanse no longer required MAC and polykey
+ memory_cleanse(poly_key, sizeof(poly_key));
+ return true;
+}
+
+bool ChaCha20Poly1305AEAD::GetLength(uint32_t* len24_out, uint64_t seqnr_aad, int aad_pos, const uint8_t* ciphertext)
+{
+ // enforce valid aad position to avoid accessing outside of the 64byte keystream cache
+ // (there is space for 21 times 3 bytes)
+ assert(aad_pos >= 0 && aad_pos < CHACHA20_ROUND_OUTPUT - CHACHA20_POLY1305_AEAD_AAD_LEN);
+ if (m_cached_aad_seqnr != seqnr_aad) {
+ // we need to calculate the 64 keystream bytes since we reached a new aad sequence number
+ m_cached_aad_seqnr = seqnr_aad;
+ m_chacha_header.SetIV(seqnr_aad); // use LE for the nonce
+ m_chacha_header.Seek(0); // block counter 0
+ m_chacha_header.Keystream(m_aad_keystream_buffer, CHACHA20_ROUND_OUTPUT); // write keystream to the cache
+ }
+
+ // decrypt the ciphertext length by XORing the right position of the 64byte keystream cache with the ciphertext
+ *len24_out = (ciphertext[0] ^ m_aad_keystream_buffer[aad_pos + 0]) |
+ (ciphertext[1] ^ m_aad_keystream_buffer[aad_pos + 1]) << 8 |
+ (ciphertext[2] ^ m_aad_keystream_buffer[aad_pos + 2]) << 16;
+
+ return true;
+}
diff --git a/src/crypto/chacha_poly_aead.h b/src/crypto/chacha_poly_aead.h
new file mode 100644
index 0000000000..b3ba781cdd
--- /dev/null
+++ b/src/crypto/chacha_poly_aead.h
@@ -0,0 +1,146 @@
+// Copyright (c) 2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_CRYPTO_CHACHA_POLY_AEAD_H
+#define BITCOIN_CRYPTO_CHACHA_POLY_AEAD_H
+
+#include <crypto/chacha20.h>
+
+#include <cmath>
+
+static constexpr int CHACHA20_POLY1305_AEAD_KEY_LEN = 32;
+static constexpr int CHACHA20_POLY1305_AEAD_AAD_LEN = 3; /* 3 bytes length */
+static constexpr int CHACHA20_ROUND_OUTPUT = 64; /* 64 bytes per round */
+static constexpr int AAD_PACKAGES_PER_ROUND = 21; /* 64 / 3 round down*/
+
+/* A AEAD class for ChaCha20-Poly1305@bitcoin.
+ *
+ * ChaCha20 is a stream cipher designed by Daniel Bernstein and described in
+ * <ref>[http://cr.yp.to/chacha/chacha-20080128.pdf ChaCha20]</ref>. It operates
+ * by permuting 128 fixed bits, 128 or 256 bits of key, a 64 bit nonce and a 64
+ * bit counter into 64 bytes of output. This output is used as a keystream, with
+ * any unused bytes simply discarded.
+ *
+ * Poly1305 <ref>[http://cr.yp.to/mac/poly1305-20050329.pdf Poly1305]</ref>, also
+ * by Daniel Bernstein, is a one-time Carter-Wegman MAC that computes a 128 bit
+ * integrity tag given a message and a single-use 256 bit secret key.
+ *
+ * The chacha20-poly1305@bitcoin combines these two primitives into an
+ * authenticated encryption mode. The construction used is based on that proposed
+ * for TLS by Adam Langley in
+ * <ref>[http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 "ChaCha20
+ * and Poly1305 based Cipher Suites for TLS", Adam Langley]</ref>, but differs in
+ * the layout of data passed to the MAC and in the addition of encryption of the
+ * packet lengths.
+ *
+ * ==== Detailed Construction ====
+ *
+ * The chacha20-poly1305@bitcoin cipher requires two 256 bits of key material as
+ * output from the key exchange. Each key (K_1 and K_2) are used by two separate
+ * instances of chacha20.
+ *
+ * The instance keyed by K_1 is a stream cipher that is used only to encrypt the 3
+ * byte packet length field and has its own sequence number. The second instance,
+ * keyed by K_2, is used in conjunction with poly1305 to build an AEAD
+ * (Authenticated Encryption with Associated Data) that is used to encrypt and
+ * authenticate the entire packet.
+ *
+ * Two separate cipher instances are used here so as to keep the packet lengths
+ * confidential but not create an oracle for the packet payload cipher by
+ * decrypting and using the packet length prior to checking the MAC. By using an
+ * independently-keyed cipher instance to encrypt the length, an active attacker
+ * seeking to exploit the packet input handling as a decryption oracle can learn
+ * nothing about the payload contents or its MAC (assuming key derivation,
+ * ChaCha20 and Poly1305 are secure).
+ *
+ * The AEAD is constructed as follows: for each packet, generate a Poly1305 key by
+ * taking the first 256 bits of ChaCha20 stream output generated using K_2, an IV
+ * consisting of the packet sequence number encoded as an LE uint64 and a ChaCha20
+ * block counter of zero. The K_2 ChaCha20 block counter is then set to the
+ * little-endian encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance
+ * is used for encryption of the packet payload.
+ *
+ * ==== Packet Handling ====
+ *
+ * When receiving a packet, the length must be decrypted first. When 3 bytes of
+ * ciphertext length have been received, they may be decrypted.
+ *
+ * A ChaCha20 round always calculates 64bytes which is sufficient to crypt 21
+ * times a 3 bytes length field (21*3 = 63). The length field sequence number can
+ * thus be used 21 times (keystream caching).
+ *
+ * The length field must be enc-/decrypted with the ChaCha20 keystream keyed with
+ * K_1 defined by block counter 0, the length field sequence number in little
+ * endian and a keystream position from 0 to 60.
+ *
+ * Once the entire packet has been received, the MAC MUST be checked before
+ * decryption. A per-packet Poly1305 key is generated as described above and the
+ * MAC tag calculated using Poly1305 with this key over the ciphertext of the
+ * packet length and the payload together. The calculated MAC is then compared in
+ * constant time with the one appended to the packet and the packet decrypted
+ * using ChaCha20 as described above (with K_2, the packet sequence number as
+ * nonce and a starting block counter of 1).
+ *
+ * Detection of an invalid MAC MUST lead to immediate connection termination.
+ *
+ * To send a packet, first encode the 3 byte length and encrypt it using K_1 as
+ * described above. Encrypt the packet payload (using K_2) and append it to the
+ * encrypted length. Finally, calculate a MAC tag and append it.
+ *
+ * The initiating peer MUST use <code>K_1_A, K_2_A</code> to encrypt messages on
+ * the send channel, <code>K_1_B, K_2_B</code> MUST be used to decrypt messages on
+ * the receive channel.
+ *
+ * The responding peer MUST use <code>K_1_A, K_2_A</code> to decrypt messages on
+ * the receive channel, <code>K_1_B, K_2_B</code> MUST be used to encrypt messages
+ * on the send channel.
+ *
+ * Optimized implementations of ChaCha20-Poly1305@bitcoin are relatively fast in
+ * general, therefore it is very likely that encrypted messages require not more
+ * CPU cycles per bytes then the current unencrypted p2p message format
+ * (ChaCha20/Poly1305 versus double SHA256).
+ *
+ * The initial packet sequence numbers are 0.
+ *
+ * K_2 ChaCha20 cipher instance (payload) must never reuse a {key, nonce} for
+ * encryption nor may it be used to encrypt more than 2^70 bytes under the same
+ * {key, nonce}.
+ *
+ * K_1 ChaCha20 cipher instance (length field/AAD) must never reuse a {key, nonce,
+ * position-in-keystream} for encryption nor may it be used to encrypt more than
+ * 2^70 bytes under the same {key, nonce}.
+ *
+ * We use message sequence numbers for both communication directions.
+ */
+
+class ChaCha20Poly1305AEAD
+{
+private:
+ ChaCha20 m_chacha_main; // payload and poly1305 key-derivation cipher instance
+ ChaCha20 m_chacha_header; // AAD cipher instance (encrypted length)
+ unsigned char m_aad_keystream_buffer[CHACHA20_ROUND_OUTPUT]; // aad keystream cache
+ uint64_t m_cached_aad_seqnr; // aad keystream cache hint
+
+public:
+ ChaCha20Poly1305AEAD(const unsigned char* K_1, size_t K_1_len, const unsigned char* K_2, size_t K_2_len);
+
+ explicit ChaCha20Poly1305AEAD(const ChaCha20Poly1305AEAD&) = delete;
+
+ /** Encrypts/decrypts a packet
+ seqnr_payload, the message sequence number
+ seqnr_aad, the messages AAD sequence number which allows reuse of the AAD keystream
+ aad_pos, position to use in the AAD keystream to encrypt the AAD
+ dest, output buffer, must be of a size equal or larger then CHACHA20_POLY1305_AEAD_AAD_LEN + payload (+ POLY1305_TAG_LEN in encryption) bytes
+ destlen, length of the destination buffer
+ src, the AAD+payload to encrypt or the AAD+payload+MAC to decrypt
+ src_len, the length of the source buffer
+ is_encrypt, set to true if we encrypt (creates and appends the MAC instead of verifying it)
+ */
+ bool Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos, unsigned char* dest, size_t dest_len, const unsigned char* src, size_t src_len, bool is_encrypt);
+
+ /** decrypts the 3 bytes AAD data and decodes it into a uint32_t field */
+ bool GetLength(uint32_t* len24_out, uint64_t seqnr_aad, int aad_pos, const uint8_t* ciphertext);
+};
+
+#endif // BITCOIN_CRYPTO_CHACHA_POLY_AEAD_H
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index 20f33baf2c..c3ce8d7af0 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -53,7 +53,7 @@ struct DBHeightKey {
int height;
DBHeightKey() : height(0) {}
- DBHeightKey(int height_in) : height(height_in) {}
+ explicit DBHeightKey(int height_in) : height(height_in) {}
template<typename Stream>
void Serialize(Stream& s) const
@@ -76,7 +76,7 @@ struct DBHeightKey {
struct DBHashKey {
uint256 hash;
- DBHashKey(const uint256& hash_in) : hash(hash_in) {}
+ explicit DBHashKey(const uint256& hash_in) : hash(hash_in) {}
ADD_SERIALIZE_METHODS;
diff --git a/src/init.cpp b/src/init.cpp
index c506a87ade..068b05286c 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -468,7 +468,7 @@ void SetupServerArgs()
"and level 4 tries to reconnect the blocks, "
"each level includes the checks of the previous levels "
"(0-4, default: %u)", DEFAULT_CHECKLEVEL), true, OptionsCategory::DEBUG_TEST);
- gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, ::ChainActive() and mapBlocksUnlinked occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST);
+ gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for the block tree, setBlockIndexCandidates, ::ChainActive() and mapBlocksUnlinked occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", true, OptionsCategory::DEBUG_TEST);
@@ -1126,8 +1126,9 @@ bool AppInitParameterInteraction()
}
fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
- if (chainparams.RequireStandard() && !fRequireStandard)
+ if (!chainparams.IsTestChain() && !fRequireStandard) {
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
+ }
nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp);
if (!g_wallet_init_interface.ParameterInteraction()) return false;
@@ -1161,7 +1162,7 @@ static bool LockDataDirectory(bool probeOnly)
return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), datadir.string()));
}
if (!LockDirectory(datadir, ".lock", probeOnly)) {
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), datadir.string(), _(PACKAGE_NAME)));
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), datadir.string(), PACKAGE_NAME));
}
return true;
}
@@ -1179,7 +1180,7 @@ bool AppInitSanityChecks()
// Sanity check
if (!InitSanityCheck())
- return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME)));
+ return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME));
// Probe the data directory lock to give an early error message, if possible
// We cannot hold the data directory lock here, as the forking for daemon() hasn't yet happened,
@@ -1493,7 +1494,8 @@ bool AppInitMain(InitInterfaces& interfaces)
// If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around).
- if (!mapBlockIndex.empty() && !LookupBlockIndex(chainparams.GetConsensus().hashGenesisBlock)) {
+ if (!::BlockIndex().empty() &&
+ !LookupBlockIndex(chainparams.GetConsensus().hashGenesisBlock)) {
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
}
@@ -1514,7 +1516,7 @@ bool AppInitMain(InitInterfaces& interfaces)
}
// At this point we're either in reindex or we've loaded a useful
- // block tree into mapBlockIndex!
+ // block tree into BlockIndex()!
pcoinsdbview.reset(new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState));
pcoinscatcher.reset(new CCoinsViewErrorCatcher(pcoinsdbview.get()));
@@ -1558,7 +1560,7 @@ bool AppInitMain(InitInterfaces& interfaces)
if (!fReset) {
// Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate.
// It both disconnects blocks based on ::ChainActive(), and drops block data in
- // mapBlockIndex based on lack of available witness data.
+ // BlockIndex() based on lack of available witness data.
uiInterface.InitMessage(_("Rewinding blocks..."));
if (!RewindBlockIndex(chainparams)) {
strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain");
@@ -1730,7 +1732,7 @@ bool AppInitMain(InitInterfaces& interfaces)
//// debug print
{
LOCK(cs_main);
- LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
+ LogPrintf("block tree size = %u\n", ::BlockIndex().size());
chain_active_height = ::ChainActive().Height();
}
LogPrintf("nBestHeight = %d\n", chain_active_height);
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index 161dd01ffe..02f39cef8e 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -205,7 +205,7 @@ public:
class RpcHandlerImpl : public Handler
{
public:
- RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
+ explicit RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
{
m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
if (!m_wrapped_command) return false;
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 34c982e1e6..deb1618ceb 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -36,7 +36,7 @@ namespace {
class PendingWalletTxImpl : public PendingWalletTx
{
public:
- explicit PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {}
+ explicit PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet) {}
const CTransaction& get() override { return *m_tx; }
@@ -47,7 +47,7 @@ public:
auto locked_chain = m_wallet.chain().lock();
LOCK(m_wallet.cs_wallet);
CValidationState state;
- if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), m_key, state)) {
+ if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), state)) {
reject_reason = state.GetRejectReason();
return false;
}
@@ -56,7 +56,6 @@ public:
CTransactionRef m_tx;
CWallet& m_wallet;
- CReserveKey m_key;
};
//! Construct wallet tx struct.
@@ -140,9 +139,11 @@ public:
void abortRescan() override { m_wallet->AbortRescan(); }
bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }
std::string getWalletName() override { return m_wallet->GetName(); }
- bool getKeyFromPool(bool internal, CPubKey& pub_key) override
+ bool getNewDestination(const OutputType type, const std::string label, CTxDestination& dest) override
{
- return m_wallet->GetKeyFromPool(pub_key, internal);
+ LOCK(m_wallet->cs_wallet);
+ std::string error;
+ return m_wallet->GetNewDestination(type, label, dest, error);
}
bool getPubKey(const CKeyID& address, CPubKey& pub_key) override { return m_wallet->GetPubKey(address, pub_key); }
bool getPrivKey(const CKeyID& address, CKey& key) override { return m_wallet->GetKey(address, key); }
@@ -236,7 +237,7 @@ public:
auto locked_chain = m_wallet->chain().lock();
LOCK(m_wallet->cs_wallet);
auto pending = MakeUnique<PendingWalletTxImpl>(*m_wallet);
- if (!m_wallet->CreateTransaction(*locked_chain, recipients, pending->m_tx, pending->m_key, fee, change_pos,
+ if (!m_wallet->CreateTransaction(*locked_chain, recipients, pending->m_tx, fee, change_pos,
fail_reason, coin_control, sign)) {
return {};
}
@@ -476,7 +477,7 @@ public:
}
std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override
{
- return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CCryptoKeyStore*) { fn(); }));
+ return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); }));
}
std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override
{
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index 9c9b29a813..db47dbafaf 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -78,8 +78,8 @@ public:
//! Get wallet name.
virtual std::string getWalletName() = 0;
- // Get key from pool.
- virtual bool getKeyFromPool(bool internal, CPubKey& pub_key) = 0;
+ // Get a new address.
+ virtual bool getNewDestination(const OutputType type, const std::string label, CTxDestination& dest) = 0;
//! Get public key.
virtual bool getPubKey(const CKeyID& address, CPubKey& pub_key) = 0;
diff --git a/src/keystore.h b/src/keystore.h
deleted file mode 100644
index 4bd99e255d..0000000000
--- a/src/keystore.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_KEYSTORE_H
-#define BITCOIN_KEYSTORE_H
-
-#include <key.h>
-#include <pubkey.h>
-#include <script/script.h>
-#include <script/sign.h>
-#include <script/standard.h>
-#include <sync.h>
-
-#include <boost/signals2/signal.hpp>
-
-/** A virtual base class for key stores */
-class CKeyStore : public SigningProvider
-{
-public:
- //! Add a key to the store.
- virtual bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) =0;
-
- //! Check whether a key corresponding to a given address is present in the store.
- virtual bool HaveKey(const CKeyID &address) const =0;
- virtual std::set<CKeyID> GetKeys() const =0;
-
- //! Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
- virtual bool AddCScript(const CScript& redeemScript) =0;
- virtual bool HaveCScript(const CScriptID &hash) const =0;
- virtual std::set<CScriptID> GetCScripts() const =0;
-
- //! Support for Watch-only addresses
- virtual bool AddWatchOnly(const CScript &dest) =0;
- virtual bool RemoveWatchOnly(const CScript &dest) =0;
- virtual bool HaveWatchOnly(const CScript &dest) const =0;
- virtual bool HaveWatchOnly() const =0;
-};
-
-/** Basic key store, that keeps keys in an address->secret map */
-class CBasicKeyStore : public CKeyStore
-{
-protected:
- mutable CCriticalSection cs_KeyStore;
-
- using KeyMap = std::map<CKeyID, CKey>;
- using WatchKeyMap = std::map<CKeyID, CPubKey>;
- using ScriptMap = std::map<CScriptID, CScript>;
- using WatchOnlySet = std::set<CScript>;
-
- KeyMap mapKeys GUARDED_BY(cs_KeyStore);
- WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
- ScriptMap mapScripts GUARDED_BY(cs_KeyStore);
- WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
-
- void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
-
-public:
- bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
- bool AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); }
- bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
- bool HaveKey(const CKeyID &address) const override;
- std::set<CKeyID> GetKeys() const override;
- bool GetKey(const CKeyID &address, CKey &keyOut) const override;
- bool AddCScript(const CScript& redeemScript) override;
- bool HaveCScript(const CScriptID &hash) const override;
- std::set<CScriptID> GetCScripts() const override;
- bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
-
- bool AddWatchOnly(const CScript &dest) override;
- bool RemoveWatchOnly(const CScript &dest) override;
- bool HaveWatchOnly(const CScript &dest) const override;
- bool HaveWatchOnly() const override;
-};
-
-/** Return the CKeyID of the key involved in a script (if there is a unique one). */
-CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest);
-
-/** Checks if a CKey is in the given CKeyStore compressed or otherwise*/
-bool HaveKey(const CKeyStore& store, const CKey& key);
-
-#endif // BITCOIN_KEYSTORE_H
diff --git a/src/net.cpp b/src/net.cpp
index 75a47d7ad2..7d11111b25 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2039,7 +2039,7 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b
{
int nErr = WSAGetLastError();
if (nErr == WSAEADDRINUSE)
- strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), _(PACKAGE_NAME));
+ strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), PACKAGE_NAME);
else
strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr));
LogPrintf("%s\n", strError);
diff --git a/src/net_processing.h b/src/net_processing.h
index 39c22d7118..dffc3f273f 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -19,6 +19,7 @@ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100;
/** Default for BIP61 (sending reject messages) */
static constexpr bool DEFAULT_ENABLE_BIP61{false};
+static const bool DEFAULT_PEERBLOOMFILTERS = false;
class PeerLogicValidation final : public CValidationInterface, public NetEventsInterface {
private:
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 78b3b6ae3a..6d4738c835 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -65,6 +65,12 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
{
CNetAddr addr;
+ // From our perspective, onion addresses are not hostnames but rather
+ // direct encodings of CNetAddr much like IPv4 dotted-decimal notation
+ // or IPv6 colon-separated hextet notation. Since we can't use
+ // getaddrinfo to decode them and it wouldn't make sense to resolve
+ // them, we return a network address representing it instead. See
+ // CNetAddr::SetSpecial(const std::string&) for more details.
if (addr.SetSpecial(std::string(pszName))) {
vIP.push_back(addr);
return true;
@@ -74,15 +80,25 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
struct addrinfo aiHint;
memset(&aiHint, 0, sizeof(struct addrinfo));
+ // We want a TCP port, which is a streaming socket type
aiHint.ai_socktype = SOCK_STREAM;
aiHint.ai_protocol = IPPROTO_TCP;
+ // We don't care which address family (IPv4 or IPv6) is returned
aiHint.ai_family = AF_UNSPEC;
+ // If we allow lookups of hostnames, use the AI_ADDRCONFIG flag to only
+ // return addresses whose family we have an address configured for.
+ //
+ // If we don't allow lookups, then use the AI_NUMERICHOST flag for
+ // getaddrinfo to only decode numerical network addresses and suppress
+ // hostname lookups.
aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
struct addrinfo *aiRes = nullptr;
int nErr = getaddrinfo(pszName, nullptr, &aiHint, &aiRes);
if (nErr)
return false;
+ // Traverse the linked list starting with aiTrav, add all non-internal
+ // IPv4,v6 addresses to vIP while respecting nMaxSolutions.
struct addrinfo *aiTrav = aiRes;
while (aiTrav != nullptr && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
{
@@ -112,6 +128,21 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
return (vIP.size() > 0);
}
+/**
+ * Resolve a host string to its corresponding network addresses.
+ *
+ * @param pszName The string representing a host. Could be a name or a numerical
+ * IP address (IPv6 addresses in their bracketed form are
+ * allowed).
+ * @param[out] vIP The resulting network addresses to which the specified host
+ * string resolved.
+ *
+ * @returns Whether or not the specified host string successfully resolved to
+ * any resulting network addresses.
+ *
+ * @see Lookup(const char *, std::vector<CService>&, int, bool, unsigned int)
+ * for additional parameter descriptions.
+ */
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
{
std::string strHost(pszName);
@@ -124,6 +155,12 @@ bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nM
return LookupIntern(strHost.c_str(), vIP, nMaxSolutions, fAllowLookup);
}
+ /**
+ * Resolve a host string to its first corresponding network address.
+ *
+ * @see LookupHost(const char *, std::vector<CNetAddr>&, unsigned int, bool) for
+ * additional parameter descriptions.
+ */
bool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup)
{
std::vector<CNetAddr> vIP;
@@ -134,6 +171,26 @@ bool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup)
return true;
}
+/**
+ * Resolve a service string to its corresponding service.
+ *
+ * @param pszName The string representing a service. Could be a name or a
+ * numerical IP address (IPv6 addresses should be in their
+ * disambiguated bracketed form), optionally followed by a port
+ * number. (e.g. example.com:8333 or
+ * [2001:db8:85a3:8d3:1319:8a2e:370:7348]:420)
+ * @param[out] vAddr The resulting services to which the specified service string
+ * resolved.
+ * @param portDefault The default port for resulting services if not specified
+ * by the service string.
+ * @param fAllowLookup Whether or not hostname lookups are permitted. If yes,
+ * external queries may be performed.
+ * @param nMaxSolutions The maximum number of results we want, specifying 0
+ * means "as many solutions as we get."
+ *
+ * @returns Whether or not the service string successfully resolved to any
+ * resulting services.
+ */
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions)
{
if (pszName[0] == 0)
@@ -152,6 +209,12 @@ bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault,
return true;
}
+/**
+ * Resolve a service string to its first corresponding service.
+ *
+ * @see Lookup(const char *, std::vector<CService>&, int, bool, unsigned int)
+ * for additional parameter descriptions.
+ */
bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup)
{
std::vector<CService> vService;
@@ -162,6 +225,16 @@ bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLoo
return true;
}
+/**
+ * Resolve a service string with a numeric IP to its first corresponding
+ * service.
+ *
+ * @returns The resulting CService if the resolution was successful, [::]:0
+ * otherwise.
+ *
+ * @see Lookup(const char *, CService&, int, bool) for additional parameter
+ * descriptions.
+ */
CService LookupNumeric(const char *pszName, int portDefault)
{
CService addr;
@@ -231,22 +304,29 @@ enum class IntrRecvError {
};
/**
- * Read bytes from socket. This will either read the full number of bytes requested
- * or return False on error or timeout.
- * This function can be interrupted by calling InterruptSocks5()
+ * Try to read a specified number of bytes from a socket. Please read the "see
+ * also" section for more detail.
*
- * @param data Buffer to receive into
- * @param len Length of data to receive
- * @param timeout Timeout in milliseconds for receive operation
+ * @param data The buffer where the read bytes should be stored.
+ * @param len The number of bytes to read into the specified buffer.
+ * @param timeout The total timeout in milliseconds for this read.
+ * @param hSocket The socket (has to be in non-blocking mode) from which to read
+ * bytes.
*
- * @note This function requires that hSocket is in non-blocking mode.
+ * @returns An IntrRecvError indicating the resulting status of this read.
+ * IntrRecvError::OK only if all of the specified number of bytes were
+ * read.
+ *
+ * @see This function can be interrupted by calling InterruptSocks5(bool).
+ * Sockets can be made non-blocking with SetSocketNonBlocking(const
+ * SOCKET&, bool).
*/
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket)
{
int64_t curTime = GetTimeMillis();
int64_t endTime = curTime + timeout;
- // Maximum time to wait in one select call. It will take up until this time (in millis)
- // to break off in case of an interruption.
+ // Maximum time to wait for I/O readiness. It will take up until this time
+ // (in millis) to break off in case of an interruption.
const int64_t maxWait = 1000;
while (len > 0 && curTime < endTime) {
ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
@@ -261,11 +341,13 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
if (!IsSelectableSocket(hSocket)) {
return IntrRecvError::NetworkError;
}
+ // Only wait at most maxWait milliseconds at a time, unless
+ // we're approaching the end of the specified total timeout
int timeout_ms = std::min(endTime - curTime, maxWait);
#ifdef USE_POLL
struct pollfd pollfd = {};
pollfd.fd = hSocket;
- pollfd.events = POLLIN | POLLOUT;
+ pollfd.events = POLLIN;
int nRet = poll(&pollfd, 1, timeout_ms);
#else
struct timeval tval = MillisToTimeval(timeout_ms);
@@ -320,7 +402,24 @@ static std::string Socks5ErrorString(uint8_t err)
}
}
-/** Connect using SOCKS5 (as described in RFC1928) */
+/**
+ * Connect to a specified destination service through an already connected
+ * SOCKS5 proxy.
+ *
+ * @param strDest The destination fully-qualified domain name.
+ * @param port The destination port.
+ * @param auth The credentials with which to authenticate with the specified
+ * SOCKS5 proxy.
+ * @param hSocket The SOCKS5 proxy socket.
+ *
+ * @returns Whether or not the operation succeeded.
+ *
+ * @note The specified SOCKS5 proxy socket must already be connected to the
+ * SOCKS5 proxy.
+ *
+ * @see <a href="https://www.ietf.org/rfc/rfc1928.txt">RFC1928: SOCKS Protocol
+ * Version 5</a>
+ */
static bool Socks5(const std::string& strDest, int port, const ProxyCredentials *auth, const SOCKET& hSocket)
{
IntrRecvError recvr;
@@ -328,15 +427,15 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
if (strDest.size() > 255) {
return error("Hostname too long");
}
- // Accepted authentication methods
+ // Construct the version identifier/method selection message
std::vector<uint8_t> vSocks5Init;
- vSocks5Init.push_back(SOCKSVersion::SOCKS5);
+ vSocks5Init.push_back(SOCKSVersion::SOCKS5); // We want the SOCK5 protocol
if (auth) {
- vSocks5Init.push_back(0x02); // Number of methods
+ vSocks5Init.push_back(0x02); // 2 method identifiers follow...
vSocks5Init.push_back(SOCKS5Method::NOAUTH);
vSocks5Init.push_back(SOCKS5Method::USER_PASS);
} else {
- vSocks5Init.push_back(0x01); // Number of methods
+ vSocks5Init.push_back(0x01); // 1 method identifier follows...
vSocks5Init.push_back(SOCKS5Method::NOAUTH);
}
ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
@@ -440,8 +539,16 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return true;
}
+/**
+ * Try to create a socket file descriptor with specific properties in the
+ * communications domain (address family) of the specified service.
+ *
+ * For details on the desired properties, see the inline comments in the source
+ * code.
+ */
SOCKET CreateSocket(const CService &addrConnect)
{
+ // Create a sockaddr from the specified service.
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
@@ -449,10 +556,13 @@ SOCKET CreateSocket(const CService &addrConnect)
return INVALID_SOCKET;
}
+ // Create a TCP socket in the address family of the specified service.
SOCKET hSocket = socket(((struct sockaddr*)&sockaddr)->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET)
return INVALID_SOCKET;
+ // Ensure that waiting for I/O on this socket won't result in undefined
+ // behavior.
if (!IsSelectableSocket(hSocket)) {
CloseSocket(hSocket);
LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
@@ -461,17 +571,18 @@ SOCKET CreateSocket(const CService &addrConnect)
#ifdef SO_NOSIGPIPE
int set = 1;
- // Different way of disabling SIGPIPE on BSD
+ // Set the no-sigpipe option on the socket for BSD systems, other UNIXes
+ // should use the MSG_NOSIGNAL flag for every send.
setsockopt(hSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int));
#endif
- //Disable Nagle's algorithm
+ // Set the no-delay option (disable Nagle's algorithm) on the TCP socket.
SetSocketNoDelay(hSocket);
- // Set to non-blocking
+ // Set the non-blocking option on the socket.
if (!SetSocketNonBlocking(hSocket, true)) {
CloseSocket(hSocket);
- LogPrintf("ConnectSocketDirectly: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
+ LogPrintf("CreateSocket: Setting socket to non-blocking failed, error %s\n", NetworkErrorString(WSAGetLastError()));
}
return hSocket;
}
@@ -486,8 +597,21 @@ static void LogConnectFailure(bool manual_connection, const char* fmt, const Arg
}
}
+/**
+ * Try to connect to the specified service on the specified socket.
+ *
+ * @param addrConnect The service to which to connect.
+ * @param hSocket The socket on which to connect.
+ * @param nTimeout Wait this many milliseconds for the connection to be
+ * established.
+ * @param manual_connection Whether or not the connection was manually requested
+ * (e.g. thru the addnode RPC)
+ *
+ * @returns Whether or not a connection was successfully made.
+ */
bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, int nTimeout, bool manual_connection)
{
+ // Create a sockaddr from the specified service.
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
if (hSocket == INVALID_SOCKET) {
@@ -498,12 +622,17 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToString());
return false;
}
+
+ // Connect to the addrConnect service on the hSocket socket.
if (connect(hSocket, (struct sockaddr*)&sockaddr, len) == SOCKET_ERROR)
{
int nErr = WSAGetLastError();
// WSAEINVAL is here because some legacy version of winsock uses it
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL)
{
+ // Connection didn't actually fail, but is being established
+ // asynchronously. Thus, use async I/O api (select/poll)
+ // synchronously to check for successful connection with a timeout.
#ifdef USE_POLL
struct pollfd pollfd = {};
pollfd.fd = hSocket;
@@ -516,6 +645,10 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
FD_SET(hSocket, &fdset);
int nRet = select(hSocket + 1, nullptr, &fdset, nullptr, &timeout);
#endif
+ // Upon successful completion, both select and poll return the total
+ // number of file descriptors that have been selected. A value of 0
+ // indicates that the call timed out and no file descriptors have
+ // been selected.
if (nRet == 0)
{
LogPrint(BCLog::NET, "connection to %s timeout\n", addrConnect.ToString());
@@ -526,6 +659,11 @@ bool ConnectSocketDirectly(const CService &addrConnect, const SOCKET& hSocket, i
LogPrintf("select() for %s failed: %s\n", addrConnect.ToString(), NetworkErrorString(WSAGetLastError()));
return false;
}
+
+ // Even if the select/poll was successful, the connect might not
+ // have been successful. The reason for this failure is hidden away
+ // in the SO_ERROR for the socket in modern systems. We read it into
+ // nRet here.
socklen_t nRetSize = sizeof(nRet);
if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&nRet, &nRetSize) == SOCKET_ERROR)
{
@@ -569,6 +707,22 @@ bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
return true;
}
+/**
+ * Set the name proxy to use for all connections to nodes specified by a
+ * hostname. After setting this proxy, connecting to a node sepcified by a
+ * hostname won't result in a local lookup of said hostname, rather, connect to
+ * the node by asking the name proxy for a proxy connection to the hostname,
+ * effectively delegating the hostname lookup to the specified proxy.
+ *
+ * This delegation increases privacy for those who set the name proxy as they no
+ * longer leak their external hostname queries to their DNS servers.
+ *
+ * @returns Whether or not the operation succeeded.
+ *
+ * @note SOCKS5's support for UDP-over-SOCKS5 has been considered, but no SOCK5
+ * server in common use (most notably Tor) actually implements UDP
+ * support, and a DNS resolver is beyond the scope of this project.
+ */
bool SetNameProxy(const proxyType &addrProxy) {
if (!addrProxy.IsValid())
return false;
@@ -599,6 +753,21 @@ bool IsProxy(const CNetAddr &addr) {
return false;
}
+/**
+ * Connect to a specified destination service through a SOCKS5 proxy by first
+ * connecting to the SOCKS5 proxy.
+ *
+ * @param proxy The SOCKS5 proxy.
+ * @param strDest The destination service to which to connect.
+ * @param port The destination port.
+ * @param hSocket The socket on which to connect to the SOCKS5 proxy.
+ * @param nTimeout Wait this many milliseconds for the connection to the SOCKS5
+ * proxy to be established.
+ * @param outProxyConnectionFailed[out] Whether or not the connection to the
+ * SOCKS5 proxy failed.
+ *
+ * @returns Whether or not the operation succeeded.
+ */
bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, const SOCKET& hSocket, int nTimeout, bool *outProxyConnectionFailed)
{
// first connect to proxy server
@@ -623,6 +792,17 @@ bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int
return true;
}
+/**
+ * Parse and resolve a specified subnet string into the appropriate internal
+ * representation.
+ *
+ * @param pszName A string representation of a subnet of the form `network
+ * address [ "/", ( CIDR-style suffix | netmask ) ]`(e.g.
+ * `2001:db8::/32`, `192.0.2.0/255.255.255.0`, or `8.8.8.8`).
+ * @param ret The resulting internal representation of a subnet.
+ *
+ * @returns Whether the operation succeeded or not.
+ */
bool LookupSubNet(const char* pszName, CSubNet& ret)
{
std::string strSubnet(pszName);
@@ -630,6 +810,8 @@ bool LookupSubNet(const char* pszName, CSubNet& ret)
std::vector<CNetAddr> vIP;
std::string strAddress = strSubnet.substr(0, slash);
+ // TODO: Use LookupHost(const char *, CNetAddr&, bool) instead to just get
+ // one CNetAddr.
if (LookupHost(strAddress.c_str(), vIP, 1, false))
{
CNetAddr network = vIP[0];
@@ -637,8 +819,8 @@ bool LookupSubNet(const char* pszName, CSubNet& ret)
{
std::string strNetmask = strSubnet.substr(slash + 1);
int32_t n;
- // IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n
- if (ParseInt32(strNetmask, &n)) { // If valid number, assume /24 syntax
+ if (ParseInt32(strNetmask, &n)) {
+ // If valid number, assume CIDR variable-length subnet masking
ret = CSubNet(network, n);
return ret.IsValid();
}
diff --git a/src/outputtype.cpp b/src/outputtype.cpp
index 73ffb801f2..bcaa05f4b6 100644
--- a/src/outputtype.cpp
+++ b/src/outputtype.cpp
@@ -5,9 +5,10 @@
#include <outputtype.h>
-#include <keystore.h>
#include <pubkey.h>
#include <script/script.h>
+#include <script/sign.h>
+#include <script/signingprovider.h>
#include <script/standard.h>
#include <assert.h>
@@ -73,7 +74,7 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
}
}
-CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& script, OutputType type)
+CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType type)
{
// Add script to keystore
keystore.AddCScript(script);
@@ -98,4 +99,3 @@ CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript&
default: assert(false);
}
}
-
diff --git a/src/outputtype.h b/src/outputtype.h
index 6c30fd1950..6acbaa2f3e 100644
--- a/src/outputtype.h
+++ b/src/outputtype.h
@@ -7,7 +7,7 @@
#define BITCOIN_OUTPUTTYPE_H
#include <attributes.h>
-#include <keystore.h>
+#include <script/signingprovider.h>
#include <script/standard.h>
#include <string>
@@ -44,7 +44,7 @@ std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key);
* This function will automatically add the script (and any other
* necessary scripts) to the keystore.
*/
-CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& script, OutputType);
+CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType);
#endif // BITCOIN_OUTPUTTYPE_H
diff --git a/src/protocol.h b/src/protocol.h
index a790a06906..91d043947b 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -261,9 +261,6 @@ enum ServiceFlags : uint64_t {
// NODE_WITNESS indicates that a node can be asked for blocks and transactions including
// witness data.
NODE_WITNESS = (1 << 3),
- // NODE_XTHIN means the node supports Xtreme Thinblocks
- // If this is turned off then the node will not service nor make xthin requests
- NODE_XTHIN = (1 << 4),
// NODE_NETWORK_LIMITED means the same as NODE_NETWORK with the limitation of only
// serving the last 288 (2 day) blocks
// See BIP159 for details on how this is implemented.
diff --git a/src/psbt.h b/src/psbt.h
index f3840b9ed3..6d77db0c6f 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -12,6 +12,7 @@
#include <primitives/transaction.h>
#include <pubkey.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
// Magic bytes
static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff};
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index fa6c9c9f7a..29423db3d0 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -358,12 +358,15 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
return QString();
}
}
+
+ // Add entry
+ walletModel->wallet().setAddressBook(DecodeDestination(strAddress), strLabel, "send");
}
else if(type == Receive)
{
// Generate a new address to associate with given label
- CPubKey newKey;
- if(!walletModel->wallet().getKeyFromPool(false /* internal */, newKey))
+ CTxDestination dest;
+ if(!walletModel->wallet().getNewDestination(address_type, strLabel, dest))
{
WalletModel::UnlockContext ctx(walletModel->requestUnlock());
if(!ctx.isValid())
@@ -372,23 +375,18 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
editStatus = WALLET_UNLOCK_FAILURE;
return QString();
}
- if(!walletModel->wallet().getKeyFromPool(false /* internal */, newKey))
+ if(!walletModel->wallet().getNewDestination(address_type, strLabel, dest))
{
editStatus = KEY_GENERATION_FAILURE;
return QString();
}
}
- walletModel->wallet().learnRelatedScripts(newKey, address_type);
- strAddress = EncodeDestination(GetDestinationForKey(newKey, address_type));
+ strAddress = EncodeDestination(dest);
}
else
{
return QString();
}
-
- // Add entry
- walletModel->wallet().setAddressBook(DecodeDestination(strAddress), strLabel,
- (type == Send ? "send" : "receive"));
return QString::fromStdString(strAddress);
}
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index aa8bbab85d..4a9742f7b7 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -448,6 +448,9 @@ int GuiMain(int argc, char* argv[])
// Register meta types used for QMetaObject::invokeMethod
qRegisterMetaType< bool* >();
+#ifdef ENABLE_WALLET
+ qRegisterMetaType<WalletModel*>();
+#endif
// Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
// IMPORTANT if it is no longer a typedef use the normal variant above
qRegisterMetaType< CAmount >("CAmount");
@@ -459,7 +462,7 @@ int GuiMain(int argc, char* argv[])
SetupUIArgs();
std::string error;
if (!node->parseParameters(argc, argv, error)) {
- QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME),
+ QMessageBox::critical(nullptr, PACKAGE_NAME,
QObject::tr("Error parsing command line arguments: %1.").arg(QString::fromStdString(error)));
return EXIT_FAILURE;
}
@@ -496,12 +499,12 @@ int GuiMain(int argc, char* argv[])
/// - Do not call GetDataDir(true) before this step finishes
if (!fs::is_directory(GetDataDir(false)))
{
- QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME),
+ QMessageBox::critical(nullptr, PACKAGE_NAME,
QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", ""))));
return EXIT_FAILURE;
}
if (!node->readConfigFiles(error)) {
- QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME),
+ QMessageBox::critical(nullptr, PACKAGE_NAME,
QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error)));
return EXIT_FAILURE;
}
@@ -516,7 +519,7 @@ int GuiMain(int argc, char* argv[])
try {
node->selectParams(gArgs.GetChainName());
} catch(std::exception &e) {
- QMessageBox::critical(nullptr, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what()));
+ QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(e.what()));
return EXIT_FAILURE;
}
#ifdef ENABLE_WALLET
@@ -573,7 +576,7 @@ int GuiMain(int argc, char* argv[])
if (app.baseInitialize()) {
app.requestInitialize();
#if defined(Q_OS_WIN)
- WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());
+ WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(PACKAGE_NAME), (HWND)app.getMainWinId());
#endif
app.exec();
app.requestShutdown();
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 98c291aa63..c9a09573f9 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -294,15 +294,15 @@ void BitcoinGUI::createActions()
quitAction->setStatusTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
- aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About %1").arg(tr(PACKAGE_NAME)), this);
- aboutAction->setStatusTip(tr("Show information about %1").arg(tr(PACKAGE_NAME)));
+ aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About %1").arg(PACKAGE_NAME), this);
+ aboutAction->setStatusTip(tr("Show information about %1").arg(PACKAGE_NAME));
aboutAction->setMenuRole(QAction::AboutRole);
aboutAction->setEnabled(false);
aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this);
- optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(tr(PACKAGE_NAME)));
+ optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(PACKAGE_NAME));
optionsAction->setMenuRole(QAction::PreferencesRole);
optionsAction->setEnabled(false);
toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
@@ -344,7 +344,7 @@ void BitcoinGUI::createActions()
showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
showHelpMessageAction->setMenuRole(QAction::NoRole);
- showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(tr(PACKAGE_NAME)));
+ showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(PACKAGE_NAME));
connect(quitAction, &QAction::triggered, qApp, QApplication::quit);
connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked);
@@ -728,7 +728,7 @@ void BitcoinGUI::createTrayIcon()
#ifndef Q_OS_MAC
if (QSystemTrayIcon::isSystemTrayAvailable()) {
trayIcon = new QSystemTrayIcon(m_network_style->getTrayAndWindowIcon(), this);
- QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + m_network_style->getTitleAddText();
+ QString toolTip = tr("%1 client").arg(PACKAGE_NAME) + " " + m_network_style->getTitleAddText();
trayIcon->setToolTip(toolTip);
}
#endif
@@ -1291,7 +1291,7 @@ void BitcoinGUI::updateProxyIcon()
void BitcoinGUI::updateWindowTitle()
{
- QString window_title = tr(PACKAGE_NAME);
+ QString window_title = PACKAGE_NAME;
#ifdef ENABLE_WALLET
if (walletFrame) {
WalletModel* const wallet_model = walletFrame->currentWalletModel();
@@ -1375,12 +1375,13 @@ static bool ThreadSafeMessageBox(BitcoinGUI* gui, const std::string& message, co
style &= ~CClientUIInterface::SECURE;
bool ret = false;
// In case of modal message, use blocking connection to wait for user to click a button
- QMetaObject::invokeMethod(gui, "message",
+ bool invoked = QMetaObject::invokeMethod(gui, "message",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(unsigned int, style),
Q_ARG(bool*, &ret));
+ assert(invoked);
return ret;
}
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index dc997e96cc..87736cd185 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -9,14 +9,13 @@
#define UNUSED
#endif
static const char UNUSED *bitcoin_strings[] = {
-QT_TRANSLATE_NOOP("bitcoin-core", "Bitcoin Core"),
QT_TRANSLATE_NOOP("bitcoin-core", "The %s developers"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"-maxtxfee is set very high! Fees this large could be paid on a single "
"transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Can't generate a change-address key. Private keys are disabled for this "
-"wallet."),
+"Can't generate a change-address key. No keys in the internal keypool and "
+"can't generate any keys."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot obtain a lock on data directory %s. %s is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -88,9 +87,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: The network does not appear to fully agree! Some miners appear to "
"be experiencing issues."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Warning: Unknown block versions being mined! It's possible unknown rules are "
-"in effect"),
-QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; "
"if your balance or transactions are incorrect you should restore from a "
"backup."),
@@ -124,15 +120,13 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet %s. Duplicate -wallet fi
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error upgrading chainstate database"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: A fatal internal error occurred, see debug.log for details"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low for %s"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is too low!"),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."),
QT_TRANSLATE_NOOP("bitcoin-core", "Failed to rescan the wallet during initialization"),
QT_TRANSLATE_NOOP("bitcoin-core", "Importing..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Information"),
QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"),
@@ -150,6 +144,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."),
QT_TRANSLATE_NOOP("bitcoin-core", "Prune cannot be configured with a negative value."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -blockfilterindex."),
QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -txindex."),
QT_TRANSLATE_NOOP("bitcoin-core", "Pruning blockstore..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Reducing -maxconnections from %d to %d, because of system limitations."),
@@ -179,9 +174,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large for fee policy"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer. %s is probably already running."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unable to create the PID file '%s': %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate initial keys"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate keys"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to start HTTP server. See debug log for details."),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -blockfilterindex value %s."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported logging category %s=%s."),
QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading UTXO database"),
@@ -189,9 +186,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading txindex database"),
QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe characters."),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks..."),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet(s)..."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Wallet %s resides outside wallet directory %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart %s to complete"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Warning"),
QT_TRANSLATE_NOOP("bitcoin-core", "Warning: unknown new rules activated (versionbit %i)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Zapping all transactions from wallet..."),
};
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index ce950150df..238be08480 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -184,34 +184,39 @@ void ClientModel::updateBanlist()
static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
{
// emits signal "showProgress"
- QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
+ bool invoked = QMetaObject::invokeMethod(clientmodel, "showProgress", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(title)),
Q_ARG(int, nProgress));
+ assert(invoked);
}
static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConnections)
{
// Too noisy: qDebug() << "NotifyNumConnectionsChanged: " + QString::number(newNumConnections);
- QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
+ bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNumConnections", Qt::QueuedConnection,
Q_ARG(int, newNumConnections));
+ assert(invoked);
}
static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkActive)
{
- QMetaObject::invokeMethod(clientmodel, "updateNetworkActive", Qt::QueuedConnection,
+ bool invoked = QMetaObject::invokeMethod(clientmodel, "updateNetworkActive", Qt::QueuedConnection,
Q_ARG(bool, networkActive));
+ assert(invoked);
}
static void NotifyAlertChanged(ClientModel *clientmodel)
{
qDebug() << "NotifyAlertChanged";
- QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
+ bool invoked = QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
+ assert(invoked);
}
static void BannedListChanged(ClientModel *clientmodel)
{
qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__);
- QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
+ bool invoked = QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
+ assert(invoked);
}
static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int height, int64_t blockTime, double verificationProgress, bool fHeader)
@@ -233,11 +238,12 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, int heig
// if we are in-sync or if we notify a header update, update the UI regardless of last update time
if (fHeader || !initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
//pass an async signal to the UI thread
- QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
+ bool invoked = QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
Q_ARG(int, height),
Q_ARG(QDateTime, QDateTime::fromTime_t(blockTime)),
Q_ARG(double, verificationProgress),
Q_ARG(bool, fHeader));
+ assert(invoked);
nLastUpdateNotification = now;
}
}
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 6b9f79aaf8..03d18d2845 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -418,7 +418,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (amount > 0)
{
- CTxOut txout(amount, static_cast<CScript>(std::vector<unsigned char>(24, 0)));
+ // Assumes a p2pkh script size
+ CTxOut txout(amount, CScript() << std::vector<unsigned char>(24, 0));
txDummy.vout.push_back(txout);
fDust |= IsDust(txout, model->node().getDustRelayFee());
}
@@ -509,7 +510,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// Never create dust outputs; if we would, just add the dust to the fee.
if (nChange > 0 && nChange < MIN_CHANGE)
{
- CTxOut txout(nChange, static_cast<CScript>(std::vector<unsigned char>(24, 0)));
+ // Assumes a p2pkh script size
+ CTxOut txout(nChange, CScript() << std::vector<unsigned char>(24, 0));
if (IsDust(txout, model->node().getDustRelayFee()))
{
nPayFee += nChange;
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 70e52c9f1d..dc1da7f8a9 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,10 +11,10 @@
#include <base58.h>
#include <chainparams.h>
-#include <primitives/transaction.h>
-#include <key_io.h>
#include <interfaces/node.h>
+#include <key_io.h>
#include <policy/policy.h>
+#include <primitives/transaction.h>
#include <protocol.h>
#include <script/script.h>
#include <script/standard.h>
@@ -639,7 +639,7 @@ fs::path static GetAutostartFilePath()
std::string chain = gArgs.GetChainName();
if (chain == CBaseChainParams::MAIN)
return GetAutostartDir() / "bitcoin.desktop";
- return GetAutostartDir() / strprintf("bitcoin-%s.lnk", chain);
+ return GetAutostartDir() / strprintf("bitcoin-%s.desktop", chain);
}
bool GetStartOnSystemStartup()
@@ -841,9 +841,6 @@ QString formatServicesStr(quint64 mask)
case NODE_WITNESS:
strList.append("WITNESS");
break;
- case NODE_XTHIN:
- strList.append("XTHIN");
- break;
default:
strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check));
}
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index c595361934..102e37e471 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -119,16 +119,16 @@ Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_siz
m_chain_state_size(chain_state_size)
{
ui->setupUi(this);
- ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME)));
- ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME)));
+ ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(PACKAGE_NAME));
+ ui->storageLabel->setText(ui->storageLabel->text().arg(PACKAGE_NAME));
ui->lblExplanation1->setText(ui->lblExplanation1->text()
- .arg(tr(PACKAGE_NAME))
+ .arg(PACKAGE_NAME)
.arg(m_blockchain_size)
.arg(2009)
.arg(tr("Bitcoin"))
);
- ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(tr(PACKAGE_NAME)));
+ ui->lblExplanation2->setText(ui->lblExplanation2->text().arg(PACKAGE_NAME));
uint64_t pruneTarget = std::max<int64_t>(0, gArgs.GetArg("-prune", 0));
requiredSpace = m_blockchain_size;
@@ -145,7 +145,7 @@ Intro::Intro(QWidget *parent, uint64_t blockchain_size, uint64_t chain_state_siz
}
requiredSpace += m_chain_state_size;
ui->sizeWarningLabel->setText(
- tr("%1 will download and store a copy of the Bitcoin block chain.").arg(tr(PACKAGE_NAME)) + " " +
+ tr("%1 will download and store a copy of the Bitcoin block chain.").arg(PACKAGE_NAME) + " " +
storageRequiresMsg.arg(requiredSpace) + " " +
tr("The wallet will also be stored in this directory.")
);
@@ -221,7 +221,7 @@ bool Intro::pickDataDirectory(interfaces::Node& node)
}
break;
} catch (const fs::filesystem_error&) {
- QMessageBox::critical(nullptr, tr(PACKAGE_NAME),
+ QMessageBox::critical(nullptr, PACKAGE_NAME,
tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir));
/* fall through, back to choosing screen */
}
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index c6ecbc3f87..bff7469071 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -59,7 +59,7 @@
<translation>&amp;Delete</translation>
</message>
<message>
- <location filename="../addressbookpage.cpp" line="+85"/>
+ <location filename="../addressbookpage.cpp" line="+84"/>
<source>Choose the address to send coins to</source>
<translation type="unfinished"></translation>
</message>
@@ -90,7 +90,7 @@
</message>
<message>
<location line="+5"/>
- <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <source>These are your Bitcoin addresses for receiving payments. Use the &apos;Create new receiving address&apos; button in the receive tab to create new addresses.</source>
<translation type="unfinished"></translation>
</message>
<message>
@@ -132,7 +132,7 @@
<context>
<name>AddressTableModel</name>
<message>
- <location filename="../addresstablemodel.cpp" line="+164"/>
+ <location filename="../addresstablemodel.cpp" line="+163"/>
<source>Label</source>
<translation type="unfinished"></translation>
</message>
@@ -297,7 +297,7 @@
<context>
<name>BanTableModel</name>
<message>
- <location filename="../bantablemodel.cpp" line="+88"/>
+ <location filename="../bantablemodel.cpp" line="+86"/>
<source>IP/Netmask</source>
<translation type="unfinished"></translation>
</message>
@@ -315,12 +315,12 @@
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+574"/>
+ <location line="+638"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-652"/>
+ <location line="-716"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@@ -400,12 +400,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+157"/>
+ <location line="+217"/>
<source>Wallet:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+330"/>
+ <location line="+334"/>
<source>Click to disable network activity.</source>
<translation type="unfinished"></translation>
</message>
@@ -430,12 +430,12 @@
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
- <location line="+315"/>
+ <location line="+317"/>
<source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-970"/>
+ <location line="-1036"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -465,12 +465,7 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
- <location line="+660"/>
- <source>Bitcoin</source>
- <translation>Bitcoin</translation>
- </message>
- <message>
- <location line="-733"/>
+ <location line="-73"/>
<source>&amp;Send</source>
<translation>&amp;Send</translation>
</message>
@@ -505,12 +500,12 @@
<translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation>
</message>
<message>
- <location line="+61"/>
+ <location line="+118"/>
<source>&amp;File</source>
<translation>&amp;File</translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+14"/>
<source>&amp;Settings</source>
<translation>&amp;Settings</translation>
</message>
@@ -525,7 +520,7 @@
<translation>Tabs toolbar</translation>
</message>
<message>
- <location line="-211"/>
+ <location line="-271"/>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
@@ -545,12 +540,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+10"/>
<source>&amp;Command-line options</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+484"/>
+ <location line="+540"/>
<source>%n active connection(s) to Bitcoin network</source>
<translation>
<numerusform>%n active connection to Bitcoin network</numerusform>
@@ -591,27 +586,27 @@
<translation>Transactions after this will not yet be visible.</translation>
</message>
<message>
- <location line="+27"/>
+ <location line="+28"/>
<source>Error</source>
<translation>Error</translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>Warning</source>
<translation>Warning</translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>Information</source>
<translation>Information</translation>
</message>
<message>
- <location line="-78"/>
+ <location line="-81"/>
<source>Up to date</source>
<translation>Up to date</translation>
</message>
<message>
- <location line="-593"/>
+ <location line="-657"/>
<source>&amp;Sending addresses</source>
<translation type="unfinished"></translation>
</message>
@@ -621,12 +616,52 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+6"/>
+ <source>Open Wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Open a wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Close Wallet...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Close wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
<source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+63"/>
+ <location line="+30"/>
+ <source>default wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+13"/>
+ <source>Opening Wallet &lt;b&gt;%1&lt;/b&gt;...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
+ <source>Open Wallet Failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+15"/>
+ <source>No wallets available</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+48"/>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Window</translation>
</message>
@@ -651,7 +686,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+228"/>
+ <location line="+232"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
@@ -666,7 +701,17 @@
<translation>Catching up...</translation>
</message>
<message>
- <location line="+151"/>
+ <location line="+50"/>
+ <source>Error: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Warning: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+99"/>
<source>Date: %1
</source>
<translation type="unfinished"></translation>
@@ -737,7 +782,7 @@
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+395"/>
+ <location filename="../bitcoin.cpp" line="+390"/>
<source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source>
<translation type="unfinished"></translation>
</message>
@@ -830,7 +875,7 @@
<translation type="unfinished">Confirmed</translation>
</message>
<message>
- <location filename="../coincontroldialog.cpp" line="+58"/>
+ <location filename="../coincontroldialog.cpp" line="+54"/>
<source>Copy address</source>
<translation type="unfinished"></translation>
</message>
@@ -1031,7 +1076,7 @@
<context>
<name>HelpMessageDialog</name>
<message>
- <location filename="../utilitydialog.cpp" line="+44"/>
+ <location filename="../utilitydialog.cpp" line="+39"/>
<source>version</source>
<translation type="unfinished">version</translation>
</message>
@@ -1120,7 +1165,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+80"/>
+ <location line="+75"/>
<source>Error: Specified data directory &quot;%1&quot; cannot be created.</source>
<translation type="unfinished"></translation>
</message>
@@ -1171,7 +1216,7 @@
<message>
<location line="+7"/>
<location line="+26"/>
- <location filename="../modaloverlay.cpp" line="+140"/>
+ <location filename="../modaloverlay.cpp" line="+141"/>
<source>Unknown...</source>
<translation type="unfinished"></translation>
</message>
@@ -1207,8 +1252,8 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../modaloverlay.cpp" line="-1"/>
- <source>Unknown. Syncing Headers (%1)...</source>
+ <location filename="../modaloverlay.cpp" line="+6"/>
+ <source>Unknown. Syncing Headers (%1, %2%)...</source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -1540,12 +1585,12 @@
<translation>default</translation>
</message>
<message>
- <location line="+63"/>
+ <location line="+67"/>
<source>none</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+93"/>
+ <location line="+89"/>
<source>Confirm options reset</source>
<translation>Confirm options reset</translation>
</message>
@@ -1689,7 +1734,7 @@
<name>PaymentServer</name>
<message>
<location filename="../paymentserver.cpp" line="+226"/>
- <location line="+338"/>
+ <location line="+346"/>
<location line="+42"/>
<location line="+110"/>
<location line="+14"/>
@@ -1698,7 +1743,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-521"/>
+ <location line="-529"/>
<source>Cannot start bitcoin: click-to-pay handler</source>
<translation type="unfinished"></translation>
</message>
@@ -1706,14 +1751,14 @@
<location line="+62"/>
<location line="+9"/>
<location line="+16"/>
+ <location line="+16"/>
<location line="+5"/>
- <location line="+12"/>
<location line="+7"/>
<source>URI handling</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-49"/>
+ <location line="-53"/>
<source>&apos;bitcoin://&apos; is not a valid URI. Use &apos;bitcoin:&apos; instead.</source>
<translation type="unfinished"></translation>
</message>
@@ -1728,12 +1773,13 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+16"/>
+ <location line="+36"/>
<source>Cannot process payment request because BIP70 support was not compiled in.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <location line="-32"/>
<source>Invalid payment address %1</source>
<translation type="unfinished"></translation>
</message>
@@ -1744,16 +1790,17 @@
</message>
<message>
<location line="+14"/>
+ <location line="+9"/>
<source>Payment request file handling</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="-8"/>
<source>Payment request file cannot be read! This can be caused by an invalid payment request file.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+195"/>
+ <location line="+199"/>
<location line="+9"/>
<location line="+31"/>
<location line="+10"/>
@@ -1832,7 +1879,7 @@
<context>
<name>PeerTableModel</name>
<message>
- <location filename="../peertablemodel.cpp" line="+109"/>
+ <location filename="../peertablemodel.cpp" line="+108"/>
<source>User Agent</source>
<translation type="unfinished"></translation>
</message>
@@ -1865,17 +1912,17 @@
<context>
<name>QObject</name>
<message>
- <location filename="../bitcoinunits.cpp" line="+197"/>
+ <location filename="../bitcoinunits.cpp" line="+195"/>
<source>Amount</source>
<translation type="unfinished">Amount</translation>
</message>
<message>
- <location filename="../guiutil.cpp" line="+111"/>
+ <location filename="../guiutil.cpp" line="+108"/>
<source>Enter a Bitcoin address (e.g. %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+687"/>
+ <location line="+702"/>
<source>%1 d</source>
<translation type="unfinished"></translation>
</message>
@@ -1985,20 +2032,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="+185"/>
- <source>%1 didn&apos;t yet exit safely...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../modaloverlay.cpp" line="-29"/>
- <source>unknown</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QObject::QObject</name>
- <message>
- <location filename="../bitcoin.cpp" line="-113"/>
+ <location filename="../bitcoin.cpp" line="+74"/>
<source>Error parsing command line arguments: %1.</source>
<translation type="unfinished"></translation>
</message>
@@ -2017,11 +2051,21 @@
<source>Error: %1</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <location line="+57"/>
+ <source>%1 didn&apos;t yet exit safely...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../modaloverlay.cpp" line="-36"/>
+ <source>unknown</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>QRImageWidget</name>
<message>
- <location filename="../receiverequestdialog.cpp" line="+32"/>
+ <location filename="../qrimagewidget.cpp" line="+29"/>
<source>&amp;Save Image...</source>
<translation type="unfinished"></translation>
</message>
@@ -2031,6 +2075,21 @@
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+13"/>
+ <source>Resulting URI too long, try to reduce the text for label / message.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>Error encoding URI into QR Code.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+38"/>
+ <source>QR code support not available.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+32"/>
<source>Save QR Code</source>
<translation type="unfinished"></translation>
@@ -2056,7 +2115,7 @@
<location line="+23"/>
<location line="+36"/>
<location line="+23"/>
- <location line="+713"/>
+ <location line="+716"/>
<location line="+23"/>
<location line="+23"/>
<location line="+23"/>
@@ -2078,7 +2137,7 @@
<translation>N/A</translation>
</message>
<message>
- <location line="-1427"/>
+ <location line="-1430"/>
<source>Client version</source>
<translation>Client version</translation>
</message>
@@ -2178,7 +2237,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+238"/>
+ <location line="+241"/>
<source>&amp;Reset</source>
<translation type="unfinished"></translation>
</message>
@@ -2206,8 +2265,8 @@
</message>
<message>
<location line="+65"/>
- <location filename="../rpcconsole.cpp" line="+501"/>
- <location line="+754"/>
+ <location filename="../rpcconsole.cpp" line="+498"/>
+ <location line="+757"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
</message>
@@ -2242,13 +2301,13 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1161"/>
- <location line="+1069"/>
+ <location line="-1164"/>
+ <location line="+1072"/>
<source>User Agent</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-734"/>
+ <location line="-737"/>
<source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
<translation type="unfinished"></translation>
</message>
@@ -2263,7 +2322,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+641"/>
+ <location line="+644"/>
<source>Services</source>
<translation type="unfinished"></translation>
</message>
@@ -2313,7 +2372,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1166"/>
+ <location line="-1169"/>
<source>Last block time</source>
<translation>Last block time</translation>
</message>
@@ -2328,7 +2387,7 @@
<translation>&amp;Console</translation>
</message>
<message>
- <location line="+214"/>
+ <location line="+217"/>
<source>&amp;Network Traffic</source>
<translation type="unfinished"></translation>
</message>
@@ -2348,7 +2407,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../forms/debugwindow.ui" line="-318"/>
+ <location filename="../forms/debugwindow.ui" line="-321"/>
<source>Debug log file</source>
<translation>Debug log file</translation>
</message>
@@ -2358,7 +2417,7 @@
<translation>Clear console</translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-249"/>
+ <location filename="../rpcconsole.cpp" line="-252"/>
<source>1 &amp;hour</source>
<translation type="unfinished"></translation>
</message>
@@ -2396,7 +2455,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+161"/>
+ <location line="+164"/>
<source>Welcome to the %1 RPC console.</source>
<translation type="unfinished"></translation>
</message>
@@ -2513,43 +2572,43 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-39"/>
- <location line="+153"/>
- <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
+ <location line="+136"/>
+ <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don&apos;t support them. When checked, an address compatible with older wallets will be created instead.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-59"/>
- <source>Clear all fields of the form.</source>
+ <location line="+3"/>
+ <source>Generate legacy address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Clear</source>
+ <location line="-178"/>
+ <location line="+153"/>
+ <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+78"/>
- <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don&apos;t support them. When unchecked, an address compatible with older wallets will be created instead.</source>
+ <location line="-76"/>
+ <source>&amp;Create new receiving address</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Generate native segwit (Bech32) address</source>
+ <location line="+17"/>
+ <source>Clear all fields of the form.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+61"/>
- <source>Requested payments history</source>
+ <location line="+3"/>
+ <source>Clear</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-162"/>
- <source>&amp;Request payment</source>
+ <location line="+142"/>
+ <source>Requested payments history</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+187"/>
+ <location line="+25"/>
<source>Show the selected request (does the same as double clicking an entry)</source>
<translation type="unfinished"></translation>
</message>
@@ -2569,7 +2628,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../receivecoinsdialog.cpp" line="+47"/>
+ <location filename="../receivecoinsdialog.cpp" line="+45"/>
<source>Copy URI</source>
<translation type="unfinished"></translation>
</message>
@@ -2612,7 +2671,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../receiverequestdialog.cpp" line="+65"/>
+ <location filename="../receiverequestdialog.cpp" line="+63"/>
<source>Request payment to %1</source>
<translation type="unfinished"></translation>
</message>
@@ -2651,16 +2710,6 @@
<source>Wallet</source>
<translation type="unfinished">Wallet</translation>
</message>
- <message>
- <location line="+11"/>
- <source>Resulting URI too long, try to reduce the text for label / message.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+5"/>
- <source>Error encoding URI into QR Code.</source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -2704,7 +2753,7 @@
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
- <location filename="../sendcoinsdialog.cpp" line="+593"/>
+ <location filename="../sendcoinsdialog.cpp" line="+600"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -2891,7 +2940,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>S&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-505"/>
+ <location filename="../sendcoinsdialog.cpp" line="-512"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@@ -2931,10 +2980,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+133"/>
- <location line="+5"/>
- <location line="+6"/>
- <location line="+4"/>
+ <location line="+117"/>
+ <source> from wallet &apos;%1&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+14"/>
+ <location line="+11"/>
+ <source>%1 to &apos;%2&apos;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-6"/>
+ <location line="+10"/>
<source>%1 to %2</source>
<translation type="unfinished"></translation>
</message>
@@ -2954,12 +3012,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-61"/>
- <source>from wallet %1</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+40"/>
+ <location line="-21"/>
<source>Please, review your transaction.</source>
<translation type="unfinished"></translation>
</message>
@@ -2979,12 +3032,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+9"/>
+ <source>To review recipient list click &quot;Show Details...&quot;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
<source>Confirm send coins</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+191"/>
+ <location line="+190"/>
<source>The recipient address is not valid. Please recheck.</source>
<translation type="unfinished"></translation>
</message>
@@ -3179,7 +3237,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>SendConfirmationDialog</name>
<message>
- <location filename="../sendcoinsdialog.cpp" line="+83"/>
+ <location filename="../sendcoinsdialog.cpp" line="+88"/>
<location line="+5"/>
<source>Yes</source>
<translation type="unfinished"></translation>
@@ -3399,7 +3457,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionDesc</name>
<message numerus="yes">
- <location filename="../transactiondesc.cpp" line="+35"/>
+ <location filename="../transactiondesc.cpp" line="+34"/>
<source>Open for %n more block(s)</source>
<translation>
<numerusform>Open for %n more block</numerusform>
@@ -3640,7 +3698,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionTableModel</name>
<message>
- <location filename="../transactiontablemodel.cpp" line="+227"/>
+ <location filename="../transactiontablemodel.cpp" line="+223"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -3776,7 +3834,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>TransactionView</name>
<message>
- <location filename="../transactionview.cpp" line="+71"/>
+ <location filename="../transactionview.cpp" line="+70"/>
<location line="+16"/>
<source>All</source>
<translation type="unfinished"></translation>
@@ -3975,12 +4033,30 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>UnitDisplayStatusBarControl</name>
<message>
- <location filename="../bitcoingui.cpp" line="+154"/>
+ <location filename="../bitcoingui.cpp" line="+155"/>
<source>Unit to show amounts in. Click to select another unit.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
+ <name>WalletController</name>
+ <message>
+ <location filename="../walletcontroller.cpp" line="+70"/>
+ <source>Close wallet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Are you sure you wish to close wallet &lt;i&gt;%1&lt;/i&gt;?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>WalletFrame</name>
<message>
<location filename="../walletframe.cpp" line="+29"/>
@@ -4043,7 +4119,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+35"/>
+ <location line="+30"/>
<source>default wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -4099,7 +4175,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<context>
<name>bitcoin-core</name>
<message>
- <location filename="../bitcoinstrings.cpp" line="+29"/>
+ <location filename="../bitcoinstrings.cpp" line="+28"/>
<source>Distributed under the MIT software license, see the accompanying file %s or %s</source>
<translation type="unfinished"></translation>
</message>
@@ -4119,7 +4195,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+74"/>
+ <location line="+70"/>
<source>Error: A fatal internal error occurred, see debug.log for details</source>
<translation type="unfinished"></translation>
</message>
@@ -4129,22 +4205,22 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+30"/>
+ <location line="+31"/>
<source>Unable to start HTTP server. See debug log for details.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-172"/>
- <source>Bitcoin Core</source>
- <translation type="unfinished">Bitcoin Core</translation>
+ <location line="-168"/>
+ <source>The %s developers</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>The %s developers</source>
+ <location line="+4"/>
+ <source>Can&apos;t generate a change-address key. No keys in the internal keypool and can&apos;t generate any keys.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+7"/>
+ <location line="+3"/>
<source>Cannot obtain a lock on data directory %s. %s is probably already running.</source>
<translation type="unfinished"></translation>
</message>
@@ -4199,7 +4275,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+7"/>
<source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
<translation type="unfinished"></translation>
</message>
@@ -4290,11 +4366,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+6"/>
- <source>Error: Disk space is low!</source>
- <translation>Error: Disk space is low!</translation>
- </message>
- <message>
- <location line="+1"/>
<source>Failed to listen on any port. Use -listen=0 if you want this.</source>
<translation>Failed to listen on any port. Use -listen=0 if you want this.</translation>
</message>
@@ -4314,7 +4385,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>Incorrect or no genesis block found. Wrong datadir for network?</translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+1"/>
<source>Initialization sanity check failed. %s is shutting down.</source>
<translation type="unfinished"></translation>
</message>
@@ -4334,22 +4405,27 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+23"/>
<source>Specified blocks directory &quot;%s&quot; does not exist.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+24"/>
+ <location line="+26"/>
<source>Upgrading txindex database</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-42"/>
+ <location line="-45"/>
<source>Loading P2P addresses...</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="-15"/>
+ <source>Error: Disk space is too low!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+16"/>
<source>Loading banlist...</source>
<translation type="unfinished"></translation>
</message>
@@ -4364,7 +4440,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished"></translation>
</message>
@@ -4394,12 +4470,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+3"/>
<source>Unable to generate keys</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+4"/>
<source>Unsupported logging category %s=%s.</source>
<translation type="unfinished"></translation>
</message>
@@ -4419,12 +4495,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>Verifying blocks...</translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+2"/>
<source>Wallet needed to be rewritten: restart %s to complete</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-158"/>
+ <location line="-155"/>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4439,7 +4515,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+38"/>
+ <location line="+35"/>
<source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
<translation type="unfinished"></translation>
</message>
@@ -4454,17 +4530,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+2"/>
<source>Error: Disk space is low for %s</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
- <source>Information</source>
- <translation>Information</translation>
- </message>
- <message>
- <location line="+3"/>
+ <location line="+8"/>
<source>Invalid -onion address or hostname: &apos;%s&apos;</source>
<translation type="unfinished"></translation>
</message>
@@ -4489,7 +4560,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+3"/>
+ <source>Prune mode is incompatible with -blockfilterindex.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Reducing -maxconnections from %d to %d, because of system limitations.</source>
<translation type="unfinished"></translation>
</message>
@@ -4556,26 +4632,26 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+2"/>
- <source>Unable to generate initial keys</source>
+ <source>Unable to create the PID file &apos;%s&apos;: %s</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+9"/>
- <source>Verifying wallet(s)...</source>
+ <location line="+1"/>
+ <source>Unable to generate initial keys</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
- <source>Wallet %s resides outside wallet directory %s</source>
+ <location line="+3"/>
+ <source>Unknown -blockfilterindex value %s.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <source>Warning</source>
- <translation>Warning</translation>
+ <location line="+7"/>
+ <source>Verifying wallet(s)...</source>
+ <translation type="unfinished"></translation>
</message>
<message>
- <location line="+1"/>
+ <location line="+2"/>
<source>Warning: unknown new rules activated (versionbit %i)</source>
<translation type="unfinished"></translation>
</message>
@@ -4585,7 +4661,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-182"/>
+ <location line="-178"/>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<translation type="unfinished"></translation>
</message>
@@ -4606,11 +4682,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
</message>
<message>
<location line="+14"/>
- <source>Warning: Unknown block versions being mined! It&apos;s possible unknown rules are in effect</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+3"/>
<source>Warning: Wallet file corrupt, data salvaged! Original %s saved as %s in %s; if your balance or transactions are incorrect you should restore from a backup.</source>
<translation type="unfinished"></translation>
</message>
@@ -4625,12 +4696,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+22"/>
+ <location line="+20"/>
<source>Keypool ran out, please call keypoolrefill first</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+20"/>
+ <location line="+21"/>
<source>Starting network threads...</source>
<translation type="unfinished"></translation>
</message>
@@ -4665,22 +4736,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+10"/>
<source>Unknown network specified in -onlynet: &apos;%s&apos;</source>
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-48"/>
+ <location line="-51"/>
<source>Insufficient funds</source>
<translation>Insufficient funds</translation>
</message>
<message>
- <location line="-120"/>
- <source>Can&apos;t generate a change-address key. Private keys are disabled for this wallet.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+8"/>
+ <location line="-107"/>
<source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.</source>
<translation type="unfinished"></translation>
</message>
@@ -4695,12 +4761,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+24"/>
+ <location line="+21"/>
<source>Cannot write to data directory &apos;%s&apos;; check permissions.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+39"/>
+ <location line="+37"/>
<source>Loading block index...</source>
<translation>Loading block index...</translation>
</message>
@@ -4710,24 +4776,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee of &quot;100 satos
<translation>Loading wallet...</translation>
</message>
<message>
- <location line="-42"/>
+ <location line="-40"/>
<source>Cannot downgrade wallet</source>
<translation>Cannot downgrade wallet</translation>
</message>
<message>
- <location line="+50"/>
+ <location line="+49"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-42"/>
+ <location line="-41"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
- <message>
- <location line="+12"/>
- <source>Error</source>
- <translation>Error</translation>
- </message>
</context>
</TS>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 40dc7bf400..57cafaaac0 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -87,12 +87,12 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
/* Display elements init */
QDir translations(":translations");
- ui->bitcoinAtStartup->setToolTip(ui->bitcoinAtStartup->toolTip().arg(tr(PACKAGE_NAME)));
- ui->bitcoinAtStartup->setText(ui->bitcoinAtStartup->text().arg(tr(PACKAGE_NAME)));
+ ui->bitcoinAtStartup->setToolTip(ui->bitcoinAtStartup->toolTip().arg(PACKAGE_NAME));
+ ui->bitcoinAtStartup->setText(ui->bitcoinAtStartup->text().arg(PACKAGE_NAME));
- ui->openBitcoinConfButton->setToolTip(ui->openBitcoinConfButton->toolTip().arg(tr(PACKAGE_NAME)));
+ ui->openBitcoinConfButton->setToolTip(ui->openBitcoinConfButton->toolTip().arg(PACKAGE_NAME));
- ui->lang->setToolTip(ui->lang->toolTip().arg(tr(PACKAGE_NAME)));
+ ui->lang->setToolTip(ui->lang->toolTip().arg(PACKAGE_NAME));
ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
for (const QString &langStr : translations.entryList())
{
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index c99515fe1c..f3f5d28af9 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -666,16 +666,14 @@ void PaymentServer::fetchPaymentACK(WalletModel* walletModel, const SendCoinsRec
payment.add_transactions(transaction.data(), transaction.size());
// Create a new refund address, or re-use:
- CPubKey newKey;
- if (walletModel->wallet().getKeyFromPool(false /* internal */, newKey)) {
+ CTxDestination dest;
+ const OutputType change_type = walletModel->wallet().getDefaultChangeType() != OutputType::CHANGE_AUTO ? walletModel->wallet().getDefaultChangeType() : walletModel->wallet().getDefaultAddressType();
+ if (walletModel->wallet().getNewDestination(change_type, "", dest)) {
// BIP70 requests encode the scriptPubKey directly, so we are not restricted to address
// types supported by the receiver. As a result, we choose the address format we also
// use for change. Despite an actual payment and not change, this is a close match:
// it's the output type we use subject to privacy issues, but not restricted by what
// other software supports.
- const OutputType change_type = walletModel->wallet().getDefaultChangeType() != OutputType::CHANGE_AUTO ? walletModel->wallet().getDefaultChangeType() : walletModel->wallet().getDefaultAddressType();
- walletModel->wallet().learnRelatedScripts(newKey, change_type);
- CTxDestination dest = GetDestinationForKey(newKey, change_type);
std::string label = tr("Refund from %1").arg(recipient.authenticatedMerchant).toStdString();
walletModel->wallet().setAddressBook(dest, label, "refund");
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 071a197c3c..84b4a2d0d8 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -457,7 +457,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
QChar nonbreaking_hyphen(8209);
ui->dataDir->setToolTip(ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir"));
ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(QString(nonbreaking_hyphen) + "blocksdir"));
- ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(tr(PACKAGE_NAME)));
+ ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(PACKAGE_NAME));
if (platformStyle->getImagesOnButtons()) {
ui->openDebugLogfileButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
@@ -804,7 +804,7 @@ void RPCConsole::clear(bool clearHistory)
QString clsKey = "Ctrl-L";
#endif
- message(CMD_REPLY, (tr("Welcome to the %1 RPC console.").arg(tr(PACKAGE_NAME)) + "<br>" +
+ message(CMD_REPLY, (tr("Welcome to the %1 RPC console.").arg(PACKAGE_NAME) + "<br>" +
tr("Use up and down arrows to navigate history, and %1 to clear screen.").arg("<b>"+clsKey+"</b>") + "<br>" +
tr("Type %1 for an overview of available commands.").arg("<b>help</b>") + "<br>" +
tr("For more information on using this console type %1.").arg("<b>help-console</b>") +
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 0126a2920e..98eeee1a47 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -39,7 +39,7 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw
devicePixelRatio = static_cast<QGuiApplication*>(QCoreApplication::instance())->devicePixelRatio();
// define text to place
- QString titleText = tr(PACKAGE_NAME);
+ QString titleText = PACKAGE_NAME;
QString versionText = QString("Version %1").arg(QString::fromStdString(FormatFullVersion()));
QString copyrightText = QString::fromUtf8(CopyrightHolders(strprintf("\xc2\xA9 %u-%u ", 2009, COPYRIGHT_YEAR)).c_str());
QString titleAddText = networkStyle->getTitleAddText();
@@ -156,11 +156,12 @@ void SplashScreen::finish()
static void InitMessage(SplashScreen *splash, const std::string &message)
{
- QMetaObject::invokeMethod(splash, "showMessage",
+ bool invoked = QMetaObject::invokeMethod(splash, "showMessage",
Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(int, Qt::AlignBottom|Qt::AlignHCenter),
Q_ARG(QColor, QColor(55,55,55)));
+ assert(invoked);
}
static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress, bool resume_possible)
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index e54915ec75..120dff95c0 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -68,7 +68,8 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe
if (status == CT_NEW) txid = hash;
}));
ConfirmSend();
- QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
+ bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
+ assert(invoked);
return txid;
}
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 6fe35b13cf..1064c60dfd 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -687,10 +687,11 @@ public:
{
QString strHash = QString::fromStdString(hash.GetHex());
qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status);
- QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection,
+ bool invoked = QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection,
Q_ARG(QString, strHash),
Q_ARG(int, status),
Q_ARG(bool, showTransaction));
+ assert(invoked);
}
private:
uint256 hash;
@@ -725,12 +726,16 @@ static void ShowProgress(TransactionTableModel *ttm, const std::string &title, i
if (nProgress == 100)
{
fQueueNotifications = false;
- if (vQueueNotifications.size() > 10) // prevent balloon spam, show maximum 10 balloons
- QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
+ if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
+ bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
+ assert(invoked);
+ }
for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
{
- if (vQueueNotifications.size() - i <= 10)
- QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
+ if (vQueueNotifications.size() - i <= 10) {
+ bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
+ assert(invoked);
+ }
vQueueNotifications[i].invoke(ttm);
}
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index aa810690c9..6509a701f3 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -36,7 +36,7 @@ HelpMessageDialog::HelpMessageDialog(interfaces::Node& node, QWidget *parent, bo
{
ui->setupUi(this);
- QString version = tr(PACKAGE_NAME) + " " + tr("version") + " " + QString::fromStdString(FormatFullVersion());
+ QString version = QString{PACKAGE_NAME} + " " + tr("version") + " " + QString::fromStdString(FormatFullVersion());
/* On x86 add a bit specifier to the version so that users can distinguish between
* 32 and 64 bit builds. On other architectures, 32/64 bit may be more ambiguous.
*/
@@ -48,7 +48,7 @@ HelpMessageDialog::HelpMessageDialog(interfaces::Node& node, QWidget *parent, bo
if (about)
{
- setWindowTitle(tr("About %1").arg(tr(PACKAGE_NAME)));
+ setWindowTitle(tr("About %1").arg(PACKAGE_NAME));
std::string licenseInfo = LicenseInfo();
/// HTML-format the license message from the core
@@ -150,7 +150,7 @@ ShutdownWindow::ShutdownWindow(QWidget *parent, Qt::WindowFlags f):
{
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(new QLabel(
- tr("%1 is shutting down...").arg(tr(PACKAGE_NAME)) + "<br /><br />" +
+ tr("%1 is shutting down...").arg(PACKAGE_NAME) + "<br /><br />" +
tr("Do not shut down the computer until this window disappears.")));
setLayout(layout);
}
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index 4d489d7f44..2aedb77798 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -124,7 +124,8 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
} else {
// Handler callback runs in a different thread so fix wallet model thread affinity.
wallet_model->moveToThread(thread());
- QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection, Q_ARG(WalletModel*, wallet_model));
+ bool invoked = QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection, Q_ARG(WalletModel*, wallet_model));
+ assert(invoked);
}
return wallet_model;
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index c1eba61749..57406179f7 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -221,9 +221,12 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return TransactionCreationFailed;
}
- // Reject absurdly high fee
- if (nFeeRequired > m_wallet->getDefaultMaxTxFee())
+ // Reject absurdly high fee. (This can never happen because the
+ // wallet never creates transactions with fee greater than
+ // m_default_max_tx_fee. This merely a belt-and-suspenders check).
+ if (nFeeRequired > m_wallet->getDefaultMaxTxFee()) {
return AbsurdFee;
+ }
}
return SendCoinsReturn(OK);
@@ -374,13 +377,15 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri
static void NotifyUnload(WalletModel* walletModel)
{
qDebug() << "NotifyUnload";
- QMetaObject::invokeMethod(walletModel, "unload");
+ bool invoked = QMetaObject::invokeMethod(walletModel, "unload");
+ assert(invoked);
}
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel)
{
qDebug() << "NotifyKeyStoreStatusChanged";
- QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
+ bool invoked = QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection);
+ assert(invoked);
}
static void NotifyAddressBookChanged(WalletModel *walletmodel,
@@ -392,38 +397,43 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel,
QString strPurpose = QString::fromStdString(purpose);
qDebug() << "NotifyAddressBookChanged: " + strAddress + " " + strLabel + " isMine=" + QString::number(isMine) + " purpose=" + strPurpose + " status=" + QString::number(status);
- QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
+ bool invoked = QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection,
Q_ARG(QString, strAddress),
Q_ARG(QString, strLabel),
Q_ARG(bool, isMine),
Q_ARG(QString, strPurpose),
Q_ARG(int, status));
+ assert(invoked);
}
static void NotifyTransactionChanged(WalletModel *walletmodel, const uint256 &hash, ChangeType status)
{
Q_UNUSED(hash);
Q_UNUSED(status);
- QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection);
+ bool invoked = QMetaObject::invokeMethod(walletmodel, "updateTransaction", Qt::QueuedConnection);
+ assert(invoked);
}
static void ShowProgress(WalletModel *walletmodel, const std::string &title, int nProgress)
{
// emits signal "showProgress"
- QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection,
+ bool invoked = QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(title)),
Q_ARG(int, nProgress));
+ assert(invoked);
}
static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly)
{
- QMetaObject::invokeMethod(walletmodel, "updateWatchOnlyFlag", Qt::QueuedConnection,
+ bool invoked = QMetaObject::invokeMethod(walletmodel, "updateWatchOnlyFlag", Qt::QueuedConnection,
Q_ARG(bool, fHaveWatchonly));
+ assert(invoked);
}
static void NotifyCanGetAddressesChanged(WalletModel* walletmodel)
{
- QMetaObject::invokeMethod(walletmodel, "canGetAddressesChanged");
+ bool invoked = QMetaObject::invokeMethod(walletmodel, "canGetAddressesChanged");
+ assert(invoked);
}
void WalletModel::subscribeToCoreSignals()
diff --git a/src/rest.cpp b/src/rest.cpp
index ab409947d3..eba7aae50f 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -12,6 +12,7 @@
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <rpc/blockchain.h>
+#include <rpc/protocol.h>
#include <rpc/server.h>
#include <streams.h>
#include <sync.h>
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 743efc1e65..b7dcd59c6d 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -165,8 +165,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
static UniValue getblockcount(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"getblockcount",
"\nReturns the height of the most-work fully-validated chain.\n"
"The genesis block has height 0.\n",
@@ -178,7 +176,7 @@ static UniValue getblockcount(const JSONRPCRequest& request)
HelpExampleCli("getblockcount", "")
+ HelpExampleRpc("getblockcount", "")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
return ::ChainActive().Height();
@@ -186,8 +184,6 @@ static UniValue getblockcount(const JSONRPCRequest& request)
static UniValue getbestblockhash(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"getbestblockhash",
"\nReturns the hash of the best (tip) block in the most-work fully-validated chain.\n",
{},
@@ -198,7 +194,7 @@ static UniValue getbestblockhash(const JSONRPCRequest& request)
HelpExampleCli("getbestblockhash", "")
+ HelpExampleRpc("getbestblockhash", "")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
return ::ChainActive().Tip()->GetBlockHash().GetHex();
@@ -216,8 +212,6 @@ void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)
static UniValue waitfornewblock(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 1)
- throw std::runtime_error(
RPCHelpMan{"waitfornewblock",
"\nWaits for a specific new block and returns useful info about it.\n"
"\nReturns the current block on timeout or exit.\n",
@@ -234,7 +228,7 @@ static UniValue waitfornewblock(const JSONRPCRequest& request)
HelpExampleCli("waitfornewblock", "1000")
+ HelpExampleRpc("waitfornewblock", "1000")
},
- }.ToString());
+ }.Check(request);
int timeout = 0;
if (!request.params[0].isNull())
timeout = request.params[0].get_int();
@@ -257,8 +251,6 @@ static UniValue waitfornewblock(const JSONRPCRequest& request)
static UniValue waitforblock(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"waitforblock",
"\nWaits for a specific new block and returns useful info about it.\n"
"\nReturns the current block on timeout or exit.\n",
@@ -276,7 +268,7 @@ static UniValue waitforblock(const JSONRPCRequest& request)
HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
+ HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
},
- }.ToString());
+ }.Check(request);
int timeout = 0;
uint256 hash(ParseHashV(request.params[0], "blockhash"));
@@ -302,8 +294,6 @@ static UniValue waitforblock(const JSONRPCRequest& request)
static UniValue waitforblockheight(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"waitforblockheight",
"\nWaits for (at least) block height and returns the height and hash\n"
"of the current tip.\n"
@@ -322,7 +312,7 @@ static UniValue waitforblockheight(const JSONRPCRequest& request)
HelpExampleCli("waitforblockheight", "\"100\", 1000")
+ HelpExampleRpc("waitforblockheight", "\"100\", 1000")
},
- }.ToString());
+ }.Check(request);
int timeout = 0;
int height = request.params[0].get_int();
@@ -347,8 +337,6 @@ static UniValue waitforblockheight(const JSONRPCRequest& request)
static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 0) {
- throw std::runtime_error(
RPCHelpMan{"syncwithvalidationinterfacequeue",
"\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
{},
@@ -357,16 +345,14 @@ static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request)
HelpExampleCli("syncwithvalidationinterfacequeue","")
+ HelpExampleRpc("syncwithvalidationinterfacequeue","")
},
- }.ToString());
- }
+ }.Check(request);
+
SyncWithValidationInterfaceQueue();
return NullUniValue;
}
static UniValue getdifficulty(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"getdifficulty",
"\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
{},
@@ -377,7 +363,7 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
HelpExampleCli("getdifficulty", "")
+ HelpExampleRpc("getdifficulty", "")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
return GetDifficulty(::ChainActive().Tip());
@@ -504,8 +490,6 @@ UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose)
static UniValue getrawmempool(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 1)
- throw std::runtime_error(
RPCHelpMan{"getrawmempool",
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
"\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
@@ -528,7 +512,7 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
HelpExampleCli("getrawmempool", "true")
+ HelpExampleRpc("getrawmempool", "true")
},
- }.ToString());
+ }.Check(request);
bool fVerbose = false;
if (!request.params[0].isNull())
@@ -539,8 +523,6 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
static UniValue getmempoolancestors(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw std::runtime_error(
RPCHelpMan{"getmempoolancestors",
"\nIf txid is in the mempool, returns all in-mempool ancestors.\n",
{
@@ -566,8 +548,7 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
HelpExampleCli("getmempoolancestors", "\"mytxid\"")
+ HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
},
- }.ToString());
- }
+ }.Check(request);
bool fVerbose = false;
if (!request.params[1].isNull())
@@ -609,8 +590,6 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
static UniValue getmempooldescendants(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw std::runtime_error(
RPCHelpMan{"getmempooldescendants",
"\nIf txid is in the mempool, returns all in-mempool descendants.\n",
{
@@ -636,8 +615,7 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
HelpExampleCli("getmempooldescendants", "\"mytxid\"")
+ HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
},
- }.ToString());
- }
+ }.Check(request);
bool fVerbose = false;
if (!request.params[1].isNull())
@@ -679,8 +657,6 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
static UniValue getmempoolentry(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1) {
- throw std::runtime_error(
RPCHelpMan{"getmempoolentry",
"\nReturns mempool data for given transaction\n",
{
@@ -695,8 +671,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
HelpExampleCli("getmempoolentry", "\"mytxid\"")
+ HelpExampleRpc("getmempoolentry", "\"mytxid\"")
},
- }.ToString());
- }
+ }.Check(request);
uint256 hash = ParseHashV(request.params[0], "parameter 1");
@@ -715,8 +690,6 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
static UniValue getblockhash(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"getblockhash",
"\nReturns hash of block in best-block-chain at height provided.\n",
{
@@ -729,7 +702,7 @@ static UniValue getblockhash(const JSONRPCRequest& request)
HelpExampleCli("getblockhash", "1000")
+ HelpExampleRpc("getblockhash", "1000")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
@@ -743,8 +716,6 @@ static UniValue getblockhash(const JSONRPCRequest& request)
static UniValue getblockheader(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"getblockheader",
"\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
"If verbose is true, returns an Object with information about blockheader <hash>.\n",
@@ -780,7 +751,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
},
- }.ToString());
+ }.Check(request);
uint256 hash(ParseHashV(request.params[0], "hash"));
@@ -846,7 +817,7 @@ static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex)
static UniValue getblock(const JSONRPCRequest& request)
{
- const RPCHelpMan help{"getblock",
+ RPCHelpMan{"getblock",
"\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
"If verbosity is 1, returns an Object with information about block <hash>.\n"
"If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n",
@@ -898,11 +869,7 @@ static UniValue getblock(const JSONRPCRequest& request)
HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
uint256 hash(ParseHashV(request.params[0], "blockhash"));
@@ -1013,8 +980,6 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
static UniValue pruneblockchain(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"pruneblockchain", "",
{
{"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block height to prune up to. May be set to a discrete height, or a unix timestamp\n"
@@ -1027,7 +992,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
HelpExampleCli("pruneblockchain", "1000")
+ HelpExampleRpc("pruneblockchain", "1000")
},
- }.ToString());
+ }.Check(request);
if (!fPruneMode)
throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
@@ -1071,8 +1036,6 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"gettxoutsetinfo",
"\nReturns statistics about the unspent transaction output set.\n"
"Note this call may take some time.\n",
@@ -1093,7 +1056,7 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
HelpExampleCli("gettxoutsetinfo", "")
+ HelpExampleRpc("gettxoutsetinfo", "")
},
- }.ToString());
+ }.Check(request);
UniValue ret(UniValue::VOBJ);
@@ -1116,8 +1079,6 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
UniValue gettxout(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
- throw std::runtime_error(
RPCHelpMan{"gettxout",
"\nReturns details about an unspent transaction output.\n",
{
@@ -1151,7 +1112,7 @@ UniValue gettxout(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("gettxout", "\"txid\", 1")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
@@ -1197,8 +1158,6 @@ static UniValue verifychain(const JSONRPCRequest& request)
{
int nCheckLevel = gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL);
int nCheckDepth = gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
- if (request.fHelp || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"verifychain",
"\nVerifies blockchain database.\n",
{
@@ -1212,7 +1171,7 @@ static UniValue verifychain(const JSONRPCRequest& request)
HelpExampleCli("verifychain", "")
+ HelpExampleRpc("verifychain", "")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
@@ -1297,8 +1256,6 @@ static void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const Consensus::
UniValue getblockchaininfo(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"getblockchaininfo",
"Returns an object containing various state info regarding blockchain processing.\n",
{},
@@ -1350,7 +1307,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
HelpExampleCli("getblockchaininfo", "")
+ HelpExampleRpc("getblockchaininfo", "")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
@@ -1417,8 +1374,6 @@ struct CompareBlocksByHeight
static UniValue getchaintips(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"getchaintips",
"Return information about all known tips in the block tree,"
" including the main chain as well as orphaned branches.\n",
@@ -1449,14 +1404,14 @@ static UniValue getchaintips(const JSONRPCRequest& request)
HelpExampleCli("getchaintips", "")
+ HelpExampleRpc("getchaintips", "")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
/*
* Idea: the set of chain tips is ::ChainActive().tip, plus orphan blocks which do not have another orphan building off of them.
* Algorithm:
- * - Make one pass through mapBlockIndex, picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
+ * - Make one pass through g_blockman.m_block_index, picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
* - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
* - add ::ChainActive().Tip()
*/
@@ -1464,7 +1419,7 @@ static UniValue getchaintips(const JSONRPCRequest& request)
std::set<const CBlockIndex*> setOrphans;
std::set<const CBlockIndex*> setPrevs;
- for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex)
+ for (const std::pair<const uint256, CBlockIndex*>& item : ::BlockIndex())
{
if (!::ChainActive().Contains(item.second)) {
setOrphans.insert(item.second);
@@ -1540,8 +1495,6 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool)
static UniValue getmempoolinfo(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"getmempoolinfo",
"\nReturns details on the active state of the TX memory pool.\n",
{},
@@ -1560,15 +1513,13 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
HelpExampleCli("getmempoolinfo", "")
+ HelpExampleRpc("getmempoolinfo", "")
},
- }.ToString());
+ }.Check(request);
return MempoolInfoToJSON(::mempool);
}
static UniValue preciousblock(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"preciousblock",
"\nTreats a block as if it were received before others with the same work.\n"
"\nA later preciousblock call can override the effect of an earlier one.\n"
@@ -1581,7 +1532,7 @@ static UniValue preciousblock(const JSONRPCRequest& request)
HelpExampleCli("preciousblock", "\"blockhash\"")
+ HelpExampleRpc("preciousblock", "\"blockhash\"")
},
- }.ToString());
+ }.Check(request);
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CBlockIndex* pblockindex;
@@ -1606,8 +1557,6 @@ static UniValue preciousblock(const JSONRPCRequest& request)
static UniValue invalidateblock(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"invalidateblock",
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n",
{
@@ -1618,7 +1567,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
HelpExampleCli("invalidateblock", "\"blockhash\"")
+ HelpExampleRpc("invalidateblock", "\"blockhash\"")
},
- }.ToString());
+ }.Check(request);
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CValidationState state;
@@ -1646,8 +1595,6 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
static UniValue reconsiderblock(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"reconsiderblock",
"\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
"This can be used to undo the effects of invalidateblock.\n",
@@ -1659,7 +1606,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
HelpExampleCli("reconsiderblock", "\"blockhash\"")
+ HelpExampleRpc("reconsiderblock", "\"blockhash\"")
},
- }.ToString());
+ }.Check(request);
uint256 hash(ParseHashV(request.params[0], "blockhash"));
@@ -1685,8 +1632,6 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
static UniValue getchaintxstats(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"getchaintxstats",
"\nCompute statistics about the total number and rate of transactions in the chain.\n",
{
@@ -1708,7 +1653,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
HelpExampleCli("getchaintxstats", "")
+ HelpExampleRpc("getchaintxstats", "2016")
},
- }.ToString());
+ }.Check(request);
const CBlockIndex* pindex;
int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
@@ -1818,7 +1763,7 @@ static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t)
static UniValue getblockstats(const JSONRPCRequest& request)
{
- const RPCHelpMan help{"getblockstats",
+ RPCHelpMan{"getblockstats",
"\nCompute per block statistics for a given window. All amounts are in satoshis.\n"
"It won't work for some heights with pruning.\n",
{
@@ -1873,10 +1818,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
HelpExampleCli("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'")
+ HelpExampleRpc("getblockstats", "1000 '[\"minfeerate\",\"avgfeerate\"]'")
},
- };
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
LOCK(cs_main);
@@ -2077,8 +2019,6 @@ static UniValue getblockstats(const JSONRPCRequest& request)
static UniValue savemempool(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0) {
- throw std::runtime_error(
RPCHelpMan{"savemempool",
"\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
{},
@@ -2087,8 +2027,7 @@ static UniValue savemempool(const JSONRPCRequest& request)
HelpExampleCli("savemempool", "")
+ HelpExampleRpc("savemempool", "")
},
- }.ToString());
- }
+ }.Check(request);
if (!::mempool.IsLoaded()) {
throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
@@ -2163,8 +2102,6 @@ public:
UniValue scantxoutset(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"scantxoutset",
"\nEXPERIMENTAL warning: this call may be removed or changed in future releases.\n"
"\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
@@ -2213,8 +2150,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
"]\n"
},
RPCExamples{""},
- }.ToString()
- );
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
@@ -2301,8 +2237,6 @@ UniValue scantxoutset(const JSONRPCRequest& request)
static UniValue getblockfilter(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw std::runtime_error(
RPCHelpMan{"getblockfilter",
"\nRetrieve a BIP 157 content filter for a particular block.\n",
{
@@ -2318,9 +2252,7 @@ static UniValue getblockfilter(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"")
}
- }.ToString()
- );
- }
+ }.Check(request);
uint256 block_hash = ParseHashV(request.params[0], "blockhash");
std::string filtertype_name = "basic";
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 6636a8a29a..48bc88823a 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -78,8 +78,6 @@ static UniValue GetNetworkHashPS(int lookup, int height) {
static UniValue getnetworkhashps(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"getnetworkhashps",
"\nReturns the estimated network hashes per second based on the last n blocks.\n"
"Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"
@@ -95,7 +93,7 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request)
HelpExampleCli("getnetworkhashps", "")
+ HelpExampleRpc("getnetworkhashps", "")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1);
@@ -144,8 +142,6 @@ static UniValue generateBlocks(const CScript& coinbase_script, int nGenerate, ui
static UniValue generatetoaddress(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
- throw std::runtime_error(
RPCHelpMan{"generatetoaddress",
"\nMine blocks immediately to a specified address (before the RPC call returns)\n",
{
@@ -162,7 +158,7 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
+ "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", "")
},
- }.ToString());
+ }.Check(request);
int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
@@ -182,8 +178,6 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
static UniValue getmininginfo(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0) {
- throw std::runtime_error(
RPCHelpMan{"getmininginfo",
"\nReturns a json object containing mining-related information.",
{},
@@ -203,8 +197,7 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
HelpExampleCli("getmininginfo", "")
+ HelpExampleRpc("getmininginfo", "")
},
- }.ToString());
- }
+ }.Check(request);
LOCK(cs_main);
@@ -224,8 +217,6 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
static UniValue prioritisetransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 3)
- throw std::runtime_error(
RPCHelpMan{"prioritisetransaction",
"Accepts the transaction into mined blocks at a higher (or lower) priority\n",
{
@@ -244,7 +235,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
+ HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
@@ -290,8 +281,6 @@ static std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
static UniValue getblocktemplate(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 1)
- throw std::runtime_error(
RPCHelpMan{"getblocktemplate",
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
"It returns data needed to construct a block to work on.\n"
@@ -301,7 +290,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
" https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
" https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n",
{
- {"template_request", RPCArg::Type::OBJ, RPCArg::Optional::NO, "A json object in the following spec",
+ {"template_request", RPCArg::Type::OBJ, "{}", "A json object in the following spec",
{
{"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"},
{"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings",
@@ -366,7 +355,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
HelpExampleCli("getblocktemplate", "{\"rules\": [\"segwit\"]}")
+ HelpExampleRpc("getblocktemplate", "{\"rules\": [\"segwit\"]}")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
@@ -696,8 +685,6 @@ protected:
static UniValue submitblock(const JSONRPCRequest& request)
{
// We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw std::runtime_error(
RPCHelpMan{"submitblock",
"\nAttempts to submit new block to network.\n"
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n",
@@ -710,8 +697,7 @@ static UniValue submitblock(const JSONRPCRequest& request)
HelpExampleCli("submitblock", "\"mydata\"")
+ HelpExampleRpc("submitblock", "\"mydata\"")
},
- }.ToString());
- }
+ }.Check(request);
std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
CBlock& block = *blockptr;
@@ -761,8 +747,6 @@ static UniValue submitblock(const JSONRPCRequest& request)
static UniValue submitheader(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1) {
- throw std::runtime_error(
RPCHelpMan{"submitheader",
"\nDecode the given hexdata as a header and submit it as a candidate chain tip if valid."
"\nThrows when the header is invalid.\n",
@@ -776,8 +760,7 @@ static UniValue submitheader(const JSONRPCRequest& request)
HelpExampleCli("submitheader", "\"aabbcc\"") +
HelpExampleRpc("submitheader", "\"aabbcc\"")
},
- }.ToString());
- }
+ }.Check(request);
CBlockHeader h;
if (!DecodeHexBlockHeader(h, request.params[0].get_str())) {
@@ -801,8 +784,6 @@ static UniValue submitheader(const JSONRPCRequest& request)
static UniValue estimatesmartfee(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"estimatesmartfee",
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
"confirmation within conf_target blocks if possible and return the number of blocks\n"
@@ -835,7 +816,7 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("estimatesmartfee", "6")
},
- }.ToString());
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
@@ -866,8 +847,6 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request)
static UniValue estimaterawfee(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"estimaterawfee",
"\nWARNING: This interface is unstable and may disappear or change!\n"
"\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
@@ -908,7 +887,7 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("estimaterawfee", "6 0.9")
},
- }.ToString());
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 7a1bdec7b9..6be4057366 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -25,8 +25,6 @@
static UniValue validateaddress(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"validateaddress",
"\nReturn information about the given bitcoin address.\n",
{
@@ -47,7 +45,7 @@ static UniValue validateaddress(const JSONRPCRequest& request)
HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
+ HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
},
- }.ToString());
+ }.Check(request);
CTxDestination dest = DecodeDestination(request.params[0].get_str());
bool isValid = IsValidDestination(dest);
@@ -70,9 +68,6 @@ static UniValue validateaddress(const JSONRPCRequest& request)
static UniValue createmultisig(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
- {
- std::string msg =
RPCHelpMan{"createmultisig",
"\nCreates a multi-signature address with n signature of m keys required.\n"
"It returns a json object with the address and redeemScript.\n",
@@ -96,9 +91,7 @@ static UniValue createmultisig(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("createmultisig", "2, \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"")
},
- }.ToString();
- throw std::runtime_error(msg);
- }
+ }.Check(request);
int required = request.params[0].get_int();
@@ -122,7 +115,7 @@ static UniValue createmultisig(const JSONRPCRequest& request)
}
// Construct using pay-to-script-hash:
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CScript inner;
const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner);
@@ -135,8 +128,6 @@ static UniValue createmultisig(const JSONRPCRequest& request)
UniValue getdescriptorinfo(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1) {
- throw std::runtime_error(
RPCHelpMan{"getdescriptorinfo",
{"\nAnalyses a descriptor.\n"},
{
@@ -153,9 +144,7 @@ UniValue getdescriptorinfo(const JSONRPCRequest& request)
RPCExamples{
"Analyse a descriptor\n" +
HelpExampleCli("getdescriptorinfo", "\"wpkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)\"")
- }}.ToString()
- );
- }
+ }}.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR});
@@ -175,8 +164,6 @@ UniValue getdescriptorinfo(const JSONRPCRequest& request)
UniValue deriveaddresses(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.empty() || request.params.size() > 2) {
- throw std::runtime_error(
RPCHelpMan{"deriveaddresses",
{"\nDerives one or more addresses corresponding to an output descriptor.\n"
"Examples of output descriptors are:\n"
@@ -197,9 +184,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
RPCExamples{
"First three native segwit receive addresses\n" +
HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu\" \"[0,2]\"")
- }}.ToString()
- );
- }
+ }}.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType()}); // Range argument is checked later
const std::string desc_str = request.params[0].get_str();
@@ -254,8 +239,6 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
static UniValue verifymessage(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 3)
- throw std::runtime_error(
RPCHelpMan{"verifymessage",
"\nVerify a signed message\n",
{
@@ -276,7 +259,7 @@ static UniValue verifymessage(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
@@ -313,8 +296,6 @@ static UniValue verifymessage(const JSONRPCRequest& request)
static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 2)
- throw std::runtime_error(
RPCHelpMan{"signmessagewithprivkey",
"\nSign a message with the private key of an address\n",
{
@@ -332,7 +313,7 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
},
- }.ToString());
+ }.Check(request);
std::string strPrivkey = request.params[0].get_str();
std::string strMessage = request.params[1].get_str();
@@ -355,8 +336,6 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
static UniValue setmocktime(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"setmocktime",
"\nSet the local time to given timestamp (-regtest only)\n",
{
@@ -365,8 +344,7 @@ static UniValue setmocktime(const JSONRPCRequest& request)
},
RPCResults{},
RPCExamples{""},
- }.ToString()
- );
+ }.Check(request);
if (!Params().MineBlocksOnDemand())
throw std::runtime_error("setmocktime for regression testing (-regtest mode) only");
@@ -421,8 +399,6 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request)
/* Please, avoid using the word "pool" here in the RPC interface or help,
* as users will undoubtedly confuse it with the other "memory pool"
*/
- if (request.fHelp || request.params.size() > 1)
- throw std::runtime_error(
RPCHelpMan{"getmemoryinfo",
"Returns an object containing information about memory usage.\n",
{
@@ -451,7 +427,7 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request)
HelpExampleCli("getmemoryinfo", "")
+ HelpExampleRpc("getmemoryinfo", "")
},
- }.ToString());
+ }.Check(request);
std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str();
if (mode == "stats") {
@@ -489,8 +465,6 @@ static void EnableOrDisableLogCategories(UniValue cats, bool enable) {
UniValue logging(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 2) {
- throw std::runtime_error(
RPCHelpMan{"logging",
"Gets and sets the logging configuration.\n"
"When called without an argument, returns the list of categories with status that are currently being debug logged or not.\n"
@@ -522,8 +496,7 @@ UniValue logging(const JSONRPCRequest& request)
HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
+ HelpExampleRpc("logging", "[\"all\"], [\"libevent\"]")
},
- }.ToString());
- }
+ }.Check(request);
uint32_t original_log_categories = LogInstance().GetCategoryMask();
if (request.params[0].isArray()) {
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index d993a88458..16b59e3d58 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -26,8 +26,6 @@
static UniValue getconnectioncount(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"getconnectioncount",
"\nReturns the number of connections to other nodes.\n",
{},
@@ -38,7 +36,7 @@ static UniValue getconnectioncount(const JSONRPCRequest& request)
HelpExampleCli("getconnectioncount", "")
+ HelpExampleRpc("getconnectioncount", "")
},
- }.ToString());
+ }.Check(request);
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -48,8 +46,6 @@ static UniValue getconnectioncount(const JSONRPCRequest& request)
static UniValue ping(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"ping",
"\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
"Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
@@ -60,7 +56,7 @@ static UniValue ping(const JSONRPCRequest& request)
HelpExampleCli("ping", "")
+ HelpExampleRpc("ping", "")
},
- }.ToString());
+ }.Check(request);
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -74,8 +70,6 @@ static UniValue ping(const JSONRPCRequest& request)
static UniValue getpeerinfo(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"getpeerinfo",
"\nReturns data about each connected network node as a json array of objects.\n",
{},
@@ -131,7 +125,7 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
HelpExampleCli("getpeerinfo", "")
+ HelpExampleRpc("getpeerinfo", "")
},
- }.ToString());
+ }.Check(request);
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -258,8 +252,6 @@ static UniValue addnode(const JSONRPCRequest& request)
static UniValue disconnectnode(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() == 0 || request.params.size() >= 3)
- throw std::runtime_error(
RPCHelpMan{"disconnectnode",
"\nImmediately disconnects from the specified peer node.\n"
"\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n"
@@ -275,7 +267,7 @@ static UniValue disconnectnode(const JSONRPCRequest& request)
+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
+ HelpExampleRpc("disconnectnode", "\"\", 1")
},
- }.ToString());
+ }.Check(request);
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -304,8 +296,6 @@ static UniValue disconnectnode(const JSONRPCRequest& request)
static UniValue getaddednodeinfo(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 1)
- throw std::runtime_error(
RPCHelpMan{"getaddednodeinfo",
"\nReturns information about the given added node, or all added nodes\n"
"(note that onetry addnodes are not listed here)\n",
@@ -331,7 +321,7 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request)
HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
+ HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")
},
- }.ToString());
+ }.Check(request);
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -374,8 +364,6 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request)
static UniValue getnettotals(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 0)
- throw std::runtime_error(
RPCHelpMan{"getnettotals",
"\nReturns information about network traffic, including bytes in, bytes out,\n"
"and current time.\n",
@@ -400,7 +388,7 @@ static UniValue getnettotals(const JSONRPCRequest& request)
HelpExampleCli("getnettotals", "")
+ HelpExampleRpc("getnettotals", "")
},
- }.ToString());
+ }.Check(request);
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -443,8 +431,6 @@ static UniValue GetNetworksInfo()
static UniValue getnetworkinfo(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"getnetworkinfo",
"Returns an object containing various state info regarding P2P networking.\n",
{},
@@ -485,7 +471,7 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
HelpExampleCli("getnetworkinfo", "")
+ HelpExampleRpc("getnetworkinfo", "")
},
- }.ToString());
+ }.Check(request);
LOCK(cs_main);
UniValue obj(UniValue::VOBJ);
@@ -602,8 +588,6 @@ static UniValue setban(const JSONRPCRequest& request)
static UniValue listbanned(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"listbanned",
"\nList all banned IPs/Subnets.\n",
{},
@@ -612,7 +596,7 @@ static UniValue listbanned(const JSONRPCRequest& request)
HelpExampleCli("listbanned", "")
+ HelpExampleRpc("listbanned", "")
},
- }.ToString());
+ }.Check(request);
if(!g_banman) {
throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
@@ -639,8 +623,6 @@ static UniValue listbanned(const JSONRPCRequest& request)
static UniValue clearbanned(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"clearbanned",
"\nClear all banned IPs.\n",
{},
@@ -649,7 +631,7 @@ static UniValue clearbanned(const JSONRPCRequest& request)
HelpExampleCli("clearbanned", "")
+ HelpExampleRpc("clearbanned", "")
},
- }.ToString());
+ }.Check(request);
if (!g_banman) {
throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
}
@@ -661,8 +643,6 @@ static UniValue clearbanned(const JSONRPCRequest& request)
static UniValue setnetworkactive(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1) {
- throw std::runtime_error(
RPCHelpMan{"setnetworkactive",
"\nDisable/enable all p2p network activity.\n",
{
@@ -670,9 +650,7 @@ static UniValue setnetworkactive(const JSONRPCRequest& request)
},
RPCResults{},
RPCExamples{""},
- }.ToString()
- );
- }
+ }.Check(request);
if (!g_connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -685,8 +663,6 @@ static UniValue setnetworkactive(const JSONRPCRequest& request)
static UniValue getnodeaddresses(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 1) {
- throw std::runtime_error(
RPCHelpMan{"getnodeaddresses",
"\nReturn known addresses which can potentially be used to find new nodes in the network\n",
{
@@ -707,8 +683,7 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request)
HelpExampleCli("getnodeaddresses", "8")
+ HelpExampleRpc("getnodeaddresses", "8")
},
- }.ToString());
- }
+ }.Check(request);
if (!g_connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 6bcbccbd4f..ef6537e4ec 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -6,15 +6,6 @@
#ifndef BITCOIN_RPC_PROTOCOL_H
#define BITCOIN_RPC_PROTOCOL_H
-#include <fs.h>
-
-#include <list>
-#include <map>
-#include <stdint.h>
-#include <string>
-
-#include <univalue.h>
-
//! HTTP status codes
enum HTTPStatusCode
{
@@ -92,18 +83,4 @@ enum RPCErrorCode
RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode
};
-UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id);
-UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);
-std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
-UniValue JSONRPCError(int code, const std::string& message);
-
-/** Generate a new RPC authentication cookie and write it to disk */
-bool GenerateAuthCookie(std::string *cookie_out);
-/** Read the RPC authentication cookie from disk */
-bool GetAuthCookie(std::string *cookie_out);
-/** Delete RPC authentication cookie from disk */
-void DeleteAuthCookie();
-/** Parse JSON-RPC batch reply into a vector */
-std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num);
-
#endif // BITCOIN_RPC_PROTOCOL_H
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 6ac16622c2..532765b3d8 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -10,7 +10,6 @@
#include <core_io.h>
#include <index/txindex.h>
#include <key_io.h>
-#include <keystore.h>
#include <merkleblock.h>
#include <node/coin.h>
#include <node/psbt.h>
@@ -24,6 +23,7 @@
#include <script/script.h>
#include <script/script_error.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <script/standard.h>
#include <uint256.h>
#include <util/moneystr.h>
@@ -71,7 +71,7 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue&
static UniValue getrawtransaction(const JSONRPCRequest& request)
{
- const RPCHelpMan help{
+ RPCHelpMan{
"getrawtransaction",
"\nReturn the raw transaction data.\n"
@@ -149,11 +149,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
+ HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"")
+ HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
bool in_active_chain = true;
uint256 hash = ParseHashV(request.params[0], "parameter 1");
@@ -217,8 +213,6 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
static UniValue gettxoutproof(const JSONRPCRequest& request)
{
- if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
- throw std::runtime_error(
RPCHelpMan{"gettxoutproof",
"\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
"\nNOTE: By default this function only works sometimes. This is when there is an\n"
@@ -237,8 +231,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
"\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n"
},
RPCExamples{""},
- }.ToString()
- );
+ }.Check(request);
std::set<uint256> setTxids;
uint256 oneTxid;
@@ -313,8 +306,6 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
static UniValue verifytxoutproof(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"verifytxoutproof",
"\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
"and throwing an RPC error if the block is not in our best chain\n",
@@ -325,8 +316,7 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof can not be validated.\n"
},
RPCExamples{""},
- }.ToString()
- );
+ }.Check(request);
CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
CMerkleBlock merkleBlock;
@@ -358,8 +348,6 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
static UniValue createrawtransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) {
- throw std::runtime_error(
RPCHelpMan{"createrawtransaction",
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
"Outputs can be addresses or data.\n"
@@ -408,8 +396,7 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"")
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
},
- }.ToString());
- }
+ }.Check(request);
RPCTypeCheck(request.params, {
UniValue::VARR,
@@ -426,7 +413,7 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
static UniValue decoderawtransaction(const JSONRPCRequest& request)
{
- const RPCHelpMan help{"decoderawtransaction",
+ RPCHelpMan{"decoderawtransaction",
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"},
@@ -483,11 +470,7 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
HelpExampleCli("decoderawtransaction", "\"hexstring\"")
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
@@ -518,7 +501,7 @@ static std::string GetAllOutputTypes()
static UniValue decodescript(const JSONRPCRequest& request)
{
- const RPCHelpMan help{"decodescript",
+ RPCHelpMan{"decodescript",
"\nDecode a hex-encoded script.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"},
@@ -549,11 +532,7 @@ static UniValue decodescript(const JSONRPCRequest& request)
HelpExampleCli("decodescript", "\"hexstring\"")
+ HelpExampleRpc("decodescript", "\"hexstring\"")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR});
@@ -610,8 +589,6 @@ static UniValue decodescript(const JSONRPCRequest& request)
static UniValue combinerawtransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"combinerawtransaction",
"\nCombine multiple partially signed transactions into one transaction.\n"
"The combined transaction may be another partially signed transaction or a \n"
@@ -629,7 +606,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]")
},
- }.ToString());
+ }.Check(request);
UniValue txs = request.params[0].get_array();
@@ -694,8 +671,6 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
- throw std::runtime_error(
RPCHelpMan{"signrawtransactionwithkey",
"\nSign inputs for raw transaction (serialized, hex-encoded).\n"
"The second argument is an array of base58-encoded private\n"
@@ -752,7 +727,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
HelpExampleCli("signrawtransactionwithkey", "\"myhex\" \"[\\\"key1\\\",\\\"key2\\\"]\"")
+ HelpExampleRpc("signrawtransactionwithkey", "\"myhex\", \"[\\\"key1\\\",\\\"key2\\\"]\"")
},
- }.ToString());
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true);
@@ -761,7 +736,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
const UniValue& keys = request.params[1].get_array();
for (unsigned int idx = 0; idx < keys.size(); ++idx) {
UniValue k = keys[idx];
@@ -784,7 +759,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
static UniValue sendrawtransaction(const JSONRPCRequest& request)
{
- const RPCHelpMan help{"sendrawtransaction",
+ RPCHelpMan{"sendrawtransaction",
"\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
"\nAlso see createrawtransaction and signrawtransactionwithkey calls.\n",
{
@@ -806,11 +781,7 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
RPCTypeCheck(request.params, {
UniValue::VSTR,
@@ -848,7 +819,7 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
static UniValue testmempoolaccept(const JSONRPCRequest& request)
{
- const RPCHelpMan help{"testmempoolaccept",
+ RPCHelpMan{"testmempoolaccept",
"\nReturns result of mempool acceptance tests indicating if raw transaction (serialized, hex-encoded) would be accepted by mempool.\n"
"\nThis checks if the transaction violates the consensus or policy rules.\n"
"\nSee sendrawtransaction call.\n",
@@ -881,11 +852,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
RPCTypeCheck(request.params, {
UniValue::VARR,
@@ -964,8 +931,6 @@ static std::string WriteHDKeypath(std::vector<uint32_t>& keypath)
UniValue decodepsbt(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"decodepsbt",
"\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n",
{
@@ -1062,7 +1027,7 @@ UniValue decodepsbt(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("decodepsbt", "\"psbt\"")
},
- }.ToString());
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR});
@@ -1239,8 +1204,6 @@ UniValue decodepsbt(const JSONRPCRequest& request)
UniValue combinepsbt(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"combinepsbt",
"\nCombine multiple partially signed Bitcoin transactions into one transaction.\n"
"Implements the Combiner role.\n",
@@ -1257,7 +1220,7 @@ UniValue combinepsbt(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("combinepsbt", "[\"mybase64_1\", \"mybase64_2\", \"mybase64_3\"]")
},
- }.ToString());
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VARR}, true);
@@ -1289,8 +1252,6 @@ UniValue combinepsbt(const JSONRPCRequest& request)
UniValue finalizepsbt(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"finalizepsbt",
"Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n"
"network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n"
@@ -1312,7 +1273,7 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("finalizepsbt", "\"psbt\"")
},
- }.ToString());
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true);
@@ -1348,8 +1309,6 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
UniValue createpsbt(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
- throw std::runtime_error(
RPCHelpMan{"createpsbt",
"\nCreates a transaction in the Partially Signed Transaction format.\n"
"Implements the Creator role.\n",
@@ -1392,7 +1351,7 @@ UniValue createpsbt(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
},
- }.ToString());
+ }.Check(request);
RPCTypeCheck(request.params, {
@@ -1424,7 +1383,7 @@ UniValue createpsbt(const JSONRPCRequest& request)
UniValue converttopsbt(const JSONRPCRequest& request)
{
- const RPCHelpMan help{"converttopsbt",
+ RPCHelpMan{"converttopsbt",
"\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n"
"createpsbt and walletcreatefundedpsbt should be used for new applications.\n",
{
@@ -1448,11 +1407,7 @@ UniValue converttopsbt(const JSONRPCRequest& request)
"\nConvert the transaction to a PSBT\n"
+ HelpExampleCli("converttopsbt", "\"rawtransaction\"")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true);
@@ -1495,8 +1450,6 @@ UniValue converttopsbt(const JSONRPCRequest& request)
UniValue utxoupdatepsbt(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw std::runtime_error(
RPCHelpMan{"utxoupdatepsbt",
"\nUpdates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set or the mempool.\n",
{
@@ -1514,8 +1467,7 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
},
RPCExamples {
HelpExampleCli("utxoupdatepsbt", "\"psbt\"")
- }}.ToString());
- }
+ }}.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}, true);
@@ -1585,8 +1537,6 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
UniValue joinpsbts(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1) {
- throw std::runtime_error(
RPCHelpMan{"joinpsbts",
"\nJoins multiple distinct PSBTs with different inputs and outputs into one PSBT with inputs and outputs from all of the PSBTs\n"
"No input in any of the PSBTs can be in more than one of the PSBTs.\n",
@@ -1601,8 +1551,7 @@ UniValue joinpsbts(const JSONRPCRequest& request)
},
RPCExamples {
HelpExampleCli("joinpsbts", "\"psbt\"")
- }}.ToString());
- }
+ }}.Check(request);
RPCTypeCheck(request.params, {UniValue::VARR}, true);
@@ -1659,8 +1608,6 @@ UniValue joinpsbts(const JSONRPCRequest& request)
UniValue analyzepsbt(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1) {
- throw std::runtime_error(
RPCHelpMan{"analyzepsbt",
"\nAnalyzes and provides information about the current status of a PSBT and its inputs\n",
{
@@ -1694,8 +1641,7 @@ UniValue analyzepsbt(const JSONRPCRequest& request)
},
RPCExamples {
HelpExampleCli("analyzepsbt", "\"psbt\"")
- }}.ToString());
- }
+ }}.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR});
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index 14fcb628eb..1c96d01232 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -8,11 +8,12 @@
#include <coins.h>
#include <core_io.h>
#include <key_io.h>
-#include <keystore.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
-#include <rpc/protocol.h>
+#include <rpc/request.h>
#include <rpc/util.h>
+#include <script/sign.h>
+#include <script/signingprovider.h>
#include <tinyformat.h>
#include <univalue.h>
#include <util/rbf.h>
@@ -148,7 +149,7 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
vErrorsRet.push_back(entry);
}
-UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore* keystore, std::map<COutPoint, Coin>& coins, bool is_temp_keystore, const UniValue& hashType)
+UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins, bool is_temp_keystore, const UniValue& hashType)
{
// Add previous txouts given in the RPC call:
if (!prevTxsUnival.isNull()) {
diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h
index c115d33a77..d198887b93 100644
--- a/src/rpc/rawtransaction_util.h
+++ b/src/rpc/rawtransaction_util.h
@@ -7,7 +7,7 @@
#include <map>
-class CBasicKeyStore;
+class FillableSigningProvider;
class UniValue;
struct CMutableTransaction;
class Coin;
@@ -24,7 +24,7 @@ class COutPoint;
* @param hashType The signature hash type
* @returns JSON object with details of signed transaction
*/
-UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore* keystore, std::map<COutPoint, Coin>& coins, bool tempKeystore, const UniValue& hashType);
+UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxs, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins, bool tempKeystore, const UniValue& hashType);
/** Create a transaction from univalue parameters */
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf);
diff --git a/src/rpc/protocol.cpp b/src/rpc/request.cpp
index 33b0130a94..56cac6661e 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/request.cpp
@@ -1,15 +1,16 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <rpc/protocol.h>
+#include <rpc/request.h>
+
+#include <fs.h>
#include <random.h>
-#include <tinyformat.h>
+#include <rpc/protocol.h>
#include <util/system.h>
#include <util/strencodings.h>
-#include <util/time.h>
/**
* JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
@@ -148,3 +149,36 @@ std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num)
}
return batch;
}
+
+void JSONRPCRequest::parse(const UniValue& valRequest)
+{
+ // Parse request
+ if (!valRequest.isObject())
+ throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
+ const UniValue& request = valRequest.get_obj();
+
+ // Parse id now so errors from here on will have the id
+ id = find_value(request, "id");
+
+ // Parse method
+ UniValue valMethod = find_value(request, "method");
+ if (valMethod.isNull())
+ throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
+ if (!valMethod.isStr())
+ throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
+ strMethod = valMethod.get_str();
+ if (fLogIPs)
+ LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s\n", SanitizeString(strMethod),
+ this->authUser, this->peerAddr);
+ else
+ LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser);
+
+ // Parse params
+ UniValue valParams = find_value(request, "params");
+ if (valParams.isArray() || valParams.isObject())
+ params = valParams;
+ else if (valParams.isNull())
+ params = UniValue(UniValue::VARR);
+ else
+ throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
+}
diff --git a/src/rpc/request.h b/src/rpc/request.h
new file mode 100644
index 0000000000..99eb4f9354
--- /dev/null
+++ b/src/rpc/request.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_RPC_REQUEST_H
+#define BITCOIN_RPC_REQUEST_H
+
+#include <string>
+
+#include <univalue.h>
+
+UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id);
+UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);
+std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
+UniValue JSONRPCError(int code, const std::string& message);
+
+/** Generate a new RPC authentication cookie and write it to disk */
+bool GenerateAuthCookie(std::string *cookie_out);
+/** Read the RPC authentication cookie from disk */
+bool GetAuthCookie(std::string *cookie_out);
+/** Delete RPC authentication cookie from disk */
+void DeleteAuthCookie();
+/** Parse JSON-RPC batch reply into a vector */
+std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num);
+
+class JSONRPCRequest
+{
+public:
+ UniValue id;
+ std::string strMethod;
+ UniValue params;
+ bool fHelp;
+ std::string URI;
+ std::string authUser;
+ std::string peerAddr;
+
+ JSONRPCRequest() : id(NullUniValue), params(NullUniValue), fHelp(false) {}
+ void parse(const UniValue& valRequest);
+};
+
+#endif // BITCOIN_RPC_REQUEST_H
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 145b99b567..18f7426bcf 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -178,8 +178,6 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
static UniValue uptime(const JSONRPCRequest& jsonRequest)
{
- if (jsonRequest.fHelp || jsonRequest.params.size() > 0)
- throw std::runtime_error(
RPCHelpMan{"uptime",
"\nReturns the total uptime of the server.\n",
{},
@@ -190,15 +188,13 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest)
HelpExampleCli("uptime", "")
+ HelpExampleRpc("uptime", "")
},
- }.ToString());
+ }.Check(jsonRequest);
return GetTime() - GetStartupTime();
}
static UniValue getrpcinfo(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 0) {
- throw std::runtime_error(
RPCHelpMan{"getrpcinfo",
"\nReturns details of the RPC server.\n",
{},
@@ -217,9 +213,7 @@ static UniValue getrpcinfo(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("getrpcinfo", "")
+ HelpExampleRpc("getrpcinfo", "")},
- }.ToString()
- );
- }
+ }.Check(request);
LOCK(g_rpc_server_info.mutex);
UniValue active_commands(UniValue::VARR);
@@ -334,39 +328,6 @@ bool RPCIsInWarmup(std::string *outStatus)
return fRPCInWarmup;
}
-void JSONRPCRequest::parse(const UniValue& valRequest)
-{
- // Parse request
- if (!valRequest.isObject())
- throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
- const UniValue& request = valRequest.get_obj();
-
- // Parse id now so errors from here on will have the id
- id = find_value(request, "id");
-
- // Parse method
- UniValue valMethod = find_value(request, "method");
- if (valMethod.isNull())
- throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
- if (!valMethod.isStr())
- throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
- strMethod = valMethod.get_str();
- if (fLogIPs)
- LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s\n", SanitizeString(strMethod),
- this->authUser, this->peerAddr);
- else
- LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser);
-
- // Parse params
- UniValue valParams = find_value(request, "params");
- if (valParams.isArray() || valParams.isObject())
- params = valParams;
- else if (valParams.isNull())
- params = UniValue(UniValue::VARR);
- else
- throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
-}
-
bool IsDeprecatedRPCEnabled(const std::string& method)
{
const std::vector<std::string> enabled_methods = gArgs.GetArgs("-deprecatedrpc");
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 431ff0bb7c..b060db5bf9 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -7,13 +7,14 @@
#define BITCOIN_RPC_SERVER_H
#include <amount.h>
-#include <rpc/protocol.h>
+#include <rpc/request.h>
#include <uint256.h>
#include <list>
#include <map>
#include <stdint.h>
#include <string>
+#include <functional>
#include <univalue.h>
@@ -27,21 +28,6 @@ namespace RPCServer
void OnStopped(std::function<void ()> slot);
}
-class JSONRPCRequest
-{
-public:
- UniValue id;
- std::string strMethod;
- UniValue params;
- bool fHelp;
- std::string URI;
- std::string authUser;
- std::string peerAddr;
-
- JSONRPCRequest() : id(NullUniValue), params(NullUniValue), fHelp(false) {}
- void parse(const UniValue& valRequest);
-};
-
/** Query whether RPC is running */
bool IsRPCRunning();
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 67ccb225b5..de90276677 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -3,8 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key_io.h>
-#include <keystore.h>
#include <outputtype.h>
+#include <script/signingprovider.h>
#include <rpc/util.h>
#include <script/descriptor.h>
#include <tinyformat.h>
@@ -131,8 +131,8 @@ CPubKey HexToPubKey(const std::string& hex_in)
return vchPubKey;
}
-// Retrieves a public key for an address from the given CKeyStore
-CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in)
+// Retrieves a public key for an address from the given FillableSigningProvider
+CPubKey AddrToPubKey(FillableSigningProvider* const keystore, const std::string& addr_in)
{
CTxDestination dest = DecodeDestination(addr_in);
if (!IsValidDestination(dest)) {
@@ -153,7 +153,7 @@ CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in)
}
// Creates a multisig address from a given list of public keys, number of signatures required, and the address type
-CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, CKeyStore& keystore, CScript& script_out)
+CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FillableSigningProvider& keystore, CScript& script_out)
{
// Gather public keys
if (required < 1) {
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 8762281d73..4c3322b879 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -9,6 +9,7 @@
#include <outputtype.h>
#include <pubkey.h>
#include <rpc/protocol.h>
+#include <rpc/request.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/standard.h>
@@ -19,7 +20,7 @@
#include <boost/variant.hpp>
-class CKeyStore;
+class FillableSigningProvider;
class CPubKey;
class CScript;
struct InitInterfaces;
@@ -72,8 +73,8 @@ extern std::string HelpExampleCli(const std::string& methodname, const std::stri
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
CPubKey HexToPubKey(const std::string& hex_in);
-CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in);
-CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, CKeyStore& keystore, CScript& script_out);
+CPubKey AddrToPubKey(FillableSigningProvider* const keystore, const std::string& addr_in);
+CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, FillableSigningProvider& keystore, CScript& script_out);
UniValue DescribeAddress(const CTxDestination& dest);
@@ -226,7 +227,7 @@ struct RPCResults {
struct RPCExamples {
const std::string m_examples;
- RPCExamples(
+ explicit RPCExamples(
std::string examples)
: m_examples(std::move(examples))
{
@@ -242,6 +243,15 @@ public:
std::string ToString() const;
/** If the supplied number of args is neither too small nor too high */
bool IsValidNumArgs(size_t num_args) const;
+ /**
+ * Check if the given request is valid according to this command or if
+ * the user is asking for help information, and throw help when appropriate.
+ */
+ inline void Check(const JSONRPCRequest& request) const {
+ if (request.fHelp || !IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(ToString());
+ }
+ }
private:
const std::string m_name;
diff --git a/src/script/descriptor.h b/src/script/descriptor.h
index af7ae229ca..29915c6c92 100644
--- a/src/script/descriptor.h
+++ b/src/script/descriptor.h
@@ -7,6 +7,7 @@
#include <script/script.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <vector>
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 95b25b4911..f8701b6d01 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -926,7 +926,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
// Drop the signature in pre-segwit scripts but not segwit scripts
if (sigversion == SigVersion::BASE) {
- int found = FindAndDelete(scriptCode, CScript(vchSig));
+ int found = FindAndDelete(scriptCode, CScript() << vchSig);
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
}
@@ -992,7 +992,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
{
valtype& vchSig = stacktop(-isig-k);
if (sigversion == SigVersion::BASE) {
- int found = FindAndDelete(scriptCode, CScript(vchSig));
+ int found = FindAndDelete(scriptCode, CScript() << vchSig);
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
}
diff --git a/src/script/keyorigin.h b/src/script/keyorigin.h
new file mode 100644
index 0000000000..610f233500
--- /dev/null
+++ b/src/script/keyorigin.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_SCRIPT_KEYORIGIN_H
+#define BITCOIN_SCRIPT_KEYORIGIN_H
+
+#include <serialize.h>
+#include <streams.h>
+#include <vector>
+
+struct KeyOriginInfo
+{
+ unsigned char fingerprint[4]; //!< First 32 bits of the Hash160 of the public key at the root of the path
+ std::vector<uint32_t> path;
+
+ friend bool operator==(const KeyOriginInfo& a, const KeyOriginInfo& b)
+ {
+ return std::equal(std::begin(a.fingerprint), std::end(a.fingerprint), std::begin(b.fingerprint)) && a.path == b.path;
+ }
+
+ ADD_SERIALIZE_METHODS;
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action)
+ {
+ READWRITE(fingerprint);
+ READWRITE(path);
+ }
+
+ void clear()
+ {
+ memset(fingerprint, 0, 4);
+ path.clear();
+ }
+};
+
+#endif // BITCOIN_SCRIPT_KEYORIGIN_H
diff --git a/src/script/script.h b/src/script/script.h
index 11e8661a5b..6355b8a704 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -437,7 +437,9 @@ public:
explicit CScript(opcodetype b) { operator<<(b); }
explicit CScript(const CScriptNum& b) { operator<<(b); }
- explicit CScript(const std::vector<unsigned char>& b) { operator<<(b); }
+ // delete non-existent constructor to defend against future introduction
+ // e.g. via prevector
+ explicit CScript(const std::vector<unsigned char>& b) = delete;
CScript& operator<<(int64_t b) { return push_int64(b); }
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 5320dc0876..13481af9c5 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -8,6 +8,7 @@
#include <key.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
+#include <script/signingprovider.h>
#include <script/standard.h>
#include <uint256.h>
@@ -423,22 +424,10 @@ public:
}
};
-template<typename M, typename K, typename V>
-bool LookupHelper(const M& map, const K& key, V& value)
-{
- auto it = map.find(key);
- if (it != map.end()) {
- value = it->second;
- return true;
- }
- return false;
-}
-
}
const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(32, 32);
const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR = DummySignatureCreator(33, 32);
-const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
bool IsSolvable(const SigningProvider& provider, const CScript& script)
{
@@ -459,53 +448,6 @@ bool IsSolvable(const SigningProvider& provider, const CScript& script)
return false;
}
-bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const
-{
- return m_provider->GetCScript(scriptid, script);
-}
-
-bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const
-{
- return m_provider->GetPubKey(keyid, pubkey);
-}
-
-bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const
-{
- if (m_hide_secret) return false;
- return m_provider->GetKey(keyid, key);
-}
-
-bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
-{
- if (m_hide_origin) return false;
- return m_provider->GetKeyOrigin(keyid, info);
-}
-
-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
-{
- std::pair<CPubKey, KeyOriginInfo> out;
- bool ret = LookupHelper(origins, keyid, out);
- if (ret) info = std::move(out.second);
- return ret;
-}
-bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); }
-
-FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b)
-{
- FlatSigningProvider ret;
- ret.scripts = a.scripts;
- ret.scripts.insert(b.scripts.begin(), b.scripts.end());
- ret.pubkeys = a.pubkeys;
- ret.pubkeys.insert(b.pubkeys.begin(), b.pubkeys.end());
- ret.keys = a.keys;
- ret.keys.insert(b.keys.begin(), b.keys.end());
- ret.origins = a.origins;
- ret.origins.insert(b.origins.begin(), b.origins.end());
- return ret;
-}
-
bool IsSegWitOutput(const SigningProvider& provider, const CScript& script)
{
std::vector<valtype> solutions;
diff --git a/src/script/sign.h b/src/script/sign.h
index e5c0329a61..0e751afd3b 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -10,6 +10,7 @@
#include <hash.h>
#include <pubkey.h>
#include <script/interpreter.h>
+#include <script/keyorigin.h>
#include <streams.h>
class CKey;
@@ -17,77 +18,10 @@ class CKeyID;
class CScript;
class CScriptID;
class CTransaction;
+class SigningProvider;
struct CMutableTransaction;
-struct KeyOriginInfo
-{
- unsigned char fingerprint[4]; //!< First 32 bits of the Hash160 of the public key at the root of the path
- std::vector<uint32_t> path;
-
- friend bool operator==(const KeyOriginInfo& a, const KeyOriginInfo& b)
- {
- return std::equal(std::begin(a.fingerprint), std::end(a.fingerprint), std::begin(b.fingerprint)) && a.path == b.path;
- }
-
- ADD_SERIALIZE_METHODS;
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action)
- {
- READWRITE(fingerprint);
- READWRITE(path);
- }
-
- void clear()
- {
- memset(fingerprint, 0, 4);
- path.clear();
- }
-};
-
-/** An interface to be implemented by keystores that support signing. */
-class SigningProvider
-{
-public:
- virtual ~SigningProvider() {}
- 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& keyid, KeyOriginInfo& info) const { return false; }
-};
-
-extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
-
-class HidingSigningProvider : public SigningProvider
-{
-private:
- const bool m_hide_secret;
- const bool m_hide_origin;
- const SigningProvider* m_provider;
-
-public:
- HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {}
- bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
- bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
- bool GetKey(const CKeyID& keyid, CKey& key) const override;
- bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
-};
-
-struct FlatSigningProvider final : public SigningProvider
-{
- std::map<CScriptID, CScript> scripts;
- std::map<CKeyID, CPubKey> pubkeys;
- std::map<CKeyID, std::pair<CPubKey, 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;
-};
-
-FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b);
-
/** Interface for signature creators. */
class BaseSignatureCreator {
public:
diff --git a/src/keystore.cpp b/src/script/signingprovider.cpp
index f6d19416ce..01757e2f65 100644
--- a/src/keystore.cpp
+++ b/src/script/signingprovider.cpp
@@ -1,18 +1,78 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <keystore.h>
+#include <script/keyorigin.h>
+#include <script/signingprovider.h>
+#include <script/standard.h>
#include <util/system.h>
-void CBasicKeyStore::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey)
+const SigningProvider& DUMMY_SIGNING_PROVIDER = SigningProvider();
+
+template<typename M, typename K, typename V>
+bool LookupHelper(const M& map, const K& key, V& value)
+{
+ auto it = map.find(key);
+ if (it != map.end()) {
+ value = it->second;
+ return true;
+ }
+ return false;
+}
+
+bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const
+{
+ return m_provider->GetCScript(scriptid, script);
+}
+
+bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const
+{
+ return m_provider->GetPubKey(keyid, pubkey);
+}
+
+bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const
+{
+ if (m_hide_secret) return false;
+ return m_provider->GetKey(keyid, key);
+}
+
+bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
+{
+ if (m_hide_origin) return false;
+ return m_provider->GetKeyOrigin(keyid, info);
+}
+
+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
+{
+ std::pair<CPubKey, KeyOriginInfo> out;
+ bool ret = LookupHelper(origins, keyid, out);
+ if (ret) info = std::move(out.second);
+ return ret;
+}
+bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); }
+
+FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b)
+{
+ FlatSigningProvider ret;
+ ret.scripts = a.scripts;
+ ret.scripts.insert(b.scripts.begin(), b.scripts.end());
+ ret.pubkeys = a.pubkeys;
+ ret.pubkeys.insert(b.pubkeys.begin(), b.pubkeys.end());
+ ret.keys = a.keys;
+ ret.keys.insert(b.keys.begin(), b.keys.end());
+ ret.origins = a.origins;
+ ret.origins.insert(b.origins.begin(), b.origins.end());
+ return ret;
+}
+
+void FillableSigningProvider::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey)
{
AssertLockHeld(cs_KeyStore);
CKeyID key_id = pubkey.GetID();
- // We must actually know about this key already.
- assert(HaveKey(key_id) || mapWatchKeys.count(key_id));
// This adds the redeemscripts necessary to detect P2WPKH and P2SH-P2WPKH
// outputs. Technically P2WPKH outputs don't have a redeemscript to be
// spent. However, our current IsMine logic requires the corresponding
@@ -32,23 +92,17 @@ void CBasicKeyStore::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey)
}
}
-bool CBasicKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
+bool FillableSigningProvider::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
{
CKey key;
if (!GetKey(address, key)) {
- LOCK(cs_KeyStore);
- WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
- if (it != mapWatchKeys.end()) {
- vchPubKeyOut = it->second;
- return true;
- }
return false;
}
vchPubKeyOut = key.GetPubKey();
return true;
}
-bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
+bool FillableSigningProvider::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{
LOCK(cs_KeyStore);
mapKeys[pubkey.GetID()] = key;
@@ -56,13 +110,13 @@ bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
return true;
}
-bool CBasicKeyStore::HaveKey(const CKeyID &address) const
+bool FillableSigningProvider::HaveKey(const CKeyID &address) const
{
LOCK(cs_KeyStore);
return mapKeys.count(address) > 0;
}
-std::set<CKeyID> CBasicKeyStore::GetKeys() const
+std::set<CKeyID> FillableSigningProvider::GetKeys() const
{
LOCK(cs_KeyStore);
std::set<CKeyID> set_address;
@@ -72,7 +126,7 @@ std::set<CKeyID> CBasicKeyStore::GetKeys() const
return set_address;
}
-bool CBasicKeyStore::GetKey(const CKeyID &address, CKey &keyOut) const
+bool FillableSigningProvider::GetKey(const CKeyID &address, CKey &keyOut) const
{
LOCK(cs_KeyStore);
KeyMap::const_iterator mi = mapKeys.find(address);
@@ -83,23 +137,23 @@ bool CBasicKeyStore::GetKey(const CKeyID &address, CKey &keyOut) const
return false;
}
-bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
+bool FillableSigningProvider::AddCScript(const CScript& redeemScript)
{
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
- return error("CBasicKeyStore::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
+ return error("FillableSigningProvider::AddCScript(): redeemScripts > %i bytes are invalid", MAX_SCRIPT_ELEMENT_SIZE);
LOCK(cs_KeyStore);
mapScripts[CScriptID(redeemScript)] = redeemScript;
return true;
}
-bool CBasicKeyStore::HaveCScript(const CScriptID& hash) const
+bool FillableSigningProvider::HaveCScript(const CScriptID& hash) const
{
LOCK(cs_KeyStore);
return mapScripts.count(hash) > 0;
}
-std::set<CScriptID> CBasicKeyStore::GetCScripts() const
+std::set<CScriptID> FillableSigningProvider::GetCScripts() const
{
LOCK(cs_KeyStore);
std::set<CScriptID> set_script;
@@ -109,7 +163,7 @@ std::set<CScriptID> CBasicKeyStore::GetCScripts() const
return set_script;
}
-bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
+bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const
{
LOCK(cs_KeyStore);
ScriptMap::const_iterator mi = mapScripts.find(hash);
@@ -121,60 +175,7 @@ bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut)
return false;
}
-static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
-{
- //TODO: Use Solver to extract this?
- CScript::const_iterator pc = dest.begin();
- opcodetype opcode;
- std::vector<unsigned char> vch;
- if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch))
- return false;
- pubKeyOut = CPubKey(vch);
- if (!pubKeyOut.IsFullyValid())
- return false;
- if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch))
- return false;
- return true;
-}
-
-bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
-{
- LOCK(cs_KeyStore);
- setWatchOnly.insert(dest);
- CPubKey pubKey;
- if (ExtractPubKey(dest, pubKey)) {
- mapWatchKeys[pubKey.GetID()] = pubKey;
- ImplicitlyLearnRelatedKeyScripts(pubKey);
- }
- return true;
-}
-
-bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest)
-{
- LOCK(cs_KeyStore);
- setWatchOnly.erase(dest);
- CPubKey pubKey;
- if (ExtractPubKey(dest, pubKey)) {
- mapWatchKeys.erase(pubKey.GetID());
- }
- // Related CScripts are not removed; having superfluous scripts around is
- // harmless (see comment in ImplicitlyLearnRelatedKeyScripts).
- return true;
-}
-
-bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
-{
- LOCK(cs_KeyStore);
- return setWatchOnly.count(dest) > 0;
-}
-
-bool CBasicKeyStore::HaveWatchOnly() const
-{
- LOCK(cs_KeyStore);
- return (!setWatchOnly.empty());
-}
-
-CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest)
+CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest)
{
// Only supports destinations which map to single public keys, i.e. P2PKH,
// P2WPKH, and P2SH-P2WPKH.
@@ -196,10 +197,3 @@ CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest)
}
return CKeyID();
}
-
-bool HaveKey(const CKeyStore& store, const CKey& key)
-{
- CKey key2;
- key2.Set(key.begin(), key.end(), !key.IsCompressed());
- return store.HaveKey(key.GetPubKey().GetID()) || store.HaveKey(key2.GetPubKey().GetID());
-}
diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h
new file mode 100644
index 0000000000..4eec2311d4
--- /dev/null
+++ b/src/script/signingprovider.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_SCRIPT_SIGNINGPROVIDER_H
+#define BITCOIN_SCRIPT_SIGNINGPROVIDER_H
+
+#include <key.h>
+#include <pubkey.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <sync.h>
+
+struct KeyOriginInfo;
+
+/** An interface to be implemented by keystores that support signing. */
+class SigningProvider
+{
+public:
+ virtual ~SigningProvider() {}
+ virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
+ virtual bool HaveCScript(const CScriptID &scriptid) 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 HaveKey(const CKeyID &address) const { return false; }
+ virtual bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return false; }
+};
+
+extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
+
+class HidingSigningProvider : public SigningProvider
+{
+private:
+ const bool m_hide_secret;
+ const bool m_hide_origin;
+ const SigningProvider* m_provider;
+
+public:
+ HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {}
+ bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
+ bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
+ bool GetKey(const CKeyID& keyid, CKey& key) const override;
+ bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
+};
+
+struct FlatSigningProvider final : public SigningProvider
+{
+ std::map<CScriptID, CScript> scripts;
+ std::map<CKeyID, CPubKey> pubkeys;
+ std::map<CKeyID, std::pair<CPubKey, 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;
+};
+
+FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b);
+
+/** Fillable signing provider that keeps keys in an address->secret map */
+class FillableSigningProvider : public SigningProvider
+{
+protected:
+ mutable CCriticalSection cs_KeyStore;
+
+ using KeyMap = std::map<CKeyID, CKey>;
+ using ScriptMap = std::map<CScriptID, CScript>;
+
+ KeyMap mapKeys GUARDED_BY(cs_KeyStore);
+ ScriptMap mapScripts GUARDED_BY(cs_KeyStore);
+
+ void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
+
+public:
+ virtual bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
+ virtual bool AddKey(const CKey &key) { return AddKeyPubKey(key, key.GetPubKey()); }
+ virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
+ virtual bool HaveKey(const CKeyID &address) const override;
+ virtual std::set<CKeyID> GetKeys() const;
+ virtual bool GetKey(const CKeyID &address, CKey &keyOut) const override;
+ virtual bool AddCScript(const CScript& redeemScript);
+ virtual bool HaveCScript(const CScriptID &hash) const override;
+ virtual std::set<CScriptID> GetCScripts() const;
+ virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
+};
+
+/** Return the CKeyID of the key involved in a script (if there is a unique one). */
+CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest);
+
+#endif // BITCOIN_SCRIPT_SIGNINGPROVIDER_H
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index b7d6cd925c..fc6898f444 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -9,7 +9,6 @@
#include <pubkey.h>
#include <script/script.h>
-
typedef std::vector<unsigned char> valtype;
bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index eeb54b4cf0..da0abd495a 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -533,9 +533,6 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
BOOST_CHECK(addrman.size() == 0);
// Empty addrman should return blank addrman info.
@@ -568,9 +565,6 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
// Add twenty two addresses.
CNetAddr source = ResolveIP("252.2.2.2");
for (unsigned int i = 1; i < 23; i++) {
@@ -627,9 +621,6 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
{
CAddrManTest addrman;
- // Set addrman addr placement to be deterministic.
- addrman.MakeDeterministic();
-
BOOST_CHECK(addrman.size() == 0);
// Empty addrman should return blank addrman info.
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 4e2acca4c3..4ac12bf969 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -4,6 +4,7 @@
#include <crypto/aes.h>
#include <crypto/chacha20.h>
+#include <crypto/chacha_poly_aead.h>
#include <crypto/poly1305.h>
#include <crypto/hkdf_sha256_32.h>
#include <crypto/hmac_sha256.h>
@@ -585,6 +586,131 @@ BOOST_AUTO_TEST_CASE(hkdf_hmac_sha256_l32_tests)
"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d");
}
+static void TestChaCha20Poly1305AEAD(bool must_succeed, unsigned int expected_aad_length, const std::string& hex_m, const std::string& hex_k1, const std::string& hex_k2, const std::string& hex_aad_keystream, const std::string& hex_encrypted_message, const std::string& hex_encrypted_message_seq_999)
+{
+ // we need two sequence numbers, one for the payload cipher instance...
+ uint32_t seqnr_payload = 0;
+ // ... and one for the AAD (length) cipher instance
+ uint32_t seqnr_aad = 0;
+ // we need to keep track of the position in the AAD cipher instance
+ // keystream since we use the same 64byte output 21 times
+ // (21 times 3 bytes length < 64)
+ int aad_pos = 0;
+
+ std::vector<unsigned char> aead_K_1 = ParseHex(hex_k1);
+ std::vector<unsigned char> aead_K_2 = ParseHex(hex_k2);
+ std::vector<unsigned char> plaintext_buf = ParseHex(hex_m);
+ std::vector<unsigned char> expected_aad_keystream = ParseHex(hex_aad_keystream);
+ std::vector<unsigned char> expected_ciphertext_and_mac = ParseHex(hex_encrypted_message);
+ std::vector<unsigned char> expected_ciphertext_and_mac_sequence999 = ParseHex(hex_encrypted_message_seq_999);
+
+ std::vector<unsigned char> ciphertext_buf(plaintext_buf.size() + POLY1305_TAGLEN, 0);
+ std::vector<unsigned char> plaintext_buf_new(plaintext_buf.size(), 0);
+ std::vector<unsigned char> cmp_ctx_buffer(64);
+ uint32_t out_len = 0;
+
+ // create the AEAD instance
+ ChaCha20Poly1305AEAD aead(aead_K_1.data(), aead_K_1.size(), aead_K_2.data(), aead_K_2.size());
+
+ // create a chacha20 instance to compare against
+ ChaCha20 cmp_ctx(aead_K_2.data(), 32);
+
+ // encipher
+ bool res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, ciphertext_buf.data(), ciphertext_buf.size(), plaintext_buf.data(), plaintext_buf.size(), true);
+ // make sure the operation succeeded if expected to succeed
+ BOOST_CHECK_EQUAL(res, must_succeed);
+ if (!res) return;
+
+ // verify ciphertext & mac against the test vector
+ BOOST_CHECK_EQUAL(expected_ciphertext_and_mac.size(), ciphertext_buf.size());
+ BOOST_CHECK(memcmp(ciphertext_buf.data(), expected_ciphertext_and_mac.data(), ciphertext_buf.size()) == 0);
+
+ // manually construct the AAD keystream
+ cmp_ctx.SetIV(seqnr_aad);
+ cmp_ctx.Seek(0);
+ cmp_ctx.Keystream(cmp_ctx_buffer.data(), 64);
+ BOOST_CHECK(memcmp(expected_aad_keystream.data(), cmp_ctx_buffer.data(), expected_aad_keystream.size()) == 0);
+ // crypt the 3 length bytes and compare the length
+ uint32_t len_cmp = 0;
+ len_cmp = (ciphertext_buf[0] ^ cmp_ctx_buffer[aad_pos + 0]) |
+ (ciphertext_buf[1] ^ cmp_ctx_buffer[aad_pos + 1]) << 8 |
+ (ciphertext_buf[2] ^ cmp_ctx_buffer[aad_pos + 2]) << 16;
+ BOOST_CHECK_EQUAL(len_cmp, expected_aad_length);
+
+ // encrypt / decrypt 1000 packets
+ for (size_t i = 0; i < 1000; ++i) {
+ res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, ciphertext_buf.data(), ciphertext_buf.size(), plaintext_buf.data(), plaintext_buf.size(), true);
+ BOOST_CHECK(res);
+ BOOST_CHECK(aead.GetLength(&out_len, seqnr_aad, aad_pos, ciphertext_buf.data()));
+ BOOST_CHECK_EQUAL(out_len, expected_aad_length);
+ res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, plaintext_buf_new.data(), plaintext_buf_new.size(), ciphertext_buf.data(), ciphertext_buf.size(), false);
+ BOOST_CHECK(res);
+
+ // make sure we repetitive get the same plaintext
+ BOOST_CHECK(memcmp(plaintext_buf.data(), plaintext_buf_new.data(), plaintext_buf.size()) == 0);
+
+ // compare sequence number 999 against the test vector
+ if (seqnr_payload == 999) {
+ BOOST_CHECK(memcmp(ciphertext_buf.data(), expected_ciphertext_and_mac_sequence999.data(), expected_ciphertext_and_mac_sequence999.size()) == 0);
+ }
+ // set nonce and block counter, output the keystream
+ cmp_ctx.SetIV(seqnr_aad);
+ cmp_ctx.Seek(0);
+ cmp_ctx.Keystream(cmp_ctx_buffer.data(), 64);
+
+ // crypt the 3 length bytes and compare the length
+ len_cmp = 0;
+ len_cmp = (ciphertext_buf[0] ^ cmp_ctx_buffer[aad_pos + 0]) |
+ (ciphertext_buf[1] ^ cmp_ctx_buffer[aad_pos + 1]) << 8 |
+ (ciphertext_buf[2] ^ cmp_ctx_buffer[aad_pos + 2]) << 16;
+ BOOST_CHECK_EQUAL(len_cmp, expected_aad_length);
+
+ // increment the sequence number(s)
+ // always increment the payload sequence number
+ // increment the AAD keystream position by its size (3)
+ // increment the AAD sequence number if we would hit the 64 byte limit
+ seqnr_payload++;
+ aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
+ if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
+ aad_pos = 0;
+ seqnr_aad++;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(chacha20_poly1305_aead_testvector)
+{
+ /* test chacha20poly1305@bitcoin AEAD */
+
+ // must fail with no message
+ TestChaCha20Poly1305AEAD(false, 0,
+ "",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000", "", "", "");
+
+ TestChaCha20Poly1305AEAD(true, 0,
+ /* m */ "0000000000000000000000000000000000000000000000000000000000000000",
+ /* k1 (payload) */ "0000000000000000000000000000000000000000000000000000000000000000",
+ /* k2 (AAD) */ "0000000000000000000000000000000000000000000000000000000000000000",
+ /* AAD keystream */ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586",
+ /* encrypted message & MAC */ "76b8e09f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32d2fc11829c1b6c1df1f551cd6131ff08",
+ /* encrypted message & MAC at sequence 999 */ "b0a03d5bd2855d60699e7d3a3133fa47be740fe4e4c1f967555e2d9271f31c3aaa7aa16ec62c5e24f040c08bb20c3598");
+ TestChaCha20Poly1305AEAD(true, 1,
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586",
+ "77b8e09f07e7be5551387a98ba977c732d080dcb0f29a048e3656912c6533e32baf0c85b6dff8602b06cf52a6aefc62e",
+ "b1a03d5bd2855d60699e7d3a3133fa47be740fe4e4c1f967555e2d9271f31c3a8bd94d54b5ecabbc41ffbb0c90924080");
+ TestChaCha20Poly1305AEAD(true, 255,
+ "ff0000f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c507b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab78fab78c9",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "ff0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "c640c1711e3ee904ac35c57ab9791c8a1c408603a90b77a83b54f6c844cb4b06d94e7fc6c800e165acd66147e80ec45a567f6ce66d05ec0cae679dceeb890017",
+ "3940c1e92da4582ff6f92a776aeb14d014d384eeb30f660dacf70a14a23fd31e91212701334e2ce1acf5199dc84f4d61ddbe6571bca5af874b4c9226c26e650995d157644e1848b96ed6c2102d5489a050e71d29a5a66ece11de5fb5c9558d54da28fe45b0bc4db4e5b88030bfc4a352b4b7068eccf656bae7ad6a35615315fc7c49d4200388d5eca67c2e822e069336c69b40db67e0f3c81209c50f3216a4b89fb3ae1b984b7851a2ec6f68ab12b101ab120e1ea7313bb93b5a0f71185c7fea017ddb92769861c29dba4fbc432280d5dff21b36d1c4c790128b22699950bb18bf74c448cdfe547d8ed4f657d8005fdc0cd7a050c2d46050a44c4376355858981fbe8b184288276e7a93eabc899c4a",
+ "f039c6689eaeef0456685200feaab9d54bbd9acde4410a3b6f4321296f4a8ca2604b49727d8892c57e005d799b2a38e85e809f20146e08eec75169691c8d4f54a0d51a1e1c7b381e0474eb02f994be9415ef3ffcbd2343f0601e1f3b172a1d494f838824e4df570f8e3b0c04e27966e36c82abd352d07054ef7bd36b84c63f9369afe7ed79b94f953873006b920c3fa251a771de1b63da927058ade119aa898b8c97e42a606b2f6df1e2d957c22f7593c1e2002f4252f4c9ae4bf773499e5cfcfe14dfc1ede26508953f88553bf4a76a802f6a0068d59295b01503fd9a600067624203e880fdf53933b96e1f4d9eb3f4e363dd8165a278ff667a41ee42b9892b077cefff92b93441f7be74cf10e6cd");
+}
+
BOOST_AUTO_TEST_CASE(countbits_tests)
{
FastRandomContext ctx;
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 93883d1d98..a50d6854f8 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -6,10 +6,11 @@
#include <banman.h>
#include <chainparams.h>
-#include <keystore.h>
#include <net.h>
#include <net_processing.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
+#include <script/standard.h>
#include <serialize.h>
#include <util/memory.h>
#include <util/system.h>
@@ -369,7 +370,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{
CKey key;
key.MakeNewKey(true);
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKey(key));
// 50 orphan transactions:
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 11e79937be..7c60abb93f 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -3,12 +3,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key.h>
-#include <keystore.h>
#include <policy/policy.h>
#include <script/script.h>
#include <script/script_error.h>
#include <script/interpreter.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <tinyformat.h>
#include <uint256.h>
#include <test/setup_common.h>
@@ -174,7 +174,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
BOOST_AUTO_TEST_CASE(multisig_Sign)
{
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CKey key[4];
for (int i = 0; i < 4; i++)
{
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index 735b67c06e..f451d80984 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -4,13 +4,13 @@
#include <consensus/tx_verify.h>
#include <key.h>
-#include <keystore.h>
#include <validation.h>
#include <policy/policy.h>
#include <script/script.h>
#include <script/script_error.h>
#include <policy/settings.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <test/setup_common.h>
#include <vector>
@@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(sign)
// scriptPubKey: HASH160 <hash> EQUAL
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CKey key[4];
for (int i = 0; i < 4; i++)
{
@@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE(set)
{
LOCK(cs_main);
// Test the CScript::Set* methods
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CKey key[4];
std::vector<CPubKey> keys;
for (int i = 0; i < 4; i++)
@@ -265,7 +265,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
LOCK(cs_main);
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CKey key[6];
std::vector<CPubKey> keys;
for (int i = 0; i < 6; i++)
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index 046b220e3f..412a57dd9d 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -3,8 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key.h>
-#include <keystore.h>
#include <script/script.h>
+#include <script/signingprovider.h>
#include <script/standard.h>
#include <test/setup_common.h>
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index ae903df0ad..84a70fe78b 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -6,10 +6,10 @@
#include <core_io.h>
#include <key.h>
-#include <keystore.h>
#include <script/script.h>
#include <script/script_error.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <test/setup_common.h>
@@ -1199,7 +1199,7 @@ SignatureData CombineSignatures(const CTxOut& txout, const CMutableTransaction&
BOOST_AUTO_TEST_CASE(script_combineSigs)
{
// Test the ProduceSignature's ability to combine signatures function
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
std::vector<CKey> keys;
std::vector<CPubKey> pubkeys;
for (int i = 0; i < 3; i++)
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index f77b77a972..34192c6b6a 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -12,12 +12,12 @@
#include <consensus/validation.h>
#include <core_io.h>
#include <key.h>
-#include <keystore.h>
#include <validation.h>
#include <policy/policy.h>
#include <policy/settings.h>
#include <script/script.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <script/script_error.h>
#include <script/standard.h>
#include <streams.h>
@@ -289,7 +289,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
// paid to a TX_PUBKEYHASH.
//
static std::vector<CMutableTransaction>
-SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
+SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet)
{
std::vector<CMutableTransaction> dummyTransactions;
dummyTransactions.resize(2);
@@ -322,7 +322,7 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
BOOST_AUTO_TEST_CASE(test_Get)
{
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
@@ -346,7 +346,7 @@ BOOST_AUTO_TEST_CASE(test_Get)
BOOST_CHECK_EQUAL(coins.GetValueIn(CTransaction(t1)), (50+21+22)*CENT);
}
-static void CreateCreditAndSpend(const CKeyStore& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true)
+static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true)
{
CMutableTransaction outputm;
outputm.nVersion = 1;
@@ -423,7 +423,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
CKey key;
key.MakeNewKey(true); // Need to use compressed keys in segwit or the signing will fail
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKeyPubKey(key, key.GetPubKey()));
CKeyID hash = key.GetPubKey().GetID();
CScript scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(hash.begin(), hash.end());
@@ -507,7 +507,7 @@ SignatureData CombineSignatures(const CMutableTransaction& input1, const CMutabl
BOOST_AUTO_TEST_CASE(test_witness)
{
- CBasicKeyStore keystore, keystore2;
+ FillableSigningProvider keystore, keystore2;
CKey key1, key2, key3, key1L, key2L;
CPubKey pubkey1, pubkey2, pubkey3, pubkey1L, pubkey2L;
key1.MakeNewKey(true);
@@ -682,7 +682,7 @@ BOOST_AUTO_TEST_CASE(test_witness)
BOOST_AUTO_TEST_CASE(test_IsStandard)
{
LOCK(cs_main);
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 45c97fa2aa..f99a3748c9 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -8,8 +8,8 @@
#include <txmempool.h>
#include <script/standard.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <test/setup_common.h>
-#include <keystore.h>
#include <boost/test/unit_test.hpp>
@@ -161,7 +161,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
CScript p2wpkh_scriptPubKey = GetScriptForWitness(p2pkh_scriptPubKey);
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKey(coinbaseKey));
BOOST_CHECK(keystore.AddCScript(p2pk_scriptPubKey));
diff --git a/src/test/util.cpp b/src/test/util.cpp
index a2ea648324..b7bb6deeaa 100644
--- a/src/test/util.cpp
+++ b/src/test/util.cpp
@@ -23,14 +23,9 @@ const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqq
std::string getnewaddress(CWallet& w)
{
constexpr auto output_type = OutputType::BECH32;
-
- CPubKey new_key;
- if (!w.GetKeyFromPool(new_key)) assert(false);
-
- w.LearnRelatedScripts(new_key, output_type);
- const auto dest = GetDestinationForKey(new_key, output_type);
-
- w.SetAddressBook(dest, /* label */ "", "receive");
+ CTxDestination dest;
+ std::string error;
+ if (!w.GetNewDestination(output_type, "", dest, error)) assert(false);
return EncodeDestination(dest);
}
diff --git a/src/timedata.cpp b/src/timedata.cpp
index b43639d729..f4613eeec8 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -100,7 +100,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
if (!fMatch)
{
fDone = true;
- std::string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), _(PACKAGE_NAME));
+ std::string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), PACKAGE_NAME);
SetMiscWarning(strMessage);
uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
}
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index a1c730ba08..3f40785c21 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -759,7 +759,9 @@ void InterruptTorControl()
{
if (gBase) {
LogPrintf("tor: Thread interrupt\n");
- event_base_loopbreak(gBase);
+ event_base_once(gBase, -1, EV_TIMEOUT, [](evutil_socket_t, short, void*) {
+ event_base_loopbreak(gBase);
+ }, nullptr, nullptr);
}
}
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 73fe2a8ee4..90b92969b9 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -250,7 +250,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
- // Load mapBlockIndex
+ // Load m_block_index
while (pcursor->Valid()) {
boost::this_thread::interruption_point();
if (ShutdownRequested()) return false;
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 61b81d51eb..72b37b9187 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -1184,10 +1184,11 @@ int GetNumCores()
std::string CopyrightHolders(const std::string& strPrefix)
{
- std::string strCopyrightHolders = strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION));
+ const auto copyright_devs = strprintf(_(COPYRIGHT_HOLDERS), COPYRIGHT_HOLDERS_SUBSTITUTION);
+ std::string strCopyrightHolders = strPrefix + copyright_devs;
- // Check for untranslated substitution to make sure Bitcoin Core copyright is not removed by accident
- if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Bitcoin Core") == std::string::npos) {
+ // Make sure Bitcoin Core copyright is not removed by accident
+ if (copyright_devs.find("Bitcoin Core") == std::string::npos) {
strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers";
}
return strCopyrightHolders;
diff --git a/src/validation.cpp b/src/validation.cpp
index 262b6856a4..f585bc7d2d 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -77,7 +77,11 @@ bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIn
return false;
}
-static CChainState g_chainstate;
+namespace {
+BlockManager g_blockman;
+} // anon namespace
+
+static CChainState g_chainstate(g_blockman);
CChainState& ChainstateActive() { return g_chainstate; }
@@ -95,7 +99,6 @@ CChain& ChainActive() { return g_chainstate.m_chain; }
*/
RecursiveMutex cs_main;
-BlockMap& mapBlockIndex = ::ChainstateActive().mapBlockIndex;
CBlockIndex *pindexBestHeader = nullptr;
Mutex g_best_block_mutex;
std::condition_variable g_best_block_cv;
@@ -125,12 +128,7 @@ CScript COINBASE_FLAGS;
// Internal stuff
namespace {
- CBlockIndex *&pindexBestInvalid = ::ChainstateActive().pindexBestInvalid;
-
- /** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
- * Pruned nodes may have entries where B is missing data.
- */
- std::multimap<CBlockIndex*, CBlockIndex*>& mapBlocksUnlinked = ::ChainstateActive().mapBlocksUnlinked;
+ CBlockIndex* pindexBestInvalid = nullptr;
CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile;
@@ -148,6 +146,13 @@ namespace {
std::set<int> setDirtyFileInfo;
} // anon namespace
+CBlockIndex* LookupBlockIndex(const uint256& hash)
+{
+ AssertLockHeld(cs_main);
+ BlockMap::const_iterator it = g_blockman.m_block_index.find(hash);
+ return it == g_blockman.m_block_index.end() ? nullptr : it->second;
+}
+
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
{
AssertLockHeld(cs_main);
@@ -611,7 +616,21 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
size_t nLimitDescendantSize = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;
std::string errString;
if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
- return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString);
+ setAncestors.clear();
+ // If the new transaction is relatively small (up to 40k weight)
+ // and has at most one ancestor (ie ancestor limit of 2, including
+ // the new transaction), allow it if its parent has exactly the
+ // descendant limit descendants.
+ //
+ // This allows protocols which rely on distrusting counterparties
+ // being able to broadcast descendants of an unconfirmed transaction
+ // to be secure by simply only having two immediately-spendable
+ // outputs - one for each counterparty. For more info on the uses for
+ // this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html
+ if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT ||
+ !pool.CalculateMemPoolAncestors(entry, setAncestors, 2, nLimitAncestorSize, nLimitDescendants + 1, nLimitDescendantSize + EXTRA_DESCENDANT_TX_SIZE_LIMIT, errString)) {
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString);
+ }
}
// A transaction that spends outputs that would be replaced by it is invalid. Now
@@ -1047,6 +1066,11 @@ bool CChainState::IsInitialBlockDownload() const
static CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr;
+BlockMap& BlockIndex()
+{
+ return g_blockman.m_block_index;
+}
+
static void AlertNotify(const std::string& strMessage)
{
uiInterface.NotifyAlertChanged();
@@ -1160,7 +1184,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(c
void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
if (state.GetReason() != ValidationInvalidReason::BLOCK_MUTATED) {
pindex->nStatus |= BLOCK_FAILED_VALID;
- m_failed_blocks.insert(pindex);
+ m_blockman.m_failed_blocks.insert(pindex);
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
InvalidChainFound(pindex);
@@ -1695,8 +1719,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// relative to a piece of software is an objective fact these defaults can be easily reviewed.
// This setting doesn't force the selection of any particular chain but makes validating some faster by
// effectively caching the result of part of the verification.
- BlockMap::const_iterator it = mapBlockIndex.find(hashAssumeValid);
- if (it != mapBlockIndex.end()) {
+ BlockMap::const_iterator it = m_blockman.m_block_index.find(hashAssumeValid);
+ if (it != m_blockman.m_block_index.end()) {
if (it->second->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->nChainWork >= nMinimumChainWork) {
@@ -2366,10 +2390,11 @@ CBlockIndex* CChainState::FindMostWorkChain() {
if (fFailedChain) {
pindexFailed->nStatus |= BLOCK_FAILED_CHILD;
} else if (fMissingData) {
- // If we're missing data, then add back to mapBlocksUnlinked,
+ // If we're missing data, then add back to m_blocks_unlinked,
// so that if the block arrives in the future we can try adding
// to setBlockIndexCandidates again.
- mapBlocksUnlinked.insert(std::make_pair(pindexFailed->pprev, pindexFailed));
+ m_blockman.m_blocks_unlinked.insert(
+ std::make_pair(pindexFailed->pprev, pindexFailed));
}
setBlockIndexCandidates.erase(pindexFailed);
pindexFailed = pindexFailed->pprev;
@@ -2720,12 +2745,12 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
to_mark_failed->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(to_mark_failed);
setBlockIndexCandidates.erase(to_mark_failed);
- m_failed_blocks.insert(to_mark_failed);
+ m_blockman.m_failed_blocks.insert(to_mark_failed);
// The resulting new best tip may not be in setBlockIndexCandidates anymore, so
// add it again.
- BlockMap::iterator it = mapBlockIndex.begin();
- while (it != mapBlockIndex.end()) {
+ BlockMap::iterator it = m_blockman.m_block_index.begin();
+ while (it != m_blockman.m_block_index.end()) {
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, m_chain.Tip())) {
setBlockIndexCandidates.insert(it->second);
}
@@ -2752,8 +2777,8 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
int nHeight = pindex->nHeight;
// Remove the invalidity flag from this block and all its descendants.
- BlockMap::iterator it = mapBlockIndex.begin();
- while (it != mapBlockIndex.end()) {
+ BlockMap::iterator it = m_blockman.m_block_index.begin();
+ while (it != m_blockman.m_block_index.end()) {
if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) {
it->second->nStatus &= ~BLOCK_FAILED_MASK;
setDirtyBlockIndex.insert(it->second);
@@ -2764,7 +2789,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
// Reset invalid block marker if it was pointing to one of those.
pindexBestInvalid = nullptr;
}
- m_failed_blocks.erase(it->second);
+ m_blockman.m_failed_blocks.erase(it->second);
}
it++;
}
@@ -2774,7 +2799,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
if (pindex->nStatus & BLOCK_FAILED_MASK) {
pindex->nStatus &= ~BLOCK_FAILED_MASK;
setDirtyBlockIndex.insert(pindex);
- m_failed_blocks.erase(pindex);
+ m_blockman.m_failed_blocks.erase(pindex);
}
pindex = pindex->pprev;
}
@@ -2784,14 +2809,14 @@ void ResetBlockFailureFlags(CBlockIndex *pindex) {
return ::ChainstateActive().ResetBlockFailureFlags(pindex);
}
-CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
+CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block)
{
AssertLockHeld(cs_main);
// Check for duplicate
uint256 hash = block.GetHash();
- BlockMap::iterator it = mapBlockIndex.find(hash);
- if (it != mapBlockIndex.end())
+ BlockMap::iterator it = m_block_index.find(hash);
+ if (it != m_block_index.end())
return it->second;
// Construct new block index object
@@ -2800,10 +2825,10 @@ CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
// to avoid miners withholding blocks but broadcasting headers, to get a
// competitive advantage.
pindexNew->nSequenceId = 0;
- BlockMap::iterator mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first;
+ BlockMap::iterator mi = m_block_index.insert(std::make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
- BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock);
- if (miPrev != mapBlockIndex.end())
+ BlockMap::iterator miPrev = m_block_index.find(block.hashPrevBlock);
+ if (miPrev != m_block_index.end())
{
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
@@ -2852,17 +2877,17 @@ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pi
if (m_chain.Tip() == nullptr || !setBlockIndexCandidates.value_comp()(pindex, m_chain.Tip())) {
setBlockIndexCandidates.insert(pindex);
}
- std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex);
+ std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = m_blockman.m_blocks_unlinked.equal_range(pindex);
while (range.first != range.second) {
std::multimap<CBlockIndex*, CBlockIndex*>::iterator it = range.first;
queue.push_back(it->second);
range.first++;
- mapBlocksUnlinked.erase(it);
+ m_blockman.m_blocks_unlinked.erase(it);
}
}
} else {
if (pindexNew->pprev && pindexNew->pprev->IsValid(BLOCK_VALID_TREE)) {
- mapBlocksUnlinked.insert(std::make_pair(pindexNew->pprev, pindexNew));
+ m_blockman.m_blocks_unlinked.insert(std::make_pair(pindexNew->pprev, pindexNew));
}
}
}
@@ -3117,7 +3142,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
if (fCheckpointsEnabled) {
// Don't accept any forks from the main chain prior to last checkpoint.
// GetLastCheckpoint finds the last checkpoint in MapCheckpoints that's in our
- // MapBlockIndex.
+ // g_blockman.m_block_index.
CBlockIndex* pcheckpoint = GetLastCheckpoint(params.Checkpoints());
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint");
@@ -3230,15 +3255,15 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
return true;
}
-bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
+bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
{
AssertLockHeld(cs_main);
// Check for duplicate
uint256 hash = block.GetHash();
- BlockMap::iterator miSelf = mapBlockIndex.find(hash);
+ BlockMap::iterator miSelf = m_block_index.find(hash);
CBlockIndex *pindex = nullptr;
if (hash != chainparams.GetConsensus().hashGenesisBlock) {
- if (miSelf != mapBlockIndex.end()) {
+ if (miSelf != m_block_index.end()) {
// Block header is already known.
pindex = miSelf->second;
if (ppindex)
@@ -3253,8 +3278,8 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
// Get prev block index
CBlockIndex* pindexPrev = nullptr;
- BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
- if (mi == mapBlockIndex.end())
+ BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock);
+ if (mi == m_block_index.end())
return state.Invalid(ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), 0, "prev-blk-not-found");
pindexPrev = (*mi).second;
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
@@ -3306,8 +3331,6 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
if (ppindex)
*ppindex = pindex;
- CheckBlockIndex(chainparams.GetConsensus());
-
return true;
}
@@ -3319,7 +3342,10 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
LOCK(cs_main);
for (const CBlockHeader& header : headers) {
CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
- if (!::ChainstateActive().AcceptBlockHeader(header, state, chainparams, &pindex)) {
+ bool accepted = g_blockman.AcceptBlockHeader(header, state, chainparams, &pindex);
+ ::ChainstateActive().CheckBlockIndex(chainparams.GetConsensus());
+
+ if (!accepted) {
if (first_invalid) *first_invalid = header;
return false;
}
@@ -3362,7 +3388,10 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
CBlockIndex *pindexDummy = nullptr;
CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy;
- if (!AcceptBlockHeader(block, state, chainparams, &pindex))
+ bool accepted_header = m_blockman.AcceptBlockHeader(block, state, chainparams, &pindex);
+ CheckBlockIndex(chainparams.GetConsensus());
+
+ if (!accepted_header)
return false;
// Try to process all requested blocks that we don't have, but only
@@ -3513,7 +3542,7 @@ void PruneOneBlockFile(const int fileNumber)
{
LOCK(cs_LastBlockFile);
- for (const auto& entry : mapBlockIndex) {
+ for (const auto& entry : g_blockman.m_block_index) {
CBlockIndex* pindex = entry.second;
if (pindex->nFile == fileNumber) {
pindex->nStatus &= ~BLOCK_HAVE_DATA;
@@ -3523,16 +3552,16 @@ void PruneOneBlockFile(const int fileNumber)
pindex->nUndoPos = 0;
setDirtyBlockIndex.insert(pindex);
- // Prune from mapBlocksUnlinked -- any block we prune would have
+ // Prune from m_blocks_unlinked -- any block we prune would have
// to be downloaded again in order to consider its chain, at which
// point it would be considered as a candidate for
- // mapBlocksUnlinked or setBlockIndexCandidates.
- std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex->pprev);
+ // m_blocks_unlinked or setBlockIndexCandidates.
+ auto range = g_blockman.m_blocks_unlinked.equal_range(pindex->pprev);
while (range.first != range.second) {
std::multimap<CBlockIndex *, CBlockIndex *>::iterator _it = range.first;
range.first++;
if (_it->second == pindex) {
- mapBlocksUnlinked.erase(_it);
+ g_blockman.m_blocks_unlinked.erase(_it);
}
}
}
@@ -3681,7 +3710,7 @@ fs::path GetBlockPosFilename(const FlatFilePos &pos)
return BlockFileSeq().FileName(pos);
}
-CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash)
+CBlockIndex * BlockManager::InsertBlockIndex(const uint256& hash)
{
AssertLockHeld(cs_main);
@@ -3689,27 +3718,30 @@ CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash)
return nullptr;
// Return existing
- BlockMap::iterator mi = mapBlockIndex.find(hash);
- if (mi != mapBlockIndex.end())
+ BlockMap::iterator mi = m_block_index.find(hash);
+ if (mi != m_block_index.end())
return (*mi).second;
// Create new
CBlockIndex* pindexNew = new CBlockIndex();
- mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first;
+ mi = m_block_index.insert(std::make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
return pindexNew;
}
-bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree)
+bool BlockManager::LoadBlockIndex(
+ const Consensus::Params& consensus_params,
+ CBlockTreeDB& blocktree,
+ std::set<CBlockIndex*, CBlockIndexWorkComparator>& block_index_candidates)
{
if (!blocktree.LoadBlockIndexGuts(consensus_params, [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); }))
return false;
// Calculate nChainWork
std::vector<std::pair<int, CBlockIndex*> > vSortedByHeight;
- vSortedByHeight.reserve(mapBlockIndex.size());
- for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex)
+ vSortedByHeight.reserve(m_block_index.size());
+ for (const std::pair<const uint256, CBlockIndex*>& item : m_block_index)
{
CBlockIndex* pindex = item.second;
vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex));
@@ -3729,7 +3761,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx;
} else {
pindex->nChainTx = 0;
- mapBlocksUnlinked.insert(std::make_pair(pindex->pprev, pindex));
+ m_blocks_unlinked.insert(std::make_pair(pindex->pprev, pindex));
}
} else {
pindex->nChainTx = pindex->nTx;
@@ -3739,8 +3771,9 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
pindex->nStatus |= BLOCK_FAILED_CHILD;
setDirtyBlockIndex.insert(pindex);
}
- if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))
- setBlockIndexCandidates.insert(pindex);
+ if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->HaveTxsDownloaded() || pindex->pprev == nullptr)) {
+ block_index_candidates.insert(pindex);
+ }
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))
pindexBestInvalid = pindex;
if (pindex->pprev)
@@ -3752,9 +3785,21 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
return true;
}
+void BlockManager::Unload() {
+ m_failed_blocks.clear();
+ m_blocks_unlinked.clear();
+
+ for (const BlockMap::value_type& entry : m_block_index) {
+ delete entry.second;
+ }
+
+ m_block_index.clear();
+}
+
bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- if (!::ChainstateActive().LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
+ if (!g_blockman.LoadBlockIndex(
+ chainparams.GetConsensus(), *pblocktree, ::ChainstateActive().setBlockIndexCandidates))
return false;
// Load block file info
@@ -3777,7 +3822,7 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_RE
// Check presence of blk files
LogPrintf("Checking all blk files are present...\n");
std::set<int> setBlkDataFiles;
- for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex)
+ for (const std::pair<const uint256, CBlockIndex*>& item : g_blockman.m_block_index)
{
CBlockIndex* pindex = item.second;
if (pindex->nStatus & BLOCK_HAVE_DATA) {
@@ -3976,16 +4021,16 @@ bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view)
const CBlockIndex* pindexNew; // New tip during the interrupted flush.
const CBlockIndex* pindexFork = nullptr; // Latest block common to both the old and the new tip.
- if (mapBlockIndex.count(hashHeads[0]) == 0) {
+ if (m_blockman.m_block_index.count(hashHeads[0]) == 0) {
return error("ReplayBlocks(): reorganization to unknown block requested");
}
- pindexNew = mapBlockIndex[hashHeads[0]];
+ pindexNew = m_blockman.m_block_index[hashHeads[0]];
if (!hashHeads[1].IsNull()) { // The old tip is allowed to be 0, indicating it's the first flush.
- if (mapBlockIndex.count(hashHeads[1]) == 0) {
+ if (m_blockman.m_block_index.count(hashHeads[1]) == 0) {
return error("ReplayBlocks(): reorganization from unknown block requested");
}
- pindexOld = mapBlockIndex[hashHeads[1]];
+ pindexOld = m_blockman.m_block_index[hashHeads[1]];
pindexFork = LastCommonAncestor(pindexOld, pindexNew);
assert(pindexFork != nullptr);
}
@@ -4051,10 +4096,10 @@ void CChainState::EraseBlockData(CBlockIndex* index)
setDirtyBlockIndex.insert(index);
// Update indexes
setBlockIndexCandidates.erase(index);
- std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> ret = mapBlocksUnlinked.equal_range(index->pprev);
+ auto ret = m_blockman.m_blocks_unlinked.equal_range(index->pprev);
while (ret.first != ret.second) {
if (ret.first->second == index) {
- mapBlocksUnlinked.erase(ret.first++);
+ m_blockman.m_blocks_unlinked.erase(ret.first++);
} else {
++ret.first;
}
@@ -4074,7 +4119,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
// blocks will be dealt with below (releasing cs_main in between).
{
LOCK(cs_main);
- for (const auto& entry : mapBlockIndex) {
+ for (const auto& entry : m_blockman.m_block_index) {
if (IsWitnessEnabled(entry.second->pprev, params.GetConsensus()) && !(entry.second->nStatus & BLOCK_OPT_WITNESS) && !m_chain.Contains(entry.second)) {
EraseBlockData(entry.second);
}
@@ -4180,7 +4225,6 @@ bool RewindBlockIndex(const CChainParams& params) {
void CChainState::UnloadBlockIndex() {
nBlockSequenceId = 1;
- m_failed_blocks.clear();
setBlockIndexCandidates.clear();
}
@@ -4191,10 +4235,10 @@ void UnloadBlockIndex()
{
LOCK(cs_main);
::ChainActive().SetTip(nullptr);
+ g_blockman.Unload();
pindexBestInvalid = nullptr;
pindexBestHeader = nullptr;
mempool.clear();
- mapBlocksUnlinked.clear();
vinfoBlockFile.clear();
nLastBlockFile = 0;
setDirtyBlockIndex.clear();
@@ -4203,11 +4247,6 @@ void UnloadBlockIndex()
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
warningcache[b].clear();
}
-
- for (const BlockMap::value_type& entry : mapBlockIndex) {
- delete entry.second;
- }
- mapBlockIndex.clear();
fHavePruned = false;
::ChainstateActive().UnloadBlockIndex();
@@ -4220,7 +4259,7 @@ bool LoadBlockIndex(const CChainParams& chainparams)
if (!fReindex) {
bool ret = LoadBlockIndexDB(chainparams);
if (!ret) return false;
- needs_init = mapBlockIndex.empty();
+ needs_init = g_blockman.m_block_index.empty();
}
if (needs_init) {
@@ -4240,10 +4279,10 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
LOCK(cs_main);
// Check whether we're already initialized by checking for genesis in
- // mapBlockIndex. Note that we can't use m_chain here, since it is
+ // m_blockman.m_block_index. Note that we can't use m_chain here, since it is
// set based on the coins db, not the block index db, which is the only
// thing loaded at this point.
- if (mapBlockIndex.count(chainparams.GenesisBlock().GetHash()))
+ if (m_blockman.m_block_index.count(chainparams.GenesisBlock().GetHash()))
return true;
try {
@@ -4251,7 +4290,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
FlatFilePos blockPos = SaveBlockToDisk(block, 0, chainparams, nullptr);
if (blockPos.IsNull())
return error("%s: writing genesis block to disk failed", __func__);
- CBlockIndex *pindex = AddToBlockIndex(block);
+ CBlockIndex *pindex = m_blockman.AddToBlockIndex(block);
ReceivedBlockTransactions(block, pindex, blockPos, chainparams.GetConsensus());
} catch (const std::runtime_error& e) {
return error("%s: failed to write genesis block: %s", __func__, e.what());
@@ -4396,20 +4435,20 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
LOCK(cs_main);
// During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain,
- // so we have the genesis block in mapBlockIndex but no active chain. (A few of the tests when
- // iterating the block tree require that m_chain has been initialized.)
+ // so we have the genesis block in m_blockman.m_block_index but no active chain. (A few of the
+ // tests when iterating the block tree require that m_chain has been initialized.)
if (m_chain.Height() < 0) {
- assert(mapBlockIndex.size() <= 1);
+ assert(m_blockman.m_block_index.size() <= 1);
return;
}
// Build forward-pointing map of the entire block tree.
std::multimap<CBlockIndex*,CBlockIndex*> forward;
- for (const std::pair<const uint256, CBlockIndex*>& entry : mapBlockIndex) {
+ for (const std::pair<const uint256, CBlockIndex*>& entry : m_blockman.m_block_index) {
forward.insert(std::make_pair(entry.second->pprev, entry.second));
}
- assert(forward.size() == mapBlockIndex.size());
+ assert(forward.size() == m_blockman.m_block_index.size());
std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeGenesis = forward.equal_range(nullptr);
CBlockIndex *pindex = rangeGenesis.first->second;
@@ -4463,7 +4502,7 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
assert(pindex->nHeight == nHeight); // nHeight must be consistent.
assert(pindex->pprev == nullptr || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's.
assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks.
- assert(pindexFirstNotTreeValid == nullptr); // All mapBlockIndex entries must at least be TREE valid
+ assert(pindexFirstNotTreeValid == nullptr); // All m_blockman.m_block_index entries must at least be TREE valid
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) assert(pindexFirstNotTreeValid == nullptr); // TREE valid implies all parents are TREE valid
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_CHAIN) assert(pindexFirstNotChainValid == nullptr); // CHAIN valid implies all parents are CHAIN valid
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) assert(pindexFirstNotScriptsValid == nullptr); // SCRIPTS valid implies all parents are SCRIPTS valid
@@ -4482,13 +4521,13 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
}
// If some parent is missing, then it could be that this block was in
// setBlockIndexCandidates but had to be removed because of the missing data.
- // In this case it must be in mapBlocksUnlinked -- see test below.
+ // In this case it must be in m_blocks_unlinked -- see test below.
}
} else { // If this block sorts worse than the current tip or some ancestor's block has never been seen, it cannot be in setBlockIndexCandidates.
assert(setBlockIndexCandidates.count(pindex) == 0);
}
- // Check whether this block is in mapBlocksUnlinked.
- std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeUnlinked = mapBlocksUnlinked.equal_range(pindex->pprev);
+ // Check whether this block is in m_blocks_unlinked.
+ std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeUnlinked = m_blockman.m_blocks_unlinked.equal_range(pindex->pprev);
bool foundInUnlinked = false;
while (rangeUnlinked.first != rangeUnlinked.second) {
assert(rangeUnlinked.first->first == pindex->pprev);
@@ -4499,22 +4538,22 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
rangeUnlinked.first++;
}
if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed != nullptr && pindexFirstInvalid == nullptr) {
- // If this block has block data available, some parent was never received, and has no invalid parents, it must be in mapBlocksUnlinked.
+ // If this block has block data available, some parent was never received, and has no invalid parents, it must be in m_blocks_unlinked.
assert(foundInUnlinked);
}
- if (!(pindex->nStatus & BLOCK_HAVE_DATA)) assert(!foundInUnlinked); // Can't be in mapBlocksUnlinked if we don't HAVE_DATA
- if (pindexFirstMissing == nullptr) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in mapBlocksUnlinked.
+ if (!(pindex->nStatus & BLOCK_HAVE_DATA)) assert(!foundInUnlinked); // Can't be in m_blocks_unlinked if we don't HAVE_DATA
+ if (pindexFirstMissing == nullptr) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in m_blocks_unlinked.
if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == nullptr && pindexFirstMissing != nullptr) {
// We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent.
assert(fHavePruned); // We must have pruned.
- // This block may have entered mapBlocksUnlinked if:
+ // This block may have entered m_blocks_unlinked if:
// - it has a descendant that at some point had more work than the
// tip, and
// - we tried switching to that descendant but were missing
// data for some intermediate block between m_chain and the
// tip.
// So if this block is itself better than m_chain.Tip() and it wasn't in
- // setBlockIndexCandidates, then it must be in mapBlocksUnlinked.
+ // setBlockIndexCandidates, then it must be in m_blocks_unlinked.
if (!CBlockIndexWorkComparator()(pindex, m_chain.Tip()) && setBlockIndexCandidates.count(pindex) == 0) {
if (pindexFirstInvalid == nullptr) {
assert(foundInUnlinked);
@@ -4758,10 +4797,10 @@ public:
CMainCleanup() {}
~CMainCleanup() {
// block headers
- BlockMap::iterator it1 = mapBlockIndex.begin();
- for (; it1 != mapBlockIndex.end(); it1++)
+ BlockMap::iterator it1 = g_blockman.m_block_index.begin();
+ for (; it1 != g_blockman.m_block_index.end(); it1++)
delete (*it1).second;
- mapBlockIndex.clear();
+ g_blockman.m_block_index.clear();
}
};
static CMainCleanup instance_of_cmaincleanup;
diff --git a/src/validation.h b/src/validation.h
index 9573d62048..d747fdbf27 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -64,6 +64,12 @@ static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 101;
static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25;
/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */
static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101;
+/**
+ * An extra transaction can be added to a package, as long as it only has one
+ * ancestor and is no larger than this. Not really any reason to make this
+ * configurable as it doesn't materially change DoS parameters.
+ */
+static const unsigned int EXTRA_DESCENDANT_TX_SIZE_LIMIT = 10000;
/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */
static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 336;
/** Maximum kilobytes for transactions to store for processing during reorg */
@@ -126,8 +132,6 @@ static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
/** Maximum number of unconnecting headers announcements before DoS score */
static const int MAX_UNCONNECTING_HEADERS = 10;
-static const bool DEFAULT_PEERBLOOMFILTERS = true;
-
/** Default for -stopatheight */
static const int DEFAULT_STOPATHEIGHT = 0;
@@ -144,7 +148,6 @@ extern CCriticalSection cs_main;
extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool;
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
-extern BlockMap& mapBlockIndex GUARDED_BY(cs_main);
extern Mutex g_best_block_mutex;
extern std::condition_variable g_best_block_cv;
extern uint256 g_best_block;
@@ -406,12 +409,7 @@ public:
/** Replay blocks that aren't fully applied to the database. */
bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
-inline CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
-{
- AssertLockHeld(cs_main);
- BlockMap::const_iterator it = mapBlockIndex.find(hash);
- return it == mapBlockIndex.end() ? nullptr : it->second;
-}
+CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Find the last common block between the parameter chain and a locator. */
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -439,27 +437,90 @@ struct CBlockIndexWorkComparator
};
/**
- * CChainState stores and provides an API to update our local knowledge of the
- * current best chain and header tree.
+ * Maintains a tree of blocks (stored in `m_block_index`) which is consulted
+ * to determine where the most-work tip is.
*
- * It generally provides access to the current block tree, as well as functions
- * to provide new data, which it will appropriately validate and incorporate in
- * its state as necessary.
+ * This data is used mostly in `CChainState` - information about, e.g.,
+ * candidate tips is not maintained here.
+ */
+class BlockManager {
+public:
+ BlockMap m_block_index GUARDED_BY(cs_main);
+
+ /** In order to efficiently track invalidity of headers, we keep the set of
+ * blocks which we tried to connect and found to be invalid here (ie which
+ * were set to BLOCK_FAILED_VALID since the last restart). We can then
+ * walk this set and check if a new header is a descendant of something in
+ * this set, preventing us from having to walk m_block_index when we try
+ * to connect a bad block and fail.
+ *
+ * While this is more complicated than marking everything which descends
+ * from an invalid block as invalid at the time we discover it to be
+ * invalid, doing so would require walking all of m_block_index to find all
+ * descendants. Since this case should be very rare, keeping track of all
+ * BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
+ * well.
+ *
+ * Because we already walk m_block_index in height-order at startup, we go
+ * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
+ * instead of putting things in this set.
+ */
+ std::set<CBlockIndex*> m_failed_blocks;
+
+ /**
+ * All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
+ * Pruned nodes may have entries where B is missing data.
+ */
+ std::multimap<CBlockIndex*, CBlockIndex*> m_blocks_unlinked;
+
+ /**
+ * Load the blocktree off disk and into memory. Populate certain metadata
+ * per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral
+ * collections like setDirtyBlockIndex.
+ *
+ * @param[out] block_index_candidates Fill this set with any valid blocks for
+ * which we've downloaded all transactions.
+ */
+ bool LoadBlockIndex(
+ const Consensus::Params& consensus_params,
+ CBlockTreeDB& blocktree,
+ std::set<CBlockIndex*, CBlockIndexWorkComparator>& block_index_candidates)
+ EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ /** Clear all data members. */
+ void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ /** Create a new block index entry for a given block hash */
+ CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ /**
+ * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
+ * that it doesn't descend from an invalid block, and then add it to m_block_index.
+ */
+ bool AcceptBlockHeader(
+ const CBlockHeader& block,
+ CValidationState& state,
+ const CChainParams& chainparams,
+ CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+};
+
+/**
+ * CChainState stores and provides an API to update our local knowledge of the
+ * current best chain.
*
* Eventually, the API here is targeted at being exposed externally as a
* consumable libconsensus library, so any functions added must only call
* other class member functions, pure functions in other parts of the consensus
* library, callbacks via the validation interface, or read/write-to-disk
* functions (eventually this will also be via callbacks).
+ *
+ * Anything that is contingent on the current tip of the chain is stored here,
+ * whereas block information and metadata independent of the current tip is
+ * kept in `BlockMetadataManager`.
*/
class CChainState {
private:
- /**
- * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
- * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
- * missing the data for the block.
- */
- std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
/**
* Every received block is assigned a unique and increasing identifier, so we
@@ -473,26 +534,6 @@ private:
/** chainwork for the last block that preciousblock has been applied to. */
arith_uint256 nLastPreciousChainwork = 0;
- /** In order to efficiently track invalidity of headers, we keep the set of
- * blocks which we tried to connect and found to be invalid here (ie which
- * were set to BLOCK_FAILED_VALID since the last restart). We can then
- * walk this set and check if a new header is a descendant of something in
- * this set, preventing us from having to walk mapBlockIndex when we try
- * to connect a bad block and fail.
- *
- * While this is more complicated than marking everything which descends
- * from an invalid block as invalid at the time we discover it to be
- * invalid, doing so would require walking all of mapBlockIndex to find all
- * descendants. Since this case should be very rare, keeping track of all
- * BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
- * well.
- *
- * Because we already walk mapBlockIndex in height-order at startup, we go
- * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
- * instead of putting things in this set.
- */
- std::set<CBlockIndex*> m_failed_blocks;
-
/**
* the ChainState CriticalSection
* A lock that must be held when modifying this ChainState - held in ActivateBestChain()
@@ -507,15 +548,23 @@ private:
*/
mutable std::atomic<bool> m_cached_finished_ibd{false};
+ //! Reference to a BlockManager instance which itself is shared across all
+ //! CChainState instances. Keeping a local reference allows us to test more
+ //! easily as opposed to referencing a global.
+ BlockManager& m_blockman;
+
public:
+ CChainState(BlockManager& blockman) : m_blockman(blockman) { }
+
//! The current chain of blockheaders we consult and build on.
//! @see CChain, CBlockIndex.
CChain m_chain;
- BlockMap mapBlockIndex GUARDED_BY(cs_main);
- std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
- CBlockIndex *pindexBestInvalid = nullptr;
-
- bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ /**
+ * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
+ * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
+ * missing the data for the block.
+ */
+ std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
/**
* Update the on-disk chain state.
@@ -541,11 +590,6 @@ public:
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) LOCKS_EXCLUDED(cs_main);
- /**
- * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
- * that it doesn't descend from an invalid block, and then add it to mapBlockIndex.
- */
- bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Block (dis)connection on a given view:
@@ -572,13 +616,6 @@ public:
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload() const;
-private:
- bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
- bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
-
- CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- /** Create a new block index entry for a given block hash */
- CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Make various assertions about the state of the block index.
*
@@ -586,6 +623,10 @@ private:
*/
void CheckBlockIndex(const Consensus::Params& consensusParams);
+private:
+ bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
+ bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
+
void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -615,6 +656,9 @@ CChainState& ChainstateActive();
/** @returns the most-work chain. */
CChain& ChainActive();
+/** @returns the global block index map. */
+BlockMap& BlockIndex();
+
/** Global variable that points to the coins database (protected by cs_main) */
extern std::unique_ptr<CCoinsViewDB> pcoinsdbview;
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index dd56ea10ab..0b76c1a0eb 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -107,8 +107,7 @@ bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingM
return true;
}
-
-static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
+bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
@@ -118,7 +117,7 @@ static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMateri
return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
}
-static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
+bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
{
CCrypter cKeyCrypter;
std::vector<unsigned char> chIV(WALLET_CRYPTO_IV_SIZE);
@@ -128,7 +127,7 @@ static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<u
return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
}
-static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
+bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
{
CKeyingMaterial vchSecret;
if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
@@ -140,188 +139,3 @@ static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsi
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
return key.VerifyPubKey(vchPubKey);
}
-
-bool CCryptoKeyStore::SetCrypted()
-{
- LOCK(cs_KeyStore);
- if (fUseCrypto)
- return true;
- if (!mapKeys.empty())
- return false;
- fUseCrypto = true;
- return true;
-}
-
-bool CCryptoKeyStore::IsLocked() const
-{
- if (!IsCrypted()) {
- return false;
- }
- LOCK(cs_KeyStore);
- return vMasterKey.empty();
-}
-
-bool CCryptoKeyStore::Lock()
-{
- if (!SetCrypted())
- return false;
-
- {
- LOCK(cs_KeyStore);
- vMasterKey.clear();
- }
-
- NotifyStatusChanged(this);
- return true;
-}
-
-bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
-{
- {
- LOCK(cs_KeyStore);
- if (!SetCrypted())
- return false;
-
- bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
- bool keyFail = false;
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
- for (; mi != mapCryptedKeys.end(); ++mi)
- {
- const CPubKey &vchPubKey = (*mi).second.first;
- const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- CKey key;
- if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
- {
- keyFail = true;
- break;
- }
- keyPass = true;
- if (fDecryptionThoroughlyChecked)
- break;
- }
- if (keyPass && keyFail)
- {
- LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
- throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
- }
- if (keyFail || (!keyPass && !accept_no_keys))
- return false;
- vMasterKey = vMasterKeyIn;
- fDecryptionThoroughlyChecked = true;
- }
- NotifyStatusChanged(this);
- return true;
-}
-
-bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
-{
- LOCK(cs_KeyStore);
- if (!IsCrypted()) {
- return CBasicKeyStore::AddKeyPubKey(key, pubkey);
- }
-
- if (IsLocked()) {
- return false;
- }
-
- std::vector<unsigned char> vchCryptedSecret;
- CKeyingMaterial vchSecret(key.begin(), key.end());
- if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
- return false;
- }
-
- if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
- return false;
- }
- return true;
-}
-
-
-bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
-{
- LOCK(cs_KeyStore);
- if (!SetCrypted()) {
- return false;
- }
-
- mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
- ImplicitlyLearnRelatedKeyScripts(vchPubKey);
- return true;
-}
-
-bool CCryptoKeyStore::HaveKey(const CKeyID &address) const
-{
- LOCK(cs_KeyStore);
- if (!IsCrypted()) {
- return CBasicKeyStore::HaveKey(address);
- }
- return mapCryptedKeys.count(address) > 0;
-}
-
-bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
-{
- LOCK(cs_KeyStore);
- if (!IsCrypted()) {
- return CBasicKeyStore::GetKey(address, keyOut);
- }
-
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
- if (mi != mapCryptedKeys.end())
- {
- const CPubKey &vchPubKey = (*mi).second.first;
- const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
- }
- return false;
-}
-
-bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
-{
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
-
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
- if (mi != mapCryptedKeys.end())
- {
- vchPubKeyOut = (*mi).second.first;
- return true;
- }
- // Check for watch-only pubkeys
- return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
-}
-
-std::set<CKeyID> CCryptoKeyStore::GetKeys() const
-{
- LOCK(cs_KeyStore);
- if (!IsCrypted()) {
- return CBasicKeyStore::GetKeys();
- }
- std::set<CKeyID> set_address;
- for (const auto& mi : mapCryptedKeys) {
- set_address.insert(mi.first);
- }
- return set_address;
-}
-
-bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
-{
- LOCK(cs_KeyStore);
- if (!mapCryptedKeys.empty() || IsCrypted())
- return false;
-
- fUseCrypto = true;
- for (const KeyMap::value_type& mKey : mapKeys)
- {
- const CKey &key = mKey.second;
- CPubKey vchPubKey = key.GetPubKey();
- CKeyingMaterial vchSecret(key.begin(), key.end());
- std::vector<unsigned char> vchCryptedSecret;
- if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
- return false;
- if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
- return false;
- }
- mapKeys.clear();
- return true;
-}
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index 8e195ca8fa..17a4e9820c 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -5,9 +5,9 @@
#ifndef BITCOIN_WALLET_CRYPTER_H
#define BITCOIN_WALLET_CRYPTER_H
-#include <keystore.h>
#include <serialize.h>
#include <support/allocators/secure.h>
+#include <script/signingprovider.h>
#include <atomic>
@@ -109,54 +109,8 @@ public:
}
};
-/** Keystore which keeps the private keys encrypted.
- * It derives from the basic key store, which is used if no encryption is active.
- */
-class CCryptoKeyStore : public CBasicKeyStore
-{
-private:
-
- CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore);
-
- //! if fUseCrypto is true, mapKeys must be empty
- //! if fUseCrypto is false, vMasterKey must be empty
- std::atomic<bool> fUseCrypto;
-
- //! keeps track of whether Unlock has run a thorough check before
- bool fDecryptionThoroughlyChecked;
-
-protected:
- using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
-
- bool SetCrypted();
-
- //! will encrypt previously unencrypted keys
- bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
-
- bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false);
- CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
-
-public:
- CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)
- {
- }
-
- bool IsCrypted() const { return fUseCrypto; }
- bool IsLocked() const;
- bool Lock();
-
- virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
- bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
- bool HaveKey(const CKeyID &address) const override;
- bool GetKey(const CKeyID &address, CKey& keyOut) const override;
- bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
- std::set<CKeyID> GetKeys() const override;
-
- /**
- * Wallet status (encrypted, locked) changed.
- * Note: Called without locks held.
- */
- boost::signals2::signal<void (CCryptoKeyStore* wallet)> NotifyStatusChanged;
-};
+bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext);
+bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext);
+bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key);
#endif // BITCOIN_WALLET_CRYPTER_H
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 46cf6b7616..619197a57a 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -272,18 +272,14 @@ Result CreateRateBumpTransaction(CWallet* wallet, const uint256& txid, const CCo
new_coin_control.m_min_depth = 1;
CTransactionRef tx_new = MakeTransactionRef();
- CReserveKey reservekey(wallet);
CAmount fee_ret;
int change_pos_in_out = -1; // No requested location for change
std::string fail_reason;
- if (!wallet->CreateTransaction(*locked_chain, recipients, tx_new, reservekey, fee_ret, change_pos_in_out, fail_reason, new_coin_control, false)) {
+ if (!wallet->CreateTransaction(*locked_chain, recipients, tx_new, fee_ret, change_pos_in_out, fail_reason, new_coin_control, false)) {
errors.push_back("Unable to create transaction: " + fail_reason);
return Result::WALLET_ERROR;
}
- // If change key hasn't been ReturnKey'ed by this point, we take it out of keypool
- reservekey.KeepKey();
-
// Write back new fee if successful
new_fee = fee_ret;
@@ -330,9 +326,8 @@ Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransacti
mapValue_t mapValue = oldWtx.mapValue;
mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
- CReserveKey reservekey(wallet);
CValidationState state;
- if (!wallet->CommitTransaction(tx, std::move(mapValue), oldWtx.vOrderForm, reservekey, state)) {
+ if (!wallet->CommitTransaction(tx, std::move(mapValue), oldWtx.vOrderForm, state)) {
// NOTE: CommitTransaction never returns false, so this should never happen.
errors.push_back(strprintf("The transaction was rejected: %s", FormatStateMessage(state)));
return Result::WALLET_ERROR;
diff --git a/src/wallet/ismine.cpp b/src/wallet/ismine.cpp
index 6138d4ae44..b7ef2d4490 100644
--- a/src/wallet/ismine.cpp
+++ b/src/wallet/ismine.cpp
@@ -8,6 +8,7 @@
#include <key.h>
#include <script/script.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
#include <wallet/wallet.h>
typedef std::vector<unsigned char> valtype;
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 3112dca9f5..7e973194d9 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -109,8 +109,6 @@ UniValue importprivkey(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
- throw std::runtime_error(
RPCHelpMan{"importprivkey",
"\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n"
"Hint: use importmulti to import more than one private key.\n"
@@ -135,7 +133,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
},
- }.ToString());
+ }.Check(request);
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
@@ -217,8 +215,6 @@ UniValue abortrescan(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 0)
- throw std::runtime_error(
RPCHelpMan{"abortrescan",
"\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
@@ -232,7 +228,7 @@ UniValue abortrescan(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("abortrescan", "")
},
- }.ToString());
+ }.Check(request);
if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
pwallet->AbortRescan();
@@ -283,8 +279,6 @@ UniValue importaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
- throw std::runtime_error(
RPCHelpMan{"importaddress",
"\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
@@ -309,7 +303,7 @@ UniValue importaddress(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
},
- }.ToString());
+ }.Check(request);
std::string strLabel;
@@ -376,8 +370,6 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 2)
- throw std::runtime_error(
RPCHelpMan{"importprunedfunds",
"\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n",
{
@@ -386,8 +378,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
},
RPCResults{},
RPCExamples{""},
- }.ToString()
- );
+ }.Check(request);
CMutableTransaction tx;
if (!DecodeHexTx(tx, request.params[0].get_str()))
@@ -443,8 +434,6 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"removeprunedfunds",
"\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\n",
{
@@ -456,7 +445,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
},
- }.ToString());
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -485,8 +474,6 @@ UniValue importpubkey(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
- throw std::runtime_error(
RPCHelpMan{"importpubkey",
"\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
"Hint: use importmulti to import more than one public key.\n"
@@ -507,7 +494,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")
},
- }.ToString());
+ }.Check(request);
std::string strLabel;
@@ -570,8 +557,6 @@ UniValue importwallet(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"importwallet",
"\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
@@ -587,7 +572,7 @@ UniValue importwallet(const JSONRPCRequest& request)
"\nImport using the json rpc call\n"
+ HelpExampleRpc("importwallet", "\"test\"")
},
- }.ToString());
+ }.Check(request);
if (pwallet->chain().havePruned()) {
// Exit early and print an error.
@@ -735,8 +720,6 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"dumpprivkey",
"\nReveals the private key corresponding to 'address'.\n"
"Then the importprivkey can be used with this output\n",
@@ -751,7 +734,7 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
+ HelpExampleCli("importprivkey", "\"mykey\"")
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"")
},
- }.ToString());
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -783,8 +766,6 @@ UniValue dumpwallet(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"dumpwallet",
"\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
"Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n"
@@ -802,7 +783,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
HelpExampleCli("dumpwallet", "\"test\"")
+ HelpExampleRpc("dumpwallet", "\"test\"")
},
- }.ToString());
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -1322,8 +1303,6 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
return NullUniValue;
}
- if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"importmulti",
"\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), optionally rescanning the blockchain from the earliest creation time of the imported scripts. Requires a new wallet backup.\n"
"If an address/script is imported without all of the private keys required to spend from that address, it will be watchonly. The 'watchonly' option must be set to true in this case or a warning will be returned.\n"
@@ -1384,8 +1363,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
"{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
},
- }.ToString()
- );
+ }.Check(mainRequest);
RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index eae5f876ea..ab732dc0d8 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -52,6 +52,14 @@ static inline bool GetAvoidReuseFlag(CWallet * const pwallet, const UniValue& pa
return avoid_reuse;
}
+/** Checks if a CKey is in the given CWallet compressed or otherwise*/
+bool HaveKey(const CWallet& wallet, const CKey& key)
+{
+ CKey key2;
+ key2.Set(key.begin(), key.end(), !key.IsCompressed());
+ return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
+}
+
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
@@ -159,8 +167,6 @@ static UniValue getnewaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"getnewaddress",
"\nReturns a new Bitcoin address for receiving payments.\n"
"If 'label' is specified, it is added to the address book \n"
@@ -176,7 +182,7 @@ static UniValue getnewaddress(const JSONRPCRequest& request)
HelpExampleCli("getnewaddress", "")
+ HelpExampleRpc("getnewaddress", "")
},
- }.ToString());
+ }.Check(request);
LOCK(pwallet->cs_wallet);
@@ -196,19 +202,11 @@ static UniValue getnewaddress(const JSONRPCRequest& request)
}
}
- if (!pwallet->IsLocked()) {
- pwallet->TopUpKeyPool();
- }
-
- // Generate a new key that is added to wallet
- CPubKey newKey;
- if (!pwallet->GetKeyFromPool(newKey)) {
- throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
+ CTxDestination dest;
+ std::string error;
+ if (!pwallet->GetNewDestination(output_type, label, dest, error)) {
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error);
}
- pwallet->LearnRelatedScripts(newKey, output_type);
- CTxDestination dest = GetDestinationForKey(newKey, output_type);
-
- pwallet->SetAddressBook(dest, label, "receive");
return EncodeDestination(dest);
}
@@ -222,8 +220,6 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 1)
- throw std::runtime_error(
RPCHelpMan{"getrawchangeaddress",
"\nReturns a new Bitcoin address, for receiving change.\n"
"This is for use with raw transactions, NOT normal use.\n",
@@ -237,7 +233,7 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
HelpExampleCli("getrawchangeaddress", "")
+ HelpExampleRpc("getrawchangeaddress", "")
},
- }.ToString());
+ }.Check(request);
LOCK(pwallet->cs_wallet);
@@ -245,10 +241,6 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
}
- if (!pwallet->IsLocked()) {
- pwallet->TopUpKeyPool();
- }
-
OutputType output_type = pwallet->m_default_change_type != OutputType::CHANGE_AUTO ? pwallet->m_default_change_type : pwallet->m_default_address_type;
if (!request.params[0].isNull()) {
if (!ParseOutputType(request.params[0].get_str(), output_type)) {
@@ -256,16 +248,11 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
}
}
- CReserveKey reservekey(pwallet);
- CPubKey vchPubKey;
- if (!reservekey.GetReservedKey(vchPubKey, true))
- throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
-
- reservekey.KeepKey();
-
- pwallet->LearnRelatedScripts(vchPubKey, output_type);
- CTxDestination dest = GetDestinationForKey(vchPubKey, output_type);
-
+ CTxDestination dest;
+ std::string error;
+ if (!pwallet->GetNewChangeDestination(output_type, dest, error)) {
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error);
+ }
return EncodeDestination(dest);
}
@@ -279,8 +266,6 @@ static UniValue setlabel(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 2)
- throw std::runtime_error(
RPCHelpMan{"setlabel",
"\nSets the label associated with the given address.\n",
{
@@ -292,7 +277,7 @@ static UniValue setlabel(const JSONRPCRequest& request)
HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"")
+ HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"")
},
- }.ToString());
+ }.Check(request);
LOCK(pwallet->cs_wallet);
@@ -332,7 +317,6 @@ static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet
CScript scriptPubKey = GetScriptForDestination(address);
// Create and send the transaction
- CReserveKey reservekey(pwallet);
CAmount nFeeRequired;
std::string strError;
std::vector<CRecipient> vecSend;
@@ -340,13 +324,13 @@ static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
CTransactionRef tx;
- if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
+ if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strError, coin_control)) {
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
CValidationState state;
- if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, reservekey, state)) {
+ if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, state)) {
strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
@@ -362,8 +346,6 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 9)
- throw std::runtime_error(
RPCHelpMan{"sendtoaddress",
"\nSend an amount to a given address." +
HelpRequiringPassphrase(pwallet) + "\n",
@@ -395,7 +377,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -460,8 +442,6 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"listaddressgroupings",
"\nLists groups of addresses which have had their common ownership\n"
"made public by common use as inputs or as the resulting change\n"
@@ -484,7 +464,7 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request)
HelpExampleCli("listaddressgroupings", "")
+ HelpExampleRpc("listaddressgroupings", "")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -523,8 +503,6 @@ static UniValue signmessage(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 2)
- throw std::runtime_error(
RPCHelpMan{"signmessage",
"\nSign a message with the private key of an address" +
HelpRequiringPassphrase(pwallet) + "\n",
@@ -545,7 +523,7 @@ static UniValue signmessage(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")
},
- }.ToString());
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -591,8 +569,6 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"getreceivedbyaddress",
"\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n",
{
@@ -612,7 +588,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -663,8 +639,6 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"getreceivedbylabel",
"\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n",
{
@@ -684,7 +658,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -733,8 +707,6 @@ static UniValue getbalance(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 4)
- throw std::runtime_error(
RPCHelpMan{"getbalance",
"\nReturns the total available balance.\n"
"The available balance is what the wallet considers currently spendable, and is\n"
@@ -756,7 +728,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("getbalance", "\"*\", 6")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -796,14 +768,12 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 0)
- throw std::runtime_error(
RPCHelpMan{"getunconfirmedbalance",
"DEPRECATED\nIdentical to getbalances().mine.untrusted_pending\n",
{},
RPCResults{},
RPCExamples{""},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -825,7 +795,7 @@ static UniValue sendmany(const JSONRPCRequest& request)
return NullUniValue;
}
- const RPCHelpMan help{"sendmany",
+ RPCHelpMan{"sendmany",
"\nSend multiple times. Amounts are double-precision floating point numbers." +
HelpRequiringPassphrase(pwallet) + "\n",
{
@@ -866,11 +836,7 @@ static UniValue sendmany(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -948,16 +914,15 @@ static UniValue sendmany(const JSONRPCRequest& request)
std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext());
// Send
- CReserveKey keyChange(pwallet);
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
std::string strFailReason;
CTransactionRef tx;
- bool fCreated = pwallet->CreateTransaction(*locked_chain, vecSend, tx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
+ bool fCreated = pwallet->CreateTransaction(*locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strFailReason, coin_control);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state;
- if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, keyChange, state)) {
+ if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, state)) {
strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state));
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
}
@@ -974,8 +939,6 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) {
- std::string msg =
RPCHelpMan{"addmultisigaddress",
"\nAdd a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
"Each key is a Bitcoin address or hex-encoded public key.\n"
@@ -1004,9 +967,7 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
},
- }.ToString();
- throw std::runtime_error(msg);
- }
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -1211,8 +1172,6 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 4)
- throw std::runtime_error(
RPCHelpMan{"listreceivedbyaddress",
"\nList balances by receiving address.\n",
{
@@ -1243,7 +1202,7 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1264,8 +1223,6 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 3)
- throw std::runtime_error(
RPCHelpMan{"listreceivedbylabel",
"\nList received transactions by label.\n",
{
@@ -1289,7 +1246,7 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request)
+ HelpExampleCli("listreceivedbylabel", "6 true")
+ HelpExampleRpc("listreceivedbylabel", "6, true, true")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1404,8 +1361,6 @@ UniValue listtransactions(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 4)
- throw std::runtime_error(
RPCHelpMan{"listtransactions",
"\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
@@ -1457,7 +1412,7 @@ UniValue listtransactions(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1538,8 +1493,6 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 4)
- throw std::runtime_error(
RPCHelpMan{"listsinceblock",
"\nGet all transactions in blocks since block [blockhash], or all transactions if omitted.\n"
"If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
@@ -1592,7 +1545,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
+ HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1683,8 +1636,6 @@ static UniValue gettransaction(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"gettransaction",
"\nGet detailed information about in-wallet transaction <txid>\n",
{
@@ -1732,7 +1683,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
+ HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1785,8 +1736,6 @@ static UniValue abandontransaction(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1) {
- throw std::runtime_error(
RPCHelpMan{"abandontransaction",
"\nMark in-wallet transaction <txid> as abandoned\n"
"This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
@@ -1801,8 +1750,7 @@ static UniValue abandontransaction(const JSONRPCRequest& request)
HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
},
- }.ToString());
- }
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1833,8 +1781,6 @@ static UniValue backupwallet(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"backupwallet",
"\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n",
{
@@ -1845,7 +1791,7 @@ static UniValue backupwallet(const JSONRPCRequest& request)
HelpExampleCli("backupwallet", "\"backup.dat\"")
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1872,8 +1818,6 @@ static UniValue keypoolrefill(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 1)
- throw std::runtime_error(
RPCHelpMan{"keypoolrefill",
"\nFills the keypool."+
HelpRequiringPassphrase(pwallet) + "\n",
@@ -1885,7 +1829,7 @@ static UniValue keypoolrefill(const JSONRPCRequest& request)
HelpExampleCli("keypoolrefill", "")
+ HelpExampleRpc("keypoolrefill", "")
},
- }.ToString());
+ }.Check(request);
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
@@ -1922,8 +1866,6 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 2) {
- throw std::runtime_error(
RPCHelpMan{"walletpassphrase",
"\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
"This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
@@ -1943,8 +1885,7 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
},
- }.ToString());
- }
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -2009,8 +1950,6 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 2) {
- throw std::runtime_error(
RPCHelpMan{"walletpassphrasechange",
"\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n",
{
@@ -2022,8 +1961,7 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request)
HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
+ HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
},
- }.ToString());
- }
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -2063,8 +2001,6 @@ static UniValue walletlock(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 0) {
- throw std::runtime_error(
RPCHelpMan{"walletlock",
"\nRemoves the wallet encryption key from memory, locking the wallet.\n"
"After calling this method, you will need to call walletpassphrase again\n"
@@ -2081,8 +2017,7 @@ static UniValue walletlock(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("walletlock", "")
},
- }.ToString());
- }
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -2107,8 +2042,6 @@ static UniValue encryptwallet(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1) {
- throw std::runtime_error(
RPCHelpMan{"encryptwallet",
"\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
"After this, any calls that interact with private keys such as sending or signing \n"
@@ -2131,8 +2064,7 @@ static UniValue encryptwallet(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
},
- }.ToString());
- }
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -2171,8 +2103,6 @@ static UniValue lockunspent(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
RPCHelpMan{"lockunspent",
"\nUpdates list of temporarily unspendable outputs.\n"
"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
@@ -2209,7 +2139,7 @@ static UniValue lockunspent(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
},
- }.ToString());
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -2300,8 +2230,6 @@ static UniValue listlockunspent(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 0)
- throw std::runtime_error(
RPCHelpMan{"listlockunspent",
"\nReturns list of temporarily unspendable outputs.\n"
"See the lockunspent call to lock and unlock transactions for spending.\n",
@@ -2327,7 +2255,7 @@ static UniValue listlockunspent(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("listlockunspent", "")
},
- }.ToString());
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -2357,8 +2285,6 @@ static UniValue settxfee(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 1) {
- throw std::runtime_error(
RPCHelpMan{"settxfee",
"\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n",
{
@@ -2371,8 +2297,7 @@ static UniValue settxfee(const JSONRPCRequest& request)
HelpExampleCli("settxfee", "0.00001")
+ HelpExampleRpc("settxfee", "0.00001")
},
- }.ToString());
- }
+ }.Check(request);
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@@ -2399,7 +2324,7 @@ static UniValue getbalances(const JSONRPCRequest& request)
}
CWallet& wallet = *rpc_wallet;
- const RPCHelpMan help{
+ RPCHelpMan{
"getbalances",
"Returns an object with all balances in " + CURRENCY_UNIT + ".\n",
{},
@@ -2420,11 +2345,7 @@ static UniValue getbalances(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("getbalances", "") +
HelpExampleRpc("getbalances", "")},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -2469,7 +2390,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
return NullUniValue;
}
- const RPCHelpMan help{"getwalletinfo",
+ RPCHelpMan{"getwalletinfo",
"Returns an object containing various wallet state info.\n",
{},
RPCResult{
@@ -2499,11 +2420,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
HelpExampleCli("getwalletinfo", "")
+ HelpExampleRpc("getwalletinfo", "")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -2550,8 +2467,6 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
static UniValue listwalletdir(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0) {
- throw std::runtime_error(
RPCHelpMan{"listwalletdir",
"Returns a list of wallets in the wallet directory.\n",
{},
@@ -2569,8 +2484,7 @@ static UniValue listwalletdir(const JSONRPCRequest& request)
HelpExampleCli("listwalletdir", "")
+ HelpExampleRpc("listwalletdir", "")
},
- }.ToString());
- }
+ }.Check(request);
UniValue wallets(UniValue::VARR);
for (const auto& path : ListWalletDir()) {
@@ -2586,8 +2500,6 @@ static UniValue listwalletdir(const JSONRPCRequest& request)
static UniValue listwallets(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
RPCHelpMan{"listwallets",
"Returns a list of currently loaded wallets.\n"
"For full information on the wallet, use \"getwalletinfo\"\n",
@@ -2602,7 +2514,7 @@ static UniValue listwallets(const JSONRPCRequest& request)
HelpExampleCli("listwallets", "")
+ HelpExampleRpc("listwallets", "")
},
- }.ToString());
+ }.Check(request);
UniValue obj(UniValue::VARR);
@@ -2621,8 +2533,6 @@ static UniValue listwallets(const JSONRPCRequest& request)
static UniValue loadwallet(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"loadwallet",
"\nLoads a wallet from a wallet file or directory."
"\nNote that all wallet command-line options used when starting bitcoind will be"
@@ -2640,7 +2550,7 @@ static UniValue loadwallet(const JSONRPCRequest& request)
HelpExampleCli("loadwallet", "\"test.dat\"")
+ HelpExampleRpc("loadwallet", "\"test.dat\"")
},
- }.ToString());
+ }.Check(request);
WalletLocation location(request.params[0].get_str());
@@ -2674,12 +2584,10 @@ static UniValue setwalletflag(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- std::string flags = "";
- for (auto& it : WALLET_FLAG_MAP)
- if (it.second & MUTABLE_WALLET_FLAGS)
- flags += (flags == "" ? "" : ", ") + it.first;
- throw std::runtime_error(
+ std::string flags = "";
+ for (auto& it : WALLET_FLAG_MAP)
+ if (it.second & MUTABLE_WALLET_FLAGS)
+ flags += (flags == "" ? "" : ", ") + it.first;
RPCHelpMan{"setwalletflag",
"\nChange the state of the given wallet flag for a wallet.\n",
{
@@ -2697,8 +2605,7 @@ static UniValue setwalletflag(const JSONRPCRequest& request)
HelpExampleCli("setwalletflag", "avoid_reuse")
+ HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
},
- }.ToString());
- }
+ }.Check(request);
std::string flag_str = request.params[0].get_str();
bool value = request.params[1].isNull() || request.params[1].get_bool();
@@ -2737,7 +2644,7 @@ static UniValue setwalletflag(const JSONRPCRequest& request)
static UniValue createwallet(const JSONRPCRequest& request)
{
- const RPCHelpMan help{
+ RPCHelpMan{
"createwallet",
"\nCreates and loads a new wallet.\n",
{
@@ -2757,22 +2664,14 @@ static UniValue createwallet(const JSONRPCRequest& request)
HelpExampleCli("createwallet", "\"testwallet\"")
+ HelpExampleRpc("createwallet", "\"testwallet\"")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
- std::string error;
- std::string warning;
+ }.Check(request);
uint64_t flags = 0;
if (!request.params[1].isNull() && request.params[1].get_bool()) {
flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS;
}
- bool create_blank = false; // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
if (!request.params[2].isNull() && request.params[2].get_bool()) {
- create_blank = true;
flags |= WALLET_FLAG_BLANK_WALLET;
}
SecureString passphrase;
@@ -2783,55 +2682,24 @@ static UniValue createwallet(const JSONRPCRequest& request)
// Empty string is invalid
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Cannot encrypt a wallet with a blank password");
}
- // Born encrypted wallets need to be blank first so that wallet creation doesn't make any unencrypted keys
- flags |= WALLET_FLAG_BLANK_WALLET;
}
if (!request.params[4].isNull() && request.params[4].get_bool()) {
flags |= WALLET_FLAG_AVOID_REUSE;
}
- WalletLocation location(request.params[0].get_str());
- if (location.Exists()) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Wallet " + location.GetName() + " already exists.");
- }
-
- // Wallet::Verify will check if we're trying to create a wallet with a duplication name.
- if (!CWallet::Verify(*g_rpc_interfaces->chain, location, false, error, warning)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Wallet file verification failed: " + error);
- }
-
- std::shared_ptr<CWallet> const wallet = CWallet::CreateWalletFromFile(*g_rpc_interfaces->chain, location, flags);
- if (!wallet) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed.");
- }
-
- // Encrypt the wallet if there's a passphrase
- if (!passphrase.empty() && !(flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- if (!wallet->EncryptWallet(passphrase)) {
- throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet created but failed to encrypt.");
- }
-
- if (!create_blank) {
- // Unlock the wallet
- if (!wallet->Unlock(passphrase)) {
- throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet was encrypted but could not be unlocked");
- }
-
- // Set a seed for the wallet
- CPubKey master_pub_key = wallet->GenerateNewSeed();
- wallet->SetHDSeed(master_pub_key);
- wallet->NewKeyPool();
-
- // Relock the wallet
- wallet->Lock();
- }
+ std::string error;
+ std::string warning;
+ WalletCreationStatus status;
+ std::shared_ptr<CWallet> wallet = CreateWallet(*g_rpc_interfaces->chain, request.params[0].get_str(), error, warning, status, passphrase, flags);
+ if (status == WalletCreationStatus::CREATION_FAILED) {
+ throw JSONRPCError(RPC_WALLET_ERROR, error);
+ } else if (status == WalletCreationStatus::ENCRYPTION_FAILED) {
+ throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error);
+ } else if (status != WalletCreationStatus::SUCCESS) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed");
}
- AddWallet(wallet);
-
- wallet->postInitProcess();
-
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
obj.pushKV("warning", warning);
@@ -2841,8 +2709,6 @@ static UniValue createwallet(const JSONRPCRequest& request)
static UniValue unloadwallet(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() > 1) {
- throw std::runtime_error(
RPCHelpMan{"unloadwallet",
"Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
"Specifying the wallet name on a wallet endpoint is invalid.",
@@ -2854,8 +2720,7 @@ static UniValue unloadwallet(const JSONRPCRequest& request)
HelpExampleCli("unloadwallet", "wallet_name")
+ HelpExampleRpc("unloadwallet", "wallet_name")
},
- }.ToString());
- }
+ }.Check(request);
std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
@@ -2892,7 +2757,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
return NullUniValue;
}
- const RPCHelpMan help{
+ RPCHelpMan{
"listunspent",
"\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
@@ -2946,11 +2811,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
+ HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'")
+ HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
int nMinDepth = 1;
if (!request.params[0].isNull()) {
@@ -3219,7 +3080,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
return NullUniValue;
}
- const RPCHelpMan help{"fundrawtransaction",
+ RPCHelpMan{"fundrawtransaction",
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
"This will not modify existing inputs, and will add at most one change output to the outputs.\n"
"No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
@@ -3283,11 +3144,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
"\nSend the transaction\n"
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
},
- };
-
- if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
- throw std::runtime_error(help.ToString());
- }
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
@@ -3320,8 +3177,6 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
- throw std::runtime_error(
RPCHelpMan{"signrawtransactionwithwallet",
"\nSign inputs for raw transaction (serialized, hex-encoded).\n"
"The second optional argument (may be null) is an array of previous transaction outputs that\n"
@@ -3371,7 +3226,7 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"")
+ HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"")
},
- }.ToString());
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
@@ -3404,8 +3259,6 @@ static UniValue bumpfee(const JSONRPCRequest& request)
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw std::runtime_error(
RPCHelpMan{"bumpfee",
"\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
"An opt-in RBF transaction with the given txid must be in the wallet.\n"
@@ -3453,8 +3306,7 @@ static UniValue bumpfee(const JSONRPCRequest& request)
"\nBump the fee, get the new transaction\'s txid\n" +
HelpExampleCli("bumpfee", "<txid>")
},
- }.ToString());
- }
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
uint256 hash(ParseHashV(request.params[0], "txid"));
@@ -3567,8 +3419,6 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 2) {
- throw std::runtime_error(
RPCHelpMan{"rescanblockchain",
"\nRescan the local blockchain for wallet related transactions.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
@@ -3586,8 +3436,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
HelpExampleCli("rescanblockchain", "100000 120000")
+ HelpExampleRpc("rescanblockchain", "100000, 120000")
},
- }.ToString());
- }
+ }.Check(request);
WalletRescanReserver reserver(pwallet);
if (!reserver.reserve()) {
@@ -3774,8 +3623,6 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1) {
- throw std::runtime_error(
RPCHelpMan{"getaddressinfo",
"\nReturn information about the given bitcoin address. Some information requires the address\n"
"to be in the wallet.\n",
@@ -3824,8 +3671,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
HelpExampleCli("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
+ HelpExampleRpc("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
},
- }.ToString());
- }
+ }.Check(request);
LOCK(pwallet->cs_wallet);
@@ -3902,8 +3748,6 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
RPCHelpMan{"getaddressesbylabel",
"\nReturns the list of addresses assigned the specified label.\n",
{
@@ -3920,7 +3764,7 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request)
HelpExampleCli("getaddressesbylabel", "\"tabby\"")
+ HelpExampleRpc("getaddressesbylabel", "\"tabby\"")
},
- }.ToString());
+ }.Check(request);
LOCK(pwallet->cs_wallet);
@@ -3961,8 +3805,6 @@ static UniValue listlabels(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 1)
- throw std::runtime_error(
RPCHelpMan{"listlabels",
"\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n",
{
@@ -3984,7 +3826,7 @@ static UniValue listlabels(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("listlabels", "receive")
},
- }.ToString());
+ }.Check(request);
LOCK(pwallet->cs_wallet);
@@ -4018,8 +3860,6 @@ UniValue sethdseed(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 2) {
- throw std::runtime_error(
RPCHelpMan{"sethdseed",
"\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
"HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
@@ -4040,8 +3880,7 @@ UniValue sethdseed(const JSONRPCRequest& request)
+ HelpExampleCli("sethdseed", "true \"wifkey\"")
+ HelpExampleRpc("sethdseed", "true, \"wifkey\"")
},
- }.ToString());
- }
+ }.Check(request);
if (pwallet->chain().isInitialBlockDownload()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download");
@@ -4097,8 +3936,6 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
- throw std::runtime_error(
RPCHelpMan{"walletprocesspsbt",
"\nUpdate a PSBT with input information from our wallet and then sign inputs\n"
"that we can sign for." +
@@ -4125,7 +3962,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
RPCExamples{
HelpExampleCli("walletprocesspsbt", "\"psbt\"")
},
- }.ToString());
+ }.Check(request);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
@@ -4166,8 +4003,6 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
- throw std::runtime_error(
RPCHelpMan{"walletcreatefundedpsbt",
"\nCreates and funds a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough\n"
"Implements the Creator and Updater roles.\n",
@@ -4239,7 +4074,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
"\nCreate a transaction with no inputs\n"
+ HelpExampleCli("walletcreatefundedpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
},
- }.ToString());
+ }.Check(request);
RPCTypeCheck(request.params, {
UniValue::VARR,
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index ef95d0544f..8af05dea45 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -272,7 +272,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
if (blockTime > 0) {
auto locked_chain = wallet.chain().lock();
LockAssertion lock(::cs_main);
- auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
+ auto inserted = ::BlockIndex().emplace(GetRandHash(), new CBlockIndex);
assert(inserted.second);
const uint256& hash = inserted.first->first;
block = inserted.first->second;
@@ -361,17 +361,16 @@ public:
CWalletTx& AddTx(CRecipient recipient)
{
CTransactionRef tx;
- CReserveKey reservekey(wallet.get());
CAmount fee;
int changePos = -1;
std::string error;
CCoinControl dummy;
{
auto locked_chain = m_chain->lock();
- BOOST_CHECK(wallet->CreateTransaction(*locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy));
+ BOOST_CHECK(wallet->CreateTransaction(*locked_chain, {recipient}, tx, fee, changePos, error, dummy));
}
CValidationState state;
- BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, state));
+ BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, state));
CMutableTransaction blocktx;
{
LOCK(wallet->cs_wallet);
@@ -464,8 +463,9 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
wallet->SetMinVersion(FEATURE_LATEST);
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
BOOST_CHECK(!wallet->TopUpKeyPool(1000));
- CPubKey pubkey;
- BOOST_CHECK(!wallet->GetKeyFromPool(pubkey, false));
+ CTxDestination dest;
+ std::string error;
+ BOOST_CHECK(!wallet->GetNewDestination(OutputType::BECH32, "", dest, error));
}
// Explicit calculation which is used to test the wallet constant
@@ -488,7 +488,7 @@ static size_t CalculateNestedKeyhashInputSize(bool use_max_sig)
CScript script_pubkey = CScript() << OP_HASH160 << std::vector<unsigned char>(script_id.begin(), script_id.end()) << OP_EQUAL;
// Add inner-script to key store and key to watchonly
- CBasicKeyStore keystore;
+ FillableSigningProvider keystore;
keystore.AddCScript(inner_script);
keystore.AddKeyPubKey(key, pubkey);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index cf0b28f5ca..452d4f7a6a 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -13,13 +13,13 @@
#include <interfaces/wallet.h>
#include <key.h>
#include <key_io.h>
-#include <keystore.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/descriptor.h>
#include <script/script.h>
+#include <script/signingprovider.h>
#include <util/bip32.h>
#include <util/error.h>
#include <util/fees.h>
@@ -160,6 +160,70 @@ std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string&
return LoadWallet(chain, WalletLocation(name), error, warning);
}
+std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning, WalletCreationStatus& status, const SecureString& passphrase, uint64_t wallet_creation_flags)
+{
+ // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
+ bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET);
+
+ // Born encrypted wallets need to be created blank first.
+ if (!passphrase.empty()) {
+ wallet_creation_flags |= WALLET_FLAG_BLANK_WALLET;
+ }
+
+ // Check the wallet file location
+ WalletLocation location(name);
+ if (location.Exists()) {
+ error = "Wallet " + location.GetName() + " already exists.";
+ status = WalletCreationStatus::CREATION_FAILED;
+ return nullptr;
+ }
+
+ // Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
+ std::string wallet_error;
+ if (!CWallet::Verify(chain, location, false, wallet_error, warning)) {
+ error = "Wallet file verification failed: " + wallet_error;
+ status = WalletCreationStatus::CREATION_FAILED;
+ return nullptr;
+ }
+
+ // Make the wallet
+ std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, wallet_creation_flags);
+ if (!wallet) {
+ error = "Wallet creation failed";
+ status = WalletCreationStatus::CREATION_FAILED;
+ return nullptr;
+ }
+
+ // Encrypt the wallet
+ if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ if (!wallet->EncryptWallet(passphrase)) {
+ error = "Error: Wallet created but failed to encrypt.";
+ status = WalletCreationStatus::ENCRYPTION_FAILED;
+ return nullptr;
+ }
+ if (!create_blank) {
+ // Unlock the wallet
+ if (!wallet->Unlock(passphrase)) {
+ error = "Error: Wallet was encrypted but could not be unlocked";
+ status = WalletCreationStatus::ENCRYPTION_FAILED;
+ return nullptr;
+ }
+
+ // Set a seed for the wallet
+ CPubKey master_pub_key = wallet->GenerateNewSeed();
+ wallet->SetHDSeed(master_pub_key);
+ wallet->NewKeyPool();
+
+ // Relock the wallet
+ wallet->Lock();
+ }
+ }
+ AddWallet(wallet);
+ wallet->postInitProcess();
+ status = WalletCreationStatus::SUCCESS;
+ return wallet;
+}
+
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
const uint256 CMerkleTx::ABANDON_HASH(uint256S("0000000000000000000000000000000000000000000000000000000000000001"));
@@ -294,14 +358,14 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& secret, const C
// Make sure we aren't adding private keys to private key disabled wallets
assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
- // CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey
+ // FillableSigningProvider has no concept of wallet databases, but calls AddCryptedKey
// which is overridden below. To avoid flushes, the database handle is
// tunneled through to it.
bool needsDB = !encrypted_batch;
if (needsDB) {
encrypted_batch = &batch;
}
- if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) {
+ if (!AddKeyPubKeyInner(secret, pubkey)) {
if (needsDB) encrypted_batch = nullptr;
return false;
}
@@ -336,7 +400,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
const std::vector<unsigned char> &vchCryptedSecret)
{
- if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
+ if (!AddCryptedKeyInner(vchPubKey, vchCryptedSecret))
return false;
{
LOCK(cs_wallet);
@@ -404,7 +468,7 @@ void CWallet::UpgradeKeyMetadata()
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
- return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
+ return AddCryptedKeyInner(vchPubKey, vchCryptedSecret);
}
/**
@@ -431,7 +495,7 @@ bool CWallet::AddCScript(const CScript& redeemScript)
bool CWallet::AddCScriptWithDB(WalletBatch& batch, const CScript& redeemScript)
{
- if (!CCryptoKeyStore::AddCScript(redeemScript))
+ if (!FillableSigningProvider::AddCScript(redeemScript))
return false;
if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) {
UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET);
@@ -452,12 +516,40 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
return true;
}
- return CCryptoKeyStore::AddCScript(redeemScript);
+ return FillableSigningProvider::AddCScript(redeemScript);
+}
+
+static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
+{
+ //TODO: Use Solver to extract this?
+ CScript::const_iterator pc = dest.begin();
+ opcodetype opcode;
+ std::vector<unsigned char> vch;
+ if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch))
+ return false;
+ pubKeyOut = CPubKey(vch);
+ if (!pubKeyOut.IsFullyValid())
+ return false;
+ if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch))
+ return false;
+ return true;
+}
+
+bool CWallet::AddWatchOnlyInMem(const CScript &dest)
+{
+ LOCK(cs_KeyStore);
+ setWatchOnly.insert(dest);
+ CPubKey pubKey;
+ if (ExtractPubKey(dest, pubKey)) {
+ mapWatchKeys[pubKey.GetID()] = pubKey;
+ ImplicitlyLearnRelatedKeyScripts(pubKey);
+ }
+ return true;
}
bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest)
{
- if (!CCryptoKeyStore::AddWatchOnly(dest))
+ if (!AddWatchOnlyInMem(dest))
return false;
const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)];
UpdateTimeFirstKey(meta.nCreateTime);
@@ -490,8 +582,17 @@ bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
bool CWallet::RemoveWatchOnly(const CScript &dest)
{
AssertLockHeld(cs_wallet);
- if (!CCryptoKeyStore::RemoveWatchOnly(dest))
- return false;
+ {
+ LOCK(cs_KeyStore);
+ setWatchOnly.erase(dest);
+ CPubKey pubKey;
+ if (ExtractPubKey(dest, pubKey)) {
+ mapWatchKeys.erase(pubKey.GetID());
+ }
+ // Related CScripts are not removed; having superfluous scripts around is
+ // harmless (see comment in ImplicitlyLearnRelatedKeyScripts).
+ }
+
if (!HaveWatchOnly())
NotifyWatchonlyChanged(false);
if (!WalletBatch(*database).EraseWatchOnly(dest))
@@ -502,7 +603,19 @@ bool CWallet::RemoveWatchOnly(const CScript &dest)
bool CWallet::LoadWatchOnly(const CScript &dest)
{
- return CCryptoKeyStore::AddWatchOnly(dest);
+ return AddWatchOnlyInMem(dest);
+}
+
+bool CWallet::HaveWatchOnly(const CScript &dest) const
+{
+ LOCK(cs_KeyStore);
+ return setWatchOnly.count(dest) > 0;
+}
+
+bool CWallet::HaveWatchOnly() const
+{
+ LOCK(cs_KeyStore);
+ return (!setWatchOnly.empty());
}
bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys)
@@ -518,7 +631,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_key
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
continue; // try another master key
- if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys)) {
+ if (Unlock(_vMasterKey, accept_no_keys)) {
// Now that we've unlocked, upgrade the key metadata
UpgradeKeyMetadata();
return true;
@@ -544,7 +657,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
return false;
- if (CCryptoKeyStore::Unlock(_vMasterKey))
+ if (Unlock(_vMasterKey))
{
int64_t nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
@@ -2666,17 +2779,13 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- CReserveKey reservekey(this);
CTransactionRef tx_new;
- if (!CreateTransaction(*locked_chain, vecSend, tx_new, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
+ if (!CreateTransaction(*locked_chain, vecSend, tx_new, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
return false;
}
if (nChangePosInOut != -1) {
tx.vout.insert(tx.vout.begin() + nChangePosInOut, tx_new->vout[nChangePosInOut]);
- // We don't have the normal Create/Commit cycle, and don't want to risk
- // reusing change, so just remove the key from the keypool here.
- reservekey.KeepKey();
}
// Copy output sizes from new transaction; they may have had the fee
@@ -2696,11 +2805,6 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
}
}
- if (nFeeRet > this->m_default_max_tx_fee) {
- strFailReason = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
- return false;
- }
-
return true;
}
@@ -2792,10 +2896,11 @@ OutputType CWallet::TransactionChangeType(OutputType change_type, const std::vec
return m_default_address_type;
}
-bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet,
+bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet,
int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
{
CAmount nValue = 0;
+ ReserveDestination reservedest(this);
int nChangePosRequest = nChangePosInOut;
unsigned int nSubtractFeeFromAmount = 0;
for (const auto& recipient : vecSend)
@@ -2833,7 +2938,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
CoinSelectionParams coin_selection_params; // Parameters for coin selection, init with dummy
// Create change script that will be used if we need change
- // TODO: pass in scriptChange instead of reservekey so
+ // TODO: pass in scriptChange instead of reservedest so
// change transaction isn't always pay-to-bitcoin-address
CScript scriptChange;
@@ -2853,19 +2958,16 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
strFailReason = _("Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.");
return false;
}
- CPubKey vchPubKey;
- bool ret;
- ret = reservekey.GetReservedKey(vchPubKey, true);
+ CTxDestination dest;
+ const OutputType change_type = TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : m_default_change_type, vecSend);
+ bool ret = reservedest.GetReservedDestination(change_type, dest, true);
if (!ret)
{
- strFailReason = _("Keypool ran out, please call keypoolrefill first");
+ strFailReason = "Keypool ran out, please call keypoolrefill first";
return false;
}
- const OutputType change_type = TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : m_default_change_type, vecSend);
-
- LearnRelatedScripts(vchPubKey, change_type);
- scriptChange = GetScriptForDestination(GetDestinationForKey(vchPubKey, change_type));
+ scriptChange = GetScriptForDestination(dest);
}
CTxOut change_prototype_txout(0, scriptChange);
coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout);
@@ -3013,14 +3115,6 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
return false;
}
- // If we made it here and we aren't even able to meet the relay fee on the next pass, give up
- // because we must be at the maximum allowed fee.
- if (nFeeNeeded < chain().relayMinFee().GetFee(nBytes))
- {
- strFailReason = _("Transaction too large for fee policy");
- return false;
- }
-
if (nFeeRet >= nFeeNeeded) {
// Reduce fee to only the needed amount if possible. This
// prevents potential overpayment in fees if the coins
@@ -3086,8 +3180,6 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
}
}
- if (nChangePosInOut == -1) reservekey.ReturnKey(); // Return any reserved key if we don't have change
-
// Shuffle selected coins and fill in final vin
txNew.vin.clear();
std::vector<CInputCoin> selected_coins(setCoins.begin(), setCoins.end());
@@ -3137,6 +3229,11 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
}
}
+ if (nFeeRet > m_default_max_tx_fee) {
+ strFailReason = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
+ return false;
+ }
+
if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits
if (!chain().checkChainLimits(tx)) {
@@ -3145,6 +3242,10 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
}
}
+ // Before we return success, we assume any change key will be used to prevent
+ // accidental re-use.
+ reservedest.KeepDestination();
+
WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Needed:%d Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
nFeeRet, nBytes, nFeeNeeded, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
feeCalc.est.pass.start, feeCalc.est.pass.end,
@@ -3159,7 +3260,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
/**
* Call after CreateTransaction unless you want to abort
*/
-bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CReserveKey& reservekey, CValidationState& state)
+bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CValidationState& state)
{
{
auto locked_chain = chain().lock();
@@ -3173,8 +3274,6 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
WalletLogPrintf("CommitTransaction:\n%s", wtxNew.tx->ToString()); /* Continued */
{
- // Take key pair from key pool so it won't be used again
- reservekey.KeepKey();
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
@@ -3425,8 +3524,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
{
LOCK(cs_wallet);
- if (IsLocked())
- return false;
+ if (IsLocked()) return false;
// Top up key pool
unsigned int nTargetSize;
@@ -3487,8 +3585,7 @@ bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
{
LOCK(cs_wallet);
- if (!IsLocked())
- TopUpKeyPool();
+ TopUpKeyPool();
bool fReturningInternal = fRequestedInternal;
fReturningInternal &= (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) || IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
@@ -3575,6 +3672,42 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
return true;
}
+bool CWallet::GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, std::string& error)
+{
+ LOCK(cs_wallet);
+ error.clear();
+
+ TopUpKeyPool();
+
+ // Generate a new key that is added to wallet
+ CPubKey new_key;
+ if (!GetKeyFromPool(new_key)) {
+ error = "Error: Keypool ran out, please call keypoolrefill first";
+ return false;
+ }
+ LearnRelatedScripts(new_key, type);
+ dest = GetDestinationForKey(new_key, type);
+
+ SetAddressBook(dest, label, "receive");
+ return true;
+}
+
+bool CWallet::GetNewChangeDestination(const OutputType type, CTxDestination& dest, std::string& error)
+{
+ error.clear();
+
+ TopUpKeyPool();
+
+ ReserveDestination reservedest(this);
+ if (!reservedest.GetReservedDestination(type, dest, true)) {
+ error = "Error: Keypool ran out, please call keypoolrefill first";
+ return false;
+ }
+
+ reservedest.KeepDestination();
+ return true;
+}
+
static int64_t GetOldestKeyTimeInPool(const std::set<int64_t>& setKeyPool, WalletBatch& batch) {
if (setKeyPool.empty()) {
return GetTime();
@@ -3754,7 +3887,7 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
return result;
}
-bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
+bool ReserveDestination::GetReservedDestination(const OutputType type, CTxDestination& dest, bool internal)
{
if (!pwallet->CanGetAddresses(internal)) {
return false;
@@ -3770,25 +3903,29 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
fInternal = keypool.fInternal;
}
assert(vchPubKey.IsValid());
- pubkey = vchPubKey;
+ pwallet->LearnRelatedScripts(vchPubKey, type);
+ address = GetDestinationForKey(vchPubKey, type);
+ dest = address;
return true;
}
-void CReserveKey::KeepKey()
+void ReserveDestination::KeepDestination()
{
if (nIndex != -1)
pwallet->KeepKey(nIndex);
nIndex = -1;
vchPubKey = CPubKey();
+ address = CNoDestination();
}
-void CReserveKey::ReturnKey()
+void ReserveDestination::ReturnDestination()
{
if (nIndex != -1) {
pwallet->ReturnKey(nIndex, fInternal, vchPubKey);
}
nIndex = -1;
vchPubKey = CPubKey();
+ address = CNoDestination();
}
void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id)
@@ -4119,12 +4256,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
walletFile));
}
else if (nLoadWalletRet == DBErrors::TOO_NEW) {
- chain.initError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, _(PACKAGE_NAME)));
+ chain.initError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, PACKAGE_NAME));
return nullptr;
}
else if (nLoadWalletRet == DBErrors::NEED_REWRITE)
{
- chain.initError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), _(PACKAGE_NAME)));
+ chain.initError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), PACKAGE_NAME));
return nullptr;
}
else {
@@ -4590,3 +4727,203 @@ bool CWallet::AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, cons
mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path);
return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true);
}
+
+bool CWallet::SetCrypted()
+{
+ LOCK(cs_KeyStore);
+ if (fUseCrypto)
+ return true;
+ if (!mapKeys.empty())
+ return false;
+ fUseCrypto = true;
+ return true;
+}
+
+bool CWallet::IsLocked() const
+{
+ if (!IsCrypted()) {
+ return false;
+ }
+ LOCK(cs_KeyStore);
+ return vMasterKey.empty();
+}
+
+bool CWallet::Lock()
+{
+ if (!SetCrypted())
+ return false;
+
+ {
+ LOCK(cs_KeyStore);
+ vMasterKey.clear();
+ }
+
+ NotifyStatusChanged(this);
+ return true;
+}
+
+bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys)
+{
+ {
+ LOCK(cs_KeyStore);
+ if (!SetCrypted())
+ return false;
+
+ bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys
+ bool keyFail = false;
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
+ for (; mi != mapCryptedKeys.end(); ++mi)
+ {
+ const CPubKey &vchPubKey = (*mi).second.first;
+ const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
+ CKey key;
+ if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key))
+ {
+ keyFail = true;
+ break;
+ }
+ keyPass = true;
+ if (fDecryptionThoroughlyChecked)
+ break;
+ }
+ if (keyPass && keyFail)
+ {
+ LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
+ throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt.");
+ }
+ if (keyFail || (!keyPass && !accept_no_keys))
+ return false;
+ vMasterKey = vMasterKeyIn;
+ fDecryptionThoroughlyChecked = true;
+ }
+ NotifyStatusChanged(this);
+ return true;
+}
+
+bool CWallet::HaveKey(const CKeyID &address) const
+{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return FillableSigningProvider::HaveKey(address);
+ }
+ return mapCryptedKeys.count(address) > 0;
+}
+
+bool CWallet::GetKey(const CKeyID &address, CKey& keyOut) const
+{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return FillableSigningProvider::GetKey(address, keyOut);
+ }
+
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
+ if (mi != mapCryptedKeys.end())
+ {
+ const CPubKey &vchPubKey = (*mi).second.first;
+ const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
+ return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
+ }
+ return false;
+}
+
+bool CWallet::GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const
+{
+ LOCK(cs_KeyStore);
+ WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
+ if (it != mapWatchKeys.end()) {
+ pubkey_out = it->second;
+ return true;
+ }
+ return false;
+}
+
+bool CWallet::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
+{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ if (!FillableSigningProvider::GetPubKey(address, vchPubKeyOut)) {
+ return GetWatchPubKey(address, vchPubKeyOut);
+ }
+ return true;
+ }
+
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
+ if (mi != mapCryptedKeys.end())
+ {
+ vchPubKeyOut = (*mi).second.first;
+ return true;
+ }
+ // Check for watch-only pubkeys
+ return GetWatchPubKey(address, vchPubKeyOut);
+}
+
+std::set<CKeyID> CWallet::GetKeys() const
+{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return FillableSigningProvider::GetKeys();
+ }
+ std::set<CKeyID> set_address;
+ for (const auto& mi : mapCryptedKeys) {
+ set_address.insert(mi.first);
+ }
+ return set_address;
+}
+
+bool CWallet::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
+{
+ LOCK(cs_KeyStore);
+ if (!mapCryptedKeys.empty() || IsCrypted())
+ return false;
+
+ fUseCrypto = true;
+ for (const KeyMap::value_type& mKey : mapKeys)
+ {
+ const CKey &key = mKey.second;
+ CPubKey vchPubKey = key.GetPubKey();
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ std::vector<unsigned char> vchCryptedSecret;
+ if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
+ return false;
+ if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
+ return false;
+ }
+ mapKeys.clear();
+ return true;
+}
+
+bool CWallet::AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey)
+{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return FillableSigningProvider::AddKeyPubKey(key, pubkey);
+ }
+
+ if (IsLocked()) {
+ return false;
+ }
+
+ std::vector<unsigned char> vchCryptedSecret;
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
+ return false;
+ }
+
+ if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
+ return false;
+ }
+ return true;
+}
+
+
+bool CWallet::AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
+{
+ LOCK(cs_KeyStore);
+ if (!SetCrypted()) {
+ return false;
+ }
+
+ mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
+ ImplicitlyLearnRelatedKeyScripts(vchPubKey);
+ return true;
+}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 7b5465c219..6a7097bf44 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -35,6 +35,8 @@
#include <utility>
#include <vector>
+#include <boost/signals2/signal.hpp>
+
//! Explicitly unload and delete the wallet.
//! Blocks the current thread after signaling the unload intent so that all
//! wallet clients release the wallet.
@@ -49,6 +51,14 @@ std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> GetWallet(const std::string& name);
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::string& warning);
+enum WalletCreationStatus {
+ SUCCESS,
+ CREATION_FAILED,
+ ENCRYPTION_FAILED
+};
+
+std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning, WalletCreationStatus& status, const SecureString& passphrase, uint64_t wallet_creation_flags);
+
//! Default for -keypool
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
//! -paytxfee default
@@ -85,11 +95,11 @@ static constexpr size_t DUMMY_NESTED_P2WPKH_INPUT_SIZE = 91;
class CCoinControl;
class COutput;
-class CReserveKey;
class CScript;
class CWalletTx;
struct FeeCalculation;
enum class FeeEstimateMode;
+class ReserveDestination;
/** (client) version numbers for particular wallet features */
enum WalletFeature
@@ -254,55 +264,57 @@ public:
}
};
-/** A wrapper to reserve a key from a wallet keypool
+/** A wrapper to reserve an address from a wallet
*
- * CReserveKey is used to reserve a key from the keypool. It is passed around
- * during the CreateTransaction/CommitTransaction procedure.
+ * ReserveDestination is used to reserve an address.
+ * It is currently only used inside of CreateTransaction.
*
- * Instantiating a CReserveKey does not reserve a keypool key. To do so,
- * GetReservedKey() needs to be called on the object. Once a key has been
- * reserved, call KeepKey() on the CReserveKey object to make sure it is not
- * returned to the keypool. Call ReturnKey() to return the key to the keypool
- * so it can be re-used (for example, if the key was used in a new transaction
+ * Instantiating a ReserveDestination does not reserve an address. To do so,
+ * GetReservedDestination() needs to be called on the object. Once an address has been
+ * reserved, call KeepDestination() on the ReserveDestination object to make sure it is not
+ * returned. Call ReturnDestination() to return the address so it can be re-used (for
+ * example, if the address was used in a new transaction
* and that transaction was not completed and needed to be aborted).
*
- * If a key is reserved and KeepKey() is not called, then the key will be
- * returned to the keypool when the CReserveObject goes out of scope.
+ * If an address is reserved and KeepDestination() is not called, then the address will be
+ * returned when the ReserveDestination goes out of scope.
*/
-class CReserveKey
+class ReserveDestination
{
protected:
- //! The wallet to reserve the keypool key from
+ //! The wallet to reserve from
CWallet* pwallet;
- //! The index of the key in the keypool
+ //! The index of the address's key in the keypool
int64_t nIndex{-1};
- //! The public key
+ //! The public key for the address
CPubKey vchPubKey;
+ //! The destination
+ CTxDestination address;
//! Whether this is from the internal (change output) keypool
bool fInternal{false};
public:
- //! Construct a CReserveKey object. This does NOT reserve a key from the keypool yet
- explicit CReserveKey(CWallet* pwalletIn)
+ //! Construct a ReserveDestination object. This does NOT reserve an address yet
+ explicit ReserveDestination(CWallet* pwalletIn)
{
pwallet = pwalletIn;
}
- CReserveKey(const CReserveKey&) = delete;
- CReserveKey& operator=(const CReserveKey&) = delete;
+ ReserveDestination(const ReserveDestination&) = delete;
+ ReserveDestination& operator=(const ReserveDestination&) = delete;
//! Destructor. If a key has been reserved and not KeepKey'ed, it will be returned to the keypool
- ~CReserveKey()
+ ~ReserveDestination()
{
- ReturnKey();
+ ReturnDestination();
}
- //! Reserve a key from the keypool
- bool GetReservedKey(CPubKey &pubkey, bool internal = false);
- //! Return a key to the keypool
- void ReturnKey();
- //! Keep the key. Do not return it to the keypool when this object goes out of scope
- void KeepKey();
+ //! Reserve an address
+ bool GetReservedDestination(const OutputType type, CTxDestination& pubkey, bool internal);
+ //! Return reserved address
+ void ReturnDestination();
+ //! Keep the address. Do not return it's key to the keypool when this object goes out of scope
+ void KeepDestination();
};
/** Address book data */
@@ -709,9 +721,35 @@ class WalletRescanReserver; //forward declarations for ScanForWalletTransactions
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/
-class CWallet final : public CCryptoKeyStore, private interfaces::Chain::Notifications
+class CWallet final : public FillableSigningProvider, private interfaces::Chain::Notifications
{
private:
+ CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore);
+
+ //! if fUseCrypto is true, mapKeys must be empty
+ //! if fUseCrypto is false, vMasterKey must be empty
+ std::atomic<bool> fUseCrypto;
+
+ //! keeps track of whether Unlock has run a thorough check before
+ bool fDecryptionThoroughlyChecked;
+
+ using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;
+ using WatchOnlySet = std::set<CScript>;
+ using WatchKeyMap = std::map<CKeyID, CPubKey>;
+
+ bool SetCrypted();
+
+ //! will encrypt previously unencrypted keys
+ bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
+
+ bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false);
+ CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);
+ WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);
+ WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);
+
+ bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
+ bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey);
+
std::atomic<bool> fAbortRescan{false};
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
std::atomic<int64_t> m_scanning_start{0};
@@ -794,8 +832,9 @@ private:
* of the other AddWatchOnly which accepts a timestamp and sets
* nTimeFirstKey more intelligently for more efficient rescans.
*/
- bool AddWatchOnly(const CScript& dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool AddWatchOnly(const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool AddWatchOnlyInMem(const CScript &dest);
/** Add a KeyOriginInfo to the wallet */
bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info);
@@ -835,6 +874,9 @@ private:
*/
uint256 m_last_block_processed GUARDED_BY(cs_wallet);
+ //! Fetches a key from the keypool
+ bool GetKeyFromPool(CPubKey &key, bool internal = false);
+
public:
/*
* Main wallet lock.
@@ -879,7 +921,9 @@ public:
/** Construct wallet with specified name and database implementation. */
CWallet(interfaces::Chain* chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database)
- : m_chain(chain),
+ : fUseCrypto(false),
+ fDecryptionThoroughlyChecked(false),
+ m_chain(chain),
m_location(location),
database(std::move(database))
{
@@ -893,6 +937,10 @@ public:
encrypted_batch = nullptr;
}
+ bool IsCrypted() const { return fUseCrypto; }
+ bool IsLocked() const;
+ bool Lock();
+
std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet);
typedef std::multimap<int64_t, CWalletTx*> TxItems;
@@ -975,7 +1023,7 @@ public:
//! Adds a key to the store, and saves it to disk.
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
- bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
+ bool LoadKey(const CKey& key, const CPubKey &pubkey) { return AddKeyPubKeyInner(key, pubkey); }
//! Load metadata (used by LoadWallet)
void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -986,9 +1034,13 @@ public:
void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds an encrypted key to the store, and saves it to disk.
- bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) override;
+ bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
//! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
+ bool GetKey(const CKeyID &address, CKey& keyOut) const override;
+ bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
+ bool HaveKey(const CKeyID &address) const override;
+ std::set<CKeyID> GetKeys() const override;
bool AddCScript(const CScript& redeemScript) override;
bool LoadCScript(const CScript& redeemScript);
@@ -1005,9 +1057,15 @@ public:
//! Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- bool RemoveWatchOnly(const CScript &dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool RemoveWatchOnly(const CScript &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
bool LoadWatchOnly(const CScript &dest);
+ //! Returns whether the watch-only script is in the wallet
+ bool HaveWatchOnly(const CScript &dest) const;
+ //! Returns whether there are any watch-only things in the wallet
+ bool HaveWatchOnly() const;
+ //! Fetches a pubkey from mapWatchKeys if it exists there
+ bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const;
//! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock().
int64_t nRelockTime = 0;
@@ -1079,9 +1137,9 @@ public:
* selected by SelectCoins(); Also create the change output, when needed
* @note passing nChangePosInOut as -1 will result in setting a random position
*/
- bool CreateTransaction(interfaces::Chain::Lock& locked_chain, const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
+ bool CreateTransaction(interfaces::Chain::Lock& locked_chain, const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut,
std::string& strFailReason, const CCoinControl& coin_control, bool sign = true);
- bool CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CReserveKey& reservekey, CValidationState& state);
+ bool CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm, CValidationState& state);
bool DummySignTx(CMutableTransaction &txNew, const std::set<CTxOut> &txouts, bool use_max_sig = false) const
{
@@ -1136,7 +1194,6 @@ public:
bool ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
void KeepKey(int64_t nIndex);
void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey);
- bool GetKeyFromPool(CPubKey &key, bool internal = false);
int64_t GetOldestKeyPoolTime();
/**
* Marks all keys in the keypool up to and including reserve_key as used.
@@ -1149,6 +1206,9 @@ public:
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
+ bool GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, std::string& error);
+ bool GetNewChangeDestination(const OutputType type, CTxDestination& dest, std::string& error);
+
isminetype IsMine(const CTxIn& txin) const;
/**
* Returns amount of debit if the input matches the
@@ -1232,6 +1292,12 @@ public:
/** Keypool has new keys */
boost::signals2::signal<void ()> NotifyCanGetAddressesChanged;
+ /**
+ * Wallet status (encrypted, locked) changed.
+ * Note: Called without locks held.
+ */
+ boost::signals2::signal<void (CWallet* wallet)> NotifyStatusChanged;
+
/** Inquire whether this wallet broadcasts transactions. */
bool GetBroadcastTransactions() const { return fBroadcastTransactions; }
/** Set whether this wallet broadcasts transactions. */
@@ -1296,7 +1362,7 @@ public:
/**
* Explicitly make the wallet learn the related scripts for outputs to the
* given key. This is purely to make the wallet file compatible with older
- * software, as CBasicKeyStore automatically does this implicitly for all
+ * software, as FillableSigningProvider automatically does this implicitly for all
* keys now.
*/
void LearnRelatedScripts(const CPubKey& key, OutputType);
diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp
index a34968ef7d..cf97b7ecce 100644
--- a/src/zmq/zmqrpc.cpp
+++ b/src/zmq/zmqrpc.cpp
@@ -15,8 +15,6 @@ namespace {
UniValue getzmqnotifications(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 0) {
- throw std::runtime_error(
RPCHelpMan{"getzmqnotifications",
"\nReturns information about the active ZeroMQ notifications.\n",
{},
@@ -34,8 +32,7 @@ UniValue getzmqnotifications(const JSONRPCRequest& request)
HelpExampleCli("getzmqnotifications", "")
+ HelpExampleRpc("getzmqnotifications", "")
},
- }.ToString());
- }
+ }.Check(request);
UniValue result(UniValue::VARR);
if (g_zmq_notification_interface != nullptr) {