aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.bench.include1
-rw-r--r--src/Makefile.test.include3
-rw-r--r--src/bench/bench_bitcoin.cpp2
-rw-r--r--src/bench/crypto_hash.cpp6
-rw-r--r--src/bench/gcs_filter.cpp43
-rw-r--r--src/bench/rollingbloom.cpp3
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/bitcoin-tx.cpp2
-rw-r--r--src/bitcoind.cpp2
-rw-r--r--src/blockfilter.cpp260
-rw-r--r--src/blockfilter.h145
-rw-r--r--src/bloom.cpp6
-rw-r--r--src/compat.h6
-rw-r--r--src/core_write.cpp3
-rw-r--r--src/interfaces/handler.cpp2
-rw-r--r--src/interfaces/wallet.cpp10
-rw-r--r--src/key_io.cpp2
-rw-r--r--src/net.cpp1
-rw-r--r--src/net.h1
-rw-r--r--src/net_processing.cpp130
-rw-r--r--src/net_processing.h2
-rw-r--r--src/noui.cpp2
-rw-r--r--src/policy/policy.cpp23
-rw-r--r--src/prevector.h2
-rw-r--r--src/qt/addresstablemodel.cpp2
-rw-r--r--src/qt/bitcoin.cpp10
-rw-r--r--src/qt/bitcoingui.cpp2
-rw-r--r--src/qt/rpcconsole.cpp2
-rw-r--r--src/qt/splashscreen.cpp4
-rw-r--r--src/qt/transactiontablemodel.cpp6
-rw-r--r--src/rpc/blockchain.cpp15
-rw-r--r--src/rpc/client.cpp10
-rw-r--r--src/rpc/net.cpp2
-rw-r--r--src/rpc/rawtransaction.cpp22
-rw-r--r--src/script/ismine.cpp3
-rw-r--r--src/script/sign.cpp65
-rw-r--r--src/script/sign.h49
-rw-r--r--src/script/standard.cpp57
-rw-r--r--src/script/standard.h5
-rw-r--r--src/streams.h167
-rw-r--r--src/test/blockfilter_tests.cpp142
-rw-r--r--src/test/data/blockfilters.json9
-rw-r--r--src/test/descriptor_tests.cpp2
-rw-r--r--src/test/miner_tests.cpp4
-rw-r--r--src/test/scheduler_tests.cpp4
-rw-r--r--src/test/script_standard_tests.cpp47
-rw-r--r--src/test/script_tests.cpp8
-rw-r--r--src/test/streams_tests.cpp80
-rw-r--r--src/test/test_bitcoin.cpp10
-rw-r--r--src/test/test_bitcoin_fuzzy.cpp12
-rw-r--r--src/test/txindex_tests.cpp2
-rw-r--r--src/test/validation_block_tests.cpp2
-rw-r--r--src/txmempool.cpp7
-rw-r--r--src/txmempool.h3
-rw-r--r--src/undo.h1
-rw-r--r--src/util.cpp2
-rw-r--r--src/util.h23
-rw-r--r--src/utilstrencodings.cpp40
-rw-r--r--src/utilstrencodings.h3
-rw-r--r--src/validation.cpp29
-rw-r--r--src/validation.h8
-rw-r--r--src/validationinterface.cpp1
-rw-r--r--src/validationinterface.h4
-rw-r--r--src/wallet/coinselection.cpp3
-rw-r--r--src/wallet/feebumper.cpp2
-rw-r--r--src/wallet/rpcdump.cpp2
-rw-r--r--src/wallet/rpcwallet.cpp882
-rw-r--r--src/wallet/test/accounting_tests.cpp136
-rw-r--r--src/wallet/test/coinselector_tests.cpp10
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp47
-rw-r--r--src/wallet/wallet.h43
73 files changed, 1383 insertions, 1269 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d1693fa85c..3701ee8f3c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -96,6 +96,7 @@ BITCOIN_CORE_H = \
bech32.h \
bloom.h \
blockencodings.h \
+ blockfilter.h \
chain.h \
chainparams.h \
chainparamsbase.h \
@@ -219,6 +220,7 @@ libbitcoin_server_a_SOURCES = \
addrman.cpp \
bloom.cpp \
blockencodings.cpp \
+ blockfilter.cpp \
chain.cpp \
checkpoints.cpp \
consensus/tx_verify.cpp \
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index f5293585a0..76177630ab 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -22,6 +22,7 @@ bench_bench_bitcoin_SOURCES = \
bench/rollingbloom.cpp \
bench/crypto_hash.cpp \
bench/ccoins_caching.cpp \
+ bench/gcs_filter.cpp \
bench/merkle_root.cpp \
bench/mempool_eviction.cpp \
bench/verify_script.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 6f401636f5..abfd66efad 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -9,6 +9,7 @@ TEST_BINARY=test/test_bitcoin$(EXEEXT)
JSON_TEST_FILES = \
test/data/base58_encode_decode.json \
+ test/data/blockfilters.json \
test/data/key_io_valid.json \
test/data/key_io_invalid.json \
test/data/script_tests.json \
@@ -39,6 +40,7 @@ BITCOIN_TESTS =\
test/bip32_tests.cpp \
test/blockchain_tests.cpp \
test/blockencodings_tests.cpp \
+ test/blockfilter_tests.cpp \
test/bloom_tests.cpp \
test/bswap_tests.cpp \
test/checkqueue_tests.cpp \
@@ -94,7 +96,6 @@ BITCOIN_TESTS =\
if ENABLE_WALLET
BITCOIN_TESTS += \
- wallet/test/accounting_tests.cpp \
wallet/test/psbt_wallet_tests.cpp \
wallet/test/wallet_tests.cpp \
wallet/test/wallet_crypto_tests.cpp \
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 603b858e54..d7b8083e7c 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -13,6 +13,8 @@
#include <memory>
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
static const int64_t DEFAULT_BENCH_EVALUATIONS = 5;
static const char* DEFAULT_BENCH_FILTER = ".*";
static const char* DEFAULT_BENCH_SCALING = "1.0";
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index bab22f5984..5b0cf27e04 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -80,18 +80,16 @@ static void SipHash_32b(benchmark::State& state)
static void FastRandom_32bit(benchmark::State& state)
{
FastRandomContext rng(true);
- uint32_t x = 0;
while (state.KeepRunning()) {
- x += rng.rand32();
+ rng.rand32();
}
}
static void FastRandom_1bit(benchmark::State& state)
{
FastRandomContext rng(true);
- uint32_t x = 0;
while (state.KeepRunning()) {
- x += rng.randbool();
+ rng.randbool();
}
}
diff --git a/src/bench/gcs_filter.cpp b/src/bench/gcs_filter.cpp
new file mode 100644
index 0000000000..6f4e384e3b
--- /dev/null
+++ b/src/bench/gcs_filter.cpp
@@ -0,0 +1,43 @@
+// Copyright (c) 2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <bench/bench.h>
+#include <blockfilter.h>
+
+static void ConstructGCSFilter(benchmark::State& state)
+{
+ GCSFilter::ElementSet elements;
+ for (int i = 0; i < 10000; ++i) {
+ GCSFilter::Element element(32);
+ element[0] = static_cast<unsigned char>(i);
+ element[1] = static_cast<unsigned char>(i >> 8);
+ elements.insert(std::move(element));
+ }
+
+ uint64_t siphash_k0 = 0;
+ while (state.KeepRunning()) {
+ GCSFilter filter(siphash_k0, 0, 20, 1 << 20, elements);
+
+ siphash_k0++;
+ }
+}
+
+static void MatchGCSFilter(benchmark::State& state)
+{
+ GCSFilter::ElementSet elements;
+ for (int i = 0; i < 10000; ++i) {
+ GCSFilter::Element element(32);
+ element[0] = static_cast<unsigned char>(i);
+ element[1] = static_cast<unsigned char>(i >> 8);
+ elements.insert(std::move(element));
+ }
+ GCSFilter filter(0, 0, 20, 1 << 20, elements);
+
+ while (state.KeepRunning()) {
+ filter.Match(GCSFilter::Element());
+ }
+}
+
+BENCHMARK(ConstructGCSFilter, 1000);
+BENCHMARK(MatchGCSFilter, 50 * 1000);
diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp
index 43e7635047..0a99ea3184 100644
--- a/src/bench/rollingbloom.cpp
+++ b/src/bench/rollingbloom.cpp
@@ -12,7 +12,6 @@ static void RollingBloom(benchmark::State& state)
CRollingBloomFilter filter(120000, 0.000001);
std::vector<unsigned char> data(32);
uint32_t count = 0;
- uint64_t match = 0;
while (state.KeepRunning()) {
count++;
data[0] = count;
@@ -25,7 +24,7 @@ static void RollingBloom(benchmark::State& state)
data[1] = count >> 16;
data[2] = count >> 8;
data[3] = count;
- match += filter.contains(data);
+ filter.contains(data);
}
}
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index db713f58d2..c9414e67c7 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -24,6 +24,8 @@
#include <univalue.h>
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
static const bool DEFAULT_NAMED=false;
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 5fef4724c9..20f0218ac1 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -31,6 +31,8 @@ static bool fCreateBlank;
static std::map<std::string,UniValue> registers;
static const int CONTINUE_EXECUTION=-1;
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
static void SetupBitcoinTxArgs()
{
gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS);
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 06f8622426..bf04d95b50 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -23,6 +23,8 @@
#include <stdio.h>
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
/* Introduction text for doxygen: */
/*! \mainpage Developer documentation
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
new file mode 100644
index 0000000000..38fcfacf7f
--- /dev/null
+++ b/src/blockfilter.cpp
@@ -0,0 +1,260 @@
+// Copyright (c) 2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <blockfilter.h>
+#include <hash.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <streams.h>
+
+/// SerType used to serialize parameters in GCS filter encoding.
+static constexpr int GCS_SER_TYPE = SER_NETWORK;
+
+/// Protocol version used to serialize parameters in GCS filter encoding.
+static constexpr int GCS_SER_VERSION = 0;
+
+template <typename OStream>
+static void GolombRiceEncode(BitStreamWriter<OStream>& bitwriter, uint8_t P, uint64_t x)
+{
+ // Write quotient as unary-encoded: q 1's followed by one 0.
+ uint64_t q = x >> P;
+ while (q > 0) {
+ int nbits = q <= 64 ? static_cast<int>(q) : 64;
+ bitwriter.Write(~0ULL, nbits);
+ q -= nbits;
+ }
+ bitwriter.Write(0, 1);
+
+ // Write the remainder in P bits. Since the remainder is just the bottom
+ // P bits of x, there is no need to mask first.
+ bitwriter.Write(x, P);
+}
+
+template <typename IStream>
+static uint64_t GolombRiceDecode(BitStreamReader<IStream>& bitreader, uint8_t P)
+{
+ // Read unary-encoded quotient: q 1's followed by one 0.
+ uint64_t q = 0;
+ while (bitreader.Read(1) == 1) {
+ ++q;
+ }
+
+ uint64_t r = bitreader.Read(P);
+
+ return (q << P) + r;
+}
+
+// Map a value x that is uniformly distributed in the range [0, 2^64) to a
+// value uniformly distributed in [0, n) by returning the upper 64 bits of
+// x * n.
+//
+// See: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
+static uint64_t MapIntoRange(uint64_t x, uint64_t n)
+{
+#ifdef __SIZEOF_INT128__
+ return (static_cast<unsigned __int128>(x) * static_cast<unsigned __int128>(n)) >> 64;
+#else
+ // To perform the calculation on 64-bit numbers without losing the
+ // result to overflow, split the numbers into the most significant and
+ // least significant 32 bits and perform multiplication piece-wise.
+ //
+ // See: https://stackoverflow.com/a/26855440
+ uint64_t x_hi = x >> 32;
+ uint64_t x_lo = x & 0xFFFFFFFF;
+ uint64_t n_hi = n >> 32;
+ uint64_t n_lo = n & 0xFFFFFFFF;
+
+ uint64_t ac = x_hi * n_hi;
+ uint64_t ad = x_hi * n_lo;
+ uint64_t bc = x_lo * n_hi;
+ uint64_t bd = x_lo * n_lo;
+
+ uint64_t mid34 = (bd >> 32) + (bc & 0xFFFFFFFF) + (ad & 0xFFFFFFFF);
+ uint64_t upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32);
+ return upper64;
+#endif
+}
+
+uint64_t GCSFilter::HashToRange(const Element& element) const
+{
+ uint64_t hash = CSipHasher(m_siphash_k0, m_siphash_k1)
+ .Write(element.data(), element.size())
+ .Finalize();
+ return MapIntoRange(hash, m_F);
+}
+
+std::vector<uint64_t> GCSFilter::BuildHashedSet(const ElementSet& elements) const
+{
+ std::vector<uint64_t> hashed_elements;
+ hashed_elements.reserve(elements.size());
+ for (const Element& element : elements) {
+ hashed_elements.push_back(HashToRange(element));
+ }
+ std::sort(hashed_elements.begin(), hashed_elements.end());
+ return hashed_elements;
+}
+
+GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M)
+ : m_siphash_k0(siphash_k0), m_siphash_k1(siphash_k1), m_P(P), m_M(M), m_N(0), m_F(0)
+{}
+
+GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
+ std::vector<unsigned char> encoded_filter)
+ : GCSFilter(siphash_k0, siphash_k1, P, M)
+{
+ m_encoded = std::move(encoded_filter);
+
+ VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
+
+ uint64_t N = ReadCompactSize(stream);
+ m_N = static_cast<uint32_t>(N);
+ if (m_N != N) {
+ throw std::ios_base::failure("N must be <2^32");
+ }
+ m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_M);
+
+ // Verify that the encoded filter contains exactly N elements. If it has too much or too little
+ // data, a std::ios_base::failure exception will be raised.
+ BitStreamReader<VectorReader> bitreader(stream);
+ for (uint64_t i = 0; i < m_N; ++i) {
+ GolombRiceDecode(bitreader, m_P);
+ }
+ if (!stream.empty()) {
+ throw std::ios_base::failure("encoded_filter contains excess data");
+ }
+}
+
+GCSFilter::GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
+ const ElementSet& elements)
+ : GCSFilter(siphash_k0, siphash_k1, P, M)
+{
+ size_t N = elements.size();
+ m_N = static_cast<uint32_t>(N);
+ if (m_N != N) {
+ throw std::invalid_argument("N must be <2^32");
+ }
+ m_F = static_cast<uint64_t>(m_N) * static_cast<uint64_t>(m_M);
+
+ CVectorWriter stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
+
+ WriteCompactSize(stream, m_N);
+
+ if (elements.empty()) {
+ return;
+ }
+
+ BitStreamWriter<CVectorWriter> bitwriter(stream);
+
+ uint64_t last_value = 0;
+ for (uint64_t value : BuildHashedSet(elements)) {
+ uint64_t delta = value - last_value;
+ GolombRiceEncode(bitwriter, m_P, delta);
+ last_value = value;
+ }
+
+ bitwriter.Flush();
+}
+
+bool GCSFilter::MatchInternal(const uint64_t* element_hashes, size_t size) const
+{
+ VectorReader stream(GCS_SER_TYPE, GCS_SER_VERSION, m_encoded, 0);
+
+ // Seek forward by size of N
+ uint64_t N = ReadCompactSize(stream);
+ assert(N == m_N);
+
+ BitStreamReader<VectorReader> bitreader(stream);
+
+ uint64_t value = 0;
+ size_t hashes_index = 0;
+ for (uint32_t i = 0; i < m_N; ++i) {
+ uint64_t delta = GolombRiceDecode(bitreader, m_P);
+ value += delta;
+
+ while (true) {
+ if (hashes_index == size) {
+ return false;
+ } else if (element_hashes[hashes_index] == value) {
+ return true;
+ } else if (element_hashes[hashes_index] > value) {
+ break;
+ }
+
+ hashes_index++;
+ }
+ }
+
+ return false;
+}
+
+bool GCSFilter::Match(const Element& element) const
+{
+ uint64_t query = HashToRange(element);
+ return MatchInternal(&query, 1);
+}
+
+bool GCSFilter::MatchAny(const ElementSet& elements) const
+{
+ const std::vector<uint64_t> queries = BuildHashedSet(elements);
+ return MatchInternal(queries.data(), queries.size());
+}
+
+static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
+ const CBlockUndo& block_undo)
+{
+ GCSFilter::ElementSet elements;
+
+ for (const CTransactionRef& tx : block.vtx) {
+ for (const CTxOut& txout : tx->vout) {
+ const CScript& script = txout.scriptPubKey;
+ if (script[0] == OP_RETURN) continue;
+ elements.emplace(script.begin(), script.end());
+ }
+ }
+
+ for (const CTxUndo& tx_undo : block_undo.vtxundo) {
+ for (const Coin& prevout : tx_undo.vprevout) {
+ const CScript& script = prevout.out.scriptPubKey;
+ elements.emplace(script.begin(), script.end());
+ }
+ }
+
+ return elements;
+}
+
+BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo)
+ : m_filter_type(filter_type), m_block_hash(block.GetHash())
+{
+ switch (m_filter_type) {
+ case BlockFilterType::BASIC:
+ m_filter = GCSFilter(m_block_hash.GetUint64(0), m_block_hash.GetUint64(1),
+ BASIC_FILTER_P, BASIC_FILTER_M,
+ BasicFilterElements(block, block_undo));
+ break;
+
+ default:
+ throw std::invalid_argument("unknown filter_type");
+ }
+}
+
+uint256 BlockFilter::GetHash() const
+{
+ const std::vector<unsigned char>& data = GetEncodedFilter();
+
+ uint256 result;
+ CHash256().Write(data.data(), data.size()).Finalize(result.begin());
+ return result;
+}
+
+uint256 BlockFilter::ComputeHeader(const uint256& prev_header) const
+{
+ const uint256& filter_hash = GetHash();
+
+ uint256 result;
+ CHash256()
+ .Write(filter_hash.begin(), filter_hash.size())
+ .Write(prev_header.begin(), prev_header.size())
+ .Finalize(result.begin());
+ return result;
+}
diff --git a/src/blockfilter.h b/src/blockfilter.h
new file mode 100644
index 0000000000..46833ac0be
--- /dev/null
+++ b/src/blockfilter.h
@@ -0,0 +1,145 @@
+// Copyright (c) 2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_BLOCKFILTER_H
+#define BITCOIN_BLOCKFILTER_H
+
+#include <set>
+#include <stdint.h>
+#include <vector>
+
+#include <primitives/block.h>
+#include <serialize.h>
+#include <uint256.h>
+#include <undo.h>
+
+/**
+ * This implements a Golomb-coded set as defined in BIP 158. It is a
+ * compact, probabilistic data structure for testing set membership.
+ */
+class GCSFilter
+{
+public:
+ typedef std::vector<unsigned char> Element;
+ typedef std::set<Element> ElementSet;
+
+private:
+ uint64_t m_siphash_k0;
+ uint64_t m_siphash_k1;
+ uint8_t m_P; //!< Golomb-Rice coding parameter
+ uint32_t m_M; //!< Inverse false positive rate
+ uint32_t m_N; //!< Number of elements in the filter
+ uint64_t m_F; //!< Range of element hashes, F = N * M
+ std::vector<unsigned char> m_encoded;
+
+ /** Hash a data element to an integer in the range [0, N * M). */
+ uint64_t HashToRange(const Element& element) const;
+
+ std::vector<uint64_t> BuildHashedSet(const ElementSet& elements) const;
+
+ /** Helper method used to implement Match and MatchAny */
+ bool MatchInternal(const uint64_t* sorted_element_hashes, size_t size) const;
+
+public:
+
+ /** Constructs an empty filter. */
+ GCSFilter(uint64_t siphash_k0 = 0, uint64_t siphash_k1 = 0, uint8_t P = 0, uint32_t M = 0);
+
+ /** Reconstructs an already-created filter from an encoding. */
+ GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
+ std::vector<unsigned char> encoded_filter);
+
+ /** Builds a new filter from the params and set of elements. */
+ GCSFilter(uint64_t siphash_k0, uint64_t siphash_k1, uint8_t P, uint32_t M,
+ const ElementSet& elements);
+
+ uint8_t GetP() const { return m_P; }
+ uint32_t GetN() const { return m_N; }
+ uint32_t GetM() const { return m_M; }
+ const std::vector<unsigned char>& GetEncoded() const { return m_encoded; }
+
+ /**
+ * Checks if the element may be in the set. False positives are possible
+ * with probability 1/M.
+ */
+ bool Match(const Element& element) const;
+
+ /**
+ * Checks if any of the given elements may be in the set. False positives
+ * are possible with probability 1/M per element checked. This is more
+ * efficient that checking Match on multiple elements separately.
+ */
+ bool MatchAny(const ElementSet& elements) const;
+};
+
+constexpr uint8_t BASIC_FILTER_P = 19;
+constexpr uint32_t BASIC_FILTER_M = 784931;
+
+enum BlockFilterType : uint8_t
+{
+ BASIC = 0,
+};
+
+/**
+ * Complete block filter struct as defined in BIP 157. Serialization matches
+ * payload of "cfilter" messages.
+ */
+class BlockFilter
+{
+private:
+ BlockFilterType m_filter_type;
+ uint256 m_block_hash;
+ GCSFilter m_filter;
+
+public:
+
+ // Construct a new BlockFilter of the specified type from a block.
+ BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo);
+
+ BlockFilterType GetFilterType() const { return m_filter_type; }
+
+ const GCSFilter& GetFilter() const { return m_filter; }
+
+ const std::vector<unsigned char>& GetEncodedFilter() const
+ {
+ return m_filter.GetEncoded();
+ }
+
+ // Compute the filter hash.
+ uint256 GetHash() const;
+
+ // Compute the filter header given the previous one.
+ uint256 ComputeHeader(const uint256& prev_header) const;
+
+ template <typename Stream>
+ void Serialize(Stream& s) const {
+ s << m_block_hash
+ << static_cast<uint8_t>(m_filter_type)
+ << m_filter.GetEncoded();
+ }
+
+ template <typename Stream>
+ void Unserialize(Stream& s) {
+ std::vector<unsigned char> encoded_filter;
+ uint8_t filter_type;
+
+ s >> m_block_hash
+ >> filter_type
+ >> encoded_filter;
+
+ m_filter_type = static_cast<BlockFilterType>(filter_type);
+
+ switch (m_filter_type) {
+ case BlockFilterType::BASIC:
+ m_filter = GCSFilter(m_block_hash.GetUint64(0), m_block_hash.GetUint64(1),
+ BASIC_FILTER_P, BASIC_FILTER_M, std::move(encoded_filter));
+ break;
+
+ default:
+ throw std::ios_base::failure("unknown filter_type");
+ }
+ }
+};
+
+#endif // BITCOIN_BLOCKFILTER_H
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 94aae742f1..7732cee275 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -153,11 +153,11 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
insert(COutPoint(hash, i));
else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
{
- txnouttype type;
std::vector<std::vector<unsigned char> > vSolutions;
- if (Solver(txout.scriptPubKey, type, vSolutions) &&
- (type == TX_PUBKEY || type == TX_MULTISIG))
+ txnouttype type = Solver(txout.scriptPubKey, vSolutions);
+ if (type == TX_PUBKEY || type == TX_MULTISIG) {
insert(COutPoint(hash, i));
+ }
}
break;
}
diff --git a/src/compat.h b/src/compat.h
index 19f9813fd4..d228611160 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -14,10 +14,10 @@
// GCC 4.8 is missing some C++11 type_traits,
// https://www.gnu.org/software/gcc/gcc-5/changes.html
-#if defined(__GNUC__) && __GNUC__ < 5
-#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivial
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
+#define IS_TRIVIALLY_CONSTRUCTIBLE std::has_trivial_default_constructor
#else
-#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_constructible
+#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_default_constructible
#endif
#ifdef WIN32
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 6331a3d880..55dcb1661d 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -141,8 +141,7 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_address)
out.pushKV("hex", HexStr(script.begin(), script.end()));
std::vector<std::vector<unsigned char>> solns;
- txnouttype type;
- Solver(script, type, solns);
+ txnouttype type = Solver(script, solns);
out.pushKV("type", GetTxnOutputType(type));
CTxDestination address;
diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp
index 80f461f4d3..ddf9b342d8 100644
--- a/src/interfaces/handler.cpp
+++ b/src/interfaces/handler.cpp
@@ -15,7 +15,7 @@ namespace {
class HandlerImpl : public Handler
{
public:
- HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {}
+ explicit HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {}
void disconnect() override { m_connection.disconnect(); }
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 55a6f771e5..01467f3a1c 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -31,7 +31,7 @@ namespace {
class PendingWalletTxImpl : public PendingWalletTx
{
public:
- PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {}
+ explicit PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {}
const CTransaction& get() override { return *m_tx; }
@@ -57,7 +57,7 @@ public:
};
//! Construct wallet tx struct.
-WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
+static WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
WalletTx result;
result.tx = wtx.tx;
@@ -85,7 +85,7 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
}
//! Construct wallet tx status struct.
-WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx)
+static WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
WalletTxStatus result;
auto mi = ::mapBlockIndex.find(wtx.hashBlock);
@@ -104,7 +104,7 @@ WalletTxStatus MakeWalletTxStatus(const CWalletTx& wtx)
}
//! Construct wallet TxOut struct.
-WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth)
+static WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int depth) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
WalletTxOut result;
result.txout = wtx.tx->vout[n];
@@ -117,7 +117,7 @@ WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n, int de
class WalletImpl : public Wallet
{
public:
- WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_shared_wallet(wallet), m_wallet(*wallet.get()) {}
+ explicit WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_shared_wallet(wallet), m_wallet(*wallet.get()) {}
bool encryptWallet(const SecureString& wallet_passphrase) override
{
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 5c5e2dc031..c6a541cdb1 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -24,7 +24,7 @@ private:
const CChainParams& m_params;
public:
- DestinationEncoder(const CChainParams& params) : m_params(params) {}
+ explicit DestinationEncoder(const CChainParams& params) : m_params(params) {}
std::string operator()(const CKeyID& id) const
{
diff --git a/src/net.cpp b/src/net.cpp
index ec4fa6c267..df2cb54b7a 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -715,6 +715,7 @@ void CNode::copyStats(CNodeStats &stats)
X(nRecvBytes);
}
X(fWhitelisted);
+ X(minFeeFilter);
// It is common for nodes with good ping times to suddenly become lagged,
// due to a new block arriving or other large transfer.
diff --git a/src/net.h b/src/net.h
index f9cfea59b7..edd2f8cf0d 100644
--- a/src/net.h
+++ b/src/net.h
@@ -558,6 +558,7 @@ public:
double dPingTime;
double dPingWait;
double dMinPing;
+ CAmount minFeeFilter;
// Our address, as reported by the peer
std::string addrLocal;
// Address of this peer
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 88999ba735..a6a8814dff 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -442,7 +442,7 @@ static void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) EXCLUSIV
* lNodesAnnouncingHeaderAndIDs, and keeping that list under a certain size by
* removing the first element if necessary.
*/
-static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman)
+static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
CNodeState* nodestate = State(nodeid);
@@ -831,7 +831,7 @@ void Misbehaving(NodeId pnode, int howmuch, const std::string& message) EXCLUSIV
// active chain if they are no more than a month older (both in time, and in
// best equivalent proof of work) than the best header chain we know about and
// we fully-validated them at some point.
-static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams)
+static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
if (chainActive.Contains(pindex)) return true;
@@ -1260,7 +1260,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
}
}
-void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc)
+void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc) LOCKS_EXCLUDED(cs_main)
{
AssertLockNotHeld(cs_main);
@@ -1618,8 +1618,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
- else if (strCommand == NetMsgType::VERSION)
- {
+ if (strCommand == NetMsgType::VERSION) {
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
@@ -1662,8 +1661,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return false;
}
- if (nVersion < MIN_PEER_PROTO_VERSION)
- {
+ if (nVersion < MIN_PEER_PROTO_VERSION) {
// disconnect from peers older than this proto version
LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion);
if (enable_bip61) {
@@ -1674,8 +1672,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return false;
}
- if (nVersion == 10300)
- nVersion = 300;
if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (!vRecv.empty()) {
@@ -1796,9 +1792,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
-
- else if (pfrom->nVersion == 0)
- {
+ if (pfrom->nVersion == 0) {
// Must have a version message before anything else
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 1);
@@ -1842,18 +1836,17 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
}
pfrom->fSuccessfullyConnected = true;
+ return true;
}
- else if (!pfrom->fSuccessfullyConnected)
- {
+ if (!pfrom->fSuccessfullyConnected) {
// Must have a verack message before anything else
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 1);
return false;
}
- else if (strCommand == NetMsgType::ADDR)
- {
+ if (strCommand == NetMsgType::ADDR) {
std::vector<CAddress> vAddr;
vRecv >> vAddr;
@@ -1900,16 +1893,16 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->fGetAddr = false;
if (pfrom->fOneShot)
pfrom->fDisconnect = true;
+ return true;
}
- else if (strCommand == NetMsgType::SENDHEADERS)
- {
+ if (strCommand == NetMsgType::SENDHEADERS) {
LOCK(cs_main);
State(pfrom->GetId())->fPreferHeaders = true;
+ return true;
}
- else if (strCommand == NetMsgType::SENDCMPCT)
- {
+ if (strCommand == NetMsgType::SENDCMPCT) {
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = 0;
vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
@@ -1929,11 +1922,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1);
}
}
+ return true;
}
-
- else if (strCommand == NetMsgType::INV)
- {
+ if (strCommand == NetMsgType::INV) {
std::vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
@@ -1987,11 +1979,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
}
}
+ return true;
}
-
- else if (strCommand == NetMsgType::GETDATA)
- {
+ if (strCommand == NetMsgType::GETDATA) {
std::vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
@@ -2009,11 +2000,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());
ProcessGetData(pfrom, chainparams, connman, interruptMsgProc);
+ return true;
}
-
- else if (strCommand == NetMsgType::GETBLOCKS)
- {
+ if (strCommand == NetMsgType::GETBLOCKS) {
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
@@ -2078,11 +2068,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
break;
}
}
+ return true;
}
-
- else if (strCommand == NetMsgType::GETBLOCKTXN)
- {
+ if (strCommand == NetMsgType::GETBLOCKTXN) {
BlockTransactionsRequest req;
vRecv >> req;
@@ -2128,11 +2117,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
assert(ret);
SendBlockTransactions(block, req, pfrom, connman);
+ return true;
}
-
- else if (strCommand == NetMsgType::GETHEADERS)
- {
+ if (strCommand == NetMsgType::GETHEADERS) {
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
@@ -2196,11 +2184,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// in the SendMessages logic.
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
+ return true;
}
-
- else if (strCommand == NetMsgType::TX)
- {
+ if (strCommand == NetMsgType::TX) {
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
if (!fRelayTxes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
@@ -2384,10 +2371,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
Misbehaving(pfrom->GetId(), nDoS);
}
}
+ return true;
}
-
- else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
{
CBlockHeaderAndShortTxIDs cmpctblock;
vRecv >> cmpctblock;
@@ -2605,10 +2592,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
MarkBlockAsReceived(pblock->GetHash());
}
}
-
+ return true;
}
- else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing
{
BlockTransactions resp;
vRecv >> resp;
@@ -2680,10 +2667,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
mapBlockSource.erase(pblock->GetHash());
}
}
+ return true;
}
-
- else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing
+ if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing
{
std::vector<CBlockHeader> headers;
@@ -2708,7 +2695,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return ProcessHeadersMessage(pfrom, connman, headers, chainparams, should_punish);
}
- else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
{
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
vRecv >> *pblock;
@@ -2734,11 +2721,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(cs_main);
mapBlockSource.erase(pblock->GetHash());
}
+ return true;
}
-
- else if (strCommand == NetMsgType::GETADDR)
- {
+ if (strCommand == NetMsgType::GETADDR) {
// This asymmetric behavior for inbound and outbound connections was introduced
// to prevent a fingerprinting attack: an attacker can send specific fake addresses
// to users' AddrMan and later request them by sending getaddr messages.
@@ -2762,11 +2748,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
FastRandomContext insecure_rand;
for (const CAddress &addr : vAddr)
pfrom->PushAddress(addr, insecure_rand);
+ return true;
}
-
- else if (strCommand == NetMsgType::MEMPOOL)
- {
+ if (strCommand == NetMsgType::MEMPOOL) {
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted)
{
LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
@@ -2783,11 +2768,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(pfrom->cs_inventory);
pfrom->fSendMempool = true;
+ return true;
}
-
- else if (strCommand == NetMsgType::PING)
- {
+ if (strCommand == NetMsgType::PING) {
if (pfrom->nVersion > BIP0031_VERSION)
{
uint64_t nonce = 0;
@@ -2805,11 +2789,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// return very quickly.
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce));
}
+ return true;
}
-
- else if (strCommand == NetMsgType::PONG)
- {
+ if (strCommand == NetMsgType::PONG) {
int64_t pingUsecEnd = nTimeReceived;
uint64_t nonce = 0;
size_t nAvail = vRecv.in_avail();
@@ -2862,11 +2845,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (bPingFinished) {
pfrom->nPingNonceSent = 0;
}
+ return true;
}
-
- else if (strCommand == NetMsgType::FILTERLOAD)
- {
+ if (strCommand == NetMsgType::FILTERLOAD) {
CBloomFilter filter;
vRecv >> filter;
@@ -2883,11 +2865,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->pfilter->UpdateEmptyFull();
pfrom->fRelayTxes = true;
}
+ return true;
}
-
- else if (strCommand == NetMsgType::FILTERADD)
- {
+ if (strCommand == NetMsgType::FILTERADD) {
std::vector<unsigned char> vData;
vRecv >> vData;
@@ -2908,19 +2889,19 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 100);
}
+ return true;
}
-
- else if (strCommand == NetMsgType::FILTERCLEAR)
- {
+ if (strCommand == NetMsgType::FILTERCLEAR) {
LOCK(pfrom->cs_filter);
if (pfrom->GetLocalServices() & NODE_BLOOM) {
pfrom->pfilter.reset(new CBloomFilter());
}
pfrom->fRelayTxes = true;
+ return true;
}
- else if (strCommand == NetMsgType::FEEFILTER) {
+ if (strCommand == NetMsgType::FEEFILTER) {
CAmount newFeeFilter = 0;
vRecv >> newFeeFilter;
if (MoneyRange(newFeeFilter)) {
@@ -2930,24 +2911,21 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->GetId());
}
+ return true;
}
- else if (strCommand == NetMsgType::NOTFOUND) {
+ if (strCommand == NetMsgType::NOTFOUND) {
// We do not care about the NOTFOUND message, but logging an Unknown Command
// message would be undesirable as we transmit it ourselves.
+ return true;
}
- else {
- // Ignore unknown commands for extensibility
- LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId());
- }
-
-
-
+ // Ignore unknown commands for extensibility
+ LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId());
return true;
}
-static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool enable_bip61)
+static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
CNodeState &state = *State(pnode->GetId());
diff --git a/src/net_processing.h b/src/net_processing.h
index 7caefc80ca..f16d00032e 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -61,7 +61,7 @@ public:
bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
/** Consider evicting an outbound peer based on the amount of time they've been behind our tip */
- void ConsiderEviction(CNode *pto, int64_t time_in_seconds);
+ void ConsiderEviction(CNode *pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound */
void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams);
/** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */
diff --git a/src/noui.cpp b/src/noui.cpp
index e6d01e7b26..3a1ec2d050 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -12,6 +12,8 @@
#include <stdint.h>
#include <string>
+#include <boost/signals2/connection.hpp>
+
static bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
bool fSecure = style & CClientUIInterface::SECURE;
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index b8f7963a0c..47d6644551 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -57,11 +57,11 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
{
std::vector<std::vector<unsigned char> > vSolutions;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
+ whichType = Solver(scriptPubKey, vSolutions);
- if (whichType == TX_MULTISIG)
- {
+ if (whichType == TX_NONSTANDARD || whichType == TX_WITNESS_UNKNOWN) {
+ return false;
+ } else if (whichType == TX_MULTISIG) {
unsigned char m = vSolutions.front()[0];
unsigned char n = vSolutions.back()[0];
// Support up to x-of-3 multisig txns as standard
@@ -70,10 +70,11 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
if (m < 1 || m > n)
return false;
} else if (whichType == TX_NULL_DATA &&
- (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes))
+ (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) {
return false;
+ }
- return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN;
+ return true;
}
bool IsStandardTx(const CTransaction& tx, std::string& reason)
@@ -166,14 +167,10 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
std::vector<std::vector<unsigned char> > vSolutions;
- txnouttype whichType;
- // get the scriptPubKey corresponding to this input:
- const CScript& prevScript = prev.scriptPubKey;
- if (!Solver(prevScript, whichType, vSolutions))
+ txnouttype whichType = Solver(prev.scriptPubKey, vSolutions);
+ if (whichType == TX_NONSTANDARD) {
return false;
-
- if (whichType == TX_SCRIPTHASH)
- {
+ } else if (whichType == TX_SCRIPTHASH) {
std::vector<std::vector<unsigned char> > stack;
// convert the scriptSig into a stack, so we can inspect the redeemScript
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE))
diff --git a/src/prevector.h b/src/prevector.h
index 033952c959..7a13b98214 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -252,7 +252,7 @@ public:
resize(n);
}
- explicit prevector(size_type n, const T& val = T()) : _size(0) {
+ explicit prevector(size_type n, const T& val) : _size(0) {
change_capacity(n);
_size += n;
fill(item_ptr(0), n, val);
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 380a3ddb84..2f88e15d21 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -71,7 +71,7 @@ public:
QList<AddressTableEntry> cachedAddressTable;
AddressTableModel *parent;
- AddressTablePriv(AddressTableModel *_parent):
+ explicit AddressTablePriv(AddressTableModel *_parent):
parent(_parent) {}
void refreshAddressTable(interfaces::Wallet& wallet)
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 85fb88d338..712d20b71e 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -76,13 +76,10 @@ static void InitMessage(const std::string &message)
LogPrintf("init message: %s\n", message);
}
-/*
- Translate string to current locale using Qt.
- */
-static std::string Translate(const char* psz)
-{
+/** Translate string to current locale using Qt. */
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) {
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
-}
+};
static QString GetLangTerritory()
{
@@ -618,7 +615,6 @@ int main(int argc, char *argv[])
// Now that QSettings are accessible, initialize translations
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
- translationInterface.Translate.connect(Translate);
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen.
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index cefa9004ed..5321cd94fd 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -57,6 +57,8 @@
#include <QUrlQuery>
#include <QVBoxLayout>
+#include <boost/bind.hpp>
+
const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
#if defined(Q_OS_MAC)
"macosx"
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 66e36f0b67..00fc73574e 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -82,7 +82,7 @@ class RPCExecutor : public QObject
{
Q_OBJECT
public:
- RPCExecutor(interfaces::Node& node) : m_node(node) {}
+ explicit RPCExecutor(interfaces::Node& node) : m_node(node) {}
public Q_SLOTS:
void request(const QString &command, const QString &walletID);
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index e438d22919..0b111cc6d7 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -14,8 +14,8 @@
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <interfaces/wallet.h>
-#include <util.h>
#include <ui_interface.h>
+#include <util.h>
#include <version.h>
#include <QApplication>
@@ -24,6 +24,8 @@
#include <QPainter>
#include <QRadialGradient>
+#include <boost/bind.hpp>
+
SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) :
QWidget(0, f), curAlignment(0), m_node(node)
{
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index e379b70553..b4be068904 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -16,10 +16,10 @@
#include <core_io.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
-#include <validation.h>
#include <sync.h>
#include <uint256.h>
#include <util.h>
+#include <validation.h>
#include <QColor>
#include <QDateTime>
@@ -27,6 +27,8 @@
#include <QIcon>
#include <QList>
+#include <boost/bind.hpp>
+
// Amount column is right-aligned it contains numbers
static int column_alignments[] = {
Qt::AlignLeft|Qt::AlignVCenter, /* status */
@@ -58,7 +60,7 @@ struct TxLessThan
class TransactionTablePriv
{
public:
- TransactionTablePriv(TransactionTableModel *_parent) :
+ explicit TransactionTablePriv(TransactionTableModel *_parent) :
parent(_parent)
{
}
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 51bc218d39..a77fea8ea8 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -18,6 +18,7 @@
#include <key_io.h>
#include <policy/feerate.h>
#include <policy/policy.h>
+#include <policy/rbf.h>
#include <primitives/transaction.h>
#include <rpc/server.h>
#include <script/descriptor.h>
@@ -379,7 +380,8 @@ static std::string EntryDescriptionString()
" ... ]\n"
" \"spentby\" : [ (array) unconfirmed transactions spending outputs from this transaction\n"
" \"transactionid\", (string) child transaction id\n"
- " ... ]\n";
+ " ... ]\n"
+ " \"bip125-replaceable\" : true|false, (boolean) Whether this transaction could be replaced due to BIP125 (replace-by-fee)\n";
}
static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCKS_REQUIRED(::mempool.cs)
@@ -429,6 +431,17 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
}
info.pushKV("spentby", spent);
+
+ // Add opt-in RBF status
+ bool rbfStatus = false;
+ RBFTransactionState rbfState = IsRBFOptIn(tx, mempool);
+ if (rbfState == RBFTransactionState::UNKNOWN) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
+ } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
+ rbfStatus = true;
+ }
+
+ info.pushKV("bip125-replaceable", rbfStatus);
}
UniValue mempoolToJSON(bool fVerbose)
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index c7f3e38ac0..784d6416cf 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -40,15 +40,11 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "settxfee", 0, "amount" },
{ "sethdseed", 0, "newkeypool" },
{ "getreceivedbyaddress", 1, "minconf" },
- { "getreceivedbyaccount", 1, "minconf" },
{ "getreceivedbylabel", 1, "minconf" },
{ "listreceivedbyaddress", 0, "minconf" },
{ "listreceivedbyaddress", 1, "include_empty" },
{ "listreceivedbyaddress", 2, "include_watchonly" },
{ "listreceivedbyaddress", 3, "address_filter" },
- { "listreceivedbyaccount", 0, "minconf" },
- { "listreceivedbyaccount", 1, "include_empty" },
- { "listreceivedbyaccount", 2, "include_watchonly" },
{ "listreceivedbylabel", 0, "minconf" },
{ "listreceivedbylabel", 1, "include_empty" },
{ "listreceivedbylabel", 2, "include_watchonly" },
@@ -59,15 +55,9 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "waitforblockheight", 1, "timeout" },
{ "waitforblock", 1, "timeout" },
{ "waitfornewblock", 0, "timeout" },
- { "move", 2, "amount" },
- { "move", 3, "minconf" },
- { "sendfrom", 2, "amount" },
- { "sendfrom", 3, "minconf" },
{ "listtransactions", 1, "count" },
{ "listtransactions", 2, "skip" },
{ "listtransactions", 3, "include_watchonly" },
- { "listaccounts", 0, "minconf" },
- { "listaccounts", 1, "include_watchonly" },
{ "walletpassphrase", 1, "timeout" },
{ "getblocktemplate", 0, "template_request" },
{ "listsinceblock", 1, "target_confirmations" },
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 610a1fee6f..343b7d3b05 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -102,6 +102,7 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
" ...\n"
" ],\n"
" \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n"
+ " \"minfeefilter\": n, (numeric) The minimum fee rate for transactions this peer accepts\n"
" \"bytessent_per_msg\": {\n"
" \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
" ...\n"
@@ -169,6 +170,7 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
obj.pushKV("inflight", heights);
}
obj.pushKV("whitelisted", stats.fWhitelisted);
+ obj.pushKV("minfeefilter", ValueFromAmount(stats.minFeeFilter));
UniValue sendPerMsgCmd(UniValue::VOBJ);
for (const mapMsgCmdSize::value_type &i : stats.mapSendBytesPerMsgCmd) {
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 314184ab06..248b963c0b 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -562,7 +562,6 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
);
- LOCK(cs_main);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
CMutableTransaction mtx;
@@ -627,9 +626,8 @@ static UniValue decodescript(const JSONRPCRequest& request)
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
// is a witness program, don't return addresses for a segwit programs.
if (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") {
- txnouttype which_type;
std::vector<std::vector<unsigned char>> solutions_data;
- Solver(script, which_type, solutions_data);
+ txnouttype which_type = Solver(script, solutions_data);
// Uncompressed pubkeys cannot be used with segwit checksigs.
// If the script contains an uncompressed pubkey, skip encoding of a segwit program.
if ((which_type == TX_PUBKEY) || (which_type == TX_MULTISIG)) {
@@ -1460,11 +1458,8 @@ UniValue decodepsbt(const JSONRPCRequest& request)
UniValue keypath(UniValue::VOBJ);
keypath.pushKV("pubkey", HexStr(entry.first));
- uint32_t fingerprint = entry.second.at(0);
- keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint)));
-
- entry.second.erase(entry.second.begin());
- keypath.pushKV("path", WriteHDKeypath(entry.second));
+ keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint)));
+ keypath.pushKV("path", WriteHDKeypath(entry.second.path));
keypaths.push_back(keypath);
}
in.pushKV("bip32_derivs", keypaths);
@@ -1522,12 +1517,8 @@ UniValue decodepsbt(const JSONRPCRequest& request)
for (auto entry : output.hd_keypaths) {
UniValue keypath(UniValue::VOBJ);
keypath.pushKV("pubkey", HexStr(entry.first));
-
- uint32_t fingerprint = entry.second.at(0);
- keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint)));
-
- entry.second.erase(entry.second.begin());
- keypath.pushKV("path", WriteHDKeypath(entry.second));
+ keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint)));
+ keypath.pushKV("path", WriteHDKeypath(entry.second.path));
keypaths.push_back(keypath);
}
out.pushKV("bip32_derivs", keypaths);
@@ -1648,8 +1639,7 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
PSBTInput& input = psbtx.inputs.at(i);
- SignatureData sigdata;
- complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, sigdata, i, 1);
+ complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, i, 1);
}
UniValue result(UniValue::VOBJ);
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index e3a6278c75..1433ebf42f 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -60,8 +60,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
IsMineResult ret = IsMineResult::NO;
std::vector<valtype> vSolutions;
- txnouttype whichType;
- Solver(scriptPubKey, whichType, vSolutions);
+ txnouttype whichType = Solver(scriptPubKey, vSolutions);
CKeyID keyID;
switch (whichType)
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 1982e8a832..d779910425 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -50,10 +50,6 @@ static bool GetCScript(const SigningProvider& provider, const SignatureData& sig
static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, const CKeyID& address, CPubKey& pubkey)
{
- if (provider.GetPubKey(address, pubkey)) {
- sigdata.misc_pubkeys.emplace(pubkey.GetID(), pubkey);
- return true;
- }
// Look for pubkey in all partial sigs
const auto it = sigdata.signatures.find(address);
if (it != sigdata.signatures.end()) {
@@ -63,7 +59,15 @@ static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, c
// Look for pubkey in pubkey list
const auto& pk_it = sigdata.misc_pubkeys.find(address);
if (pk_it != sigdata.misc_pubkeys.end()) {
- pubkey = pk_it->second;
+ pubkey = pk_it->second.first;
+ return true;
+ }
+ // Query the underlying provider
+ if (provider.GetPubKey(address, pubkey)) {
+ KeyOriginInfo info;
+ if (provider.GetKeyOrigin(address, info)) {
+ sigdata.misc_pubkeys.emplace(address, std::make_pair(pubkey, std::move(info)));
+ }
return true;
}
return false;
@@ -101,8 +105,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
std::vector<unsigned char> sig;
std::vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
- return false;
+ whichTypeRet = Solver(scriptPubKey, vSolutions);
switch (whichTypeRet)
{
@@ -233,7 +236,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
return sigdata.complete;
}
-bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash)
+bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash)
{
// if this input has a final scriptsig or scriptwitness, don't do anything with it
if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) {
@@ -241,6 +244,7 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
}
// Fill SignatureData with input info
+ SignatureData sigdata;
input.FillSignatureData(sigdata);
// Get UTXO
@@ -272,6 +276,16 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
// Verify that a witness signature was produced in case one was required.
if (require_witness_sig && !sigdata.witness) return false;
input.FromSignatureData(sigdata);
+
+ // If both UTXO types are present, drop the unnecessary one.
+ if (input.non_witness_utxo && !input.witness_utxo.IsNull()) {
+ if (sigdata.witness) {
+ input.non_witness_utxo = nullptr;
+ } else {
+ input.witness_utxo.SetNull();
+ }
+ }
+
return sig_complete;
}
@@ -329,9 +343,8 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
}
// Get scripts
- txnouttype script_type;
std::vector<std::vector<unsigned char>> solutions;
- Solver(txout.scriptPubKey, script_type, solutions);
+ txnouttype script_type = Solver(txout.scriptPubKey, solutions);
SigVersion sigversion = SigVersion::BASE;
CScript next_script = txout.scriptPubKey;
@@ -342,7 +355,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
next_script = std::move(redeem_script);
// Get redeemScript type
- Solver(next_script, script_type, solutions);
+ script_type = Solver(next_script, solutions);
stack.script.pop_back();
}
if (script_type == TX_WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) {
@@ -352,7 +365,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
next_script = std::move(witness_script);
// Get witnessScript type
- Solver(next_script, script_type, solutions);
+ script_type = Solver(next_script, solutions);
stack.witness.pop_back();
stack.script = std::move(stack.witness);
stack.witness.clear();
@@ -543,7 +556,7 @@ void PSBTInput::FillSignatureData(SignatureData& sigdata) const
sigdata.witness_script = witness_script;
}
for (const auto& key_pair : hd_keypaths) {
- sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first);
+ sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
}
}
@@ -571,6 +584,9 @@ void PSBTInput::FromSignatureData(const SignatureData& sigdata)
if (witness_script.empty() && !sigdata.witness_script.empty()) {
witness_script = sigdata.witness_script;
}
+ for (const auto& entry : sigdata.misc_pubkeys) {
+ hd_keypaths.emplace(entry.second);
+ }
}
void PSBTInput::Merge(const PSBTInput& input)
@@ -612,7 +628,7 @@ void PSBTOutput::FillSignatureData(SignatureData& sigdata) const
sigdata.witness_script = witness_script;
}
for (const auto& key_pair : hd_keypaths) {
- sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first);
+ sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
}
}
@@ -624,6 +640,9 @@ void PSBTOutput::FromSignatureData(const SignatureData& sigdata)
if (witness_script.empty() && !sigdata.witness_script.empty()) {
witness_script = sigdata.witness_script;
}
+ for (const auto& entry : sigdata.misc_pubkeys) {
+ hd_keypaths.emplace(entry.second);
+ }
}
bool PSBTOutput::IsNull() const
@@ -640,14 +659,26 @@ void PSBTOutput::Merge(const PSBTOutput& output)
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
}
-bool PublicOnlySigningProvider::GetCScript(const CScriptID &scriptid, CScript& script) const
+bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const
{
return m_provider->GetCScript(scriptid, script);
}
-bool PublicOnlySigningProvider::GetPubKey(const CKeyID &address, CPubKey& pubkey) const
+bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const
+{
+ return m_provider->GetPubKey(keyid, pubkey);
+}
+
+bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const
+{
+ if (m_hide_secret) return false;
+ return m_provider->GetKey(keyid, key);
+}
+
+bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
{
- return m_provider->GetPubKey(address, pubkey);
+ if (m_hide_origin) return false;
+ return m_provider->GetKeyOrigin(keyid, info);
}
bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); }
diff --git a/src/script/sign.h b/src/script/sign.h
index 7ade715ee2..18b7320998 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -20,6 +20,12 @@ class CTransaction;
struct CMutableTransaction;
+struct KeyOriginInfo
+{
+ unsigned char fingerprint[4];
+ std::vector<uint32_t> path;
+};
+
/** An interface to be implemented by keystores that support signing. */
class SigningProvider
{
@@ -28,19 +34,24 @@ public:
virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; }
virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; }
+ virtual bool GetKeyOrigin(const CKeyID& id, KeyOriginInfo& info) const { return false; }
};
extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
-class PublicOnlySigningProvider : public SigningProvider
+class HidingSigningProvider : public SigningProvider
{
private:
+ const bool m_hide_secret;
+ const bool m_hide_origin;
const SigningProvider* m_provider;
public:
- PublicOnlySigningProvider(const SigningProvider* provider) : m_provider(provider) {}
- bool GetCScript(const CScriptID &scriptid, CScript& script) const;
- bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const;
+ HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {}
+ bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
+ bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
+ bool GetKey(const CKeyID& keyid, CKey& key) const override;
+ bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
};
struct FlatSigningProvider final : public SigningProvider
@@ -98,7 +109,7 @@ struct SignatureData {
CScript witness_script; ///< The witnessScript (if any) for the input. witnessScripts are used in P2WSH outputs.
CScriptWitness scriptWitness; ///< The scriptWitness of an input. Contains complete signatures or the traditional partial signatures format. scriptWitness is part of a transaction input per BIP 144.
std::map<CKeyID, SigPair> signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig or scriptWitness.
- std::map<CKeyID, CPubKey> misc_pubkeys;
+ std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys;
SignatureData() {}
explicit SignatureData(const CScript& script) : scriptSig(script) {}
@@ -155,7 +166,7 @@ void UnserializeFromVector(Stream& s, X&... args)
// Deserialize HD keypaths into a map
template<typename Stream>
-void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths)
+void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
{
// Make sure that the key is the size of pubkey + 1
if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) {
@@ -172,25 +183,31 @@ void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std
// Read in key path
uint64_t value_len = ReadCompactSize(s);
- std::vector<uint32_t> keypath;
- for (unsigned int i = 0; i < value_len; i += sizeof(uint32_t)) {
+ if (value_len % 4 || value_len == 0) {
+ throw std::ios_base::failure("Invalid length for HD key path");
+ }
+
+ KeyOriginInfo keypath;
+ s >> keypath.fingerprint;
+ for (unsigned int i = 4; i < value_len; i += sizeof(uint32_t)) {
uint32_t index;
s >> index;
- keypath.push_back(index);
+ keypath.path.push_back(index);
}
// Add to map
- hd_keypaths.emplace(pubkey, keypath);
+ hd_keypaths.emplace(pubkey, std::move(keypath));
}
// Serialize HD keypaths to a stream from a map
template<typename Stream>
-void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths, uint8_t type)
+void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_keypaths, uint8_t type)
{
for (auto keypath_pair : hd_keypaths) {
SerializeToVector(s, type, MakeSpan(keypath_pair.first));
- WriteCompactSize(s, keypath_pair.second.size() * sizeof(uint32_t));
- for (auto& path : keypath_pair.second) {
+ WriteCompactSize(s, (keypath_pair.second.path.size() + 1) * sizeof(uint32_t));
+ s << keypath_pair.second.fingerprint;
+ for (const auto& path : keypath_pair.second.path) {
s << path;
}
}
@@ -205,7 +222,7 @@ struct PSBTInput
CScript witness_script;
CScript final_script_sig;
CScriptWitness final_script_witness;
- std::map<CPubKey, std::vector<uint32_t>> hd_keypaths;
+ std::map<CPubKey, KeyOriginInfo> hd_keypaths;
std::map<CKeyID, SigPair> partial_sigs;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
int sighash_type = 0;
@@ -418,7 +435,7 @@ struct PSBTOutput
{
CScript redeem_script;
CScript witness_script;
- std::map<CPubKey, std::vector<uint32_t>> hd_keypaths;
+ std::map<CPubKey, KeyOriginInfo> hd_keypaths;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
bool IsNull() const;
@@ -687,7 +704,7 @@ bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, C
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
-bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash = 1);
+bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash = SIGHASH_ALL);
/** Extract signature data from a transaction input, and insert it. */
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index bfbf9f13db..08ba1b1e0f 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -87,7 +87,7 @@ static bool MatchMultisig(const CScript& script, unsigned int& required, std::ve
return (it + 1 == script.end());
}
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)
+txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
{
vSolutionsRet.clear();
@@ -95,33 +95,28 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
if (scriptPubKey.IsPayToScriptHash())
{
- typeRet = TX_SCRIPTHASH;
std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
vSolutionsRet.push_back(hashBytes);
- return true;
+ return TX_SCRIPTHASH;
}
int witnessversion;
std::vector<unsigned char> witnessprogram;
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
- typeRet = TX_WITNESS_V0_KEYHASH;
vSolutionsRet.push_back(witnessprogram);
- return true;
+ return TX_WITNESS_V0_KEYHASH;
}
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
- typeRet = TX_WITNESS_V0_SCRIPTHASH;
vSolutionsRet.push_back(witnessprogram);
- return true;
+ return TX_WITNESS_V0_SCRIPTHASH;
}
if (witnessversion != 0) {
- typeRet = TX_WITNESS_UNKNOWN;
vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
vSolutionsRet.push_back(std::move(witnessprogram));
- return true;
+ return TX_WITNESS_UNKNOWN;
}
- typeRet = TX_NONSTANDARD;
- return false;
+ return TX_NONSTANDARD;
}
// Provably prunable, data-carrying output
@@ -130,47 +125,39 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
// byte passes the IsPushOnly() test we don't care what exactly is in the
// script.
if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
- typeRet = TX_NULL_DATA;
- return true;
+ return TX_NULL_DATA;
}
std::vector<unsigned char> data;
if (MatchPayToPubkey(scriptPubKey, data)) {
- typeRet = TX_PUBKEY;
vSolutionsRet.push_back(std::move(data));
- return true;
+ return TX_PUBKEY;
}
if (MatchPayToPubkeyHash(scriptPubKey, data)) {
- typeRet = TX_PUBKEYHASH;
vSolutionsRet.push_back(std::move(data));
- return true;
+ return TX_PUBKEYHASH;
}
unsigned int required;
std::vector<std::vector<unsigned char>> keys;
if (MatchMultisig(scriptPubKey, required, keys)) {
- typeRet = TX_MULTISIG;
vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16
vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16
- return true;
+ return TX_MULTISIG;
}
vSolutionsRet.clear();
- typeRet = TX_NONSTANDARD;
- return false;
+ return TX_NONSTANDARD;
}
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
std::vector<valtype> vSolutions;
- txnouttype whichType;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
+ txnouttype whichType = Solver(scriptPubKey, vSolutions);
- if (whichType == TX_PUBKEY)
- {
+ if (whichType == TX_PUBKEY) {
CPubKey pubKey(vSolutions[0]);
if (!pubKey.IsValid())
return false;
@@ -212,11 +199,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
{
addressRet.clear();
- typeRet = TX_NONSTANDARD;
std::vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, typeRet, vSolutions))
+ typeRet = Solver(scriptPubKey, vSolutions);
+ if (typeRet == TX_NONSTANDARD) {
return false;
- if (typeRet == TX_NULL_DATA){
+ } else if (typeRet == TX_NULL_DATA) {
// This is data, not addresses
return false;
}
@@ -324,14 +311,12 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
CScript GetScriptForWitness(const CScript& redeemscript)
{
- txnouttype typ;
std::vector<std::vector<unsigned char> > vSolutions;
- if (Solver(redeemscript, typ, vSolutions)) {
- if (typ == TX_PUBKEY) {
- return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
- } else if (typ == TX_PUBKEYHASH) {
- return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
- }
+ txnouttype typ = Solver(redeemscript, vSolutions);
+ if (typ == TX_PUBKEY) {
+ return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
+ } else if (typ == TX_PUBKEYHASH) {
+ return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
}
return GetScriptForDestination(WitnessV0ScriptHash(redeemscript));
}
diff --git a/src/script/standard.h b/src/script/standard.h
index b16ac83e77..fc20fb6a08 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -135,11 +135,10 @@ const char* GetTxnOutputType(txnouttype t);
* script hash, for P2PKH it will contain the key hash, etc.
*
* @param[in] scriptPubKey Script to parse
- * @param[out] typeRet The script type
* @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
- * @return True if script matches standard template
+ * @return The script type. TX_NONSTANDARD represents a failed solve.
*/
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
+txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet);
/**
* Parse a standard scriptPubKey for the destination address. Assigns result to
diff --git a/src/streams.h b/src/streams.h
index 096ebfc9c2..d4a309be3c 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -139,6 +139,80 @@ private:
size_t nPos;
};
+/** Minimal stream for reading from an existing vector by reference
+ */
+class VectorReader
+{
+private:
+ const int m_type;
+ const int m_version;
+ const std::vector<unsigned char>& m_data;
+ size_t m_pos = 0;
+
+public:
+
+ /*
+ * @param[in] type Serialization Type
+ * @param[in] version Serialization Version (including any flags)
+ * @param[in] data Referenced byte vector to overwrite/append
+ * @param[in] pos Starting position. Vector index where reads should start.
+ */
+ VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos)
+ : m_type(type), m_version(version), m_data(data)
+ {
+ seek(pos);
+ }
+
+ /*
+ * (other params same as above)
+ * @param[in] args A list of items to deserialize starting at pos.
+ */
+ template <typename... Args>
+ VectorReader(int type, int version, const std::vector<unsigned char>& data, size_t pos,
+ Args&&... args)
+ : VectorReader(type, version, data, pos)
+ {
+ ::UnserializeMany(*this, std::forward<Args>(args)...);
+ }
+
+ template<typename T>
+ VectorReader& operator>>(T& obj)
+ {
+ // Unserialize from this stream
+ ::Unserialize(*this, obj);
+ return (*this);
+ }
+
+ int GetVersion() const { return m_version; }
+ int GetType() const { return m_type; }
+
+ size_t size() const { return m_data.size() - m_pos; }
+ bool empty() const { return m_data.size() == m_pos; }
+
+ void read(char* dst, size_t n)
+ {
+ if (n == 0) {
+ return;
+ }
+
+ // Read from the beginning of the buffer
+ size_t pos_next = m_pos + n;
+ if (pos_next > m_data.size()) {
+ throw std::ios_base::failure("VectorReader::read(): end of data");
+ }
+ memcpy(dst, m_data.data() + m_pos, n);
+ m_pos = pos_next;
+ }
+
+ void seek(size_t n)
+ {
+ m_pos += n;
+ if (m_pos > m_data.size()) {
+ throw std::ios_base::failure("VectorReader::seek(): end of data");
+ }
+ }
+};
+
/** Double ended buffer combining vector and stream-like interfaces.
*
* >> and << read and write unformatted data using the above serialization templates.
@@ -436,12 +510,105 @@ public:
}
};
+template <typename IStream>
+class BitStreamReader
+{
+private:
+ IStream& m_istream;
+
+ /// Buffered byte read in from the input stream. A new byte is read into the
+ /// buffer when m_offset reaches 8.
+ uint8_t m_buffer{0};
+
+ /// Number of high order bits in m_buffer already returned by previous
+ /// Read() calls. The next bit to be returned is at this offset from the
+ /// most significant bit position.
+ int m_offset{8};
+
+public:
+ explicit BitStreamReader(IStream& istream) : m_istream(istream) {}
+
+ /** Read the specified number of bits from the stream. The data is returned
+ * in the nbits least signficant bits of a 64-bit uint.
+ */
+ uint64_t Read(int nbits) {
+ if (nbits < 0 || nbits > 64) {
+ throw std::out_of_range("nbits must be between 0 and 64");
+ }
+
+ uint64_t data = 0;
+ while (nbits > 0) {
+ if (m_offset == 8) {
+ m_istream >> m_buffer;
+ m_offset = 0;
+ }
+ int bits = std::min(8 - m_offset, nbits);
+ data <<= bits;
+ data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);
+ m_offset += bits;
+ nbits -= bits;
+ }
+ return data;
+ }
+};
+template <typename OStream>
+class BitStreamWriter
+{
+private:
+ OStream& m_ostream;
+ /// Buffered byte waiting to be written to the output stream. The byte is
+ /// written buffer when m_offset reaches 8 or Flush() is called.
+ uint8_t m_buffer{0};
+ /// Number of high order bits in m_buffer already written by previous
+ /// Write() calls and not yet flushed to the stream. The next bit to be
+ /// written to is at this offset from the most significant bit position.
+ int m_offset{0};
+public:
+ explicit BitStreamWriter(OStream& ostream) : m_ostream(ostream) {}
+ ~BitStreamWriter()
+ {
+ Flush();
+ }
+
+ /** Write the nbits least significant bits of a 64-bit int to the output
+ * stream. Data is buffered until it completes an octet.
+ */
+ void Write(uint64_t data, int nbits) {
+ if (nbits < 0 || nbits > 64) {
+ throw std::out_of_range("nbits must be between 0 and 64");
+ }
+
+ while (nbits > 0) {
+ int bits = std::min(8 - m_offset, nbits);
+ m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
+ m_offset += bits;
+ nbits -= bits;
+
+ if (m_offset == 8) {
+ Flush();
+ }
+ }
+ }
+
+ /** Flush any unwritten bits to the output stream, padding with 0's to the
+ * next byte boundary.
+ */
+ void Flush() {
+ if (m_offset == 0) {
+ return;
+ }
+
+ m_ostream << m_buffer;
+ m_buffer = 0;
+ m_offset = 0;
+ }
+};
diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp
new file mode 100644
index 0000000000..e3cb05f09e
--- /dev/null
+++ b/src/test/blockfilter_tests.cpp
@@ -0,0 +1,142 @@
+// Copyright (c) 2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <test/data/blockfilters.json.h>
+#include <test/test_bitcoin.h>
+
+#include <blockfilter.h>
+#include <core_io.h>
+#include <serialize.h>
+#include <streams.h>
+#include <univalue.h>
+#include <utilstrencodings.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(blockfilter_tests)
+
+BOOST_AUTO_TEST_CASE(gcsfilter_test)
+{
+ GCSFilter::ElementSet included_elements, excluded_elements;
+ for (int i = 0; i < 100; ++i) {
+ GCSFilter::Element element1(32);
+ element1[0] = i;
+ included_elements.insert(std::move(element1));
+
+ GCSFilter::Element element2(32);
+ element2[1] = i;
+ excluded_elements.insert(std::move(element2));
+ }
+
+ GCSFilter filter(0, 0, 10, 1 << 10, included_elements);
+ for (const auto& element : included_elements) {
+ BOOST_CHECK(filter.Match(element));
+
+ auto insertion = excluded_elements.insert(element);
+ BOOST_CHECK(filter.MatchAny(excluded_elements));
+ excluded_elements.erase(insertion.first);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
+{
+ CScript included_scripts[5], excluded_scripts[2];
+
+ // First two are outputs on a single transaction.
+ included_scripts[0] << std::vector<unsigned char>(0, 65) << OP_CHECKSIG;
+ included_scripts[1] << OP_DUP << OP_HASH160 << std::vector<unsigned char>(1, 20) << OP_EQUALVERIFY << OP_CHECKSIG;
+
+ // Third is an output on in a second transaction.
+ included_scripts[2] << OP_1 << std::vector<unsigned char>(2, 33) << OP_1 << OP_CHECKMULTISIG;
+
+ // Last two are spent by a single transaction.
+ included_scripts[3] << OP_0 << std::vector<unsigned char>(3, 32);
+ included_scripts[4] << OP_4 << OP_ADD << OP_8 << OP_EQUAL;
+
+ // OP_RETURN output is an output on the second transaction.
+ excluded_scripts[0] << OP_RETURN << std::vector<unsigned char>(4, 40);
+
+ // This script is not related to the block at all.
+ excluded_scripts[1] << std::vector<unsigned char>(5, 33) << OP_CHECKSIG;
+
+ CMutableTransaction tx_1;
+ tx_1.vout.emplace_back(100, included_scripts[0]);
+ tx_1.vout.emplace_back(200, included_scripts[1]);
+
+ CMutableTransaction tx_2;
+ tx_2.vout.emplace_back(300, included_scripts[2]);
+ tx_2.vout.emplace_back(0, excluded_scripts[0]);
+
+ CBlock block;
+ block.vtx.push_back(MakeTransactionRef(tx_1));
+ block.vtx.push_back(MakeTransactionRef(tx_2));
+
+ CBlockUndo block_undo;
+ block_undo.vtxundo.emplace_back();
+ block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(400, included_scripts[3]), 1000, true);
+ block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[4]), 10000, false);
+
+ BlockFilter block_filter(BlockFilterType::BASIC, block, block_undo);
+ const GCSFilter& filter = block_filter.GetFilter();
+
+ for (const CScript& script : included_scripts) {
+ BOOST_CHECK(filter.Match(GCSFilter::Element(script.begin(), script.end())));
+ }
+ for (const CScript& script : excluded_scripts) {
+ BOOST_CHECK(!filter.Match(GCSFilter::Element(script.begin(), script.end())));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(blockfilters_json_test)
+{
+ UniValue json;
+ std::string json_data(json_tests::blockfilters,
+ json_tests::blockfilters + sizeof(json_tests::blockfilters));
+ if (!json.read(json_data) || !json.isArray()) {
+ BOOST_ERROR("Parse error.");
+ return;
+ }
+
+ const UniValue& tests = json.get_array();
+ for (unsigned int i = 0; i < tests.size(); i++) {
+ UniValue test = tests[i];
+ std::string strTest = test.write();
+
+ if (test.size() == 1) {
+ continue;
+ } else if (test.size() < 7) {
+ BOOST_ERROR("Bad test: " << strTest);
+ continue;
+ }
+
+ unsigned int pos = 0;
+ /*int block_height =*/ test[pos++].get_int();
+ /*uint256 block_hash =*/ ParseHashStr(test[pos++].get_str(), "block_hash");
+
+ CBlock block;
+ BOOST_REQUIRE(DecodeHexBlk(block, test[pos++].get_str()));
+
+ CBlockUndo block_undo;
+ block_undo.vtxundo.emplace_back();
+ CTxUndo& tx_undo = block_undo.vtxundo.back();
+ const UniValue& prev_scripts = test[pos++].get_array();
+ for (unsigned int ii = 0; ii < prev_scripts.size(); ii++) {
+ std::vector<unsigned char> raw_script = ParseHex(prev_scripts[ii].get_str());
+ CTxOut txout(0, CScript(raw_script.begin(), raw_script.end()));
+ tx_undo.vprevout.emplace_back(txout, 0, false);
+ }
+
+ uint256 prev_filter_header_basic = ParseHashStr(test[pos++].get_str(), "prev_filter_header_basic");
+ std::vector<unsigned char> filter_basic = ParseHex(test[pos++].get_str());
+ uint256 filter_header_basic = ParseHashStr(test[pos++].get_str(), "filter_header_basic");
+
+ BlockFilter computed_filter_basic(BlockFilterType::BASIC, block, block_undo);
+ BOOST_CHECK(computed_filter_basic.GetFilter().GetEncoded() == filter_basic);
+
+ uint256 computed_header_basic = computed_filter_basic.ComputeHeader(prev_filter_header_basic);
+ BOOST_CHECK(computed_header_basic == filter_header_basic);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/data/blockfilters.json b/src/test/data/blockfilters.json
new file mode 100644
index 0000000000..2f00728ff6
--- /dev/null
+++ b/src/test/data/blockfilters.json
@@ -0,0 +1,9 @@
+[
+["Block Height,Block Hash,Block,[Prev Output Scripts for Block],Previous Basic Header,Basic Filter,Basic Header,Notes"],
+[0,"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943","0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",[],"0000000000000000000000000000000000000000000000000000000000000000","019dfca8","21584579b7eb08997773e5aeff3a7f932700042d0ed2a6129012b7d7ae81b750","Genesis block"],
+[2,"000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820","0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d235340101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0432e7494d010e062f503253482fffffffff0100f2052a010000002321038a7f6ef1c8ca0c588aa53fa860128077c9e6c11e6830f4d7ee4e763a56b7718fac00000000",[],"d7bdac13a59d745b1add0d2ce852f1a0442e8945fc1bf3848d3cbffd88c24fe1","0174a170","186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0",""],
+[3,"000000008b896e272758da5297bcd98fdc6d97c9b765ecec401e286dc1fdbe10","0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b60101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0486e7494d0151062f503253482fffffffff0100f2052a01000000232103f6d9ff4c12959445ca5549c811683bf9c88e637b222dd2e0311154c4c85cf423ac00000000",[],"186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0","016cf7a0","8d63aadf5ab7257cb6d2316a57b16f517bff1c6388f124ec4c04af1212729d2a",""],
+[926485,"000000000000015d6077a411a8f5cc95caf775ccf11c54e27df75ce58d187313","0000002060bbab0edbf3ef8a49608ee326f8fd75c473b7e3982095e2d100000000000000c30134f8c9b6d2470488d7a67a888f6fa12f8692e0c3411fbfb92f0f68f67eedae03ca57ef13021acc22dc4105010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2f0315230e0004ae03ca57043e3d1e1d0c8796bf579aef0c0000000000122f4e696e6a61506f6f6c2f5345475749542fffffffff038427a112000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9ed5c748e121c0fe146d973a4ac26fa4a68b0549d46ee22d25f50a5e46fe1b377ee00000000000000002952534b424c4f434b3acd16772ad61a3c5f00287480b720f6035d5e54c9efc71be94bb5e3727f10909001200000000000000000000000000000000000000000000000000000000000000000000000000100000000010145310e878941a1b2bc2d33797ee4d89d95eaaf2e13488063a2aa9a74490f510a0100000023220020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1ffffffff01002d3101000000001976a9143ebc40e411ed3c76f86711507ab952300890397288ac0400473044022001dd489a5d4e2fbd8a3ade27177f6b49296ba7695c40dbbe650ea83f106415fd02200b23a0602d8ff1bdf79dee118205fc7e9b40672bf31563e5741feb53fb86388501483045022100f88f040e90cc5dc6c6189d04718376ac19ed996bf9e4a3c29c3718d90ffd27180220761711f16c9e3a44f71aab55cbc0634907a1fa8bb635d971a9a01d368727bea10169522103b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb2103dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba621033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be153ae00000000010000000120925534261de4dcebb1ed5ab1b62bfe7a3ef968fb111dc2c910adfebc6e3bdf010000006b483045022100f50198f5ae66211a4f485190abe4dc7accdabe3bc214ebc9ea7069b97097d46e0220316a70a03014887086e335fc1b48358d46cd6bdc9af3b57c109c94af76fc915101210316cff587a01a2736d5e12e53551b18d73780b83c3bfb4fcf209c869b11b6415effffffff0220a10700000000001976a91450333046115eaa0ac9e0216565f945070e44573988ac2e7cd01a000000001976a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac00000000010000000203a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322010000006a47304402204efc3d70e4ca3049c2a425025edf22d5ca355f9ec899dbfbbeeb2268533a0f2b02204780d3739653035af4814ea52e1396d021953f948c29754edd0ee537364603dc012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff03a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322000000006a47304402202d96defdc5b4af71d6ba28c9a6042c2d5ee7bc6de565d4db84ef517445626e03022022da80320e9e489c8f41b74833dfb6a54a4eb5087cdb46eb663eef0b25caa526012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a914b7e6f7ff8658b2d1fb107e3d7be7af4742e6b1b3876f88fc00000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac0000000001000000043ffd60d3818431c495b89be84afac205d5d1ed663009291c560758bbd0a66df5010000006b483045022100f344607de9df42049688dcae8ff1db34c0c7cd25ec05516e30d2bc8f12ac9b2f022060b648f6a21745ea6d9782e17bcc4277b5808326488a1f40d41e125879723d3a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffffa5379401cce30f84731ef1ba65ce27edf2cc7ce57704507ebe8714aa16a96b92010000006a473044022020c37a63bf4d7f564c2192528709b6a38ab8271bd96898c6c2e335e5208661580220435c6f1ad4d9305d2c0a818b2feb5e45d443f2f162c0f61953a14d097fd07064012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff70e731e193235ff12c3184510895731a099112ffca4b00246c60003c40f843ce000000006a473044022053760f74c29a879e30a17b5f03a5bb057a5751a39f86fa6ecdedc36a1b7db04c022041d41c9b95f00d2d10a0373322a9025dba66c942196bc9d8adeb0e12d3024728012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff66b7a71b3e50379c8e85fc18fe3f1a408fc985f257036c34702ba205cef09f6f000000006a4730440220499bf9e2db3db6e930228d0661395f65431acae466634d098612fd80b08459ee022040e069fc9e3c60009f521cef54c38aadbd1251aee37940e6018aadb10f194d6a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a9148fc37ad460fdfbd2b44fe446f6e3071a4f64faa6878f447f0b000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac00000000",["a914feb8a29635c56d9cd913122f90678756bf23887687","76a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac"],"da49977ba1ee0d620a2c4f8f646b03cd0d230f5c6c994722e3ba884889f0be1a","09027acea61b6cc3fb33f5d52f7d088a6b2f75d234e89ca800","4cd9dd007a325199102f1fc0b7d77ca25ee3c84d46018c4353ecfcb56c0d3e7a","Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"],
+[987876,"0000000000000c00901f2049055e2a437c819d79a3d54fd63e6af796cd7b8a79","000000202694f74969fdb542090e95a56bc8aa2d646e27033850e32f1c5f000000000000f7e53676b3f12d5beb524ed617f2d25f5a93b5f4f52c1ba2678260d72712f8dd0a6dfe5740257e1a4b1768960101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1603e4120ff9c30a1c216900002f424d4920546573742fffffff0001205fa012000000001e76a914c486de584a735ec2f22da7cd9681614681f92173d83d0aa68688ac00000000",[],"e9d729b72d533c29abe5276d5cf6c152f3723f10efe000b1e0c9ca5265a8beb6","010c0b40","e6137ae5a8424c40da1e5023c16975cc97b09300b4c050e6b1c713add3836c40","Coinbase tx has unparseable output script"],
+[1263442,"000000006f27ddfe1dd680044a34548f41bed47eba9e6f0b310da21423bc5f33","000000201c8d1a529c39a396db2db234d5ec152fa651a2872966daccbde028b400000000083f14492679151dbfaa1a825ef4c18518e780c1f91044180280a7d33f4a98ff5f45765aaddc001d38333b9a02010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff230352471300fe5f45765afe94690a000963676d696e6572343208000000000000000000ffffffff024423a804000000001976a914f2c25ac3d59f3d674b1d1d0a25c27339aaac0ba688ac0000000000000000266a24aa21a9edcb26cb3052426b9ebb4d19c819ef87c19677bbf3a7c46ef0855bd1b2abe83491012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101d20978463906ba4ff5e7192494b88dd5eb0de85d900ab253af909106faa22cc5010000000004000000014777ff000000000016001446c29eabe8208a33aa1023c741fa79aa92e881ff0347304402207d7ca96134f2bcfdd6b536536fdd39ad17793632016936f777ebb32c22943fda02206014d2fb8a6aa58279797f861042ba604ebd2f8f61e5bddbd9d3be5a245047b201004b632103eeaeba7ce5dc2470221e9517fb498e8d6bd4e73b85b8be655196972eb9ccd5566754b2752103a40b74d43df244799d041f32ce1ad515a6cd99501701540e38750d883ae21d3a68ac00000000",["002027a5000c7917f785d8fc6e5a55adfca8717ecb973ebb7743849ff956d896a7ed"],"a4a4d6c6034da8aa06f01fe71f1fffbd79e032006b07f6c7a2c60a66aa310c01","0385acb4f0fe889ef0","3588f34fbbc11640f9ed40b2a66a4e096215d50389691309c1dac74d4268aa81","Includes witness data"]
+]
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index f189222be8..e739b84a48 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -64,7 +64,7 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std:
BOOST_CHECK_EQUAL(pub, pub2);
// Check that both can be serialized with private key back to the private version, but not without private key.
- std::string prv1, prv2;
+ std::string prv1;
BOOST_CHECK(parse_priv->ToPrivateString(keys_priv, prv1));
BOOST_CHECK_EQUAL(prv, prv1);
BOOST_CHECK(!parse_priv->ToPrivateString(keys_pub, prv1));
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 2da06b8d31..c4793472d4 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -29,7 +29,7 @@ BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup)
// BOOST_CHECK_EXCEPTION predicates to check the specific validation error
class HasReason {
public:
- HasReason(const std::string& reason) : m_reason(reason) {}
+ explicit HasReason(const std::string& reason) : m_reason(reason) {}
bool operator() (const std::runtime_error& e) const {
return std::string(e.what()).find(m_reason) != std::string::npos;
};
@@ -90,7 +90,7 @@ static CBlockIndex CreateBlockIndex(int nHeight)
return index;
}
-static bool TestSequenceLocks(const CTransaction &tx, int flags)
+static bool TestSequenceLocks(const CTransaction &tx, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
LOCK(mempool.cs);
return CheckSequenceLocks(tx, flags);
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 001d8eb64b..2af0ab22da 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -138,11 +138,11 @@ BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)
// the callbacks should run in exactly the order in which they were enqueued
for (int i = 0; i < 100; ++i) {
queue1.AddToProcessQueue([i, &counter1]() {
- BOOST_CHECK_EQUAL(i, counter1++);
+ assert(i == counter1++);
});
queue2.AddToProcessQueue([i, &counter2]() {
- BOOST_CHECK_EQUAL(i, counter2++);
+ assert(i == counter2++);
});
}
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index bf57272ab2..b3e4b12918 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -25,22 +25,19 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
}
CScript s;
- txnouttype whichType;
std::vector<std::vector<unsigned char> > solutions;
// TX_PUBKEY
s.clear();
s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_PUBKEY);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEY);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0]));
// TX_PUBKEYHASH
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEYHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
@@ -48,8 +45,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
CScript redeemScript(s); // initialize with leftover P2PKH script
s.clear();
s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_SCRIPTHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript)));
@@ -59,8 +55,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
ToByteVector(pubkeys[0]) <<
ToByteVector(pubkeys[1]) <<
OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG);
BOOST_CHECK_EQUAL(solutions.size(), 4U);
BOOST_CHECK(solutions[0] == std::vector<unsigned char>({1}));
BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
@@ -73,8 +68,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
ToByteVector(pubkeys[1]) <<
ToByteVector(pubkeys[2]) <<
OP_3 << OP_CHECKMULTISIG;
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG);
BOOST_CHECK_EQUAL(solutions.size(), 5U);
BOOST_CHECK(solutions[0] == std::vector<unsigned char>({2}));
BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
@@ -88,15 +82,13 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
std::vector<unsigned char>({0}) <<
std::vector<unsigned char>({75}) <<
std::vector<unsigned char>({255});
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_NULL_DATA);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NULL_DATA);
BOOST_CHECK_EQUAL(solutions.size(), 0U);
// TX_WITNESS_V0_KEYHASH
s.clear();
s << OP_0 << ToByteVector(pubkeys[0].GetID());
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_KEYHASH);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_KEYHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
@@ -107,16 +99,14 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
s.clear();
s << OP_0 << ToByteVector(scriptHash);
- BOOST_CHECK(Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_SCRIPTHASH);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_SCRIPTHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(scriptHash));
// TX_NONSTANDARD
s.clear();
s << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
- BOOST_CHECK(!Solver(s, whichType, solutions));
- BOOST_CHECK_EQUAL(whichType, TX_NONSTANDARD);
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
}
BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
@@ -127,53 +117,52 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
pubkey = key.GetPubKey();
CScript s;
- txnouttype whichType;
std::vector<std::vector<unsigned char> > solutions;
// TX_PUBKEY with incorrectly sized pubkey
s.clear();
s << std::vector<unsigned char>(30, 0x01) << OP_CHECKSIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_PUBKEYHASH with incorrectly sized key hash
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_SCRIPTHASH with incorrectly sized script hash
s.clear();
s << OP_HASH160 << std::vector<unsigned char>(21, 0x01) << OP_EQUAL;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG 0/2
s.clear();
s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG 2/1
s.clear();
s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG n = 2 with 1 pubkey
s.clear();
s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG n = 1 with 0 pubkeys
s.clear();
s << OP_1 << OP_1 << OP_CHECKMULTISIG;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_NULL_DATA with other opcodes
s.clear();
s << OP_RETURN << std::vector<unsigned char>({75}) << OP_ADD;
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_WITNESS with incorrect program size
s.clear();
s << OP_0 << std::vector<unsigned char>(19, 0x01);
- BOOST_CHECK(!Solver(s, whichType, solutions));
+ BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
}
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index bc671394c0..67c377778f 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -937,17 +937,19 @@ BOOST_AUTO_TEST_CASE(script_build)
}
}
+#ifdef UPDATE_JSON_TESTS
std::string strGen;
-
+#endif
for (TestBuilder& test : tests) {
test.Test();
std::string str = JSONPrettyPrint(test.GetJSON());
-#ifndef UPDATE_JSON_TESTS
+#ifdef UPDATE_JSON_TESTS
+ strGen += str + ",\n";
+#else
if (tests_set.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment());
}
#endif
- strGen += str + ",\n";
}
#ifdef UPDATE_JSON_TESTS
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 6a0aa864d9..26cf74830d 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -68,6 +68,86 @@ BOOST_AUTO_TEST_CASE(streams_vector_writer)
vch.clear();
}
+BOOST_AUTO_TEST_CASE(streams_vector_reader)
+{
+ std::vector<unsigned char> vch = {1, 255, 3, 4, 5, 6};
+
+ VectorReader reader(SER_NETWORK, INIT_PROTO_VERSION, vch, 0);
+ BOOST_CHECK_EQUAL(reader.size(), 6);
+ BOOST_CHECK(!reader.empty());
+
+ // Read a single byte as an unsigned char.
+ unsigned char a;
+ reader >> a;
+ BOOST_CHECK_EQUAL(a, 1);
+ BOOST_CHECK_EQUAL(reader.size(), 5);
+ BOOST_CHECK(!reader.empty());
+
+ // Read a single byte as a signed char.
+ signed char b;
+ reader >> b;
+ BOOST_CHECK_EQUAL(b, -1);
+ BOOST_CHECK_EQUAL(reader.size(), 4);
+ BOOST_CHECK(!reader.empty());
+
+ // Read a 4 bytes as an unsigned int.
+ unsigned int c;
+ reader >> c;
+ BOOST_CHECK_EQUAL(c, 100992003); // 3,4,5,6 in little-endian base-256
+ BOOST_CHECK_EQUAL(reader.size(), 0);
+ BOOST_CHECK(reader.empty());
+
+ // Reading after end of byte vector throws an error.
+ signed int d;
+ BOOST_CHECK_THROW(reader >> d, std::ios_base::failure);
+
+ // Read a 4 bytes as a signed int from the beginning of the buffer.
+ reader.seek(-6);
+ reader >> d;
+ BOOST_CHECK_EQUAL(d, 67370753); // 1,255,3,4 in little-endian base-256
+ BOOST_CHECK_EQUAL(reader.size(), 2);
+ BOOST_CHECK(!reader.empty());
+
+ // Reading after end of byte vector throws an error even if the reader is
+ // not totally empty.
+ BOOST_CHECK_THROW(reader >> d, std::ios_base::failure);
+}
+
+BOOST_AUTO_TEST_CASE(bitstream_reader_writer)
+{
+ CDataStream data(SER_NETWORK, INIT_PROTO_VERSION);
+
+ BitStreamWriter<CDataStream> bit_writer(data);
+ bit_writer.Write(0, 1);
+ bit_writer.Write(2, 2);
+ bit_writer.Write(6, 3);
+ bit_writer.Write(11, 4);
+ bit_writer.Write(1, 5);
+ bit_writer.Write(32, 6);
+ bit_writer.Write(7, 7);
+ bit_writer.Write(30497, 16);
+ bit_writer.Flush();
+
+ CDataStream data_copy(data);
+ uint32_t serialized_int1;
+ data >> serialized_int1;
+ BOOST_CHECK_EQUAL(serialized_int1, (uint32_t)0x7700C35A); // NOTE: Serialized as LE
+ uint16_t serialized_int2;
+ data >> serialized_int2;
+ BOOST_CHECK_EQUAL(serialized_int2, (uint16_t)0x1072); // NOTE: Serialized as LE
+
+ BitStreamReader<CDataStream> bit_reader(data_copy);
+ BOOST_CHECK_EQUAL(bit_reader.Read(1), 0);
+ BOOST_CHECK_EQUAL(bit_reader.Read(2), 2);
+ BOOST_CHECK_EQUAL(bit_reader.Read(3), 6);
+ BOOST_CHECK_EQUAL(bit_reader.Read(4), 11);
+ BOOST_CHECK_EQUAL(bit_reader.Read(5), 1);
+ BOOST_CHECK_EQUAL(bit_reader.Read(6), 32);
+ BOOST_CHECK_EQUAL(bit_reader.Read(7), 7);
+ BOOST_CHECK_EQUAL(bit_reader.Read(16), 30497);
+ BOOST_CHECK_THROW(bit_reader.Read(8), std::ios_base::failure);
+}
+
BOOST_AUTO_TEST_CASE(streams_serializedata_xor)
{
std::vector<char> in;
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 9c3285fb0c..a89bf785f1 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -8,15 +8,17 @@
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
-#include <validation.h>
#include <miner.h>
#include <net_processing.h>
#include <pow.h>
-#include <ui_interface.h>
-#include <streams.h>
-#include <rpc/server.h>
#include <rpc/register.h>
+#include <rpc/server.h>
#include <script/sigcache.h>
+#include <streams.h>
+#include <ui_interface.h>
+#include <validation.h>
+
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
void CConnmanTest::AddNode(CNode& node)
{
diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp
index 4d835db7be..11b7c66ccd 100644
--- a/src/test/test_bitcoin_fuzzy.cpp
+++ b/src/test/test_bitcoin_fuzzy.cpp
@@ -6,20 +6,20 @@
#include <config/bitcoin-config.h>
#endif
-#include <consensus/merkle.h>
-#include <primitives/block.h>
-#include <script/script.h>
#include <addrman.h>
+#include <blockencodings.h>
#include <chain.h>
#include <coins.h>
#include <compressor.h>
+#include <consensus/merkle.h>
#include <net.h>
+#include <primitives/block.h>
#include <protocol.h>
+#include <pubkey.h>
+#include <script/script.h>
#include <streams.h>
#include <undo.h>
#include <version.h>
-#include <pubkey.h>
-#include <blockencodings.h>
#include <stdint.h>
#include <unistd.h>
@@ -28,6 +28,8 @@
#include <memory>
#include <vector>
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
enum TEST_ID {
CBLOCK_DESERIALIZE=0,
CTRANSACTION_DESERIALIZE,
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index be7ee2428b..2a160b9988 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -61,6 +61,8 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
BOOST_ERROR("Read incorrect tx");
}
}
+
+ txindex.Stop(); // Stop thread before calling destructor
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 37c4f79133..4316f37999 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -23,7 +23,7 @@ BOOST_FIXTURE_TEST_SUITE(validation_block_tests, RegtestingSetup)
struct TestSubscriber : public CValidationInterface {
uint256 m_expected_tip;
- TestSubscriber(uint256 tip) : m_expected_tip(tip) {}
+ explicit TestSubscriber(uint256 tip) : m_expected_tip(tip) {}
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override
{
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 8bada4dce8..c7ff7b5477 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -640,8 +640,6 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children);
bool fDependsWait = false;
setEntries setParentCheck;
- int64_t parentSizes = 0;
- int64_t parentSigOpCost = 0;
for (const CTxIn &txin : tx.vin) {
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
@@ -649,10 +647,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
const CTransaction& tx2 = it2->GetTx();
assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull());
fDependsWait = true;
- if (setParentCheck.insert(it2).second) {
- parentSizes += it2->GetTxSize();
- parentSigOpCost += it2->GetSigOpCost();
- }
+ setParentCheck.insert(it2);
} else {
assert(pcoins->HaveCoin(txin.prevout));
}
diff --git a/src/txmempool.h b/src/txmempool.h
index 587d931d95..f8915cec31 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -28,6 +28,7 @@
#include <boost/signals2/signal.hpp>
class CBlockIndex;
+extern CCriticalSection cs_main;
/** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */
static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF;
@@ -543,7 +544,7 @@ public:
void addUnchecked(const uint256& hash, const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs);
void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
- void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
+ void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void removeConflicts(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);
diff --git a/src/undo.h b/src/undo.h
index a1398b7624..4a78238944 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -6,6 +6,7 @@
#ifndef BITCOIN_UNDO_H
#define BITCOIN_UNDO_H
+#include <coins.h>
#include <compressor.h>
#include <consensus/consensus.h>
#include <primitives/transaction.h>
diff --git a/src/util.cpp b/src/util.cpp
index 95bc427bb2..1aab85264f 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -86,8 +86,6 @@ const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
ArgsManager gArgs;
-CTranslationInterface translationInterface;
-
/** Init OpenSSL library multithreading support */
static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL;
void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
diff --git a/src/util.h b/src/util.h
index 23b2a787e4..e93489c1ed 100644
--- a/src/util.h
+++ b/src/util.h
@@ -19,8 +19,8 @@
#include <logging.h>
#include <sync.h>
#include <tinyformat.h>
-#include <utiltime.h>
#include <utilmemory.h>
+#include <utiltime.h>
#include <atomic>
#include <exception>
@@ -31,33 +31,24 @@
#include <unordered_set>
#include <vector>
-#include <boost/signals2/signal.hpp>
#include <boost/thread/condition_variable.hpp> // for boost::thread_interrupted
// Application startup time (used for uptime calculation)
int64_t GetStartupTime();
-/** Signals for translation. */
-class CTranslationInterface
-{
-public:
- /** Translate a message to the native language of the user. */
- boost::signals2::signal<std::string (const char* psz)> Translate;
-};
-
-extern CTranslationInterface translationInterface;
-
extern const char * const BITCOIN_CONF_FILENAME;
extern const char * const BITCOIN_PID_FILENAME;
+/** Translate a message to the native language of the user. */
+const extern std::function<std::string(const char*)> G_TRANSLATION_FUN;
+
/**
- * Translation function: Call Translate signal on UI interface, which returns a boost::optional result.
- * If no translation slot is registered, nothing is returned, and simply return the input.
+ * Translation function.
+ * If no translation function is set, simply return the input.
*/
inline std::string _(const char* psz)
{
- boost::optional<std::string> rv = translationInterface.Translate(psz);
- return rv ? (*rv) : psz;
+ return G_TRANSLATION_FUN ? (G_TRANSLATION_FUN)(psz) : psz;
}
void SetupEnvironment();
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index a06d88cb19..e66e2c238c 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -544,3 +544,43 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
return true;
}
+bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath)
+{
+ std::stringstream ss(keypath_str);
+ std::string item;
+ bool first = true;
+ while (std::getline(ss, item, '/')) {
+ if (item.compare("m") == 0) {
+ if (first) {
+ first = false;
+ continue;
+ }
+ return false;
+ }
+ // Finds whether it is hardened
+ uint32_t path = 0;
+ size_t pos = item.find("'");
+ if (pos != std::string::npos) {
+ // The hardened tick can only be in the last index of the string
+ if (pos != item.size() - 1) {
+ return false;
+ }
+ path |= 0x80000000;
+ item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick
+ }
+
+ // Ensure this is only numbers
+ if (item.find_first_not_of( "0123456789" ) != std::string::npos) {
+ return false;
+ }
+ uint32_t number;
+ if (!ParseUInt32(item, &number)) {
+ return false;
+ }
+ path |= number;
+
+ keypath.push_back(path);
+ first = false;
+ }
+ return true;
+}
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index 5f2211b5dc..8f29f8f322 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -183,4 +183,7 @@ bool ConvertBits(const O& outfn, I it, I end) {
return true;
}
+/** Parse an HD keypaths like "m/7/0'/2000". */
+bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath);
+
#endif // BITCOIN_UTILSTRENCODINGS_H
diff --git a/src/validation.cpp b/src/validation.cpp
index fceb135854..3e51221a5e 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -170,7 +170,7 @@ public:
// Block (dis)connection on a given view:
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
- CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false);
+ CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Block disconnection on our pcoinsTip:
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool);
@@ -189,8 +189,8 @@ public:
void UnloadBlockIndex();
private:
- bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace);
- bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool);
+ bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Create a new block index entry for a given block hash */
@@ -202,7 +202,7 @@ private:
*/
void CheckBlockIndex(const Consensus::Params& consensusParams);
- void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state);
+ void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -457,7 +457,7 @@ std::string FormatStateMessage(const CValidationState &state)
state.GetRejectCode());
}
-static bool IsCurrentForFeeEstimation()
+static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
if (IsInitialBlockDownload())
@@ -482,7 +482,7 @@ static bool IsCurrentForFeeEstimation()
* and instead just erase from the mempool as needed.
*/
-static void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool fAddToMempool)
+static void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
std::vector<uint256> vHashUpdate;
@@ -524,7 +524,7 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool,
// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool
// were somehow broken and returning the wrong scriptPubKeys
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool,
- unsigned int flags, bool cacheSigStore, PrecomputedTransactionData& txdata) {
+ unsigned int flags, bool cacheSigStore, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
AssertLockHeld(cs_main);
// pool.cs should be locked already, but go ahead and re-take the lock here
@@ -559,7 +559,7 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt
static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx,
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache, bool test_accept)
+ bool bypass_limits, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
const CTransaction& tx = *ptx;
const uint256 hash = tx.GetHash();
@@ -977,7 +977,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
/** (try to) add transaction to memory pool with a specified acceptance time **/
static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept)
+ bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
std::vector<COutPoint> coins_to_uncache;
bool res = AcceptToMemoryPoolWorker(chainparams, pool, state, tx, pfMissingInputs, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept);
@@ -1216,7 +1216,7 @@ static void AlertNotify(const std::string& strMessage)
t.detach(); // thread runs free
}
-static void CheckForkWarningConditions()
+static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks
@@ -1257,7 +1257,7 @@ static void CheckForkWarningConditions()
}
}
-static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
+static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
// If we are on a fork that is sufficiently large, set a warning flag
@@ -1290,7 +1290,7 @@ static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
CheckForkWarningConditions();
}
-void static InvalidChainFound(CBlockIndex* pindexNew)
+void static InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork)
pindexBestInvalid = pindexNew;
@@ -1377,7 +1377,7 @@ void InitScriptExecutionCache() {
*
* Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp
*/
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
if (!tx.IsCoinBase())
{
@@ -1743,7 +1743,7 @@ static bool IsScriptWitnessEnabled(const Consensus::Params& params)
return params.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0;
}
-static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) {
+static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
AssertLockHeld(cs_main);
unsigned int flags = SCRIPT_VERIFY_NONE;
@@ -2863,6 +2863,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
}
return true;
}
+
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
return g_chainstate.InvalidateBlock(state, chainparams, pindex);
}
diff --git a/src/validation.h b/src/validation.h
index 4965ff152a..c4c9b8b5ba 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -302,7 +302,7 @@ void PruneBlockFilesManual(int nManualPruneHeight);
* plTxnReplaced will be appended to with all transactions replaced from mempool **/
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
- bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false);
+ bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state);
@@ -329,12 +329,12 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
*
* See consensus/consensus.h for flag definitions.
*/
-bool CheckFinalTx(const CTransaction &tx, int flags = -1);
+bool CheckFinalTx(const CTransaction &tx, int flags = -1) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Test whether the LockPoints height and time are still valid on the current chain
*/
-bool TestLockPointValidity(const LockPoints* lp);
+bool TestLockPointValidity(const LockPoints* lp) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Check if transaction will be BIP 68 final in the next block to be created.
@@ -347,7 +347,7 @@ bool TestLockPointValidity(const LockPoints* lp);
*
* See consensus/consensus.h for flag definitions.
*/
-bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false);
+bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = nullptr, bool useExistingLockPoints = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Closure representing one script verification
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 248e774a8d..e25eca2368 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -7,7 +7,6 @@
#include <primitives/block.h>
#include <scheduler.h>
-#include <sync.h>
#include <txmempool.h>
#include <util.h>
#include <validation.h>
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 6e96755ea3..f0374e8e78 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -7,10 +7,12 @@
#define BITCOIN_VALIDATIONINTERFACE_H
#include <primitives/transaction.h> // CTransaction(Ref)
+#include <sync.h>
#include <functional>
#include <memory>
+extern CCriticalSection cs_main;
class CBlock;
class CBlockIndex;
struct CBlockLocator;
@@ -51,7 +53,7 @@ void CallFunctionInValidationInterfaceQueue(std::function<void ()> func);
* });
* promise.get_future().wait();
*/
-void SyncWithValidationInterfaceQueue();
+void SyncWithValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main);
/**
* Implement this to subscribe to events generated in validation
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index 3734ba66b6..fdeb89553b 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -3,9 +3,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <wallet/coinselection.h>
+
#include <util.h>
#include <utilmoneystr.h>
+#include <boost/optional.hpp>
+
// Descending order comparator
struct {
bool operator()(const OutputGroup& a, const OutputGroup& b) const
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index d5d4021305..2b8a0f6467 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -18,7 +18,7 @@
//! Check whether transaction has descendant in wallet or mempool, or has been
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
-static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet)
+static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors) EXCLUSIVE_LOCKS_REQUIRED(cs_main, wallet->cs_wallet)
{
if (wallet->HasWalletSpend(wtx.GetHash())) {
errors.push_back("Transaction has descendants in the wallet");
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 7cb41da39e..60f14e5886 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1150,7 +1150,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
" \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n"
" \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be treated as not incoming payments\n"
" \"watchonly\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n"
- " \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n"
+ " \"label\": <label> , (string, optional, default: '') Label to assign to the address, only allowed with internal=false\n"
" }\n"
" ,...\n"
" ]\n"
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 5ff3fa7067..8d9b67d82f 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -89,7 +89,7 @@ void EnsureWalletIsUnlocked(CWallet * const pwallet)
}
}
-static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
+static void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
int confirms = wtx.GetDepthInMainChain();
entry.pushKV("confirmations", confirms);
@@ -165,7 +165,7 @@ static UniValue getnewaddress(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ LOCK(pwallet->cs_wallet);
// Parse the label first so we don't generate a key if there's an error
std::string label;
@@ -206,49 +206,6 @@ CTxDestination GetLabelDestination(CWallet* const pwallet, const std::string& la
return dest;
}
-static UniValue getaccountaddress(const JSONRPCRequest& request)
-{
- std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- CWallet* const pwallet = wallet.get();
-
- if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
- return NullUniValue;
- }
-
- if (!IsDeprecatedRPCEnabled("accounts")) {
- if (request.fHelp) {
- throw std::runtime_error("getaccountaddress (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
- }
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "getaccountaddress is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
- }
-
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
- "getaccountaddress \"account\"\n"
- "\n\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
- "\nArguments:\n"
- "1. \"account\" (string, required) The account for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n"
- "\nResult:\n"
- "\"address\" (string) The account bitcoin address\n"
- "\nExamples:\n"
- + HelpExampleCli("getaccountaddress", "")
- + HelpExampleCli("getaccountaddress", "\"\"")
- + HelpExampleCli("getaccountaddress", "\"myaccount\"")
- + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
- );
-
- LOCK2(cs_main, pwallet->cs_wallet);
-
- // Parse the account first so we don't generate a key if there's an error
- std::string account = LabelFromValue(request.params[0]);
-
- UniValue ret(UniValue::VSTR);
-
- ret = EncodeDestination(GetLabelDestination(pwallet, account));
- return ret;
-}
-
-
static UniValue getrawchangeaddress(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -276,7 +233,7 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
}
- LOCK2(cs_main, pwallet->cs_wallet);
+ LOCK(pwallet->cs_wallet);
if (!pwallet->IsLocked()) {
pwallet->TopUpKeyPool();
@@ -312,13 +269,6 @@ static UniValue setlabel(const JSONRPCRequest& request)
return NullUniValue;
}
- if (!IsDeprecatedRPCEnabled("accounts") && request.strMethod == "setaccount") {
- if (request.fHelp) {
- throw std::runtime_error("setaccount (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
- }
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "setaccount is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
- }
-
if (request.fHelp || request.params.size() != 2)
throw std::runtime_error(
"setlabel \"address\" \"label\"\n"
@@ -331,7 +281,7 @@ static UniValue setlabel(const JSONRPCRequest& request)
+ HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"")
);
- LOCK2(cs_main, pwallet->cs_wallet);
+ LOCK(pwallet->cs_wallet);
CTxDestination dest = DecodeDestination(request.params[0].get_str());
if (!IsValidDestination(dest)) {
@@ -343,10 +293,6 @@ static UniValue setlabel(const JSONRPCRequest& request)
if (IsMine(*pwallet, dest)) {
pwallet->SetAddressBook(dest, label, "receive");
- if (request.strMethod == "setaccount" && old_label != label && dest == GetLabelDestination(pwallet, old_label)) {
- // for setaccount, call GetLabelDestination so a new receive address is created for the old account
- GetLabelDestination(pwallet, old_label, true);
- }
} else {
pwallet->SetAddressBook(dest, label, "send");
}
@@ -369,100 +315,7 @@ static UniValue setlabel(const JSONRPCRequest& request)
}
-static UniValue getaccount(const JSONRPCRequest& request)
-{
- std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- CWallet* const pwallet = wallet.get();
-
- if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
- return NullUniValue;
- }
-
- if (!IsDeprecatedRPCEnabled("accounts")) {
- if (request.fHelp) {
- throw std::runtime_error("getaccount (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
- }
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "getaccount is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
- }
-
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
- "getaccount \"address\"\n"
- "\nDEPRECATED. Returns the account associated with the given address.\n"
- "\nArguments:\n"
- "1. \"address\" (string, required) The bitcoin address for account lookup.\n"
- "\nResult:\n"
- "\"accountname\" (string) the account address\n"
- "\nExamples:\n"
- + HelpExampleCli("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"")
- + HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"")
- );
-
- LOCK2(cs_main, pwallet->cs_wallet);
-
- CTxDestination dest = DecodeDestination(request.params[0].get_str());
- if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- }
-
- std::string strAccount;
- std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(dest);
- if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) {
- strAccount = (*mi).second.name;
- }
- return strAccount;
-}
-
-
-static UniValue getaddressesbyaccount(const JSONRPCRequest& request)
-{
- std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- CWallet* const pwallet = wallet.get();
-
- if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
- return NullUniValue;
- }
-
- if (!IsDeprecatedRPCEnabled("accounts")) {
- if (request.fHelp) {
- throw std::runtime_error("getaddressbyaccount (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
- }
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "getaddressesbyaccount is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
- }
-
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
- "getaddressesbyaccount \"account\"\n"
- "\nDEPRECATED. Returns the list of addresses for the given account.\n"
- "\nArguments:\n"
- "1. \"account\" (string, required) The account name.\n"
- "\nResult:\n"
- "[ (json array of string)\n"
- " \"address\" (string) a bitcoin address associated with the given account\n"
- " ,...\n"
- "]\n"
- "\nExamples:\n"
- + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
- + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
- );
-
- LOCK2(cs_main, pwallet->cs_wallet);
-
- std::string strAccount = LabelFromValue(request.params[0]);
-
- // Find all addresses that have the given account
- UniValue ret(UniValue::VARR);
- for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
- const CTxDestination& dest = item.first;
- const std::string& strName = item.second.name;
- if (strName == strAccount) {
- ret.push_back(EncodeDestination(dest));
- }
- }
- return ret;
-}
-
-static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue, std::string fromAccount)
+static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue)
{
CAmount curBalance = pwallet->GetBalance();
@@ -495,7 +348,7 @@ static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
CValidationState state;
- if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(fromAccount), reservekey, g_connman.get(), state)) {
+ if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, "" /* account */, reservekey, g_connman.get(), state)) {
strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
@@ -587,7 +440,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue), {} /* fromAccount */);
+ CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue));
return tx->GetHash().GetHex();
}
@@ -789,13 +642,6 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request)
return NullUniValue;
}
- if (!IsDeprecatedRPCEnabled("accounts") && request.strMethod == "getreceivedbyaccount") {
- if (request.fHelp) {
- throw std::runtime_error("getreceivedbyaccount (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
- }
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "getreceivedbyaccount is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
- }
-
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
"getreceivedbylabel \"label\" ( minconf )\n"
@@ -863,41 +709,16 @@ static UniValue getbalance(const JSONRPCRequest& request)
if (request.fHelp || (request.params.size() > 3 ))
throw std::runtime_error(
- (IsDeprecatedRPCEnabled("accounts") ? std::string(
- "getbalance ( \"account\" minconf include_watchonly )\n"
- "\nIf account is not specified, returns the server's total available balance.\n"
- "The available balance is what the wallet considers currently spendable, and is\n"
- "thus affected by options which limit spendability such as -spendzeroconfchange.\n"
- "If account is specified (DEPRECATED), returns the balance in the account.\n"
- "Note that the account \"\" is not the same as leaving the parameter out.\n"
- "The server total may be different to the balance in the default \"\" account.\n"
- "\nArguments:\n"
- "1. \"account\" (string, optional) DEPRECATED. This argument will be removed in V0.18. \n"
- " To use this deprecated argument, start bitcoind with -deprecatedrpc=accounts. The account string may be given as a\n"
- " specific account name to find the balance associated with wallet keys in\n"
- " a named account, or as the empty string (\"\") to find the balance\n"
- " associated with wallet keys not in any named account, or as \"*\" to find\n"
- " the balance associated with all wallet keys regardless of account.\n"
- " When this option is specified, it calculates the balance in a different\n"
- " way than when it is not specified, and which can count spends twice when\n"
- " there are conflicting pending transactions (such as those created by\n"
- " the bumpfee command), temporarily resulting in low or even negative\n"
- " balances. In general, account balance calculation is not considered\n"
- " reliable and has resulted in confusing outcomes, so it is recommended to\n"
- " avoid passing this argument.\n"
- "2. minconf (numeric, optional) Only include transactions confirmed at least this many times. \n"
- " The default is 1 if an account is provided or 0 if no account is provided\n")
- : std::string(
"getbalance ( \"(dummy)\" minconf include_watchonly )\n"
"\nReturns the total available balance.\n"
"The available balance is what the wallet considers currently spendable, and is\n"
"thus affected by options which limit spendability such as -spendzeroconfchange.\n"
"\nArguments:\n"
"1. (dummy) (string, optional) Remains for backward compatibility. Must be excluded or set to \"*\".\n"
- "2. minconf (numeric, optional, default=0) Only include transactions confirmed at least this many times.\n")) +
+ "2. minconf (numeric, optional, default=0) Only include transactions confirmed at least this many times.\n"
"3. include_watchonly (bool, optional, default=false) Also include balance in watch-only addresses (see 'importaddress')\n"
"\nResult:\n"
- "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
+ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this wallet.\n"
"\nExamples:\n"
"\nThe total amount in the wallet with 1 or more confirmations\n"
+ HelpExampleCli("getbalance", "") +
@@ -913,13 +734,12 @@ static UniValue getbalance(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- const UniValue& account_value = request.params[0];
+ const UniValue& dummy_value = request.params[0];
+ if (!dummy_value.isNull() && dummy_value.get_str() != "*") {
+ throw JSONRPCError(RPC_METHOD_DEPRECATED, "dummy first argument must be excluded or set to \"*\".");
+ }
int min_depth = 0;
- if (IsDeprecatedRPCEnabled("accounts") && !account_value.isNull()) {
- // Default min_depth to 1 when an account is provided.
- min_depth = 1;
- }
if (!request.params[1].isNull()) {
min_depth = request.params[1].get_int();
}
@@ -929,18 +749,6 @@ static UniValue getbalance(const JSONRPCRequest& request)
filter = filter | ISMINE_WATCH_ONLY;
}
- if (!account_value.isNull()) {
-
- const std::string& account_param = account_value.get_str();
- const std::string* account = account_param != "*" ? &account_param : nullptr;
-
- if (!IsDeprecatedRPCEnabled("accounts") && account_param != "*") {
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "dummy first argument must be excluded or set to \"*\".");
- } else if (IsDeprecatedRPCEnabled("accounts")) {
- return ValueFromAmount(pwallet->GetLegacyBalance(filter, min_depth, account));
- }
- }
-
return ValueFromAmount(pwallet->GetBalance(filter, min_depth));
}
@@ -968,148 +776,6 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
}
-static UniValue movecmd(const JSONRPCRequest& request)
-{
- std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- CWallet* const pwallet = wallet.get();
-
- if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
- return NullUniValue;
- }
-
- if (!IsDeprecatedRPCEnabled("accounts")) {
- if (request.fHelp) {
- throw std::runtime_error("move (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
- }
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "move is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
- }
-
- if (request.fHelp || request.params.size() < 3 || request.params.size() > 5)
- throw std::runtime_error(
- "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
- "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
- "\nArguments:\n"
- "1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n"
- "2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n"
- "3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n"
- "4. (dummy) (numeric, optional) Ignored. Remains for backward compatibility.\n"
- "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
- "\nResult:\n"
- "true|false (boolean) true if successful.\n"
- "\nExamples:\n"
- "\nMove 0.01 " + CURRENCY_UNIT + " from the default account to the account named tabby\n"
- + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
- "\nMove 0.01 " + CURRENCY_UNIT + " timotei to akiko with a comment and funds have 6 confirmations\n"
- + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
- "\nAs a json rpc call\n"
- + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
- );
-
- LOCK2(cs_main, pwallet->cs_wallet);
-
- std::string strFrom = LabelFromValue(request.params[0]);
- std::string strTo = LabelFromValue(request.params[1]);
- CAmount nAmount = AmountFromValue(request.params[2]);
- if (nAmount <= 0)
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
- if (!request.params[3].isNull())
- // unused parameter, used to be nMinDepth, keep type-checking it though
- (void)request.params[3].get_int();
- std::string strComment;
- if (!request.params[4].isNull())
- strComment = request.params[4].get_str();
-
- if (!pwallet->AccountMove(strFrom, strTo, nAmount, strComment)) {
- throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
- }
-
- return true;
-}
-
-
-static UniValue sendfrom(const JSONRPCRequest& request)
-{
- std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- CWallet* const pwallet = wallet.get();
-
- if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
- return NullUniValue;
- }
-
- if (!IsDeprecatedRPCEnabled("accounts")) {
- if (request.fHelp) {
- throw std::runtime_error("sendfrom (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
- }
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "sendfrom is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
- }
-
-
- if (request.fHelp || request.params.size() < 3 || request.params.size() > 6)
- throw std::runtime_error(
- "sendfrom \"fromaccount\" \"toaddress\" amount ( minconf \"comment\" \"comment_to\" )\n"
- "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address."
- + HelpRequiringPassphrase(pwallet) + "\n"
- "\nArguments:\n"
- "1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n"
- " Specifying an account does not influence coin selection, but it does associate the newly created\n"
- " transaction with the account, so the account's balance computation and transaction history can reflect\n"
- " the spend.\n"
- "2. \"toaddress\" (string, required) The bitcoin address to send funds to.\n"
- "3. amount (numeric or string, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n"
- "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
- "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
- " This is not part of the transaction, just kept in your wallet.\n"
- "6. \"comment_to\" (string, optional) An optional comment to store the name of the person or organization \n"
- " to which you're sending the transaction. This is not part of the transaction, \n"
- " it is just kept in your wallet.\n"
- "\nResult:\n"
- "\"txid\" (string) The transaction id.\n"
- "\nExamples:\n"
- "\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must have at least 1 confirmation\n"
- + HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
- "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
- + HelpExampleCli("sendfrom", "\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
- "\nAs a json rpc call\n"
- + HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
- );
-
- // Make sure the results are valid at least up to the most recent block
- // the user could have gotten from another RPC command prior to now
- pwallet->BlockUntilSyncedToCurrentChain();
-
- LOCK2(cs_main, pwallet->cs_wallet);
-
- std::string strAccount = LabelFromValue(request.params[0]);
- CTxDestination dest = DecodeDestination(request.params[1].get_str());
- if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- }
- CAmount nAmount = AmountFromValue(request.params[2]);
- if (nAmount <= 0)
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
- int nMinDepth = 1;
- if (!request.params[3].isNull())
- nMinDepth = request.params[3].get_int();
-
- mapValue_t mapValue;
- if (!request.params[4].isNull() && !request.params[4].get_str().empty())
- mapValue["comment"] = request.params[4].get_str();
- if (!request.params[5].isNull() && !request.params[5].get_str().empty())
- mapValue["to"] = request.params[5].get_str();
-
- EnsureWalletIsUnlocked(pwallet);
-
- // Check funds
- CAmount nBalance = pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount);
- if (nAmount > nBalance)
- throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
-
- CCoinControl no_coin_control; // This is a deprecated API
- CTransactionRef tx = SendMoney(pwallet, dest, nAmount, false, no_coin_control, std::move(mapValue), std::move(strAccount));
- return tx->GetHash().GetHex();
-}
-
-
static UniValue sendmany(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -1119,12 +785,10 @@ static UniValue sendmany(const JSONRPCRequest& request)
return NullUniValue;
}
- std::string help_text;
- if (!IsDeprecatedRPCEnabled("accounts")) {
- help_text = "sendmany \"\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] replaceable conf_target \"estimate_mode\")\n"
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
+ throw std::runtime_error(
+ "sendmany \"\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] replaceable conf_target \"estimate_mode\")\n"
"\nSend multiple times. Amounts are double-precision floating point numbers.\n"
- "Note that the \"fromaccount\" argument has been removed in V0.17. To use this RPC with a \"fromaccount\" argument, restart\n"
- "bitcoind with -deprecatedrpc=accounts\n"
+ HelpRequiringPassphrase(pwallet) + "\n"
"\nArguments:\n"
"1. \"dummy\" (string, required) Must be set to \"\" for backwards compatibility.\n"
@@ -1160,49 +824,8 @@ static UniValue sendmany(const JSONRPCRequest& request)
"\nSend two amounts to two different addresses, subtract fee from amount:\n"
+ HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
"\nAs a json rpc call\n"
- + HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"");
- } else {
- help_text = "sendmany \"\" \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] replaceable conf_target \"estimate_mode\")\n"
- "\nSend multiple times. Amounts are double-precision floating point numbers."
- + HelpRequiringPassphrase(pwallet) + "\n"
- "\nArguments:\n"
- "1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\n"
- "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
- " {\n"
- " \"address\":amount (numeric or string) The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value\n"
- " ,...\n"
- " }\n"
- "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
- "4. \"comment\" (string, optional) A comment\n"
- "5. subtractfeefrom (array, optional) A json array with addresses.\n"
- " The fee will be equally deducted from the amount of each selected address.\n"
- " Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
- " If no addresses are specified here, the sender pays the fee.\n"
- " [\n"
- " \"address\" (string) Subtract fee from this address\n"
- " ,...\n"
- " ]\n"
- "6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125\n"
- "7. conf_target (numeric, optional) Confirmation target (in blocks)\n"
- "8. \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n"
- " \"UNSET\"\n"
- " \"ECONOMICAL\"\n"
- " \"CONSERVATIVE\"\n"
- "\nResult:\n"
- "\"txid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
- " the number of addresses.\n"
- "\nExamples:\n"
- "\nSend two amounts to two different addresses:\n"
- + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
- "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
- + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
- "\nSend two amounts to two different addresses, subtract fee from amount:\n"
- + HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\",\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
- "\nAs a json rpc call\n"
- + HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"");
- }
-
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 8) throw std::runtime_error(help_text);
+ + HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"")
+ );
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1214,10 +837,9 @@ static UniValue sendmany(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
- if (!IsDeprecatedRPCEnabled("accounts") && !request.params[0].get_str().empty()) {
+ if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\"");
}
- std::string strAccount = LabelFromValue(request.params[0]);
UniValue sendTo = request.params[1].get_obj();
int nMinDepth = 1;
if (!request.params[2].isNull())
@@ -1282,9 +904,7 @@ static UniValue sendmany(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
// Check funds
- if (IsDeprecatedRPCEnabled("accounts") && totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, &strAccount)) {
- throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
- } else if (!IsDeprecatedRPCEnabled("accounts") && totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, nullptr)) {
+ if (totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth, nullptr)) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Wallet has insufficient funds");
}
@@ -1301,7 +921,7 @@ static UniValue sendmany(const JSONRPCRequest& request)
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state;
- if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(strAccount), keyChange, g_connman.get(), state)) {
+ if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, "" /* account */, keyChange, g_connman.get(), state)) {
strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state));
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
}
@@ -1526,7 +1146,7 @@ struct tallyitem
}
};
-static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool by_label)
+static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
// Minimum confirmations
int nMinDepth = 1;
@@ -1635,7 +1255,6 @@ static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bo
if(fIsWatchonly)
obj.pushKV("involvesWatchonly", true);
obj.pushKV("address", EncodeDestination(address));
- obj.pushKV("account", label);
obj.pushKV("amount", ValueFromAmount(nAmount));
obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
obj.pushKV("label", label);
@@ -1661,7 +1280,6 @@ static UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bo
UniValue obj(UniValue::VOBJ);
if (entry.second.fIsWatchonly)
obj.pushKV("involvesWatchonly", true);
- obj.pushKV("account", entry.first);
obj.pushKV("amount", ValueFromAmount(nAmount));
obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
obj.pushKV("label", entry.first);
@@ -1695,7 +1313,6 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
" {\n"
" \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
" \"address\" : \"receivingaddress\", (string) The receiving address\n"
- " \"account\" : \"accountname\", (string) DEPRECATED. Backwards compatible alias for label.\n"
" \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
" \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n"
" \"label\" : \"label\", (string) The label of the receiving address. The default label is \"\".\n"
@@ -1732,13 +1349,6 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request)
return NullUniValue;
}
- if (!IsDeprecatedRPCEnabled("accounts") && request.strMethod == "listreceivedbyaccount") {
- if (request.fHelp) {
- throw std::runtime_error("listreceivedbyaccount (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
- }
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "listreceivedbyaccount is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
- }
-
if (request.fHelp || request.params.size() > 3)
throw std::runtime_error(
"listreceivedbylabel ( minconf include_empty include_watchonly)\n"
@@ -1752,7 +1362,6 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request)
"[\n"
" {\n"
" \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
- " \"account\" : \"accountname\", (string) DEPRECATED. Backwards compatible alias for label.\n"
" \"amount\" : x.xxx, (numeric) The total amount received by addresses with this label\n"
" \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n"
" \"label\" : \"label\" (string) The label of the receiving address. The default label is \"\".\n"
@@ -1787,26 +1396,24 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
*
* @param pwallet The wallet.
* @param wtx The wallet transaction.
- * @param strAccount The account, if any, or "*" for all.
* @param nMinDepth The minimum confirmation depth.
* @param fLong Whether to include the JSON version of the transaction.
* @param ret The UniValue into which the result is stored.
* @param filter The "is mine" filter bool.
*/
-static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
+static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
CAmount nFee;
- std::string strSentAccount;
+ std::string dummy_account;
std::list<COutputEntry> listReceived;
std::list<COutputEntry> listSent;
- wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
+ wtx.GetAmounts(listReceived, listSent, nFee, dummy_account, filter);
- bool fAllAccounts = (strAccount == std::string("*"));
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
// Sent
- if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
+ if ((!listSent.empty() || nFee != 0))
{
for (const COutputEntry& s : listSent)
{
@@ -1814,7 +1421,6 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const
if (involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) {
entry.pushKV("involvesWatchonly", true);
}
- if (IsDeprecatedRPCEnabled("accounts")) entry.pushKV("account", strSentAccount);
MaybePushAddress(entry, s.destination);
entry.pushKV("category", "send");
entry.pushKV("amount", ValueFromAmount(-s.amount));
@@ -1835,61 +1441,40 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const
{
for (const COutputEntry& r : listReceived)
{
- std::string account;
+ std::string label;
if (pwallet->mapAddressBook.count(r.destination)) {
- account = pwallet->mapAddressBook[r.destination].name;
+ label = pwallet->mapAddressBook[r.destination].name;
+ }
+ UniValue entry(UniValue::VOBJ);
+ if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) {
+ entry.pushKV("involvesWatchonly", true);
}
- if (fAllAccounts || (account == strAccount))
+ MaybePushAddress(entry, r.destination);
+ if (wtx.IsCoinBase())
{
- UniValue entry(UniValue::VOBJ);
- if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) {
- entry.pushKV("involvesWatchonly", true);
- }
- if (IsDeprecatedRPCEnabled("accounts")) entry.pushKV("account", account);
- MaybePushAddress(entry, r.destination);
- if (wtx.IsCoinBase())
- {
- if (wtx.GetDepthInMainChain() < 1)
- entry.pushKV("category", "orphan");
- else if (wtx.GetBlocksToMaturity() > 0)
- entry.pushKV("category", "immature");
- else
- entry.pushKV("category", "generate");
- }
+ if (wtx.GetDepthInMainChain() < 1)
+ entry.pushKV("category", "orphan");
+ else if (wtx.IsImmatureCoinBase())
+ entry.pushKV("category", "immature");
else
- {
- entry.pushKV("category", "receive");
- }
- entry.pushKV("amount", ValueFromAmount(r.amount));
- if (pwallet->mapAddressBook.count(r.destination)) {
- entry.pushKV("label", account);
- }
- entry.pushKV("vout", r.vout);
- if (fLong)
- WalletTxToJSON(wtx, entry);
- ret.push_back(entry);
+ entry.pushKV("category", "generate");
}
+ else
+ {
+ entry.pushKV("category", "receive");
+ }
+ entry.pushKV("amount", ValueFromAmount(r.amount));
+ if (pwallet->mapAddressBook.count(r.destination)) {
+ entry.pushKV("label", label);
+ }
+ entry.pushKV("vout", r.vout);
+ if (fLong)
+ WalletTxToJSON(wtx, entry);
+ ret.push_back(entry);
}
}
}
-static void AcentryToJSON(const CAccountingEntry& acentry, const std::string& strAccount, UniValue& ret)
-{
- bool fAllAccounts = (strAccount == std::string("*"));
-
- if (fAllAccounts || acentry.strAccount == strAccount)
- {
- UniValue entry(UniValue::VOBJ);
- entry.pushKV("account", acentry.strAccount);
- entry.pushKV("category", "move");
- entry.pushKV("time", acentry.nTime);
- entry.pushKV("amount", ValueFromAmount(acentry.nCreditDebit));
- if (IsDeprecatedRPCEnabled("accounts")) entry.pushKV("otheraccount", acentry.strOtherAccount);
- entry.pushKV("comment", acentry.strComment);
- ret.push_back(entry);
- }
-}
-
UniValue listtransactions(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -1899,12 +1484,10 @@ UniValue listtransactions(const JSONRPCRequest& request)
return NullUniValue;
}
- std::string help_text {};
- if (!IsDeprecatedRPCEnabled("accounts")) {
- help_text = "listtransactions (dummy count skip include_watchonly)\n"
- "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
- "Note that the \"account\" argument and \"otheraccount\" return value have been removed in V0.17. To use this RPC with an \"account\" argument, restart\n"
- "bitcoind with -deprecatedrpc=accounts\n"
+ if (request.fHelp || request.params.size() > 4)
+ throw std::runtime_error(
+ "listtransactions (dummy count skip include_watchonly)\n"
+ "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n"
"\nArguments:\n"
"1. \"dummy\" (string, optional) If set, should be \"*\" for backwards compatibility.\n"
"2. count (numeric, optional, default=10) The number of transactions to return\n"
@@ -1944,77 +1527,15 @@ UniValue listtransactions(const JSONRPCRequest& request)
"\nList transactions 100 to 120\n"
+ HelpExampleCli("listtransactions", "\"*\" 20 100") +
"\nAs a json rpc call\n"
- + HelpExampleRpc("listtransactions", "\"*\", 20, 100");
- } else {
- help_text = "listtransactions ( \"account\" count skip include_watchonly)\n"
- "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
- "\nArguments:\n"
- "1. \"account\" (string, optional) DEPRECATED. This argument will be removed in V0.18. The account name. Should be \"*\".\n"
- "2. count (numeric, optional, default=10) The number of transactions to return\n"
- "3. skip (numeric, optional, default=0) The number of transactions to skip\n"
- "4. include_watchonly (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\n"
- "\nResult:\n"
- "[\n"
- " {\n"
- " \"account\":\"accountname\", (string) DEPRECATED. This field will be removed in V0.18. The account name associated with the transaction. \n"
- " It will be \"\" for the default account.\n"
- " \"address\":\"address\", (string) The bitcoin address of the transaction. Not present for \n"
- " move transactions (category = move).\n"
- " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
- " transaction between accounts, and not associated with an address,\n"
- " transaction id or block. 'send' and 'receive' transactions are \n"
- " associated with an address, transaction id and block details\n"
- " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n"
- " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
- " and for the 'move' category for inbound funds.\n"
- " \"label\": \"label\", (string) A comment for the address/transaction, if any\n"
- " \"vout\": n, (numeric) the vout value\n"
- " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
- " 'send' category of transactions.\n"
- " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
- " 'receive' category of transactions. Negative confirmations indicate the\n"
- " transaction conflicts with the block chain\n"
- " \"trusted\": xxx, (bool) Whether we consider the outputs of this unconfirmed transaction safe to spend.\n"
- " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
- " category of transactions.\n"
- " \"blockindex\": n, (numeric) The index of the transaction in the block that includes it. Available for 'send' and 'receive'\n"
- " category of transactions.\n"
- " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
- " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
- " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
- " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
- " for 'send' and 'receive' category of transactions.\n"
- " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
- " \"otheraccount\": \"accountname\", (string) DEPRECATED. This field will be removed in V0.18. For the 'move' category of transactions, the account the funds came \n"
- " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
- " negative amounts).\n"
- " \"bip125-replaceable\": \"yes|no|unknown\", (string) Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
- " may be unknown for unconfirmed transactions not in the mempool\n"
- " \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
- " 'send' category of transactions.\n"
- " }\n"
- "]\n"
-
- "\nExamples:\n"
- "\nList the most recent 10 transactions in the systems\n"
- + HelpExampleCli("listtransactions", "") +
- "\nList transactions 100 to 120\n"
- + HelpExampleCli("listtransactions", "\"*\" 20 100") +
- "\nAs a json rpc call\n"
- + HelpExampleRpc("listtransactions", "\"*\", 20, 100");
- }
- if (request.fHelp || request.params.size() > 4) throw std::runtime_error(help_text);
+ + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
+ );
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- std::string strAccount = "*";
- if (!request.params[0].isNull()) {
- strAccount = request.params[0].get_str();
- if (!IsDeprecatedRPCEnabled("accounts") && strAccount != "*") {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"*\"");
- }
+ if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"*\"");
}
int nCount = 10;
if (!request.params[1].isNull())
@@ -2043,13 +1564,9 @@ UniValue listtransactions(const JSONRPCRequest& request)
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
CWalletTx *const pwtx = (*it).second.first;
- if (pwtx != nullptr)
- ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter);
- if (IsDeprecatedRPCEnabled("accounts")) {
- CAccountingEntry *const pacentry = (*it).second.second;
- if (pacentry != nullptr) AcentryToJSON(*pacentry, strAccount, ret);
+ if (pwtx != nullptr) {
+ ListTransactions(pwallet, *pwtx, 0, true, ret, filter);
}
-
if ((int)ret.size() >= (nCount+nFrom)) break;
}
}
@@ -2080,101 +1597,6 @@ UniValue listtransactions(const JSONRPCRequest& request)
return ret;
}
-static UniValue listaccounts(const JSONRPCRequest& request)
-{
- std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- CWallet* const pwallet = wallet.get();
-
- if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
- return NullUniValue;
- }
-
- if (!IsDeprecatedRPCEnabled("accounts")) {
- if (request.fHelp) {
- throw std::runtime_error("listaccounts (Deprecated, will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts)");
- }
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "listaccounts is deprecated and will be removed in V0.18. To use this command, start bitcoind with -deprecatedrpc=accounts.");
- }
-
- if (request.fHelp || request.params.size() > 2)
- throw std::runtime_error(
- "listaccounts ( minconf include_watchonly)\n"
- "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
- "\nArguments:\n"
- "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
- "2. include_watchonly (bool, optional, default=false) Include balances in watch-only addresses (see 'importaddress')\n"
- "\nResult:\n"
- "{ (json object where keys are account names, and values are numeric balances\n"
- " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
- " ...\n"
- "}\n"
- "\nExamples:\n"
- "\nList account balances where there at least 1 confirmation\n"
- + HelpExampleCli("listaccounts", "") +
- "\nList account balances including zero confirmation transactions\n"
- + HelpExampleCli("listaccounts", "0") +
- "\nList account balances for 6 or more confirmations\n"
- + HelpExampleCli("listaccounts", "6") +
- "\nAs json rpc call\n"
- + HelpExampleRpc("listaccounts", "6")
- );
-
- // Make sure the results are valid at least up to the most recent block
- // the user could have gotten from another RPC command prior to now
- pwallet->BlockUntilSyncedToCurrentChain();
-
- LOCK2(cs_main, pwallet->cs_wallet);
-
- int nMinDepth = 1;
- if (!request.params[0].isNull())
- nMinDepth = request.params[0].get_int();
- isminefilter includeWatchonly = ISMINE_SPENDABLE;
- if(!request.params[1].isNull())
- if(request.params[1].get_bool())
- includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
-
- std::map<std::string, CAmount> mapAccountBalances;
- for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
- if (IsMine(*pwallet, entry.first) & includeWatchonly) { // This address belongs to me
- mapAccountBalances[entry.second.name] = 0;
- }
- }
-
- for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
- const CWalletTx& wtx = pairWtx.second;
- CAmount nFee;
- std::string strSentAccount;
- std::list<COutputEntry> listReceived;
- std::list<COutputEntry> listSent;
- int nDepth = wtx.GetDepthInMainChain();
- if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
- continue;
- wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
- mapAccountBalances[strSentAccount] -= nFee;
- for (const COutputEntry& s : listSent)
- mapAccountBalances[strSentAccount] -= s.amount;
- if (nDepth >= nMinDepth)
- {
- for (const COutputEntry& r : listReceived)
- if (pwallet->mapAddressBook.count(r.destination)) {
- mapAccountBalances[pwallet->mapAddressBook[r.destination].name] += r.amount;
- }
- else
- mapAccountBalances[""] += r.amount;
- }
- }
-
- const std::list<CAccountingEntry>& acentries = pwallet->laccentries;
- for (const CAccountingEntry& entry : acentries)
- mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
-
- UniValue ret(UniValue::VOBJ);
- for (const std::pair<const std::string, CAmount>& accountBalance : mapAccountBalances) {
- ret.pushKV(accountBalance.first, ValueFromAmount(accountBalance.second));
- }
- return ret;
-}
-
static UniValue listsinceblock(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -2199,7 +1621,6 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
"\nResult:\n"
"{\n"
" \"transactions\": [\n"
- " \"account\":\"accountname\", (string) DEPRECATED. This field will be removed in V0.18. To see this deprecated field, start bitcoind with -deprecatedrpc=accounts. The account name associated with the transaction. Will be \"\" for the default account.\n"
" \"address\":\"address\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
" \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
" \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
@@ -2282,7 +1703,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
CWalletTx tx = pairWtx.second;
if (depth == -1 || tx.GetDepthInMainChain() < depth) {
- ListTransactions(pwallet, tx, "*", 0, true, transactions, filter);
+ ListTransactions(pwallet, tx, 0, true, transactions, filter);
}
}
@@ -2299,7 +1720,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
if (it != pwallet->mapWallet.end()) {
// We want all transactions regardless of confirmation count to appear here,
// even negative confirmation ones, hence the big negative.
- ListTransactions(pwallet, it->second, "*", -100000000, true, removed, filter);
+ ListTransactions(pwallet, it->second, -100000000, true, removed, filter);
}
}
paltindex = paltindex->pprev;
@@ -2348,7 +1769,6 @@ static UniValue gettransaction(const JSONRPCRequest& request)
" may be unknown for unconfirmed transactions not in the mempool\n"
" \"details\" : [\n"
" {\n"
- " \"account\" : \"accountname\", (string) DEPRECATED. This field will be removed in a V0.18. To see this deprecated field, start bitcoind with -deprecatedrpc=accounts. The account name involved in the transaction, can be \"\" for the default account.\n"
" \"address\" : \"address\", (string) The bitcoin address involved in the transaction\n"
" \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
" \"amount\" : x.xxx, (numeric) The amount in " + CURRENCY_UNIT + "\n"
@@ -2403,7 +1823,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
WalletTxToJSON(wtx, entry);
UniValue details(UniValue::VARR);
- ListTransactions(pwallet, wtx, "*", 0, false, details, filter);
+ ListTransactions(pwallet, wtx, 0, false, details, filter);
entry.pushKV("details", details);
std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags());
@@ -3326,7 +2746,6 @@ static UniValue listunspent(const JSONRPCRequest& request)
" \"vout\" : n, (numeric) the vout value\n"
" \"address\" : \"address\", (string) the bitcoin address\n"
" \"label\" : \"label\", (string) The associated label, or \"\" for the default label\n"
- " \"account\" : \"account\", (string) DEPRECATED. This field will be removed in V0.18. To see this deprecated field, start bitcoind with -deprecatedrpc=accounts. The associated account, or \"\" for the default account\n"
" \"scriptPubKey\" : \"key\", (string) the script key\n"
" \"amount\" : x.xxx, (numeric) the transaction output amount in " + CURRENCY_UNIT + "\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
@@ -3434,9 +2853,6 @@ static UniValue listunspent(const JSONRPCRequest& request)
auto i = pwallet->mapAddressBook.find(address);
if (i != pwallet->mapAddressBook.end()) {
entry.pushKV("label", i->second.name);
- if (IsDeprecatedRPCEnabled("accounts")) {
- entry.pushKV("account", i->second.name);
- }
}
if (scriptPubKey.IsPayToScriptHash()) {
@@ -4029,9 +3445,8 @@ public:
void ProcessSubScript(const CScript& subscript, UniValue& obj, bool include_addresses = false) const
{
// Always present: script type and redeemscript
- txnouttype which_type;
std::vector<std::vector<unsigned char>> solutions_data;
- Solver(subscript, which_type, solutions_data);
+ txnouttype which_type = Solver(subscript, solutions_data);
obj.pushKV("script", GetTxnOutputType(which_type));
obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
@@ -4176,10 +3591,9 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
" ]\n"
" \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output (only if \"script\" is \"multisig\")\n"
" \"pubkey\" : \"publickeyhex\", (string, optional) The hex value of the raw public key, for single-key addresses (possibly embedded in P2SH or P2WSH)\n"
- " \"embedded\" : {...}, (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdseedid\") and relation to the wallet (\"ismine\", \"iswatchonly\", \"account\").\n"
+ " \"embedded\" : {...}, (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdseedid\") and relation to the wallet (\"ismine\", \"iswatchonly\").\n"
" \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
- " \"label\" : \"label\" (string) The label associated with the address, \"\" is the default account\n"
- " \"account\" : \"account\" (string) DEPRECATED. This field will be removed in V0.18. To see this deprecated field, start bitcoind with -deprecatedrpc=accounts. The account associated with the address, \"\" is the default account\n"
+ " \"label\" : \"label\" (string) The label associated with the address, \"\" is the default label\n"
" \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n"
" \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n"
" \"hdseedid\" : \"<hash160>\" (string, optional) The Hash160 of the HD seed\n"
@@ -4221,9 +3635,6 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
ret.pushKVs(detail);
if (pwallet->mapAddressBook.count(dest)) {
ret.pushKV("label", pwallet->mapAddressBook[dest].name);
- if (IsDeprecatedRPCEnabled("accounts")) {
- ret.pushKV("account", pwallet->mapAddressBook[dest].name);
- }
}
const CKeyMetadata* meta = nullptr;
CKeyID key_id = GetKeyForDestination(*pwallet, dest);
@@ -4431,74 +3842,17 @@ UniValue sethdseed(const JSONRPCRequest& request)
return NullUniValue;
}
-bool ParseHDKeypath(std::string keypath_str, std::vector<uint32_t>& keypath)
-{
- std::stringstream ss(keypath_str);
- std::string item;
- bool first = true;
- while (std::getline(ss, item, '/')) {
- if (item.compare("m") == 0) {
- if (first) {
- first = false;
- continue;
- }
- return false;
- }
- // Finds whether it is hardened
- uint32_t path = 0;
- size_t pos = item.find("'");
- if (pos != std::string::npos) {
- // The hardened tick can only be in the last index of the string
- if (pos != item.size() - 1) {
- return false;
- }
- path |= 0x80000000;
- item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick
- }
-
- // Ensure this is only numbers
- if (item.find_first_not_of( "0123456789" ) != std::string::npos) {
- return false;
- }
- uint32_t number;
- if (!ParseUInt32(item, &number)) {
- return false;
- }
- path |= number;
-
- keypath.push_back(path);
- first = false;
- }
- return true;
-}
-
-void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths)
+void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
{
CPubKey vchPubKey;
if (!pwallet->GetPubKey(keyID, vchPubKey)) {
return;
}
- CKeyMetadata meta;
- auto it = pwallet->mapKeyMetadata.find(keyID);
- if (it != pwallet->mapKeyMetadata.end()) {
- meta = it->second;
+ KeyOriginInfo info;
+ if (!pwallet->GetKeyOrigin(keyID, info)) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
}
- std::vector<uint32_t> keypath;
- if (!meta.hdKeypath.empty()) {
- if (!ParseHDKeypath(meta.hdKeypath, keypath)) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
- }
- // Get the proper master key id
- CKey key;
- pwallet->GetKey(meta.hd_seed_id, key);
- CExtKey masterKey;
- masterKey.SetSeed(key.begin(), key.size());
- // Add to map
- keypath.insert(keypath.begin(), ReadLE32(masterKey.key.GetPubKey().GetID().begin()));
- } else { // Single pubkeys get the master fingerprint of themselves
- keypath.insert(keypath.begin(), ReadLE32(vchPubKey.GetID().begin()));
- }
- hd_keypaths.emplace(vchPubKey, keypath);
+ hd_keypaths.emplace(vchPubKey, std::move(info));
}
bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type, bool sign, bool bip32derivs)
@@ -4526,28 +3880,7 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Specified Sighash and sighash in PSBT do not match.");
}
- SignatureData sigdata;
- if (sign) {
- complete &= SignPSBTInput(*pwallet, *psbtx.tx, input, sigdata, i, sighash_type);
- } else {
- complete &= SignPSBTInput(PublicOnlySigningProvider(pwallet), *psbtx.tx, input, sigdata, i, sighash_type);
- }
-
- if (it != pwallet->mapWallet.end()) {
- // Drop the unnecessary UTXO if we added both from the wallet.
- if (sigdata.witness) {
- input.non_witness_utxo = nullptr;
- } else {
- input.witness_utxo.SetNull();
- }
- }
-
- // Get public key paths
- if (bip32derivs) {
- for (const auto& pubkey_it : sigdata.misc_pubkeys) {
- AddKeypathToMap(pwallet, pubkey_it.first, input.hd_keypaths);
- }
- }
+ complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), *psbtx.tx, input, i, sighash_type);
}
// Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
@@ -4560,15 +3893,8 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
psbt_out.FillSignatureData(sigdata);
MutableTransactionSignatureCreator creator(psbtx.tx.get_ptr(), 0, out.nValue, 1);
- ProduceSignature(*pwallet, creator, out.scriptPubKey, sigdata);
+ ProduceSignature(HidingSigningProvider(pwallet, true, !bip32derivs), creator, out.scriptPubKey, sigdata);
psbt_out.FromSignatureData(sigdata);
-
- // Get public key paths
- if (bip32derivs) {
- for (const auto& pubkey_it : sigdata.misc_pubkeys) {
- AddKeypathToMap(pwallet, pubkey_it.first, psbt_out.hd_keypaths);
- }
- }
}
return complete;
}
@@ -4599,7 +3925,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
" \"ALL|ANYONECANPAY\"\n"
" \"NONE|ANYONECANPAY\"\n"
" \"SINGLE|ANYONECANPAY\"\n"
- "4. bip32derivs (boolean, optiona, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
+ "4. bip32derivs (boolean, optional, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
"\nResult:\n"
"{\n"
@@ -4701,7 +4027,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\"\n"
" }\n"
- "5. bip32derivs (boolean, optiona, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
+ "5. bip32derivs (boolean, optional, default=false) If true, includes the BIP 32 derivation paths for public keys if we know them\n"
"\nResult:\n"
"{\n"
" \"psbt\": \"value\", (string) The resulting raw transaction (base64-encoded string)\n"
@@ -4770,76 +4096,62 @@ UniValue importmulti(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} },
- { "wallet", "walletprocesspsbt", &walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} },
- { "wallet", "walletcreatefundedpsbt", &walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} },
+ { "generating", "generate", &generate, {"nblocks","maxtries"} },
+ { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} },
{ "hidden", "resendwallettransactions", &resendwallettransactions, {} },
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} },
{ "wallet", "abandontransaction", &abandontransaction, {"txid"} },
{ "wallet", "abortrescan", &abortrescan, {} },
- { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label|account","address_type"} },
- { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} },
+ { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} },
{ "wallet", "backupwallet", &backupwallet, {"destination"} },
{ "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
{ "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys"} },
{ "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
{ "wallet", "dumpwallet", &dumpwallet, {"filename"} },
{ "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
+ { "wallet", "getaddressesbylabel", &getaddressesbylabel, {"label"} },
{ "wallet", "getaddressinfo", &getaddressinfo, {"address"} },
- { "wallet", "getbalance", &getbalance, {"account|dummy","minconf","include_watchonly"} },
- { "wallet", "getnewaddress", &getnewaddress, {"label|account","address_type"} },
+ { "wallet", "getbalance", &getbalance, {"dummy","minconf","include_watchonly"} },
+ { "wallet", "getnewaddress", &getnewaddress, {"label","address_type"} },
{ "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} },
{ "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
+ { "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} },
{ "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
{ "wallet", "getwalletinfo", &getwalletinfo, {} },
+ { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
{ "wallet", "importmulti", &importmulti, {"requests","options"} },
{ "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} },
- { "wallet", "importwallet", &importwallet, {"filename"} },
- { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
{ "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} },
{ "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} },
+ { "wallet", "importwallet", &importwallet, {"filename"} },
{ "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} },
{ "wallet", "listaddressgroupings", &listaddressgroupings, {} },
+ { "wallet", "listlabels", &listlabels, {"purpose"} },
{ "wallet", "listlockunspent", &listlockunspent, {} },
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} },
+ { "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
{ "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
- { "wallet", "listtransactions", &listtransactions, {"account|dummy","count","skip","include_watchonly"} },
+ { "wallet", "listtransactions", &listtransactions, {"dummy","count","skip","include_watchonly"} },
{ "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
{ "wallet", "listwallets", &listwallets, {} },
{ "wallet", "loadwallet", &loadwallet, {"filename"} },
{ "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
- { "wallet", "sendmany", &sendmany, {"fromaccount|dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
+ { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
+ { "wallet", "sendmany", &sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
{ "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} },
+ { "wallet", "setlabel", &setlabel, {"address","label"} },
{ "wallet", "settxfee", &settxfee, {"amount"} },
{ "wallet", "signmessage", &signmessage, {"address","message"} },
{ "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} },
{ "wallet", "unloadwallet", &unloadwallet, {"wallet_name"} },
+ { "wallet", "walletcreatefundedpsbt", &walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} },
{ "wallet", "walletlock", &walletlock, {} },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
- { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
- { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
- { "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} },
-
- /** Account functions (deprecated) */
- { "wallet", "getaccountaddress", &getaccountaddress, {"account"} },
- { "wallet", "getaccount", &getaccount, {"address"} },
- { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} },
- { "wallet", "getreceivedbyaccount", &getreceivedbylabel, {"account","minconf"} },
- { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} },
- { "wallet", "listreceivedbyaccount", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "setaccount", &setlabel, {"address","account"} },
- { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
- { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} },
-
- /** Label functions (to replace non-balance account functions) */
- { "wallet", "getaddressesbylabel", &getaddressesbylabel, {"label"} },
- { "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} },
- { "wallet", "listlabels", &listlabels, {"purpose"} },
- { "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "setlabel", &setlabel, {"address","label"} },
-
- { "generating", "generate", &generate, {"nblocks","maxtries"} },
+ { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
+ { "wallet", "walletprocesspsbt", &walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} },
};
void RegisterWalletRPCCommands(CRPCTable &t)
diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp
deleted file mode 100644
index 79060887be..0000000000
--- a/src/wallet/test/accounting_tests.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <wallet/wallet.h>
-
-#include <wallet/test/wallet_test_fixture.h>
-
-#include <stdint.h>
-
-#include <boost/test/unit_test.hpp>
-
-BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup)
-
-static void
-GetResults(CWallet& wallet, std::map<CAmount, CAccountingEntry>& results)
-{
- std::list<CAccountingEntry> aes;
-
- results.clear();
- BOOST_CHECK(wallet.ReorderTransactions() == DBErrors::LOAD_OK);
- wallet.ListAccountCreditDebit("", aes);
- for (CAccountingEntry& ae : aes)
- {
- results[ae.nOrderPos] = ae;
- }
-}
-
-BOOST_AUTO_TEST_CASE(acc_orderupgrade)
-{
- std::vector<CWalletTx*> vpwtx;
- CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef());
- CAccountingEntry ae;
- std::map<CAmount, CAccountingEntry> results;
-
- LOCK(m_wallet.cs_wallet);
-
- ae.strAccount = "";
- ae.nCreditDebit = 1;
- ae.nTime = 1333333333;
- ae.strOtherAccount = "b";
- ae.strComment = "";
- m_wallet.AddAccountingEntry(ae);
-
- wtx.mapValue["comment"] = "z";
- m_wallet.AddToWallet(wtx);
- vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash()));
- vpwtx[0]->nTimeReceived = (unsigned int)1333333335;
- vpwtx[0]->nOrderPos = -1;
-
- ae.nTime = 1333333336;
- ae.strOtherAccount = "c";
- m_wallet.AddAccountingEntry(ae);
-
- GetResults(m_wallet, results);
-
- BOOST_CHECK(m_wallet.nOrderPosNext == 3);
- BOOST_CHECK(2 == results.size());
- BOOST_CHECK(results[0].nTime == 1333333333);
- BOOST_CHECK(results[0].strComment.empty());
- BOOST_CHECK(1 == vpwtx[0]->nOrderPos);
- BOOST_CHECK(results[2].nTime == 1333333336);
- BOOST_CHECK(results[2].strOtherAccount == "c");
-
-
- ae.nTime = 1333333330;
- ae.strOtherAccount = "d";
- ae.nOrderPos = m_wallet.IncOrderPosNext();
- m_wallet.AddAccountingEntry(ae);
-
- GetResults(m_wallet, results);
-
- BOOST_CHECK(results.size() == 3);
- BOOST_CHECK(m_wallet.nOrderPosNext == 4);
- BOOST_CHECK(results[0].nTime == 1333333333);
- BOOST_CHECK(1 == vpwtx[0]->nOrderPos);
- BOOST_CHECK(results[2].nTime == 1333333336);
- BOOST_CHECK(results[3].nTime == 1333333330);
- BOOST_CHECK(results[3].strComment.empty());
-
-
- wtx.mapValue["comment"] = "y";
- {
- CMutableTransaction tx(*wtx.tx);
- ++tx.nLockTime; // Just to change the hash :)
- wtx.SetTx(MakeTransactionRef(std::move(tx)));
- }
- m_wallet.AddToWallet(wtx);
- vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash()));
- vpwtx[1]->nTimeReceived = (unsigned int)1333333336;
-
- wtx.mapValue["comment"] = "x";
- {
- CMutableTransaction tx(*wtx.tx);
- ++tx.nLockTime; // Just to change the hash :)
- wtx.SetTx(MakeTransactionRef(std::move(tx)));
- }
- m_wallet.AddToWallet(wtx);
- vpwtx.push_back(&m_wallet.mapWallet.at(wtx.GetHash()));
- vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
- vpwtx[2]->nOrderPos = -1;
-
- GetResults(m_wallet, results);
-
- BOOST_CHECK(results.size() == 3);
- BOOST_CHECK(m_wallet.nOrderPosNext == 6);
- BOOST_CHECK(0 == vpwtx[2]->nOrderPos);
- BOOST_CHECK(results[1].nTime == 1333333333);
- BOOST_CHECK(2 == vpwtx[0]->nOrderPos);
- BOOST_CHECK(results[3].nTime == 1333333336);
- BOOST_CHECK(results[4].nTime == 1333333330);
- BOOST_CHECK(results[4].strComment.empty());
- BOOST_CHECK(5 == vpwtx[1]->nOrderPos);
-
-
- ae.nTime = 1333333334;
- ae.strOtherAccount = "e";
- ae.nOrderPos = -1;
- m_wallet.AddAccountingEntry(ae);
-
- GetResults(m_wallet, results);
-
- BOOST_CHECK(results.size() == 4);
- BOOST_CHECK(m_wallet.nOrderPosNext == 7);
- BOOST_CHECK(0 == vpwtx[2]->nOrderPos);
- BOOST_CHECK(results[1].nTime == 1333333333);
- BOOST_CHECK(2 == vpwtx[0]->nOrderPos);
- BOOST_CHECK(results[3].nTime == 1333333336);
- BOOST_CHECK(results[3].strComment.empty());
- BOOST_CHECK(results[4].nTime == 1333333330);
- BOOST_CHECK(results[4].strComment.empty());
- BOOST_CHECK(results[5].nTime == 1333333334);
- BOOST_CHECK(6 == vpwtx[1]->nOrderPos);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 0776ffda9c..a24dc1b5f9 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -150,6 +150,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
add_coin(1 * CENT, 1, actual_selection);
BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 1 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees));
BOOST_CHECK(equal_sets(selection, actual_selection));
+ BOOST_CHECK_EQUAL(value_ret, 1 * CENT);
actual_selection.clear();
selection.clear();
@@ -157,6 +158,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
add_coin(2 * CENT, 2, actual_selection);
BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 2 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees));
BOOST_CHECK(equal_sets(selection, actual_selection));
+ BOOST_CHECK_EQUAL(value_ret, 2 * CENT);
actual_selection.clear();
selection.clear();
@@ -165,6 +167,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
add_coin(2 * CENT, 2, actual_selection);
BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 5 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees));
BOOST_CHECK(equal_sets(selection, actual_selection));
+ BOOST_CHECK_EQUAL(value_ret, 5 * CENT);
actual_selection.clear();
selection.clear();
@@ -181,6 +184,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
add_coin(1 * CENT, 1, actual_selection);
BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 10 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees));
BOOST_CHECK(equal_sets(selection, actual_selection));
+ BOOST_CHECK_EQUAL(value_ret, 10 * CENT);
actual_selection.clear();
selection.clear();
@@ -190,6 +194,9 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
add_coin(3 * CENT, 3, actual_selection);
add_coin(2 * CENT, 2, actual_selection);
BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 10 * CENT, 5000, selection, value_ret, not_input_fees));
+ BOOST_CHECK_EQUAL(value_ret, 10 * CENT);
+ // FIXME: this test is redundant with the above, because 1 Cent is selected, not "too small"
+ // BOOST_CHECK(equal_sets(selection, actual_selection));
// Select 0.25 Cent, not possible
BOOST_CHECK(!SelectCoinsBnB(GroupCoins(utxo_pool), 0.25 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees));
@@ -203,6 +210,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), target, 0, selection, value_ret, not_input_fees)); // Should not exhaust
// Test same value early bailout optimization
+ utxo_pool.clear();
add_coin(7 * CENT, 7, actual_selection);
add_coin(7 * CENT, 7, actual_selection);
add_coin(7 * CENT, 7, actual_selection);
@@ -217,6 +225,8 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
add_coin(5 * CENT, 7, utxo_pool);
}
BOOST_CHECK(SelectCoinsBnB(GroupCoins(utxo_pool), 30 * CENT, 5000, selection, value_ret, not_input_fees));
+ BOOST_CHECK_EQUAL(value_ret, 30 * CENT);
+ BOOST_CHECK(equal_sets(selection, actual_selection));
////////////////////
// Behavior tests //
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index 61c3fa94a6..526f2d983f 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -13,8 +13,6 @@
#include <test/test_bitcoin.h>
#include <wallet/test/wallet_test_fixture.h>
-extern bool ParseHDKeypath(std::string keypath_str, std::vector<uint32_t>& keypath);
-
BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup)
BOOST_AUTO_TEST_CASE(psbt_updater_test)
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 5a7fdf9a85..913334a767 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1894,7 +1894,7 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const
CAmount CWalletTx::GetCredit(const isminefilter& filter) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
- if (IsCoinBase() && GetBlocksToMaturity() > 0)
+ if (IsImmatureCoinBase())
return 0;
CAmount credit = 0;
@@ -1926,8 +1926,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const
CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
{
- if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
- {
+ if (IsImmatureCoinBase() && IsInMainChain()) {
if (fUseCache && fImmatureCreditCached)
return nImmatureCreditCached;
nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
@@ -1944,7 +1943,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter
return 0;
// Must wait until coinbase is safely deep enough in the chain before valuing it
- if (IsCoinBase() && GetBlocksToMaturity() > 0)
+ if (IsImmatureCoinBase())
return 0;
CAmount* cache = nullptr;
@@ -1985,8 +1984,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter
CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool fUseCache) const
{
- if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain())
- {
+ if (IsImmatureCoinBase() && IsInMainChain()) {
if (fUseCache && fImmatureWatchCreditCached)
return nImmatureWatchCreditCached;
nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
@@ -2199,7 +2197,7 @@ CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth, cons
for (const auto& entry : mapWallet) {
const CWalletTx& wtx = entry.second;
const int depth = wtx.GetDepthInMainChain();
- if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.GetBlocksToMaturity() > 0) {
+ if (depth < 0 || !CheckFinalTx(*wtx.tx) || wtx.IsImmatureCoinBase()) {
continue;
}
@@ -2259,7 +2257,7 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
if (!CheckFinalTx(*pcoin->tx))
continue;
- if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
+ if (pcoin->IsImmatureCoinBase())
continue;
int nDepth = pcoin->GetDepthInMainChain();
@@ -3528,7 +3526,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
if (!pcoin->IsTrusted())
continue;
- if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
+ if (pcoin->IsImmatureCoinBase())
continue;
int nDepth = pcoin->GetDepthInMainChain();
@@ -4406,6 +4404,11 @@ int CMerkleTx::GetBlocksToMaturity() const
return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
}
+bool CMerkleTx::IsImmatureCoinBase() const
+{
+ // note GetBlocksToMaturity is 0 for non-coinbase tx
+ return GetBlocksToMaturity() > 0;
+}
bool CWalletTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
{
@@ -4466,3 +4469,29 @@ std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outpu
}
return groups;
}
+
+bool CWallet::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const
+{
+ CKeyMetadata meta;
+ {
+ LOCK(cs_wallet);
+ auto it = mapKeyMetadata.find(keyID);
+ if (it != mapKeyMetadata.end()) {
+ meta = it->second;
+ }
+ }
+ if (!meta.hdKeypath.empty()) {
+ if (!ParseHDKeypath(meta.hdKeypath, info.path)) return false;
+ // Get the proper master key id
+ CKey key;
+ GetKey(meta.hd_seed_id, key);
+ CExtKey masterKey;
+ masterKey.SetSeed(key.begin(), key.size());
+ // Compute identifier
+ CKeyID masterid = masterKey.key.GetPubKey().GetID();
+ std::copy(masterid.begin(), masterid.begin() + 4, info.fingerprint);
+ } else { // Single pubkeys get the master fingerprint of themselves
+ std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint);
+ }
+ return true;
+}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 57b22c0e49..5f550319ed 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -264,15 +264,22 @@ public:
* 0 : in memory pool, waiting to be included in a block
* >=1 : this many blocks deep in the main chain
*/
- int GetDepthInMainChain() const;
- bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
- int GetBlocksToMaturity() const;
+ int GetDepthInMainChain() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool IsInMainChain() const EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return GetDepthInMainChain() > 0; }
+
+ /**
+ * @return number of blocks to maturity for this transaction:
+ * 0 : is not a coinbase transaction, or is a mature coinbase transaction
+ * >0 : is a coinbase transaction which matures in this many blocks
+ */
+ int GetBlocksToMaturity() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
const uint256& GetHash() const { return tx->GetHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
+ bool IsImmatureCoinBase() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
};
//Get the marginal bytes of spending the specified output
@@ -295,7 +302,7 @@ public:
* serialized in the wallet database:
*
* "comment", "to" - comment strings provided to sendtoaddress,
- * sendfrom, sendmany wallet RPCs
+ * and sendmany wallet RPCs
* "replaces_txid" - txid (as HexStr) of transaction replaced by
* bumpfee on transaction created by bumpfee
* "replaced_by_txid" - txid (as HexStr) of transaction created by
@@ -454,10 +461,10 @@ public:
//! filter decides which addresses will count towards the debit
CAmount GetDebit(const isminefilter& filter) const;
- CAmount GetCredit(const isminefilter& filter) const;
- CAmount GetImmatureCredit(bool fUseCache=true) const;
- CAmount GetAvailableCredit(bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const;
- CAmount GetImmatureWatchOnlyCredit(const bool fUseCache=true) const;
+ CAmount GetCredit(const isminefilter& filter) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CAmount GetImmatureCredit(bool fUseCache=true) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CAmount GetAvailableCredit(bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CAmount GetImmatureWatchOnlyCredit(const bool fUseCache=true) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CAmount GetChange() const;
// Get the marginal bytes if spending the specified output from this transaction
@@ -478,15 +485,15 @@ public:
bool IsEquivalentTo(const CWalletTx& tx) const;
bool InMempool() const;
- bool IsTrusted() const;
+ bool IsTrusted() const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
int64_t GetTxTime() const;
// RelayWalletTransaction may only be called if fBroadcastTransactions!
- bool RelayWalletTransaction(CConnman* connman);
+ bool RelayWalletTransaction(CConnman* connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
- bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state);
+ bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
std::set<uint256> GetConflicts() const;
};
@@ -840,7 +847,7 @@ public:
/**
* populate vCoins with vector of available COutputs.
*/
- void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0, const int nMinDepth = 0, const int nMaxDepth = 9999999) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t nMaximumCount = 0, const int nMinDepth = 0, const int nMaxDepth = 9999999) const EXCLUSIVE_LOCKS_REQUIRED(cs_main, cs_wallet);
/**
* Return list of available coins and locked coins grouped by non-change output address.
@@ -861,7 +868,7 @@ public:
bool SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<OutputGroup> groups,
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const;
- bool IsSpent(const uint256& hash, unsigned int n) const;
+ bool IsSpent(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
std::vector<OutputGroup> GroupOutputs(const std::vector<COutput>& outputs, bool single_coin) const;
bool IsLockedCoin(uint256 hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -947,9 +954,9 @@ public:
CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, const WalletRescanReserver& reserver, bool fUpdate = false);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions();
- void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
+ void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
- std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);
+ std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
CAmount GetBalance(const isminefilter& filter=ISMINE_SPENDABLE, const int min_depth=0) const;
CAmount GetUnconfirmedBalance() const;
CAmount GetImmatureBalance() const;
@@ -1034,7 +1041,7 @@ public:
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
std::set<std::set<CTxDestination>> GetAddressGroupings() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- std::map<CTxDestination, CAmount> GetAddressBalances();
+ std::map<CTxDestination, CAmount> GetAddressBalances() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
std::set<CTxDestination> GetLabelAddresses(const std::string& label) const;
void DeleteLabel(const std::string& label);
@@ -1173,7 +1180,7 @@ public:
* Obviously holding cs_main/cs_wallet when going into this call may cause
* deadlock
*/
- void BlockUntilSyncedToCurrentChain() LOCKS_EXCLUDED(cs_wallet);
+ void BlockUntilSyncedToCurrentChain() LOCKS_EXCLUDED(cs_main, cs_wallet);
/**
* Explicitly make the wallet learn the related scripts for outputs to the
@@ -1211,6 +1218,8 @@ public:
LogPrintf(("%s " + fmt).c_str(), GetDisplayName(), parameters...);
};
+ /** Implement lookup of key origin information through wallet key metadata. */
+ bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
};
/** A key allocated from the key pool. */