aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md5
-rwxr-xr-xcontrib/devtools/github-merge.py33
-rw-r--r--doc/developer-notes.md3
-rw-r--r--doc/productivity.md28
-rw-r--r--doc/release-notes-15637.md3
-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
-rwxr-xr-xtest/functional/mempool_packages.py12
-rwxr-xr-xtest/functional/mining_prioritisetransaction.py2
-rwxr-xr-xtest/functional/rpc_signrawtransaction.py1
-rwxr-xr-xtest/functional/test_framework/mininode.py2
-rw-r--r--test/sanitizer_suppressions/ubsan1
44 files changed, 791 insertions, 219 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 82c96efa0c..007ebd7ccf 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -239,7 +239,10 @@ consensus to merge a pull request (remember that discussions may have been
spread out over GitHub, mailing list and IRC discussions). The following
language is used within pull-request comments:
- - ACK means "I have tested the code and I agree it should be merged";
+ - (t)ACK means "I have tested the code and I agree it should be merged", involving
+ change-specific manual testing in addition to running the unit and functional
+ tests, and in case it is not obvious how the manual testing was done, it should
+ be described;
- NACK means "I disagree this should be merged", and must be accompanied by
sound technical justification (or in certain cases of copyright/patent/licensing
issues, legal justification). NACKs without accompanying reasoning may be
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index ab834b7623..41a640b464 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -47,13 +47,12 @@ def git_config_get(option, default=None):
except subprocess.CalledProcessError:
return default
-def retrieve_pr_info(repo,pull,ghtoken):
+def retrieve_json(req, ghtoken):
'''
- Retrieve pull request information from github.
- Return None if no title can be found, or an error happens.
+ Retrieve json from github.
+ Return None if an error happens.
'''
try:
- req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull)
if ghtoken is not None:
req.add_header('Authorization', 'token ' + ghtoken)
result = urlopen(req)
@@ -69,6 +68,18 @@ def retrieve_pr_info(repo,pull,ghtoken):
print('Warning: unable to retrieve pull information from github: %s' % e)
return None
+def retrieve_pr_info(repo,pull,ghtoken):
+ req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull)
+ return retrieve_json(req,ghtoken)
+
+def retrieve_pr_comments(repo,pull,ghtoken):
+ req = Request("https://api.github.com/repos/"+repo+"/issues/"+pull+"/comments")
+ return retrieve_json(req,ghtoken)
+
+def retrieve_pr_reviews(repo,pull,ghtoken):
+ req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull+"/reviews")
+ return retrieve_json(req,ghtoken)
+
def ask_prompt(text):
print(text,end=" ",file=stderr)
stderr.flush()
@@ -133,6 +144,16 @@ def tree_sha512sum(commit='HEAD'):
raise IOError('Non-zero return value executing git cat-file')
return overall.hexdigest()
+def get_acks_from_comments(head_commit, comments):
+ assert len(head_commit) == 6
+ ack_str ='\n\nACKs for commit {}:\n'.format(head_commit)
+ for c in comments:
+ review = [l for l in c['body'].split('\r\n') if 'ACK' in l and head_commit in l]
+ if review:
+ ack_str += ' {}:\n'.format(c['user']['login'])
+ ack_str += ' {}\n'.format(review[0])
+ return ack_str
+
def print_merge_details(pull, title, branch, base_branch, head_branch):
print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET))
subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch])
@@ -185,6 +206,9 @@ def main():
info = retrieve_pr_info(repo,pull,ghtoken)
if info is None:
sys.exit(1)
+ comments = retrieve_pr_comments(repo,pull,ghtoken) + retrieve_pr_reviews(repo,pull,ghtoken)
+ if comments is None:
+ sys.exit(1)
title = info['title'].strip()
body = info['body'].strip()
# precedence order for destination branch argument:
@@ -238,6 +262,7 @@ def main():
message = firstline + '\n\n'
message += subprocess.check_output([GIT,'log','--no-merges','--topo-order','--pretty=format:%h %s (%an)',base_branch+'..'+head_branch]).decode('utf-8')
message += '\n\nPull request description:\n\n ' + body.replace('\n', '\n ') + '\n'
+ message += get_acks_from_comments(head_commit=subprocess.check_output([GIT,'log','-1','--pretty=format:%H',head_branch]).decode('utf-8')[:6], comments=comments)
try:
subprocess.check_call([GIT,'merge','-q','--commit','--no-edit','--no-ff','-m',message.encode('utf-8'),head_branch])
except subprocess.CalledProcessError:
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 2662eea8fc..62c764bb31 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -952,8 +952,7 @@ A few guidelines for introducing and reviewing new RPC interfaces:
from there.
- A RPC method must either be a wallet method or a non-wallet method. Do not
- introduce new methods such as `signrawtransaction` that differ in behavior
- based on presence of a wallet.
+ introduce new methods that differ in behavior based on presence of a wallet.
- *Rationale*: as well as complicating the implementation and interfering
with the introduction of multi-wallet, wallet and non-wallet code should be
diff --git a/doc/productivity.md b/doc/productivity.md
index e0df558944..a93228ebdb 100644
--- a/doc/productivity.md
+++ b/doc/productivity.md
@@ -8,6 +8,7 @@ Table of Contents
* [Cache compilations with `ccache`](#cache-compilations-with-ccache)
* [Disable features with `./configure`](#disable-features-with-configure)
* [Make use of your threads with `make -j`](#make-use-of-your-threads-with-make--j)
+ * [Only build what you need](#only-build-what-you-need)
* [Multiple working directories with `git worktrees`](#multiple-working-directories-with-git-worktrees)
* [Writing code](#writing-code)
* [Format C/C++/Protobuf diffs with `clang-format-diff.py`](#format-ccprotobuf-diffs-with-clang-format-diffpy)
@@ -32,6 +33,17 @@ Install `ccache` through your distribution's package manager, and run `./configu
To use ccache for all your C/C++ projects, follow the symlinks method [here](https://ccache.samba.org/manual/latest.html#_run_modes) to set it up.
+To get the most out of ccache, put something like this in `~/.ccache/ccache.conf`:
+
+```
+max_size = 50.0G # or whatever cache size you prefer; default is 5G; 0 means unlimited
+base_dir = /home/yourname # or wherever you keep your source files
+```
+
+Note: base_dir is required for ccache to share cached compiles of the same file across different repositories / paths; it will only do this for paths under base_dir. So this option is required for effective use of ccache with git worktrees (described below).
+
+You _must not_ set base_dir to "/", or anywhere that contains system headers (according to the ccache docs).
+
### Disable features with `./configure`
After running `./autogen.sh`, which generates the `./configure` file, use `./configure --help` to identify features that you can disable to save on compilation time. A few common flags:
@@ -43,6 +55,8 @@ After running `./autogen.sh`, which generates the `./configure` file, use `./con
--without-gui
```
+If you do need the wallet enabled, it is common for devs to add `--with-incompatible-bdb`. This uses your system bdb version for the wallet, so you don't have to find a copy of bdb 4.8. Wallets from such a build will be incompatible with any release binary (and vice versa), so use with caution on mainnet.
+
### Make use of your threads with `make -j`
If you have multiple threads on your machine, you can tell `make` to utilize all of them with:
@@ -51,6 +65,20 @@ If you have multiple threads on your machine, you can tell `make` to utilize all
make -j"$(($(nproc)+1))"
```
+### Only build what you need
+
+When rebuilding during development, note that running `make`, without giving a target, will do a lot of work you probably don't need. It will build the GUI (unless you've disabled it) and all the tests (which take much longer to build than the app does).
+
+Obviously, it is important to build and run the tests at appropriate times -- but when you just want a quick compile to check your work, consider picking one or a set of build targets relevant to what you're working on, e.g.:
+
+```sh
+make src/bitcoind src/bitcoin-cli
+make src/qt/bitcoin-qt
+make -C src bitcoin_bench
+```
+
+(You can and should combine this with `-j`, as above, for a parallel build.)
+
### Multiple working directories with `git worktrees`
If you work with multiple branches or multiple copies of the repository, you should try `git worktrees`.
diff --git a/doc/release-notes-15637.md b/doc/release-notes-15637.md
new file mode 100644
index 0000000000..048d5e7218
--- /dev/null
+++ b/doc/release-notes-15637.md
@@ -0,0 +1,3 @@
+RPC changes
+-----------
+In getmempoolancestors, getmempooldescendants, getmempoolentry and getrawmempool RPCs, to be consistent with the returned value and other RPCs such as getrawtransaction, vsize has been added and size is now deprecated. size will only be returned if bitcoind is started with `-deprecatedrpc=size`. \ No newline at end of file
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 effc6b61a8..299a594585 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>
@@ -796,23 +797,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()) {
@@ -844,10 +842,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);
}
@@ -858,7 +856,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
@@ -902,15 +900,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);
@@ -920,7 +918,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;
@@ -1028,14 +1026,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)
{
const RPCHelpMan help{"sendrawtransaction",
@@ -2088,7 +2078,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. */
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 7cee215d54..507cdfa9f5 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -58,9 +58,9 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(len(mempool), MAX_ANCESTORS)
descendant_count = 1
descendant_fees = 0
- descendant_size = 0
+ descendant_vsize = 0
- ancestor_size = sum([mempool[tx]['size'] for tx in mempool])
+ ancestor_vsize = sum([mempool[tx]['vsize'] for tx in mempool])
ancestor_count = MAX_ANCESTORS
ancestor_fees = sum([mempool[tx]['fee'] for tx in mempool])
@@ -79,15 +79,15 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(mempool[x]['fees']['modified'], mempool[x]['modifiedfee'])
assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN)
assert_equal(mempool[x]['fees']['descendant'], descendant_fees)
- descendant_size += mempool[x]['size']
- assert_equal(mempool[x]['descendantsize'], descendant_size)
+ descendant_vsize += mempool[x]['vsize']
+ assert_equal(mempool[x]['descendantsize'], descendant_vsize)
descendant_count += 1
# Check that ancestor calculations are correct
assert_equal(mempool[x]['ancestorcount'], ancestor_count)
assert_equal(mempool[x]['ancestorfees'], ancestor_fees * COIN)
- assert_equal(mempool[x]['ancestorsize'], ancestor_size)
- ancestor_size -= mempool[x]['size']
+ assert_equal(mempool[x]['ancestorsize'], ancestor_vsize)
+ ancestor_vsize -= mempool[x]['vsize']
ancestor_fees -= mempool[x]['fee']
ancestor_count -= 1
diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py
index 687a5b527b..b0a069be81 100755
--- a/test/functional/mining_prioritisetransaction.py
+++ b/test/functional/mining_prioritisetransaction.py
@@ -64,7 +64,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
for i in range(3):
for j in txids[i]:
assert j in mempool
- sizes[i] += mempool[j]['size']
+ sizes[i] += mempool[j]['vsize']
assert sizes[i] > MAX_BLOCK_BASE_SIZE # Fail => raise utxo_count
# add a fee delta to something in the cheapest bucket and make sure it gets mined
diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py
index dcafc82857..780758e219 100755
--- a/test/functional/rpc_signrawtransaction.py
+++ b/test/functional/rpc_signrawtransaction.py
@@ -15,7 +15,6 @@ class SignRawTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
- self.extra_args = [["-deprecatedrpc=signrawtransaction"], []]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index 52a840941b..7a063ac526 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -171,7 +171,7 @@ class P2PConnection(asyncio.Protocol):
if len(self.recvbuf) < 4:
return
if self.recvbuf[:4] != self.magic_bytes:
- raise ValueError("got garbage %s" % repr(self.recvbuf))
+ raise ValueError("magic bytes mismatch: {} != {}".format(repr(self.magic_bytes), repr(self.recvbuf)))
if len(self.recvbuf) < 4 + 12 + 4 + 4:
return
command = self.recvbuf[4:4+12].split(b"\x00", 1)[0]
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index d55119b266..643272de52 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -15,6 +15,7 @@ unsigned-integer-overflow:coded_stream.h
unsigned-integer-overflow:core_write.cpp
unsigned-integer-overflow:crypto/chacha20.cpp
unsigned-integer-overflow:crypto/ctaes/ctaes.c
+unsigned-integer-overflow:crypto/poly1305.cpp
unsigned-integer-overflow:crypto/ripemd160.cpp
unsigned-integer-overflow:crypto/sha1.cpp
unsigned-integer-overflow:crypto/sha256.cpp