aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/Makefile.bench.include1
-rw-r--r--src/bench/poly1305.cpp41
-rw-r--r--src/crypto/poly1305.cpp141
-rw-r--r--src/crypto/poly1305.h17
-rw-r--r--src/interfaces/chain.cpp114
-rw-r--r--src/interfaces/chain.h54
-rw-r--r--src/interfaces/wallet.cpp11
-rw-r--r--src/interfaces/wallet.h3
-rw-r--r--src/net_processing.cpp40
-rw-r--r--src/node/coin.cpp22
-rw-r--r--src/node/coin.h22
-rw-r--r--src/qt/rpcconsole.cpp1
-rw-r--r--src/qt/walletcontroller.cpp14
-rw-r--r--src/qt/walletmodeltransaction.cpp2
-rw-r--r--src/rpc/blockchain.cpp7
-rw-r--r--src/rpc/misc.cpp6
-rw-r--r--src/rpc/rawtransaction.cpp53
-rw-r--r--src/rpc/server.cpp61
-rw-r--r--src/rpc/server.h31
-rw-r--r--src/test/crypto_tests.cpp82
-rw-r--r--src/test/rpc_tests.cpp5
-rw-r--r--src/validation.cpp30
-rw-r--r--src/validation.h6
-rw-r--r--src/wallet/feebumper.cpp14
-rw-r--r--src/wallet/fees.cpp9
-rw-r--r--src/wallet/init.cpp2
-rw-r--r--src/wallet/rpcdump.cpp14
-rw-r--r--src/wallet/rpcwallet.cpp21
-rw-r--r--src/wallet/rpcwallet.h9
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp9
-rw-r--r--src/wallet/test/wallet_test_fixture.h2
-rw-r--r--src/wallet/wallet.cpp56
-rw-r--r--src/wallet/wallet.h16
34 files changed, 717 insertions, 203 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index da96a1d96a..bef2c10636 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -154,6 +154,7 @@ BITCOIN_CORE_H = \
netaddress.h \
netbase.h \
netmessagemaker.h \
+ node/coin.h \
node/transaction.h \
noui.h \
optional.h \
@@ -262,6 +263,7 @@ libbitcoin_server_a_SOURCES = \
miner.cpp \
net.cpp \
net_processing.cpp \
+ node/coin.cpp \
node/transaction.cpp \
noui.cpp \
outputtype.cpp \
@@ -344,6 +346,8 @@ crypto_libbitcoin_crypto_base_a_SOURCES = \
crypto/hmac_sha256.h \
crypto/hmac_sha512.cpp \
crypto/hmac_sha512.h \
+ crypto/poly1305.h \
+ crypto/poly1305.cpp \
crypto/ripemd160.cpp \
crypto/ripemd160.h \
crypto/sha1.cpp \
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 3042f6df19..b84360e84b 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -31,6 +31,7 @@ bench_bench_bitcoin_SOURCES = \
bench/base58.cpp \
bench/bech32.cpp \
bench/lockedpool.cpp \
+ bench/poly1305.cpp \
bench/prevector.cpp
nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES)
diff --git a/src/bench/poly1305.cpp b/src/bench/poly1305.cpp
new file mode 100644
index 0000000000..16342d0fbe
--- /dev/null
+++ b/src/bench/poly1305.cpp
@@ -0,0 +1,41 @@
+// 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/poly1305.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 void POLY1305(benchmark::State& state, size_t buffersize)
+{
+ std::vector<unsigned char> tag(POLY1305_TAGLEN, 0);
+ std::vector<unsigned char> key(POLY1305_KEYLEN, 0);
+ std::vector<unsigned char> in(buffersize, 0);
+ while (state.KeepRunning())
+ poly1305_auth(tag.data(), in.data(), in.size(), key.data());
+}
+
+static void POLY1305_64BYTES(benchmark::State& state)
+{
+ POLY1305(state, BUFFER_SIZE_TINY);
+}
+
+static void POLY1305_256BYTES(benchmark::State& state)
+{
+ POLY1305(state, BUFFER_SIZE_SMALL);
+}
+
+static void POLY1305_1MB(benchmark::State& state)
+{
+ POLY1305(state, BUFFER_SIZE_LARGE);
+}
+
+BENCHMARK(POLY1305_64BYTES, 500000);
+BENCHMARK(POLY1305_256BYTES, 250000);
+BENCHMARK(POLY1305_1MB, 340);
diff --git a/src/crypto/poly1305.cpp b/src/crypto/poly1305.cpp
new file mode 100644
index 0000000000..8a86c9601c
--- /dev/null
+++ b/src/crypto/poly1305.cpp
@@ -0,0 +1,141 @@
+// 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.
+
+// Based on the public domain implementation by Andrew Moon
+// poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
+
+#include <crypto/common.h>
+#include <crypto/poly1305.h>
+
+#include <string.h>
+
+#define mul32x32_64(a,b) ((uint64_t)(a) * (b))
+
+void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) {
+ uint32_t t0,t1,t2,t3;
+ uint32_t h0,h1,h2,h3,h4;
+ uint32_t r0,r1,r2,r3,r4;
+ uint32_t s1,s2,s3,s4;
+ uint32_t b, nb;
+ size_t j;
+ uint64_t t[5];
+ uint64_t f0,f1,f2,f3;
+ uint64_t g0,g1,g2,g3,g4;
+ uint64_t c;
+ unsigned char mp[16];
+
+ /* clamp key */
+ t0 = ReadLE32(key+0);
+ t1 = ReadLE32(key+4);
+ t2 = ReadLE32(key+8);
+ t3 = ReadLE32(key+12);
+
+ /* precompute multipliers */
+ r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6;
+ r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12;
+ r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18;
+ r3 = t2 & 0x3f03fff; t3 >>= 8;
+ r4 = t3 & 0x00fffff;
+
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ /* init state */
+ h0 = 0;
+ h1 = 0;
+ h2 = 0;
+ h3 = 0;
+ h4 = 0;
+
+ /* full blocks */
+ if (inlen < 16) goto poly1305_donna_atmost15bytes;
+poly1305_donna_16bytes:
+ m += 16;
+ inlen -= 16;
+
+ t0 = ReadLE32(m-16);
+ t1 = ReadLE32(m-12);
+ t2 = ReadLE32(m-8);
+ t3 = ReadLE32(m-4);
+
+ h0 += t0 & 0x3ffffff;
+ h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
+ h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
+ h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff;
+ h4 += (t3 >> 8) | (1 << 24);
+
+
+poly1305_donna_mul:
+ t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1);
+ t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2);
+ t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3);
+ t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4);
+ t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0);
+
+ h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26);
+ t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26);
+ t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26);
+ t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26);
+ t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26);
+ h0 += b * 5;
+
+ if (inlen >= 16) goto poly1305_donna_16bytes;
+
+ /* final bytes */
+poly1305_donna_atmost15bytes:
+ if (!inlen) goto poly1305_donna_finish;
+
+ for (j = 0; j < inlen; j++) mp[j] = m[j];
+ mp[j++] = 1;
+ for (; j < 16; j++) mp[j] = 0;
+ inlen = 0;
+
+ t0 = ReadLE32(mp+0);
+ t1 = ReadLE32(mp+4);
+ t2 = ReadLE32(mp+8);
+ t3 = ReadLE32(mp+12);
+
+ h0 += t0 & 0x3ffffff;
+ h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
+ h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
+ h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff;
+ h4 += (t3 >> 8);
+
+ goto poly1305_donna_mul;
+
+poly1305_donna_finish:
+ b = h0 >> 26; h0 = h0 & 0x3ffffff;
+ h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff;
+ h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff;
+ h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff;
+ h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff;
+ h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff;
+ h1 += b;
+
+ g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff;
+ g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff;
+ g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff;
+ g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff;
+ g4 = h4 + b - (1 << 26);
+
+ b = (g4 >> 31) - 1;
+ nb = ~b;
+ h0 = (h0 & nb) | (g0 & b);
+ h1 = (h1 & nb) | (g1 & b);
+ h2 = (h2 & nb) | (g2 & b);
+ h3 = (h3 & nb) | (g3 & b);
+ h4 = (h4 & nb) | (g4 & b);
+
+ f0 = ((h0 ) | (h1 << 26)) + (uint64_t)ReadLE32(&key[16]);
+ f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)ReadLE32(&key[20]);
+ f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)ReadLE32(&key[24]);
+ f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)ReadLE32(&key[28]);
+
+ WriteLE32(&out[ 0], f0); f1 += (f0 >> 32);
+ WriteLE32(&out[ 4], f1); f2 += (f1 >> 32);
+ WriteLE32(&out[ 8], f2); f3 += (f2 >> 32);
+ WriteLE32(&out[12], f3);
+}
diff --git a/src/crypto/poly1305.h b/src/crypto/poly1305.h
new file mode 100644
index 0000000000..1598b013b9
--- /dev/null
+++ b/src/crypto/poly1305.h
@@ -0,0 +1,17 @@
+// 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_POLY1305_H
+#define BITCOIN_CRYPTO_POLY1305_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#define POLY1305_KEYLEN 32
+#define POLY1305_TAGLEN 16
+
+void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen,
+ const unsigned char key[POLY1305_KEYLEN]);
+
+#endif // BITCOIN_CRYPTO_POLY1305_H
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index 2eecea28d0..0c765f2092 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -6,22 +6,29 @@
#include <chain.h>
#include <chainparams.h>
+#include <interfaces/handler.h>
#include <interfaces/wallet.h>
#include <net.h>
+#include <node/coin.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/rbf.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <protocol.h>
+#include <rpc/protocol.h>
+#include <rpc/server.h>
+#include <shutdown.h>
#include <sync.h>
#include <threadsafety.h>
#include <timedata.h>
#include <txmempool.h>
#include <ui_interface.h>
#include <uint256.h>
+#include <univalue.h>
#include <util/system.h>
#include <validation.h>
+#include <validationinterface.h>
#include <memory>
#include <utility>
@@ -161,6 +168,94 @@ class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
using UniqueLock::UniqueLock;
};
+class NotificationsHandlerImpl : public Handler, CValidationInterface
+{
+public:
+ explicit NotificationsHandlerImpl(Chain& chain, Chain::Notifications& notifications)
+ : m_chain(chain), m_notifications(&notifications)
+ {
+ RegisterValidationInterface(this);
+ }
+ ~NotificationsHandlerImpl() override { disconnect(); }
+ void disconnect() override
+ {
+ if (m_notifications) {
+ m_notifications = nullptr;
+ UnregisterValidationInterface(this);
+ }
+ }
+ void TransactionAddedToMempool(const CTransactionRef& tx) override
+ {
+ m_notifications->TransactionAddedToMempool(tx);
+ }
+ void TransactionRemovedFromMempool(const CTransactionRef& tx) override
+ {
+ m_notifications->TransactionRemovedFromMempool(tx);
+ }
+ void BlockConnected(const std::shared_ptr<const CBlock>& block,
+ const CBlockIndex* index,
+ const std::vector<CTransactionRef>& tx_conflicted) override
+ {
+ m_notifications->BlockConnected(*block, tx_conflicted);
+ }
+ void BlockDisconnected(const std::shared_ptr<const CBlock>& block) override
+ {
+ m_notifications->BlockDisconnected(*block);
+ }
+ void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->ChainStateFlushed(locator); }
+ void ResendWalletTransactions(int64_t best_block_time, CConnman*) override
+ {
+ // `cs_main` is always held when this method is called, so it is safe to
+ // call `assumeLocked`. This is awkward, and the `assumeLocked` method
+ // should be able to be removed entirely if `ResendWalletTransactions`
+ // is replaced by a wallet timer as suggested in
+ // https://github.com/bitcoin/bitcoin/issues/15619
+ auto locked_chain = m_chain.assumeLocked();
+ m_notifications->ResendWalletTransactions(*locked_chain, best_block_time);
+ }
+ Chain& m_chain;
+ Chain::Notifications* m_notifications;
+};
+
+class RpcHandlerImpl : public Handler
+{
+public:
+ 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;
+ try {
+ return m_wrapped_command->actor(request, result, last_handler);
+ } catch (const UniValue& e) {
+ // If this is not the last handler and a wallet not found
+ // exception was thrown, return false so the next handler can
+ // try to handle the request. Otherwise, reraise the exception.
+ if (!last_handler) {
+ const UniValue& code = e["code"];
+ if (code.isNum() && code.get_int() == RPC_WALLET_NOT_FOUND) {
+ return false;
+ }
+ }
+ throw;
+ }
+ };
+ ::tableRPC.appendCommand(m_command.name, &m_command);
+ }
+
+ void disconnect() override final
+ {
+ if (m_wrapped_command) {
+ m_wrapped_command = nullptr;
+ ::tableRPC.removeCommand(m_command.name, &m_command);
+ }
+ }
+
+ ~RpcHandlerImpl() override { disconnect(); }
+
+ CRPCCommand m_command;
+ const CRPCCommand* m_wrapped_command;
+};
+
class ChainImpl : public Chain
{
public:
@@ -194,6 +289,7 @@ public:
}
return true;
}
+ void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(coins); }
double guessVerificationProgress(const uint256& block_hash) override
{
LOCK(cs_main);
@@ -245,17 +341,33 @@ public:
{
return ::mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
}
+ CFeeRate relayMinFee() override { return ::minRelayTxFee; }
+ CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
+ CFeeRate relayDustFee() override { return ::dustRelayFee; }
CAmount maxTxFee() override { return ::maxTxFee; }
bool getPruneMode() override { return ::fPruneMode; }
bool p2pEnabled() override { return g_connman != nullptr; }
bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
+ bool shutdownRequested() override { return ShutdownRequested(); }
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
void initWarning(const std::string& message) override { InitWarning(message); }
void initError(const std::string& message) override { InitError(message); }
void loadWallet(std::unique_ptr<Wallet> wallet) override { ::uiInterface.LoadWallet(wallet); }
+ void showProgress(const std::string& title, int progress, bool resume_possible) override
+ {
+ ::uiInterface.ShowProgress(title, progress, resume_possible);
+ }
+ std::unique_ptr<Handler> handleNotifications(Notifications& notifications) override
+ {
+ return MakeUnique<NotificationsHandlerImpl>(*this, notifications);
+ }
+ void waitForNotifications() override { SyncWithValidationInterfaceQueue(); }
+ std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
+ {
+ return MakeUnique<RpcHandlerImpl>(command);
+ }
};
-
} // namespace
std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index 037e8e9ff5..a9b05f27fc 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -16,8 +16,10 @@
class CBlock;
class CFeeRate;
+class CRPCCommand;
class CScheduler;
class CValidationState;
+class Coin;
class uint256;
enum class RBFTransactionState;
struct CBlockLocator;
@@ -25,6 +27,7 @@ struct FeeCalculation;
namespace interfaces {
+class Handler;
class Wallet;
//! Interface giving clients (wallet processes, maybe other analysis tools in
@@ -40,6 +43,12 @@ class Wallet;
//! asynchronously
//! (https://github.com/bitcoin/bitcoin/pull/10973#issuecomment-380101269).
//!
+//! * The isPotentialTip() and waitForNotifications() methods are too low-level
+//! and should be replaced with a higher level
+//! waitForNotificationsUpTo(block_hash) method that the wallet can call
+//! instead
+//! (https://github.com/bitcoin/bitcoin/pull/10973#discussion_r266995234).
+//!
//! * The relayTransactions() and submitToMemoryPool() methods could be replaced
//! with a higher-level broadcastTransaction method
//! (https://github.com/bitcoin/bitcoin/pull/14978#issuecomment-459373984).
@@ -160,6 +169,11 @@ public:
int64_t* time = nullptr,
int64_t* max_time = nullptr) = 0;
+ //! Look up unspent output information. Returns coins in the mempool and in
+ //! the current chain UTXO set. Iterates through all the keys in the map and
+ //! populates the values.
+ virtual void findCoins(std::map<COutPoint, Coin>& coins) = 0;
+
//! Estimate fraction of total transactions verified if blocks up to
//! the specified block hash are verified.
virtual double guessVerificationProgress(const uint256& block_hash) = 0;
@@ -188,6 +202,15 @@ public:
//! Mempool minimum fee.
virtual CFeeRate mempoolMinFee() = 0;
+ //! Relay current minimum fee (from -minrelaytxfee and -incrementalrelayfee settings).
+ virtual CFeeRate relayMinFee() = 0;
+
+ //! Relay incremental fee setting (-incrementalrelayfee), reflecting cost of relay.
+ virtual CFeeRate relayIncrementalFee() = 0;
+
+ //! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's economical to spend.
+ virtual CFeeRate relayDustFee() = 0;
+
//! Node max tx fee setting (-maxtxfee).
//! This could be replaced by a per-wallet max fee, as proposed at
//! https://github.com/bitcoin/bitcoin/issues/15355
@@ -200,9 +223,12 @@ public:
//! Check if p2p enabled.
virtual bool p2pEnabled() = 0;
- // Check if in IBD.
+ //! Check if in IBD.
virtual bool isInitialBlockDownload() = 0;
+ //! Check if shutdown requested.
+ virtual bool shutdownRequested() = 0;
+
//! Get adjusted time.
virtual int64_t getAdjustedTime() = 0;
@@ -217,6 +243,32 @@ public:
//! Send wallet load notification to the GUI.
virtual void loadWallet(std::unique_ptr<Wallet> wallet) = 0;
+
+ //! Send progress indicator.
+ virtual void showProgress(const std::string& title, int progress, bool resume_possible) = 0;
+
+ //! Chain notifications.
+ class Notifications
+ {
+ public:
+ virtual ~Notifications() {}
+ virtual void TransactionAddedToMempool(const CTransactionRef& tx) {}
+ virtual void TransactionRemovedFromMempool(const CTransactionRef& ptx) {}
+ virtual void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& tx_conflicted) {}
+ virtual void BlockDisconnected(const CBlock& block) {}
+ virtual void ChainStateFlushed(const CBlockLocator& locator) {}
+ virtual void ResendWalletTransactions(Lock& locked_chain, int64_t best_block_time) {}
+ };
+
+ //! Register handler for notifications.
+ virtual std::unique_ptr<Handler> handleNotifications(Notifications& notifications) = 0;
+
+ //! Wait for pending notifications to be handled.
+ virtual void waitForNotifications() = 0;
+
+ //! Register handler for RPC. Command is not copied, so reference
+ //! needs to remain valid until Handler is disconnected.
+ virtual std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) = 0;
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 7abbee0912..60173b29ac 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -47,8 +47,6 @@ public:
const CTransaction& get() override { return *m_tx; }
- int64_t getVirtualSize() override { return GetVirtualTransactionSize(*m_tx); }
-
bool commit(WalletValueMap value_map,
WalletOrderForm order_form,
std::string& reject_reason) override
@@ -99,12 +97,8 @@ WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, co
//! Construct wallet tx status struct.
WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx)
{
- LockAnnotation lock(::cs_main); // Temporary, for mapBlockIndex below. Removed in upcoming commit.
-
WalletTxStatus result;
- auto mi = ::mapBlockIndex.find(wtx.hashBlock);
- CBlockIndex* block = mi != ::mapBlockIndex.end() ? mi->second : nullptr;
- result.block_height = (block ? block->nHeight : std::numeric_limits<int>::max());
+ result.block_height = locked_chain.getBlockHeight(wtx.hashBlock).get_value_or(std::numeric_limits<int>::max());
result.blocks_to_maturity = wtx.GetBlocksToMaturity(locked_chain);
result.depth_in_main_chain = wtx.GetDepthInMainChain(locked_chain);
result.time_received = wtx.nTimeReceived;
@@ -514,7 +508,7 @@ public:
: m_chain(chain), m_wallet_filenames(std::move(wallet_filenames))
{
}
- void registerRpcs() override { return RegisterWalletRPCCommands(::tableRPC); }
+ void registerRpcs() override { return RegisterWalletRPCCommands(m_chain, m_rpc_handlers); }
bool verify() override { return VerifyWallets(m_chain, m_wallet_filenames); }
bool load() override { return LoadWallets(m_chain, m_wallet_filenames); }
void start(CScheduler& scheduler) override { return StartWallets(scheduler); }
@@ -524,6 +518,7 @@ public:
Chain& m_chain;
std::vector<std::string> m_wallet_filenames;
+ std::vector<std::unique_ptr<Handler>> m_rpc_handlers;
};
} // namespace
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index a931e5fafb..cabc455b1f 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -292,9 +292,6 @@ public:
//! Get transaction data.
virtual const CTransaction& get() = 0;
- //! Get virtual transaction size.
- virtual int64_t getVirtualSize() = 0;
-
//! Send pending transaction and commit to wallet.
virtual bool commit(WalletValueMap value_map,
WalletOrderForm order_form,
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 18dd2f010c..0247b9cc7e 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -2022,6 +2022,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
pfrom->AddAddressKnown(addr);
+ if (g_banman->IsBanned(addr)) continue; // Do not process banned addresses beyond remembering we received them
bool fReachable = IsReachable(addr);
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
@@ -2540,8 +2541,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
- if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::CMPCTBLOCK)
{
+ // Ignore cmpctblock received while importing
+ if (fImporting || fReindex) {
+ LogPrint(BCLog::NET, "Unexpected cmpctblock message received from peer %d\n", pfrom->GetId());
+ return true;
+ }
+
CBlockHeaderAndShortTxIDs cmpctblock;
vRecv >> cmpctblock;
@@ -2761,8 +2768,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
- if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::BLOCKTXN)
{
+ // Ignore blocktxn received while importing
+ if (fImporting || fReindex) {
+ LogPrint(BCLog::NET, "Unexpected blocktxn message received from peer %d\n", pfrom->GetId());
+ return true;
+ }
+
BlockTransactions resp;
vRecv >> resp;
@@ -2836,8 +2849,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
- if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing
+ if (strCommand == NetMsgType::HEADERS)
{
+ // Ignore headers received while importing
+ if (fImporting || fReindex) {
+ LogPrint(BCLog::NET, "Unexpected headers message received from peer %d\n", pfrom->GetId());
+ return true;
+ }
+
std::vector<CBlockHeader> headers;
// Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
@@ -2861,8 +2880,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return ProcessHeadersMessage(pfrom, connman, headers, chainparams, should_punish);
}
- if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::BLOCK)
{
+ // Ignore block received while importing
+ if (fImporting || fReindex) {
+ LogPrint(BCLog::NET, "Unexpected block message received from peer %d\n", pfrom->GetId());
+ return true;
+ }
+
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
vRecv >> *pblock;
@@ -2912,8 +2937,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->vAddrToSend.clear();
std::vector<CAddress> vAddr = connman->GetAddresses();
FastRandomContext insecure_rand;
- for (const CAddress &addr : vAddr)
- pfrom->PushAddress(addr, insecure_rand);
+ for (const CAddress &addr : vAddr) {
+ if (!g_banman->IsBanned(addr)) {
+ pfrom->PushAddress(addr, insecure_rand);
+ }
+ }
return true;
}
diff --git a/src/node/coin.cpp b/src/node/coin.cpp
new file mode 100644
index 0000000000..bb98e63f3a
--- /dev/null
+++ b/src/node/coin.cpp
@@ -0,0 +1,22 @@
+// 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 <node/coin.h>
+
+#include <txmempool.h>
+#include <validation.h>
+
+void FindCoins(std::map<COutPoint, Coin>& coins)
+{
+ LOCK2(cs_main, ::mempool.cs);
+ assert(pcoinsTip);
+ CCoinsViewCache& chain_view = *::pcoinsTip;
+ CCoinsViewMemPool mempool_view(&chain_view, ::mempool);
+ for (auto& coin : coins) {
+ if (!mempool_view.GetCoin(coin.first, coin.second)) {
+ // Either the coin is not in the CCoinsViewCache or is spent. Clear it.
+ coin.second.Clear();
+ }
+ }
+}
diff --git a/src/node/coin.h b/src/node/coin.h
new file mode 100644
index 0000000000..eb95b75cfb
--- /dev/null
+++ b/src/node/coin.h
@@ -0,0 +1,22 @@
+// 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_NODE_COIN_H
+#define BITCOIN_NODE_COIN_H
+
+#include <map>
+
+class COutPoint;
+class Coin;
+
+/**
+ * Look up unspent output information. Returns coins in the mempool and in the
+ * current chain UTXO set. Iterates through all the keys in the map and
+ * populates the values.
+ *
+ * @param[in,out] coins map to fill
+ */
+void FindCoins(std::map<COutPoint, Coin>& coins);
+
+#endif // BITCOIN_NODE_COIN_H
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index fc1e14b031..c7ced3c106 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -69,7 +69,6 @@ const QStringList historyFilter = QStringList()
<< "importmulti"
<< "sethdseed"
<< "signmessagewithprivkey"
- << "signrawtransaction"
<< "signrawtransactionwithkey"
<< "walletpassphrase"
<< "walletpassphrasechange"
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index fab86a7912..019bd65823 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -9,9 +9,11 @@
#include <algorithm>
+#include <QApplication>
#include <QMessageBox>
#include <QMutexLocker>
#include <QThread>
+#include <QWindow>
WalletController::WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent)
: QObject(parent)
@@ -97,7 +99,17 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
m_wallets.push_back(wallet_model);
connect(wallet_model, &WalletModel::unload, [this, wallet_model] {
- removeAndDeleteWallet(wallet_model);
+ // Defer removeAndDeleteWallet when no modal widget is active.
+ // TODO: remove this workaround by removing usage of QDiallog::exec.
+ if (QApplication::activeModalWidget()) {
+ connect(qApp, &QApplication::focusWindowChanged, wallet_model, [this, wallet_model]() {
+ if (!QApplication::activeModalWidget()) {
+ removeAndDeleteWallet(wallet_model);
+ }
+ }, Qt::QueuedConnection);
+ } else {
+ removeAndDeleteWallet(wallet_model);
+ }
});
// Re-emit coinsSent signal from wallet model.
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index eb3b0baf08..2694d67800 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -29,7 +29,7 @@ std::unique_ptr<interfaces::PendingWalletTx>& WalletModelTransaction::getWtx()
unsigned int WalletModelTransaction::getTransactionSize()
{
- return wtx ? wtx->getVirtualSize() : 0;
+ return wtx ? GetVirtualTransactionSize(wtx->get()) : 0;
}
CAmount WalletModelTransaction::getTransactionFee() const
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 1827aec637..d35f458b2e 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -378,7 +378,9 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
static std::string EntryDescriptionString()
{
- return " \"size\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n"
+ return " \"vsize\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n"
+ " \"size\" : n, (numeric) (DEPRECATED) same as vsize. Only returned if bitcoind is started with -deprecatedrpc=size\n"
+ " size will be completely removed in v0.20.\n"
" \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + " (DEPRECATED)\n"
" \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority (DEPRECATED)\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
@@ -416,7 +418,8 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
info.pushKV("fees", fees);
- info.pushKV("size", (int)e.GetTxSize());
+ info.pushKV("vsize", (int)e.GetTxSize());
+ if (IsDeprecatedRPCEnabled("size")) info.pushKV("size", (int)e.GetTxSize());
info.pushKV("fee", ValueFromAmount(e.GetFee()));
info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
info.pushKV("time", e.GetTime());
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 822a0beef9..0a97f80297 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -34,11 +34,7 @@ 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"
- "DEPRECATION WARNING: Parts of this command have been deprecated and moved to getaddressinfo. Clients must\n"
- "transition to using getaddressinfo to access this information before upgrading to v0.18. The following deprecated\n"
- "fields have moved to getaddressinfo and will only be shown here with -deprecatedrpc=validateaddress: ismine, iswatchonly,\n"
- "script, hex, pubkeys, sigsrequired, pubkey, addresses, embedded, iscompressed, account, timestamp, hdkeypath, kdmasterkeyid.\n",
+ "\nReturn information about the given bitcoin address.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to validate"},
},
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 1d58725a58..e3d8fb4e81 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -11,6 +11,7 @@
#include <core_io.h>
#include <index/txindex.h>
#include <init.h>
+#include <interfaces/chain.h>
#include <key_io.h>
#include <keystore.h>
#include <merkleblock.h>
@@ -791,23 +792,20 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
return EncodeHexTx(CTransaction(mergedTx));
}
+// TODO(https://github.com/bitcoin/bitcoin/pull/10973#discussion_r267084237):
+// This function is called from both wallet and node rpcs
+// (signrawtransactionwithwallet and signrawtransactionwithkey). It should be
+// moved to a util file so wallet code doesn't need to link against node code.
+// Also the dependency on interfaces::Chain should be removed, so
+// signrawtransactionwithkey doesn't need access to a Chain instance.
UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType)
{
// Fetch previous transactions (inputs):
- CCoinsView viewDummy;
- CCoinsViewCache view(&viewDummy);
- {
- LOCK2(cs_main, mempool.cs);
- CCoinsViewCache &viewChain = *pcoinsTip;
- CCoinsViewMemPool viewMempool(&viewChain, mempool);
- view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
-
- for (const CTxIn& txin : mtx.vin) {
- view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
- }
-
- view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
+ std::map<COutPoint, Coin> coins;
+ for (const CTxIn& txin : mtx.vin) {
+ coins[txin.prevout]; // Create empty map entry keyed by prevout.
}
+ chain.findCoins(coins);
// Add previous txouts given in the RPC call:
if (!prevTxsUnival.isNull()) {
@@ -839,10 +837,10 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
CScript scriptPubKey(pkData.begin(), pkData.end());
{
- const Coin& coin = view.AccessCoin(out);
- if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
+ auto coin = coins.find(out);
+ if (coin != coins.end() && !coin->second.IsSpent() && coin->second.out.scriptPubKey != scriptPubKey) {
std::string err("Previous output scriptPubKey mismatch:\n");
- err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
+ err = err + ScriptToAsmStr(coin->second.out.scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey);
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
}
@@ -853,7 +851,7 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
}
newcoin.nHeight = 1;
- view.AddCoin(out, std::move(newcoin), true);
+ coins[out] = std::move(newcoin);
}
// if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed
@@ -897,15 +895,15 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
// Sign what we can:
for (unsigned int i = 0; i < mtx.vin.size(); i++) {
CTxIn& txin = mtx.vin[i];
- const Coin& coin = view.AccessCoin(txin.prevout);
- if (coin.IsSpent()) {
+ auto coin = coins.find(txin.prevout);
+ if (coin == coins.end() || coin->second.IsSpent()) {
TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
continue;
}
- const CScript& prevPubKey = coin.out.scriptPubKey;
- const CAmount& amount = coin.out.nValue;
+ const CScript& prevPubKey = coin->second.out.scriptPubKey;
+ const CAmount& amount = coin->second.out.nValue;
- SignatureData sigdata = DataFromTransaction(mtx, i, coin.out);
+ SignatureData sigdata = DataFromTransaction(mtx, i, coin->second.out);
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mtx.vout.size())) {
ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
@@ -915,7 +913,7 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con
// amount must be specified for valid segwit signature
if (amount == MAX_MONEY && !txin.scriptWitness.IsNull()) {
- throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coin.out.ToString()));
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coin->second.out.ToString()));
}
ScriptError serror = SCRIPT_ERR_OK;
@@ -1023,14 +1021,6 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
return SignTransaction(*g_rpc_interfaces->chain, mtx, request.params[2], &keystore, true, request.params[3]);
}
-UniValue signrawtransaction(const JSONRPCRequest& request)
-{
- // This method should be removed entirely in V0.19, along with the entries in the
- // CRPCCommand table and rpc/client.cpp.
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "signrawtransaction was removed in v0.18.\n"
- "Clients should transition to using signrawtransactionwithkey and signrawtransactionwithwallet");
-}
-
static UniValue sendrawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
@@ -2080,7 +2070,6 @@ static const CRPCCommand commands[] =
{ "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees|maxfeerate"} },
{ "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
- { "hidden", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} },
{ "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} },
{ "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees|maxfeerate"} },
{ "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} },
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index cd90573da0..e803fabcc6 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -30,6 +30,7 @@ static std::string rpcWarmupStatus GUARDED_BY(cs_rpcWarmup) = "RPC server starte
static RPCTimerInterface* timerInterface = nullptr;
/* Map of name to timer. */
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
+static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler);
struct RPCCommandExecutionInfo
{
@@ -173,11 +174,11 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
{
std::string strRet;
std::string category;
- std::set<rpcfn_type> setDone;
+ std::set<intptr_t> setDone;
std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
for (const auto& entry : mapCommands)
- vCommands.push_back(make_pair(entry.second->category + entry.first, entry.second));
+ vCommands.push_back(make_pair(entry.second.front()->category + entry.first, entry.second.front()));
sort(vCommands.begin(), vCommands.end());
JSONRPCRequest jreq(helpreq);
@@ -193,9 +194,9 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
jreq.strMethod = strMethod;
try
{
- rpcfn_type pfn = pcmd->actor;
- if (setDone.insert(pfn).second)
- (*pfn)(jreq);
+ UniValue unused_result;
+ if (setDone.insert(pcmd->unique_id).second)
+ pcmd->actor(jreq, unused_result, true /* last_handler */);
}
catch (const std::exception& e)
{
@@ -337,32 +338,32 @@ CRPCTable::CRPCTable()
const CRPCCommand *pcmd;
pcmd = &vRPCCommands[vcidx];
- mapCommands[pcmd->name] = pcmd;
+ mapCommands[pcmd->name].push_back(pcmd);
}
}
-const CRPCCommand *CRPCTable::operator[](const std::string &name) const
-{
- std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
- if (it == mapCommands.end())
- return nullptr;
- return (*it).second;
-}
-
bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
{
if (IsRPCRunning())
return false;
- // don't allow overwriting for now
- std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
- if (it != mapCommands.end())
- return false;
-
- mapCommands[name] = pcmd;
+ mapCommands[name].push_back(pcmd);
return true;
}
+bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd)
+{
+ auto it = mapCommands.find(name);
+ if (it != mapCommands.end()) {
+ auto new_end = std::remove(it->second.begin(), it->second.end(), pcmd);
+ if (it->second.end() != new_end) {
+ it->second.erase(new_end, it->second.end());
+ return true;
+ }
+ }
+ return false;
+}
+
void StartRPC()
{
LogPrint(BCLog::RPC, "Starting RPC\n");
@@ -543,18 +544,28 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
}
// Find method
- const CRPCCommand *pcmd = tableRPC[request.strMethod];
- if (!pcmd)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
+ auto it = mapCommands.find(request.strMethod);
+ if (it != mapCommands.end()) {
+ UniValue result;
+ for (const auto& command : it->second) {
+ if (ExecuteCommand(*command, request, result, &command == &it->second.back())) {
+ return result;
+ }
+ }
+ }
+ throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
+}
+static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler)
+{
try
{
RPCCommandExecution execution(request.strMethod);
// Execute, convert arguments to array if necessary
if (request.params.isObject()) {
- return pcmd->actor(transformNamedArguments(request, pcmd->argNames));
+ return command.actor(transformNamedArguments(request, command.argNames), result, last_handler);
} else {
- return pcmd->actor(request);
+ return command.actor(request, result, last_handler);
}
}
catch (const std::exception& e)
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 2d62a76f3c..e2a85887ba 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -131,10 +131,31 @@ typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);
class CRPCCommand
{
public:
+ //! RPC method handler reading request and assigning result. Should return
+ //! true if request is fully handled, false if it should be passed on to
+ //! subsequent handlers.
+ using Actor = std::function<bool(const JSONRPCRequest& request, UniValue& result, bool last_handler)>;
+
+ //! Constructor taking Actor callback supporting multiple handlers.
+ CRPCCommand(std::string category, std::string name, Actor actor, std::vector<std::string> args, intptr_t unique_id)
+ : category(std::move(category)), name(std::move(name)), actor(std::move(actor)), argNames(std::move(args)),
+ unique_id(unique_id)
+ {
+ }
+
+ //! Simplified constructor taking plain rpcfn_type function pointer.
+ CRPCCommand(const char* category, const char* name, rpcfn_type fn, std::initializer_list<const char*> args)
+ : CRPCCommand(category, name,
+ [fn](const JSONRPCRequest& request, UniValue& result, bool) { result = fn(request); return true; },
+ {args.begin(), args.end()}, intptr_t(fn))
+ {
+ }
+
std::string category;
std::string name;
- rpcfn_type actor;
+ Actor actor;
std::vector<std::string> argNames;
+ intptr_t unique_id;
};
/**
@@ -143,10 +164,9 @@ public:
class CRPCTable
{
private:
- std::map<std::string, const CRPCCommand*> mapCommands;
+ std::map<std::string, std::vector<const CRPCCommand*>> mapCommands;
public:
CRPCTable();
- const CRPCCommand* operator[](const std::string& name) const;
std::string help(const std::string& name, const JSONRPCRequest& helpreq) const;
/**
@@ -169,9 +189,7 @@ public:
*
* Returns false if RPC server is already running (dump concurrency protection).
*
- * Commands cannot be overwritten (returns false).
- *
- * Commands with different method names but the same callback function will
+ * Commands with different method names but the same unique_id will
* be considered aliases, and only the first registered method name will
* show up in the help text command listing. Aliased commands do not have
* to have the same behavior. Server and client code can distinguish
@@ -179,6 +197,7 @@ public:
* register different names, types, and numbers of parameters.
*/
bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
+ bool removeCommand(const std::string& name, const CRPCCommand* pcmd);
};
bool IsDeprecatedRPCEnabled(const std::string& method);
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 86cb00a78f..352cff37d1 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/poly1305.h>
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
@@ -200,6 +201,17 @@ static void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t see
BOOST_CHECK(out == outres);
}
+static void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag)
+{
+ std::vector<unsigned char> key = ParseHex(hexkey);
+ std::vector<unsigned char> m = ParseHex(hexmessage);
+ std::vector<unsigned char> tag = ParseHex(hextag);
+ std::vector<unsigned char> tagres;
+ tagres.resize(POLY1305_TAGLEN);
+ poly1305_auth(tagres.data(), m.data(), m.size(), key.data());
+ BOOST_CHECK(tag == tagres);
+}
+
static std::string LongTestString() {
std::string ret;
for (int i=0; i<200000; i++) {
@@ -524,6 +536,76 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector)
"fab78c9");
}
+BOOST_AUTO_TEST_CASE(poly1305_testvector)
+{
+ // RFC 7539, section 2.5.2.
+ TestPoly1305("43727970746f6772617068696320466f72756d2052657365617263682047726f7570",
+ "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b",
+ "a8061dc1305136c6c22b8baf0c0127a9");
+
+ // RFC 7539, section A.3.
+ TestPoly1305("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000");
+
+ TestPoly1305("416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e747269627"
+ "5746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465"
+ "726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686"
+ "520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e2022494554"
+ "4620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c20737461746"
+ "56d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c65"
+ "6374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207"
+ "768696368206172652061646472657373656420746f",
+ "0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e",
+ "36e5f6b5c5e06070f0efca96227a863e");
+
+ TestPoly1305("416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e747269627"
+ "5746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465"
+ "726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686"
+ "520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e2022494554"
+ "4620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c20737461746"
+ "56d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c65"
+ "6374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207"
+ "768696368206172652061646472657373656420746f",
+ "36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000",
+ "f3477e7cd95417af89a6b8794c310cf0");
+
+ TestPoly1305("2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e6420676"
+ "96d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e"
+ "6420746865206d6f6d65207261746873206f757467726162652e",
+ "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0",
+ "4541669a7eaaee61e708dc7cbcc5eb62");
+
+ TestPoly1305("ffffffffffffffffffffffffffffffff",
+ "0200000000000000000000000000000000000000000000000000000000000000",
+ "03000000000000000000000000000000");
+
+ TestPoly1305("02000000000000000000000000000000",
+ "02000000000000000000000000000000ffffffffffffffffffffffffffffffff",
+ "03000000000000000000000000000000");
+
+ TestPoly1305("fffffffffffffffffffffffffffffffff0ffffffffffffffffffffffffffffff11000000000000000000000000000000",
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ "05000000000000000000000000000000");
+
+ TestPoly1305("fffffffffffffffffffffffffffffffffbfefefefefefefefefefefefefefefe01010101010101010101010101010101",
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000");
+
+ TestPoly1305("fdffffffffffffffffffffffffffffff",
+ "0200000000000000000000000000000000000000000000000000000000000000",
+ "faffffffffffffffffffffffffffffff");
+
+ TestPoly1305("e33594d7505e43b900000000000000003394d7505e4379cd01000000000000000000000000000000000000000000000001000000000000000000000000000000",
+ "0100000000000000040000000000000000000000000000000000000000000000",
+ "14000000000000005500000000000000");
+
+ TestPoly1305("e33594d7505e43b900000000000000003394d7505e4379cd010000000000000000000000000000000000000000000000",
+ "0100000000000000040000000000000000000000000000000000000000000000",
+ "13000000000000000000000000000000");
+}
+
BOOST_AUTO_TEST_CASE(countbits_tests)
{
FastRandomContext ctx;
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index ff48398925..9bb2bf551b 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -31,10 +31,9 @@ UniValue CallRPC(std::string args)
request.strMethod = strMethod;
request.params = RPCConvertValues(strMethod, vArgs);
request.fHelp = false;
- BOOST_CHECK(tableRPC[strMethod]);
- rpcfn_type method = tableRPC[strMethod]->actor;
+ if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
try {
- UniValue result = (*method)(request);
+ UniValue result = tableRPC.execute(request);
return result;
}
catch (const UniValue& objError) {
diff --git a/src/validation.cpp b/src/validation.cpp
index 97f51d2968..ae3985485e 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -36,9 +36,9 @@
#include <txmempool.h>
#include <ui_interface.h>
#include <undo.h>
-#include <util/system.h>
#include <util/moneystr.h>
#include <util/strencodings.h>
+#include <util/system.h>
#include <validationinterface.h>
#include <warnings.h>
@@ -1455,9 +1455,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
return true;
}
-namespace {
-
-bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
+static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
{
// Open history file to append
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
@@ -1484,7 +1482,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint25
return true;
}
-static bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex *pindex)
+bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex)
{
FlatFilePos pos = pindex->GetUndoPos();
if (pos.IsNull()) {
@@ -1533,8 +1531,6 @@ static bool AbortNode(CValidationState& state, const std::string& strMessage, co
return state.Error(strMessage);
}
-} // namespace
-
/**
* Restore the UTXO in a Coin at a given COutPoint
* @param undo The Coin to be restored.
@@ -3159,26 +3155,6 @@ static int GetWitnessCommitmentIndex(const CBlock& block)
return commitpos;
}
-// Compute at which vout of the block's coinbase transaction the signet
-// signature occurs, or -1 if not found.
-static int GetSignetSignatureIndex(const CBlock& block)
-{
- if (!block.vtx.empty()) {
- for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {
- if (block.vtx[0]->vout[o].scriptPubKey.size() >= 68 // at minimum 64 byte signature plus script/header data
- && block.vtx[0]->vout[o].scriptPubKey[0] == OP_RETURN // unspendable
- && block.vtx[0]->vout[o].scriptPubKey[1] == block.vtx[0]->vout[o].scriptPubKey.size() - 1 // push the rest
- && block.vtx[0]->vout[o].scriptPubKey[2] == 0xec // 's' ^ 0x9f
- && block.vtx[0]->vout[o].scriptPubKey[3] == 0xc7 // 'i' ^ 0xae
- && block.vtx[0]->vout[o].scriptPubKey[4] == 0xda // 'g' ^ 0xbd
- && block.vtx[0]->vout[o].scriptPubKey[5] == 0xa2) { // 'n' ^ 0xcc
- return (int)o;
- }
- }
- }
- return -1;
-}
-
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams)
{
int commitpos = GetWitnessCommitmentIndex(block);
diff --git a/src/validation.h b/src/validation.h
index 0acca013b5..d84e3a0dbc 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -21,6 +21,7 @@
#include <versionbits.h>
#include <algorithm>
+#include <atomic>
#include <exception>
#include <map>
#include <memory>
@@ -30,10 +31,9 @@
#include <utility>
#include <vector>
-#include <atomic>
-
class CBlockIndex;
class CBlockTreeDB;
+class CBlockUndo;
class CChainParams;
class CCoinsViewDB;
class CInv;
@@ -391,6 +391,8 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start);
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, const CMessageHeader::MessageStartChars& message_start);
+bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex);
+
/** Functions for validating blocks and updating the block tree */
/** Context-independent validity checks */
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index a1c3a21d4b..ef7f3be728 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -123,16 +123,17 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin
// The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
// future proof against changes to network wide policy for incremental relay
// fee that our node may not be aware of.
+ CFeeRate nodeIncrementalRelayFee = wallet->chain().relayIncrementalFee();
CFeeRate walletIncrementalRelayFee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);
- if (::incrementalRelayFee > walletIncrementalRelayFee) {
- walletIncrementalRelayFee = ::incrementalRelayFee;
+ if (nodeIncrementalRelayFee > walletIncrementalRelayFee) {
+ walletIncrementalRelayFee = nodeIncrementalRelayFee;
}
if (total_fee > 0) {
- CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + ::incrementalRelayFee.GetFee(maxNewTxSize);
+ CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + nodeIncrementalRelayFee.GetFee(maxNewTxSize);
if (total_fee < minTotalFee) {
errors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
- FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(::incrementalRelayFee.GetFee(maxNewTxSize))));
+ FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(nodeIncrementalRelayFee.GetFee(maxNewTxSize))));
return Result::INVALID_PARAMETER;
}
CAmount requiredFee = GetRequiredFee(*wallet, maxNewTxSize);
@@ -159,9 +160,10 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin
}
// Check that in all cases the new fee doesn't violate maxTxFee
- if (new_fee > maxTxFee) {
+ const CAmount max_tx_fee = wallet->chain().maxTxFee();
+ if (new_fee > max_tx_fee) {
errors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
- FormatMoney(new_fee), FormatMoney(maxTxFee)));
+ FormatMoney(new_fee), FormatMoney(max_tx_fee)));
return Result::WALLET_ERROR;
}
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
index 545adaebc1..560c86a70a 100644
--- a/src/wallet/fees.cpp
+++ b/src/wallet/fees.cpp
@@ -22,8 +22,9 @@ CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinC
{
CAmount fee_needed = GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
// Always obey the maximum
- if (fee_needed > maxTxFee) {
- fee_needed = maxTxFee;
+ const CAmount max_tx_fee = wallet.chain().maxTxFee();
+ if (fee_needed > max_tx_fee) {
+ fee_needed = max_tx_fee;
if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
}
return fee_needed;
@@ -31,7 +32,7 @@ CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinC
CFeeRate GetRequiredFeeRate(const CWallet& wallet)
{
- return std::max(wallet.m_min_fee, ::minRelayTxFee);
+ return std::max(wallet.m_min_fee, wallet.chain().relayMinFee());
}
CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_control, FeeCalculation* feeCalc)
@@ -96,6 +97,6 @@ CFeeRate GetDiscardRate(const CWallet& wallet)
// Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
discard_rate = (discard_rate == CFeeRate(0)) ? wallet.m_discard_rate : std::min(discard_rate, wallet.m_discard_rate);
// Discard rate must be at least dustRelayFee
- discard_rate = std::max(discard_rate, ::dustRelayFee);
+ discard_rate = std::max(discard_rate, wallet.chain().relayDustFee());
return discard_rate;
}
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 7ad343c15f..76a7eaa681 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -153,7 +153,7 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
- uiInterface.InitMessage(_("Verifying wallet(s)..."));
+ chain.initMessage(_("Verifying wallet(s)..."));
// Parameter interaction code should have thrown an error if -salvagewallet
// was enabled with more than wallet file, so the wallet_files size check
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 684d900478..6c3b5a49dc 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -595,11 +595,11 @@ UniValue importwallet(const JSONRPCRequest& request)
// Use uiInterface.ShowProgress instead of pwallet.ShowProgress because pwallet.ShowProgress has a cancel button tied to AbortRescan which
// we don't want for this progress bar showing the import progress. uiInterface.ShowProgress does not have a cancel button.
- uiInterface.ShowProgress(strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI
+ pwallet->chain().showProgress(strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI
std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
std::vector<std::pair<CScript, int64_t>> scripts;
while (file.good()) {
- uiInterface.ShowProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false);
+ pwallet->chain().showProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false);
std::string line;
std::getline(file, line);
if (line.empty() || line[0] == '#')
@@ -637,13 +637,13 @@ UniValue importwallet(const JSONRPCRequest& request)
file.close();
// We now know whether we are importing private keys, so we can error if private keys are disabled
if (keys.size() > 0 && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
+ pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when private keys are disabled");
}
double total = (double)(keys.size() + scripts.size());
double progress = 0;
for (const auto& key_tuple : keys) {
- uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
+ pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
const CKey& key = std::get<0>(key_tuple);
int64_t time = std::get<1>(key_tuple);
bool has_label = std::get<2>(key_tuple);
@@ -668,7 +668,7 @@ UniValue importwallet(const JSONRPCRequest& request)
progress++;
}
for (const auto& script_pair : scripts) {
- uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
+ pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
const CScript& script = script_pair.first;
int64_t time = script_pair.second;
CScriptID id(script);
@@ -687,10 +687,10 @@ UniValue importwallet(const JSONRPCRequest& request)
}
progress++;
}
- uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
+ pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
pwallet->UpdateTimeFirstKey(nTimeBegin);
}
- uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
+ pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
pwallet->MarkDirty();
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 31a3209a49..d32613fc77 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2367,8 +2367,8 @@ static UniValue settxfee(const JSONRPCRequest& request)
CFeeRate tx_fee_rate(nAmount, 1000);
if (tx_fee_rate == 0) {
// automatic selection
- } else if (tx_fee_rate < ::minRelayTxFee) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", ::minRelayTxFee.ToString()));
+ } else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));
} else if (tx_fee_rate < pwallet->m_min_fee) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString()));
}
@@ -3881,19 +3881,6 @@ UniValue sethdseed(const JSONRPCRequest& request)
return NullUniValue;
}
-void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
-{
- CPubKey vchPubKey;
- if (!pwallet->GetPubKey(keyID, vchPubKey)) {
- return;
- }
- KeyOriginInfo info;
- if (!pwallet->GetKeyOrigin(keyID, info)) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
- }
- hd_keypaths.emplace(vchPubKey, std::move(info));
-}
-
UniValue walletprocesspsbt(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -4156,8 +4143,8 @@ static const CRPCCommand commands[] =
};
// clang-format on
-void RegisterWalletRPCCommands(CRPCTable &t)
+void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- t.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ handlers.emplace_back(chain.handleRpc(commands[vcidx]));
}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index 58053bde59..7cf607ccc7 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -5,7 +5,9 @@
#ifndef BITCOIN_WALLET_RPCWALLET_H
#define BITCOIN_WALLET_RPCWALLET_H
+#include <memory>
#include <string>
+#include <vector>
class CRPCTable;
class CWallet;
@@ -14,7 +16,12 @@ class UniValue;
struct PartiallySignedTransaction;
class CTransaction;
-void RegisterWalletRPCCommands(CRPCTable &t);
+namespace interfaces {
+class Chain;
+class Handler;
+}
+
+void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers);
/**
* Figures out what wallet, if any, to use for a JSONRPCRequest.
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index a5fb1db86c..6a051214a9 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -13,12 +13,7 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
{
bool fFirstRun;
m_wallet.LoadWallet(fFirstRun);
- RegisterValidationInterface(&m_wallet);
+ m_wallet.m_chain_notifications_handler = m_chain->handleNotifications(m_wallet);
- RegisterWalletRPCCommands(tableRPC);
-}
-
-WalletTestingSetup::~WalletTestingSetup()
-{
- UnregisterValidationInterface(&m_wallet);
+ m_chain_client->registerRpcs();
}
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index e6fe8c9473..dcfbc55f94 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -17,9 +17,9 @@
*/
struct WalletTestingSetup: public TestingSetup {
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
- ~WalletTestingSetup();
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
+ std::unique_ptr<interfaces::ChainClient> m_chain_client = interfaces::MakeWalletClient(*m_chain, {});
CWallet m_wallet;
};
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index de686b0ddf..95756f988f 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -96,7 +96,7 @@ static void ReleaseWallet(CWallet* wallet)
wallet->WalletLogPrintf("Releasing wallet\n");
wallet->BlockUntilSyncedToCurrentChain();
wallet->Flush();
- UnregisterValidationInterface(wallet);
+ wallet->m_chain_notifications_handler.reset();
delete wallet;
// Wallet is now released, notify UnloadWallet, if any.
{
@@ -1243,7 +1243,8 @@ void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
}
}
-void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
+void CWallet::BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted) {
+ const uint256& block_hash = block.GetHash();
auto locked_chain = chain().lock();
LOCK(cs_wallet);
// TODO: Temporarily ensure that mempool removals are notified before
@@ -1258,19 +1259,19 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
TransactionRemovedFromMempool(ptx);
}
- for (size_t i = 0; i < pblock->vtx.size(); i++) {
- SyncTransaction(pblock->vtx[i], pindex->GetBlockHash(), i);
- TransactionRemovedFromMempool(pblock->vtx[i]);
+ for (size_t i = 0; i < block.vtx.size(); i++) {
+ SyncTransaction(block.vtx[i], block_hash, i);
+ TransactionRemovedFromMempool(block.vtx[i]);
}
- m_last_block_processed = pindex->GetBlockHash();
+ m_last_block_processed = block_hash;
}
-void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
+void CWallet::BlockDisconnected(const CBlock& block) {
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- for (const CTransactionRef& ptx : pblock->vtx) {
+ for (const CTransactionRef& ptx : block.vtx) {
SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
}
}
@@ -1297,7 +1298,7 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
// ...otherwise put a callback in the validation interface queue and wait
// for the queue to drain enough to execute it (indicating we are caught up
// at least with the time we entered this function).
- SyncWithValidationInterfaceQueue();
+ chain().waitForNotifications();
}
@@ -1790,7 +1791,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
progress_end = chain().guessVerificationProgress(stop_block.IsNull() ? tip_hash : stop_block);
}
double progress_current = progress_begin;
- while (block_height && !fAbortRescan && !ShutdownRequested()) {
+ while (block_height && !fAbortRescan && !chain().shutdownRequested()) {
if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100))));
}
@@ -1852,7 +1853,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
if (block_height && fAbortRescan) {
WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", *block_height, progress_current);
result.status = ScanResult::USER_ABORT;
- } else if (block_height && ShutdownRequested()) {
+ } else if (block_height && chain().shutdownRequested()) {
WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", *block_height, progress_current);
result.status = ScanResult::USER_ABORT;
}
@@ -2137,7 +2138,7 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(interfaces::Chain::
return result;
}
-void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman)
+void CWallet::ResendWalletTransactions(interfaces::Chain::Lock& locked_chain, int64_t nBestBlockTime)
{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
@@ -2155,8 +2156,7 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman
// Rebroadcast unconfirmed txes older than 5 minutes before the last
// block was found:
- auto locked_chain = chain().assumeLocked(); // Temporary. Removed in upcoming lock cleanup
- std::vector<uint256> relayed = ResendWalletTransactionsBefore(*locked_chain, nBestBlockTime-5*60);
+ std::vector<uint256> relayed = ResendWalletTransactionsBefore(locked_chain, nBestBlockTime-5*60);
if (!relayed.empty())
WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
}
@@ -2310,7 +2310,6 @@ CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const
void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const int nMinDepth, const int nMaxDepth) const
{
- AssertLockHeld(cs_main);
AssertLockHeld(cs_wallet);
vCoins.clear();
@@ -2420,7 +2419,6 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins(interfaces::Chain::Lock& locked_chain) const
{
- AssertLockHeld(cs_main);
AssertLockHeld(cs_wallet);
std::map<CTxDestination, std::vector<COutput>> result;
@@ -2692,13 +2690,13 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
return true;
}
-static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain)
+static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain)
{
- if (IsInitialBlockDownload()) {
+ if (chain.isInitialBlockDownload()) {
return false;
}
constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; // in seconds
- if (chainActive.Tip()->GetBlockTime() < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) {
+ if (locked_chain.getBlockTime(*locked_chain.getHeight()) < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) {
return false;
}
return true;
@@ -2708,7 +2706,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain)
* Return a height-based locktime for new transactions (uses the height of the
* current chain tip unless we are not synced with the current chain
*/
-static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain)
+static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain)
{
uint32_t const height = locked_chain.getHeight().get_value_or(-1);
uint32_t locktime;
@@ -2732,7 +2730,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
// enough, that fee sniping isn't a problem yet, but by implementing a fix
// now we ensure code won't be written that makes assumptions about
// nLockTime that preclude a fix later.
- if (IsCurrentForAntiFeeSniping(locked_chain)) {
+ if (IsCurrentForAntiFeeSniping(chain, locked_chain)) {
locktime = height;
// Secondly occasionally randomly pick a nLockTime even further back, so
@@ -2806,7 +2804,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
CMutableTransaction txNew;
- txNew.nLockTime = GetLocktimeForNewTransaction(locked_chain);
+ txNew.nLockTime = GetLocktimeForNewTransaction(chain(), locked_chain);
FeeCalculation feeCalc;
CAmount nFeeNeeded;
@@ -2902,7 +2900,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
// Include the fee cost for outputs. Note this is only used for BnB right now
coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION);
- if (IsDust(txout, ::dustRelayFee))
+ if (IsDust(txout, chain().relayDustFee()))
{
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
{
@@ -3003,7 +3001,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
// 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 < ::minRelayTxFee.GetFee(nBytes))
+ if (nFeeNeeded < chain().relayMinFee().GetFee(nBytes))
{
strFailReason = _("Transaction too large for fee policy");
return false;
@@ -4280,9 +4278,9 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
_("This is the transaction fee you will pay if you send a transaction."));
}
walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000);
- if (walletInstance->m_pay_tx_fee < ::minRelayTxFee) {
+ if (walletInstance->m_pay_tx_fee < chain.relayMinFee()) {
chain.initError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
- gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
+ gArgs.GetArg("-paytxfee", ""), chain.relayMinFee().ToString()));
return nullptr;
}
}
@@ -4384,8 +4382,8 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
chain.loadWallet(interfaces::MakeWallet(walletInstance));
- // Register with the validation interface. It's ok to do this after rescan since we're still holding cs_main.
- RegisterValidationInterface(walletInstance.get());
+ // Register with the validation interface. It's ok to do this after rescan since we're still holding locked_chain.
+ walletInstance->m_chain_notifications_handler = chain.handleNotifications(*walletInstance);
walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
@@ -4445,8 +4443,6 @@ int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
if (hashUnset())
return 0;
- AssertLockHeld(cs_main);
-
return locked_chain.getBlockDepth(hashBlock) * (nIndex == -1 ? -1 : 1);
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index ea196c8799..86448efcaf 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -8,6 +8,7 @@
#include <amount.h>
#include <interfaces/chain.h>
+#include <interfaces/handler.h>
#include <outputtype.h>
#include <policy/feerate.h>
#include <streams.h>
@@ -505,7 +506,7 @@ public:
CAmount GetCredit(interfaces::Chain::Lock& locked_chain, const isminefilter& filter) const;
CAmount GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true) const;
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
- // annotation "EXCLUSIVE_LOCKS_REQUIRED(cs_main, pwallet->cs_wallet)". The
+ // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The
// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
// having to resolve the issue of member access into incomplete type CWallet.
CAmount GetAvailableCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS;
@@ -637,7 +638,7 @@ 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, public CValidationInterface
+class CWallet final : public CCryptoKeyStore, private interfaces::Chain::Notifications
{
private:
std::atomic<bool> fAbortRescan{false};
@@ -808,6 +809,9 @@ public:
std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet);
+ /** Registered interfaces::Chain::Notifications handler. */
+ std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
+
/** Interface for accessing chain state. */
interfaces::Chain& chain() const { return m_chain; }
@@ -920,8 +924,8 @@ public:
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
void LoadToWallet(const CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void TransactionAddedToMempool(const CTransactionRef& tx) override;
- void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
- void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
+ void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted) override;
+ void BlockDisconnected(const CBlock& block) override;
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
struct ScanResult {
@@ -942,7 +946,7 @@ public:
ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions();
- void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void ResendWalletTransactions(interfaces::Chain::Lock& locked_chain, int64_t nBestBlockTime) override;
// ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
std::vector<uint256> ResendWalletTransactionsBefore(interfaces::Chain::Lock& locked_chain, int64_t nTime);
CAmount GetBalance(const isminefilter& filter=ISMINE_SPENDABLE, const int min_depth=0) const;
@@ -1220,6 +1224,8 @@ public:
/** Add a KeyOriginInfo to the wallet */
bool AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info);
+
+ friend struct WalletTestingSetup;
};
/** A key allocated from the key pool. */