diff options
Diffstat (limited to 'src')
102 files changed, 1437 insertions, 745 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index ed5cab7f04..ec3d81b76f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -353,6 +353,8 @@ crypto_libbitcoin_crypto_base_a_SOURCES = \ crypto/chacha20.h \ crypto/chacha20.cpp \ crypto/common.h \ + crypto/hkdf_sha256_32.cpp \ + crypto/hkdf_sha256_32.h \ crypto/hmac_sha256.cpp \ crypto/hmac_sha256.h \ crypto/hmac_sha512.cpp \ diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index ae7eb19ceb..ef8a207841 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -21,6 +21,7 @@ bench_bench_bitcoin_SOURCES = \ bench/duplicate_inputs.cpp \ bench/examples.cpp \ bench/rollingbloom.cpp \ + bench/chacha20.cpp \ bench/crypto_hash.cpp \ bench/ccoins_caching.cpp \ bench/gcs_filter.cpp \ diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index b08ecbb621..f2b520e893 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -114,8 +114,9 @@ void benchmark::BenchRunner::RunAll(Printer& printer, uint64_t num_evals, double for (const auto& p : benchmarks()) { TestingSetup test{CBaseChainParams::REGTEST}; { - assert(::chainActive.Height() == 0); - const bool witness_enabled{IsWitnessEnabled(::chainActive.Tip(), Params().GetConsensus())}; + LOCK(cs_main); + assert(::ChainActive().Height() == 0); + const bool witness_enabled{IsWitnessEnabled(::ChainActive().Tip(), Params().GetConsensus())}; assert(witness_enabled); } diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp index 9cfd5d23ef..1041a22303 100644 --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -39,9 +39,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) dummyTransactions[1].vout.resize(2); dummyTransactions[1].vout[0].nValue = 21 * COIN; - dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); + dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey())); dummyTransactions[1].vout[1].nValue = 22 * COIN; - dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); + dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey())); AddCoins(coinsRet, CTransaction(dummyTransactions[1]), 0); return dummyTransactions; diff --git a/src/bench/chacha20.cpp b/src/bench/chacha20.cpp new file mode 100644 index 0000000000..69d8c96ec0 --- /dev/null +++ b/src/bench/chacha20.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <iostream> + +#include <bench/bench.h> +#include <hash.h> +#include <crypto/chacha20.h> + +/* Number of bytes to process per iteration */ +static const uint64_t BUFFER_SIZE_TINY = 64; +static const uint64_t BUFFER_SIZE_SMALL = 256; +static const uint64_t BUFFER_SIZE_LARGE = 1024*1024; + +static void CHACHA20(benchmark::State& state, size_t buffersize) +{ + std::vector<uint8_t> key(32,0); + ChaCha20 ctx(key.data(), key.size()); + ctx.SetIV(0); + ctx.Seek(0); + std::vector<uint8_t> in(buffersize,0); + std::vector<uint8_t> out(buffersize,0); + while (state.KeepRunning()) { + ctx.Crypt(in.data(), out.data(), in.size()); + } +} + +static void CHACHA20_64BYTES(benchmark::State& state) +{ + CHACHA20(state, BUFFER_SIZE_TINY); +} + +static void CHACHA20_256BYTES(benchmark::State& state) +{ + CHACHA20(state, BUFFER_SIZE_SMALL); +} + +static void CHACHA20_1MB(benchmark::State& state) +{ + CHACHA20(state, BUFFER_SIZE_LARGE); +} + +BENCHMARK(CHACHA20_64BYTES, 500000); +BENCHMARK(CHACHA20_256BYTES, 250000); +BENCHMARK(CHACHA20_1MB, 340); diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp index 2d7a351523..80ff13612c 100644 --- a/src/bench/duplicate_inputs.cpp +++ b/src/bench/duplicate_inputs.cpp @@ -29,7 +29,8 @@ static void DuplicateInputs(benchmark::State& state) CMutableTransaction coinbaseTx{}; CMutableTransaction naughtyTx{}; - CBlockIndex* pindexPrev = ::chainActive.Tip(); + LOCK(cs_main); + CBlockIndex* pindexPrev = ::ChainActive().Tip(); assert(pindexPrev != nullptr); block.nBits = GetNextWorkRequired(pindexPrev, &block, chainparams.GetConsensus()); block.nNonce = 0; diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 7f41ea7aed..ac1d62a8f4 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -323,7 +323,7 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str } if (bScriptHash) { // Get the ID for the script, and then construct a P2SH destination for it. - scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); + scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); } // construct TxOut, append to transaction output list @@ -397,7 +397,7 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); } // Get the ID for the script, and then construct a P2SH destination for it. - scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); + scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); } // construct TxOut, append to transaction output list @@ -469,7 +469,7 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str throw std::runtime_error(strprintf( "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); } - scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey)); + scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); } // construct TxOut, append to transaction output list diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp index ac4470f04f..42a17f02ff 100644 --- a/src/crypto/chacha20.cpp +++ b/src/crypto/chacha20.cpp @@ -71,7 +71,7 @@ void ChaCha20::Seek(uint64_t pos) input[13] = pos >> 32; } -void ChaCha20::Output(unsigned char* c, size_t bytes) +void ChaCha20::Keystream(unsigned char* c, size_t bytes) { uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; @@ -178,3 +178,133 @@ void ChaCha20::Output(unsigned char* c, size_t bytes) c += 64; } } + +void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes) +{ + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + unsigned char *ctarget = nullptr; + unsigned char tmp[64]; + unsigned int i; + + if (!bytes) return; + + j0 = input[0]; + j1 = input[1]; + j2 = input[2]; + j3 = input[3]; + j4 = input[4]; + j5 = input[5]; + j6 = input[6]; + j7 = input[7]; + j8 = input[8]; + j9 = input[9]; + j10 = input[10]; + j11 = input[11]; + j12 = input[12]; + j13 = input[13]; + j14 = input[14]; + j15 = input[15]; + + for (;;) { + if (bytes < 64) { + // if m has fewer than 64 bytes available, copy m to tmp and + // read from tmp instead + for (i = 0;i < bytes;++i) tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20;i > 0;i -= 2) { + QUARTERROUND( x0, x4, x8,x12) + QUARTERROUND( x1, x5, x9,x13) + QUARTERROUND( x2, x6,x10,x14) + QUARTERROUND( x3, x7,x11,x15) + QUARTERROUND( x0, x5,x10,x15) + QUARTERROUND( x1, x6,x11,x12) + QUARTERROUND( x2, x7, x8,x13) + QUARTERROUND( x3, x4, x9,x14) + } + x0 += j0; + x1 += j1; + x2 += j2; + x3 += j3; + x4 += j4; + x5 += j5; + x6 += j6; + x7 += j7; + x8 += j8; + x9 += j9; + x10 += j10; + x11 += j11; + x12 += j12; + x13 += j13; + x14 += j14; + x15 += j15; + + x0 ^= ReadLE32(m + 0); + x1 ^= ReadLE32(m + 4); + x2 ^= ReadLE32(m + 8); + x3 ^= ReadLE32(m + 12); + x4 ^= ReadLE32(m + 16); + x5 ^= ReadLE32(m + 20); + x6 ^= ReadLE32(m + 24); + x7 ^= ReadLE32(m + 28); + x8 ^= ReadLE32(m + 32); + x9 ^= ReadLE32(m + 36); + x10 ^= ReadLE32(m + 40); + x11 ^= ReadLE32(m + 44); + x12 ^= ReadLE32(m + 48); + x13 ^= ReadLE32(m + 52); + x14 ^= ReadLE32(m + 56); + x15 ^= ReadLE32(m + 60); + + ++j12; + if (!j12) ++j13; + + WriteLE32(c + 0, x0); + WriteLE32(c + 4, x1); + WriteLE32(c + 8, x2); + WriteLE32(c + 12, x3); + WriteLE32(c + 16, x4); + WriteLE32(c + 20, x5); + WriteLE32(c + 24, x6); + WriteLE32(c + 28, x7); + WriteLE32(c + 32, x8); + WriteLE32(c + 36, x9); + WriteLE32(c + 40, x10); + WriteLE32(c + 44, x11); + WriteLE32(c + 48, x12); + WriteLE32(c + 52, x13); + WriteLE32(c + 56, x14); + WriteLE32(c + 60, x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0;i < bytes;++i) ctarget[i] = c[i]; + } + input[12] = j12; + input[13] = j13; + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} diff --git a/src/crypto/chacha20.h b/src/crypto/chacha20.h index a305977bcd..5a4674f4a8 100644 --- a/src/crypto/chacha20.h +++ b/src/crypto/chacha20.h @@ -8,7 +8,8 @@ #include <stdint.h> #include <stdlib.h> -/** A PRNG class for ChaCha20. */ +/** A class for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein + https://cr.yp.to/chacha/chacha-20080128.pdf */ class ChaCha20 { private: @@ -17,10 +18,17 @@ private: public: ChaCha20(); ChaCha20(const unsigned char* key, size_t keylen); - void SetKey(const unsigned char* key, size_t keylen); - void SetIV(uint64_t iv); - void Seek(uint64_t pos); - void Output(unsigned char* output, size_t bytes); + void SetKey(const unsigned char* key, size_t keylen); //!< set key with flexible keylength; 256bit recommended */ + void SetIV(uint64_t iv); // set the 64bit nonce + void Seek(uint64_t pos); // set the 64bit block counter + + /** outputs the keystream of size <bytes> into <c> */ + void Keystream(unsigned char* c, size_t bytes); + + /** enciphers the message <input> of length <bytes> and write the enciphered representation into <output> + * Used for encryption and decryption (XOR) + */ + void Crypt(const unsigned char* input, unsigned char* output, size_t bytes); }; #endif // BITCOIN_CRYPTO_CHACHA20_H diff --git a/src/crypto/hkdf_sha256_32.cpp b/src/crypto/hkdf_sha256_32.cpp new file mode 100644 index 0000000000..9cea5995ec --- /dev/null +++ b/src/crypto/hkdf_sha256_32.cpp @@ -0,0 +1,21 @@ +// 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 <crypto/hkdf_sha256_32.h> + +#include <assert.h> +#include <string.h> + +CHKDF_HMAC_SHA256_L32::CHKDF_HMAC_SHA256_L32(const unsigned char* ikm, size_t ikmlen, const std::string& salt) +{ + CHMAC_SHA256((const unsigned char*)salt.c_str(), salt.size()).Write(ikm, ikmlen).Finalize(m_prk); +} + +void CHKDF_HMAC_SHA256_L32::Expand32(const std::string& info, unsigned char hash[OUTPUT_SIZE]) +{ + // expand a 32byte key (single round) + assert(info.size() <= 128); + static const unsigned char one[1] = {1}; + CHMAC_SHA256(m_prk, 32).Write((const unsigned char*)info.data(), info.size()).Write(one, 1).Finalize(hash); +} diff --git a/src/crypto/hkdf_sha256_32.h b/src/crypto/hkdf_sha256_32.h new file mode 100644 index 0000000000..fa1e42aec1 --- /dev/null +++ b/src/crypto/hkdf_sha256_32.h @@ -0,0 +1,25 @@ +// 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_CRYPTO_HKDF_SHA256_32_H +#define BITCOIN_CRYPTO_HKDF_SHA256_32_H + +#include <crypto/hmac_sha256.h> + +#include <stdint.h> +#include <stdlib.h> + +/** A rfc5869 HKDF implementation with HMAC_SHA256 and fixed key output length of 32 bytes (L=32) */ +class CHKDF_HMAC_SHA256_L32 +{ +private: + unsigned char m_prk[32]; + static const size_t OUTPUT_SIZE = 32; + +public: + CHKDF_HMAC_SHA256_L32(const unsigned char* ikm, size_t ikmlen, const std::string& salt); + void Expand32(const std::string& info, unsigned char hash[OUTPUT_SIZE]); +}; + +#endif // BITCOIN_CRYPTO_HKDF_SHA256_32_H diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp index a00331dcb7..edee06cc34 100644 --- a/src/crypto/ripemd160.cpp +++ b/src/crypto/ripemd160.cpp @@ -256,7 +256,7 @@ CRIPEMD160& CRIPEMD160::Write(const unsigned char* data, size_t len) ripemd160::Transform(s, buf); bufsize = 0; } - while (end >= data + 64) { + while (end - data >= 64) { // Process full chunks directly from the source. ripemd160::Transform(s, data); bytes += 64; diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp index 5c601c54a6..3dcdcb186e 100644 --- a/src/crypto/sha1.cpp +++ b/src/crypto/sha1.cpp @@ -163,7 +163,7 @@ CSHA1& CSHA1::Write(const unsigned char* data, size_t len) sha1::Transform(s, buf); bufsize = 0; } - while (end >= data + 64) { + while (end - data >= 64) { // Process full chunks directly from the source. sha1::Transform(s, data); bytes += 64; diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp index bc64135cae..4e6aa363f7 100644 --- a/src/crypto/sha512.cpp +++ b/src/crypto/sha512.cpp @@ -168,7 +168,7 @@ CSHA512& CSHA512::Write(const unsigned char* data, size_t len) sha512::Transform(s, buf); bufsize = 0; } - while (end >= data + 128) { + while (end - data >= 128) { // Process full chunks directly from the source. sha512::Transform(s, data); data += 128; diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 58d8cc2c9d..34896f7ab2 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -115,7 +115,7 @@ static leveldb::Options GetOptions(size_t nCacheSize) } CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) - : m_name(fs::basename(path)) + : m_name{path.stem().string()} { penv = nullptr; readoptions.verify_checksums = true; @@ -11,6 +11,7 @@ #include <ext/stdio_filebuf.h> #endif +#define BOOST_FILESYSTEM_NO_DEPRECATED #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> diff --git a/src/index/base.cpp b/src/index/base.cpp index 9e48f0bd27..bcc8e2ce7c 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -63,9 +63,9 @@ bool BaseIndex::Init() if (locator.IsNull()) { m_best_block_index = nullptr; } else { - m_best_block_index = FindForkInGlobalIndex(chainActive, locator); + m_best_block_index = FindForkInGlobalIndex(::ChainActive(), locator); } - m_synced = m_best_block_index.load() == chainActive.Tip(); + m_synced = m_best_block_index.load() == ::ChainActive().Tip(); return true; } @@ -74,15 +74,15 @@ static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev) EXCLUSIV AssertLockHeld(cs_main); if (!pindex_prev) { - return chainActive.Genesis(); + return ::ChainActive().Genesis(); } - const CBlockIndex* pindex = chainActive.Next(pindex_prev); + const CBlockIndex* pindex = ::ChainActive().Next(pindex_prev); if (pindex) { return pindex; } - return chainActive.Next(chainActive.FindFork(pindex_prev)); + return ::ChainActive().Next(::ChainActive().FindFork(pindex_prev)); } void BaseIndex::ThreadSync() @@ -168,7 +168,7 @@ bool BaseIndex::Commit() bool BaseIndex::CommitInternal(CDBBatch& batch) { LOCK(cs_main); - GetDB().WriteBestBlock(batch, chainActive.GetLocator(m_best_block_index)); + GetDB().WriteBestBlock(batch, ::ChainActive().GetLocator(m_best_block_index)); return true; } @@ -280,9 +280,9 @@ bool BaseIndex::BlockUntilSyncedToCurrentChain() { // Skip the queue-draining stuff if we know we're caught up with - // chainActive.Tip(). + // ::ChainActive().Tip(). LOCK(cs_main); - const CBlockIndex* chain_tip = chainActive.Tip(); + const CBlockIndex* chain_tip = ::ChainActive().Tip(); const CBlockIndex* best_block_index = m_best_block_index.load(); if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) { return true; diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index 7367ec7cb6..929b85bfb5 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -236,7 +236,7 @@ bool TxIndex::Init() // Attempt to migrate txindex from the old database to the new one. Even if // chain_tip is null, the node could be reindexing and we still want to // delete txindex records in the old database. - if (!m_db->MigrateData(*pblocktree, chainActive.GetLocator())) { + if (!m_db->MigrateData(*pblocktree, ::ChainActive().GetLocator())) { return false; } diff --git a/src/init.cpp b/src/init.cpp index 92b3c9510a..944200e24d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -380,10 +380,10 @@ void SetupServerArgs() gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS); gArgs.AddArg("-alertnotify=<cmd>", "Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()), false, OptionsCategory::OPTIONS); - gArgs.AddArg("-blocksdir=<dir>", "Specify blocks directory (default: <datadir>/blocks)", false, OptionsCategory::OPTIONS); + gArgs.AddArg("-blocksdir=<dir>", "Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)", false, OptionsCategory::OPTIONS); gArgs.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), false, OptionsCategory::OPTIONS); - gArgs.AddArg("-blocksonly", strprintf("Whether to operate in a blocks only mode (default: %u)", DEFAULT_BLOCKSONLY), true, OptionsCategory::OPTIONS); + gArgs.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Transactions from the wallet or RPC are not affected. (default: %u)", DEFAULT_BLOCKSONLY), false, OptionsCategory::OPTIONS); gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS); gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS); gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS); @@ -457,7 +457,7 @@ void SetupServerArgs() #endif gArgs.AddArg("-whitebind=<addr>", "Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6", false, OptionsCategory::CONNECTION); gArgs.AddArg("-whitelist=<IP address or network>", "Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times." - " Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway", false, OptionsCategory::CONNECTION); + " Whitelisted peers cannot be DoS banned", false, OptionsCategory::CONNECTION); g_wallet_init_interface.AddWalletOptions(); @@ -490,7 +490,7 @@ void SetupServerArgs() "and level 4 tries to reconnect the blocks, " "each level includes the checks of the previous levels " "(0-4, default: %u)", DEFAULT_CHECKLEVEL), true, OptionsCategory::DEBUG_TEST); - gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); + gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, ::ChainActive() and mapBlocksUnlinked occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED), true, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", true, OptionsCategory::DEBUG_TEST); @@ -528,7 +528,7 @@ void SetupServerArgs() gArgs.AddArg("-mempoolreplacement", strprintf("Enable transaction replacement in the memory pool (default: %u)", DEFAULT_ENABLE_REPLACEMENT), false, OptionsCategory::NODE_RELAY); gArgs.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), false, OptionsCategory::NODE_RELAY); - gArgs.AddArg("-whitelistforcerelay", strprintf("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)", DEFAULT_WHITELISTFORCERELAY), false, OptionsCategory::NODE_RELAY); + gArgs.AddArg("-whitelistforcerelay", strprintf("Force relay of transactions from whitelisted peers even if the transactions were already in the mempool or violate local relay policy (default: %d)", DEFAULT_WHITELISTFORCERELAY), false, OptionsCategory::NODE_RELAY); gArgs.AddArg("-whitelistrelay", strprintf("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), false, OptionsCategory::NODE_RELAY); @@ -1426,7 +1426,7 @@ bool AppInitMain(InitInterfaces& interfaces) // see Step 2: parameter interactions for more information about these fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN); fDiscover = gArgs.GetBoolArg("-discover", true); - fRelayTxes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); + g_relay_txes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); for (const std::string& strAddr : gArgs.GetArgs("-externalip")) { CService addrLocal; @@ -1572,12 +1572,12 @@ bool AppInitMain(InitInterfaces& interfaces) is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull(); if (!is_coinsview_empty) { - // LoadChainTip sets chainActive based on pcoinsTip's best block + // LoadChainTip sets ::ChainActive() based on pcoinsTip's best block if (!LoadChainTip(chainparams)) { strLoadError = _("Error initializing block database"); break; } - assert(chainActive.Tip() != nullptr); + assert(::ChainActive().Tip() != nullptr); } } catch (const std::exception& e) { LogPrintf("%s\n", e.what()); @@ -1587,7 +1587,7 @@ bool AppInitMain(InitInterfaces& interfaces) if (!fReset) { // Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate. - // It both disconnects blocks based on chainActive, and drops block data in + // It both disconnects blocks based on ::ChainActive(), and drops block data in // mapBlockIndex based on lack of available witness data. uiInterface.InitMessage(_("Rewinding blocks...")); if (!RewindBlockIndex(chainparams)) { @@ -1605,7 +1605,7 @@ bool AppInitMain(InitInterfaces& interfaces) MIN_BLOCKS_TO_KEEP); } - CBlockIndex* tip = chainActive.Tip(); + CBlockIndex* tip = ::ChainActive().Tip(); RPCNotifyBlockChange(true, tip); if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { strLoadError = _("The block database contains a block which appears to be from the future. " @@ -1719,7 +1719,7 @@ bool AppInitMain(InitInterfaces& interfaces) // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly. // No locking, as this happens before any background thread is started. boost::signals2::connection block_notify_genesis_wait_connection; - if (chainActive.Tip() == nullptr) { + if (::ChainActive().Tip() == nullptr) { block_notify_genesis_wait_connection = uiInterface.NotifyBlockTip_connect(BlockNotifyGenesisWait); } else { fHaveGenesis = true; @@ -1759,7 +1759,7 @@ bool AppInitMain(InitInterfaces& interfaces) { LOCK(cs_main); LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); - chain_active_height = chainActive.Height(); + chain_active_height = ::ChainActive().Height(); } LogPrintf("nBestHeight = %d\n", chain_active_height); diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index 617be3ca71..6097d80931 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -37,11 +37,12 @@ namespace interfaces { namespace { -class LockImpl : public Chain::Lock +class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection> { Optional<int> getHeight() override { - int height = ::chainActive.Height(); + LockAnnotation lock(::cs_main); + int height = ::ChainActive().Height(); if (height >= 0) { return height; } @@ -49,8 +50,9 @@ class LockImpl : public Chain::Lock } Optional<int> getBlockHeight(const uint256& hash) override { + LockAnnotation lock(::cs_main); CBlockIndex* block = LookupBlockIndex(hash); - if (block && ::chainActive.Contains(block)) { + if (block && ::ChainActive().Contains(block)) { return block->nHeight; } return nullopt; @@ -63,30 +65,35 @@ class LockImpl : public Chain::Lock } uint256 getBlockHash(int height) override { - CBlockIndex* block = ::chainActive[height]; + LockAnnotation lock(::cs_main); + CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockHash(); } int64_t getBlockTime(int height) override { - CBlockIndex* block = ::chainActive[height]; + LockAnnotation lock(::cs_main); + CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockTime(); } int64_t getBlockMedianTimePast(int height) override { - CBlockIndex* block = ::chainActive[height]; + LockAnnotation lock(::cs_main); + CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetMedianTimePast(); } bool haveBlockOnDisk(int height) override { - CBlockIndex* block = ::chainActive[height]; + LockAnnotation lock(::cs_main); + CBlockIndex* block = ::ChainActive()[height]; return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0; } Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override { - CBlockIndex* block = ::chainActive.FindEarliestAtLeast(time, height); + LockAnnotation lock(::cs_main); + CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height); if (block) { if (hash) *hash = block->GetBlockHash(); return block->nHeight; @@ -95,8 +102,9 @@ class LockImpl : public Chain::Lock } Optional<int> findPruned(int start_height, Optional<int> stop_height) override { + LockAnnotation lock(::cs_main); if (::fPruneMode) { - CBlockIndex* block = stop_height ? ::chainActive[*stop_height] : ::chainActive.Tip(); + CBlockIndex* block = stop_height ? ::ChainActive()[*stop_height] : ::ChainActive().Tip(); while (block && block->nHeight >= start_height) { if ((block->nStatus & BLOCK_HAVE_DATA) == 0) { return block->nHeight; @@ -108,8 +116,9 @@ class LockImpl : public Chain::Lock } Optional<int> findFork(const uint256& hash, Optional<int>* height) override { + LockAnnotation lock(::cs_main); const CBlockIndex* block = LookupBlockIndex(hash); - const CBlockIndex* fork = block ? ::chainActive.FindFork(block) : nullptr; + const CBlockIndex* fork = block ? ::ChainActive().FindFork(block) : nullptr; if (height) { if (block) { *height = block->nHeight; @@ -122,11 +131,15 @@ class LockImpl : public Chain::Lock } return nullopt; } - CBlockLocator getTipLocator() override { return ::chainActive.GetLocator(); } + CBlockLocator getTipLocator() override + { + LockAnnotation lock(::cs_main); + return ::ChainActive().GetLocator(); + } Optional<int> findLocatorFork(const CBlockLocator& locator) override { LockAnnotation lock(::cs_main); - if (CBlockIndex* fork = FindForkInGlobalIndex(::chainActive, locator)) { + if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) { return fork->nHeight; } return nullopt; @@ -142,10 +155,7 @@ class LockImpl : public Chain::Lock return AcceptToMemoryPool(::mempool, state, tx, nullptr /* missing inputs */, nullptr /* txn replaced */, false /* bypass limits */, absurd_fee); } -}; -class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection> -{ using UniqueLock::UniqueLock; }; @@ -236,13 +246,12 @@ class ChainImpl : public Chain public: std::unique_ptr<Chain::Lock> lock(bool try_lock) override { - auto result = MakeUnique<LockingStateImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock); + auto result = MakeUnique<LockImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock); if (try_lock && result && !*result) return {}; // std::move necessary on some compilers due to conversion from - // LockingStateImpl to Lock pointer + // LockImpl to Lock pointer return std::move(result); } - std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); } bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override { CBlockIndex* index; @@ -319,7 +328,11 @@ public: CFeeRate relayMinFee() override { return ::minRelayTxFee; } CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; } CFeeRate relayDustFee() override { return ::dustRelayFee; } - bool getPruneMode() override { return ::fPruneMode; } + bool havePruned() override + { + LOCK(cs_main); + return ::fHavePruned; + } bool p2pEnabled() override { return g_connman != nullptr; } bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !IsInitialBlockDownload(); } bool isInitialBlockDownload() override { return IsInitialBlockDownload(); } @@ -341,9 +354,9 @@ public: { if (!old_tip.IsNull()) { LOCK(::cs_main); - if (old_tip == ::chainActive.Tip()->GetBlockHash()) return; + if (old_tip == ::ChainActive().Tip()->GetBlockHash()) return; CBlockIndex* block = LookupBlockIndex(old_tip); - if (block && block->GetAncestor(::chainActive.Height()) == ::chainActive.Tip()) return; + if (block && block->GetAncestor(::ChainActive().Height()) == ::ChainActive().Tip()) return; } SyncWithValidationInterfaceQueue(); } diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 0b7249a5ab..e675defd47 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -138,11 +138,6 @@ public: //! unlocked when the returned interface is freed. virtual std::unique_ptr<Lock> lock(bool try_lock = false) = 0; - //! Return Lock interface assuming chain is already locked. This - //! method is temporary and is only used in a few places to avoid changing - //! behavior while code is transitioned to use the Chain::Lock interface. - virtual std::unique_ptr<Lock> assumeLocked() = 0; - //! Return whether node has the block and optionally return block metadata //! or contents. //! @@ -196,8 +191,8 @@ public: //! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's economical to spend. virtual CFeeRate relayDustFee() = 0; - //! Check if pruning is enabled. - virtual bool getPruneMode() = 0; + //! Check if any block has been pruned. + virtual bool havePruned() = 0; //! Check if p2p enabled. virtual bool p2pEnabled() = 0; diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index f3ee8fe364..618cd02ea6 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -178,13 +178,13 @@ public: int getNumBlocks() override { LOCK(::cs_main); - return ::chainActive.Height(); + return ::ChainActive().Height(); } int64_t getLastBlockTime() override { LOCK(::cs_main); - if (::chainActive.Tip()) { - return ::chainActive.Tip()->GetBlockTime(); + if (::ChainActive().Tip()) { + return ::ChainActive().Tip()->GetBlockTime(); } return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network } @@ -193,7 +193,7 @@ public: const CBlockIndex* tip; { LOCK(::cs_main); - tip = ::chainActive.Tip(); + tip = ::ChainActive().Tip(); } return GuessVerificationProgress(Params().TxData(), tip); } diff --git a/src/key.cpp b/src/key.cpp index 9d982fc44f..c17f6a0ae2 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -163,6 +163,12 @@ void CKey::MakeNewKey(bool fCompressedIn) { fCompressed = fCompressedIn; } +bool CKey::Negate() +{ + assert(fValid); + return secp256k1_ec_privkey_negate(secp256k1_context_sign, keydata.data()); +} + CPrivKey CKey::GetPrivKey() const { assert(fValid); CPrivKey privkey; @@ -98,6 +98,9 @@ public: //! Generate a new private key using a cryptographic PRNG. void MakeNewKey(bool fCompressed); + //! Negate private key + bool Negate(); + /** * Convert the private key to a CPrivKey (serialized OpenSSL private key data). * This is expensive. diff --git a/src/key_io.cpp b/src/key_io.cpp index 1d53a5e074..cd41a93549 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -26,14 +26,14 @@ private: public: explicit DestinationEncoder(const CChainParams& params) : m_params(params) {} - std::string operator()(const CKeyID& id) const + std::string operator()(const PKHash& id) const { std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); data.insert(data.end(), id.begin(), id.end()); return EncodeBase58Check(data); } - std::string operator()(const CScriptID& id) const + std::string operator()(const ScriptHash& id) const { std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); data.insert(data.end(), id.begin(), id.end()); @@ -81,14 +81,14 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) { std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin()); - return CKeyID(hash); + return PKHash(hash); } // Script-hash-addresses have version 5 (or 196 testnet). // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) { std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin()); - return CScriptID(hash); + return ScriptHash(hash); } } data.clear(); diff --git a/src/keystore.cpp b/src/keystore.cpp index 148979cf35..f6d19416ce 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -178,16 +178,17 @@ CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest) { // Only supports destinations which map to single public keys, i.e. P2PKH, // P2WPKH, and P2SH-P2WPKH. - if (auto id = boost::get<CKeyID>(&dest)) { - return *id; + if (auto id = boost::get<PKHash>(&dest)) { + return CKeyID(*id); } if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) { return CKeyID(*witness_id); } - if (auto script_id = boost::get<CScriptID>(&dest)) { + if (auto script_hash = boost::get<ScriptHash>(&dest)) { CScript script; + CScriptID script_id(*script_hash); CTxDestination inner_dest; - if (store.GetCScript(*script_id, script) && ExtractDestination(script, inner_dest)) { + if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) { if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) { return CKeyID(*inner_witness_id); } diff --git a/src/miner.cpp b/src/miner.cpp index 6a88e8321d..3d53515435 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -109,7 +109,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end LOCK2(cs_main, mempool.cs); - CBlockIndex* pindexPrev = chainActive.Tip(); + CBlockIndex* pindexPrev = ::ChainActive().Tip(); assert(pindexPrev != nullptr); nHeight = pindexPrev->nHeight + 1; diff --git a/src/net.cpp b/src/net.cpp index 1335804b06..3c6f5a05f3 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -79,7 +79,7 @@ static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // S // bool fDiscover = true; bool fListen = true; -bool fRelayTxes = true; +bool g_relay_txes = !DEFAULT_BLOCKSONLY; CCriticalSection cs_mapLocalHost; std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost); static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {}; @@ -519,7 +519,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices) extern bool fDiscover; extern bool fListen; -extern bool fRelayTxes; +extern bool g_relay_txes; /** Subversion as sent to the P2P network in `version` messages */ extern std::string strSubVersion; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 71ebd72b83..cb2b9f8c03 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -422,7 +422,7 @@ static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime) CAddress addrMe = CAddress(CService(), nLocalNodeServices); connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, - nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes)); + nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes)); if (fLogIPs) { LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid); @@ -579,7 +579,7 @@ static bool TipMayBeStale(const Consensus::Params &consensusParams) EXCLUSIVE_LO static bool CanDirectFetch(const Consensus::Params &consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { - return chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; + return ::ChainActive().Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; } static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main) @@ -605,7 +605,7 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec // Make sure pindexBestKnownBlock is up to date, we'll need it. ProcessBlockAvailability(nodeid); - if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { + if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < ::ChainActive().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { // This peer has nothing interesting. return; } @@ -613,7 +613,7 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec if (state->pindexLastCommonBlock == nullptr) { // Bootstrap quickly by guessing a parent of our best tip is the forking point. // Guessing wrong in either direction is not a problem. - state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())]; + state->pindexLastCommonBlock = ::ChainActive()[std::min(state->pindexBestKnownBlock->nHeight, ::ChainActive().Height())]; } // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor @@ -655,7 +655,7 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec // We wouldn't download this block or its descendants from this peer. return; } - if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) { + if (pindex->nStatus & BLOCK_HAVE_DATA || ::ChainActive().Contains(pindex)) { if (pindex->HaveTxsDownloaded()) state->pindexLastCommonBlock = pindex; } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { @@ -1071,7 +1071,7 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); - if (chainActive.Contains(pindex)) return true; + if (::ChainActive().Contains(pindex)) return true; return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) && (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT); @@ -1183,7 +1183,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std: /** * Update our best height and announce any block hashes which weren't previously - * in chainActive to our peers. + * in ::ChainActive() to our peers. */ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) { const int nNewHeight = pindexNew->nHeight; @@ -1264,13 +1264,13 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) case MSG_WITNESS_TX: { assert(recentRejects); - if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip) + if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip) { // If the chain tip has changed previously rejected transactions // might be now valid, e.g. due to a nLockTime'd tx becoming valid, // or a double-spend. Reset the rejects filter and give those // txs a second chance. - hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash(); + hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash(); recentRejects->reset(); } @@ -1395,7 +1395,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c } // Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold if (send && !pfrom->fWhitelisted && ( - (((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (chainActive.Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) ) + (((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (::ChainActive().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) ) )) { LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId()); @@ -1465,7 +1465,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c // instead we respond with the full, non-compact block. bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness; int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; - if (CanDirectFetch(consensusParams) && pindex->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { + if (CanDirectFetch(consensusParams) && pindex->nHeight >= ::ChainActive().Height() - MAX_CMPCTBLOCK_DEPTH) { if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) { connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); } else { @@ -1485,7 +1485,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c // and we want it right after the last block so they don't // wait for other stuff first. std::vector<CInv> vInv; - vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); + vInv.push_back(CInv(MSG_BLOCK, ::ChainActive().Tip()->GetBlockHash())); connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv)); pfrom->hashContinue.SetNull(); } @@ -1606,7 +1606,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve // nUnconnectingHeaders gets reset back to 0. if (!LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) { nodestate->nUnconnectingHeaders++; - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256())); LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", headers[0].GetHash().ToString(), headers[0].hashPrevBlock.ToString(), @@ -1663,26 +1663,26 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve // because it is set in UpdateBlockAvailability. Some nullptr checks // are still present, however, as belt-and-suspenders. - if (received_new_header && pindexLast->nChainWork > chainActive.Tip()->nChainWork) { + if (received_new_header && pindexLast->nChainWork > ::ChainActive().Tip()->nChainWork) { nodestate->m_last_block_announcement = GetTime(); } if (nCount == MAX_HEADERS_RESULTS) { // Headers message had its maximum size; the peer may have more headers. - // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue + // TODO: optimize: if pindexLast is an ancestor of ::ChainActive().Tip or pindexBestHeader, continue // from there instead. LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight); - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256())); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256())); } bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); // If this set of headers is valid and ends in a block with at least as // much work as our tip, download as much as possible. - if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { + if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && ::ChainActive().Tip()->nChainWork <= pindexLast->nChainWork) { std::vector<const CBlockIndex*> vToFetch; const CBlockIndex *pindexWalk = pindexLast; // Calculate all the blocks we'd need to switch to pindexLast, up to a limit. - while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + while (pindexWalk && !::ChainActive().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) && (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) { @@ -1695,7 +1695,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve // very large reorg at a time we think we're close to caught up to // the main chain -- this shouldn't really happen. Bail out on the // direct fetch and rely on parallel download instead. - if (!chainActive.Contains(pindexWalk)) { + if (!::ChainActive().Contains(pindexWalk)) { LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); @@ -1736,7 +1736,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve // us sync -- disconnect if using an outbound slot (unless // whitelisted or addnode). // Note: We compare their tip to nMinimumChainWork (rather than - // chainActive.Tip()) because we won't start block download + // ::ChainActive().Tip()) because we won't start block download // until we have a headers chain that has at least // nMinimumChainWork, even if a peer has a chain past our tip, // as an anti-DoS measure. @@ -1750,7 +1750,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr) { // If this is an outbound peer, check to see if we should protect // it from the bad/lagging chain logic. - if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) { + if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) { LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom->GetId()); nodestate->m_chain_sync.m_protect = true; ++g_outbound_peers_with_protect_from_disconnect; @@ -2189,7 +2189,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return false; } - bool fBlocksOnly = !fRelayTxes; + bool fBlocksOnly = !g_relay_txes; // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) @@ -2220,7 +2220,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // fell back to inv we probably have a reorg which we should get the headers for first, // we now only provide a getheaders response here. When we receive the headers, we will // then ask for the blocks we need. - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash)); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), inv.hash)); LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId()); } } @@ -2291,14 +2291,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LOCK(cs_main); // Find the last block the caller has in the main chain - const CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator); + const CBlockIndex* pindex = FindForkInGlobalIndex(::ChainActive(), locator); // Send the rest of the chain if (pindex) - pindex = chainActive.Next(pindex); + pindex = ::ChainActive().Next(pindex); int nLimit = 500; LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom->GetId()); - for (; pindex; pindex = chainActive.Next(pindex)) + for (; pindex; pindex = ::ChainActive().Next(pindex)) { if (pindex->GetBlockHash() == hashStop) { @@ -2308,7 +2308,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // If pruning, don't inv blocks unless we have on disk and are likely to still have // for some reasonable time window (1 hour) that block relay might require. const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams.GetConsensus().nPowTargetSpacing; - if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= chainActive.Tip()->nHeight - nPrunedBlocksLikelyToHave)) + if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= ::ChainActive().Tip()->nHeight - nPrunedBlocksLikelyToHave)) { LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); break; @@ -2350,7 +2350,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } - if (pindex->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) { + if (pindex->nHeight < ::ChainActive().Height() - MAX_BLOCKTXN_DEPTH) { // If an older block is requested (should never happen in practice, // but can happen in tests) send a block response instead of a // blocktxn response. Sending a full block response instead of a @@ -2410,23 +2410,23 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr else { // Find the last block the caller has in the main chain - pindex = FindForkInGlobalIndex(chainActive, locator); + pindex = FindForkInGlobalIndex(::ChainActive(), locator); if (pindex) - pindex = chainActive.Next(pindex); + pindex = ::ChainActive().Next(pindex); } // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end std::vector<CBlock> vHeaders; int nLimit = MAX_HEADERS_RESULTS; LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom->GetId()); - for (; pindex; pindex = chainActive.Next(pindex)) + for (; pindex; pindex = ::ChainActive().Next(pindex)) { vHeaders.push_back(pindex->GetBlockHeader()); if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) break; } - // pindex can be nullptr either if we sent chainActive.Tip() OR - // if our peer has chainActive.Tip() (and thus we are sending an empty + // pindex can be nullptr either if we sent ::ChainActive().Tip() OR + // if our peer has ::ChainActive().Tip() (and thus we are sending an empty // headers message). In both cases it's safe to update // pindexBestHeaderSent to be our tip. // @@ -2437,7 +2437,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // without the new block. By resetting the BestHeaderSent, we ensure we // will re-announce the new block via headers (or compact blocks again) // in the SendMessages logic. - nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); + nodestate->pindexBestHeaderSent = pindex ? pindex : ::ChainActive().Tip(); connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); return true; } @@ -2445,7 +2445,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr 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))) + if (!g_relay_txes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))) { LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId()); return true; @@ -2610,7 +2610,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) { // Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers if (!IsInitialBlockDownload()) - connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); + connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256())); return true; } @@ -2654,7 +2654,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // If this was a new header with more work than our tip, update the // peer's last block announcement time - if (received_new_header && pindex->nChainWork > chainActive.Tip()->nChainWork) { + if (received_new_header && pindex->nChainWork > ::ChainActive().Tip()->nChainWork) { nodestate->m_last_block_announcement = GetTime(); } @@ -2664,7 +2664,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here return true; - if (pindex->nChainWork <= chainActive.Tip()->nChainWork || // We know something better + if (pindex->nChainWork <= ::ChainActive().Tip()->nChainWork || // We know something better pindex->nTx != 0) { // We had this block at some point, but pruned it if (fAlreadyInFlight) { // We requested this block for some reason, but our mempool will probably be useless @@ -2688,7 +2688,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // We want to be a bit conservative just to be extra careful about DoS // possibilities in compact block processing... - if (pindex->nHeight <= chainActive.Height() + 2) { + if (pindex->nHeight <= ::ChainActive().Height() + 2) { if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) || (fAlreadyInFlight && blockInFlightIt->second.first == pfrom->GetId())) { std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr; @@ -3338,7 +3338,7 @@ void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds) // their chain has more work than ours, we should sync to it, // unless it's invalid, in which case we should find that out and // disconnect from them elsewhere). - if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork) { + if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork) { if (state.m_chain_sync.m_timeout != 0) { state.m_chain_sync.m_timeout = 0; state.m_chain_sync.m_work_header = nullptr; @@ -3350,7 +3350,7 @@ void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds) // where we checked against our tip. // Either way, set a new timeout based on current tip. state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT; - state.m_chain_sync.m_work_header = chainActive.Tip(); + state.m_chain_sync.m_work_header = ::ChainActive().Tip(); state.m_chain_sync.m_sent_getheaders = false; } else if (state.m_chain_sync.m_timeout > 0 && time_in_seconds > state.m_chain_sync.m_timeout) { // No evidence yet that our peer has synced to a chain with work equal to that @@ -3363,7 +3363,7 @@ void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds) } else { assert(state.m_chain_sync.m_work_header); LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto->GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString()); - connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(state.m_chain_sync.m_work_header->pprev), uint256())); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256())); state.m_chain_sync.m_sent_getheaders = true; constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes // Bump the timeout to allow a response, which could clear the timeout @@ -3561,7 +3561,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) // Start block sync if (pindexBestHeader == nullptr) - pindexBestHeader = chainActive.Tip(); + pindexBestHeader = ::ChainActive().Tip(); bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { // Only actively request headers from a single peer, unless we're close to today. @@ -3580,7 +3580,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) if (pindexStart->pprev) pindexStart = pindexStart->pprev; LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), pto->nStartingHeight); - connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256())); + connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexStart), uint256())); } } @@ -3607,11 +3607,11 @@ bool PeerLogicValidation::SendMessages(CNode* pto) bool fFoundStartingHeader = false; // Try to find first header that our peer doesn't have, and // then send all headers past that one. If we come across any - // headers that aren't on chainActive, give up. + // headers that aren't on ::ChainActive(), give up. for (const uint256 &hash : pto->vBlockHashesToAnnounce) { const CBlockIndex* pindex = LookupBlockIndex(hash); assert(pindex); - if (chainActive[pindex->nHeight] != pindex) { + if (::ChainActive()[pindex->nHeight] != pindex) { // Bail out if we reorged away from this block fRevertToInv = true; break; @@ -3707,9 +3707,9 @@ bool PeerLogicValidation::SendMessages(CNode* pto) // Warn if we're announcing a block that is not on the main chain. // This should be very rare and could be optimized out. // Just log for now. - if (chainActive[pindex->nHeight] != pindex) { + if (::ChainActive()[pindex->nHeight] != pindex) { LogPrint(BCLog::NET, "Announcing block %s not on main chain (tip=%s)\n", - hashToAnnounce.ToString(), chainActive.Tip()->GetBlockHash().ToString()); + hashToAnnounce.ToString(), ::ChainActive().Tip()->GetBlockHash().ToString()); } // If the peer's chain has this block, don't inv it back. diff --git a/src/outputtype.cpp b/src/outputtype.cpp index 7e5690dfc5..73ffb801f2 100644 --- a/src/outputtype.cpp +++ b/src/outputtype.cpp @@ -45,14 +45,14 @@ const std::string& FormatOutputType(OutputType type) CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type) { switch (type) { - case OutputType::LEGACY: return key.GetID(); + case OutputType::LEGACY: return PKHash(key); case OutputType::P2SH_SEGWIT: case OutputType::BECH32: { - if (!key.IsCompressed()) return key.GetID(); - CTxDestination witdest = WitnessV0KeyHash(key.GetID()); + if (!key.IsCompressed()) return PKHash(key); + CTxDestination witdest = WitnessV0KeyHash(PKHash(key)); CScript witprog = GetScriptForDestination(witdest); if (type == OutputType::P2SH_SEGWIT) { - return CScriptID(witprog); + return ScriptHash(witprog); } else { return witdest; } @@ -63,10 +63,10 @@ CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type) std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key) { - CKeyID keyid = key.GetID(); + PKHash keyid(key); if (key.IsCompressed()) { CTxDestination segwit = WitnessV0KeyHash(keyid); - CTxDestination p2sh = CScriptID(GetScriptForDestination(segwit)); + CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit)); return std::vector<CTxDestination>{std::move(keyid), std::move(p2sh), std::move(segwit)}; } else { return std::vector<CTxDestination>{std::move(keyid)}; @@ -80,19 +80,19 @@ CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript& // Note that scripts over 520 bytes are not yet supported. switch (type) { case OutputType::LEGACY: - return CScriptID(script); + return ScriptHash(script); case OutputType::P2SH_SEGWIT: case OutputType::BECH32: { CTxDestination witdest = WitnessV0ScriptHash(script); CScript witprog = GetScriptForDestination(witdest); // Check if the resulting program is solvable (i.e. doesn't use an uncompressed key) - if (!IsSolvable(keystore, witprog)) return CScriptID(script); + if (!IsSolvable(keystore, witprog)) return ScriptHash(script); // Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours. keystore.AddCScript(witprog); if (type == OutputType::BECH32) { return witdest; } else { - return CScriptID(witprog); + return ScriptHash(witprog); } } default: assert(false); diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 524afd014e..6456eec016 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -526,7 +526,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo if (txHeight != nBestSeenHeight) { // Ignore side chains and re-orgs; assuming they are random they don't // affect the estimate. We'll potentially double count transactions in 1-block reorgs. - // Ignore txs if BlockPolicyEstimator is not in sync with chainActive.Tip(). + // Ignore txs if BlockPolicyEstimator is not in sync with ::ChainActive().Tip(). // It will be synced next time a block is processed. return; } diff --git a/src/prevector.h b/src/prevector.h index 99e5751634..ea8707389a 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -147,14 +147,14 @@ public: }; private: - size_type _size; + size_type _size = 0; union direct_or_indirect { char direct[sizeof(T) * N]; struct { size_type capacity; char* indirect; }; - } _union; + } _union = {}; T* direct_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.direct) + pos; } const T* direct_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.direct) + pos; } @@ -230,34 +230,34 @@ public: fill(item_ptr(0), first, last); } - prevector() : _size(0), _union{{}} {} + prevector() {} - explicit prevector(size_type n) : prevector() { + explicit prevector(size_type n) { resize(n); } - explicit prevector(size_type n, const T& val) : prevector() { + explicit prevector(size_type n, const T& val) { change_capacity(n); _size += n; fill(item_ptr(0), n, val); } template<typename InputIterator> - prevector(InputIterator first, InputIterator last) : prevector() { + prevector(InputIterator first, InputIterator last) { size_type n = last - first; change_capacity(n); _size += n; fill(item_ptr(0), first, last); } - prevector(const prevector<N, T, Size, Diff>& other) : prevector() { + prevector(const prevector<N, T, Size, Diff>& other) { size_type n = other.size(); change_capacity(n); _size += n; fill(item_ptr(0), other.begin(), other.end()); } - prevector(prevector<N, T, Size, Diff>&& other) : prevector() { + prevector(prevector<N, T, Size, Diff>&& other) { swap(other); } diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 0d9f1adcd2..6c9bae7673 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -471,8 +471,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) else if(ExtractDestination(out.txout.scriptPubKey, address)) { CPubKey pubkey; - CKeyID *keyid = boost::get<CKeyID>(&address); - if (keyid && model->wallet().getPubKey(*keyid, pubkey)) + PKHash *pkhash = boost::get<PKHash>(&address); + if (pkhash && model->wallet().getPubKey(CKeyID(*pkhash), pubkey)) { nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); } diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 64cc85d623..71f5f2ae75 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -120,8 +120,8 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; } - const CKeyID* keyID = boost::get<CKeyID>(&destination); - if (!keyID) { + const PKHash* pkhash = boost::get<PKHash>(&destination); + if (!pkhash) { ui->addressIn_SM->setValid(false); ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); @@ -137,7 +137,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() } CKey key; - if (!model->wallet().getPrivKey(*keyID, key)) + if (!model->wallet().getPrivKey(CKeyID(*pkhash), key)) { ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(tr("Private key for the entered address is not available.")); @@ -198,7 +198,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; } - if (!boost::get<CKeyID>(&destination)) { + if (!boost::get<PKHash>(&destination)) { ui->addressIn_VM->setValid(false); ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); @@ -229,7 +229,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() return; } - if (!(CTxDestination(pubkey.GetID()) == destination)) { + if (!(CTxDestination(PKHash(pubkey)) == destination)) { ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>")); return; diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 9e3518fd53..21209d4994 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -145,11 +145,13 @@ void TestGUI() } { auto locked_chain = wallet->chain().lock(); + LockAnnotation lock(::cs_main); + WalletRescanReserver reserver(wallet.get()); reserver.reserve(); CWallet::ScanResult result = wallet->ScanForWalletTransactions(locked_chain->getBlockHash(0), {} /* stop_block */, reserver, true /* fUpdate */); QCOMPARE(result.status, CWallet::ScanResult::SUCCESS); - QCOMPARE(result.last_scanned_block, chainActive.Tip()->GetBlockHash()); + QCOMPARE(result.last_scanned_block, ::ChainActive().Tip()->GetBlockHash()); QVERIFY(result.last_failed_block.IsNull()); } wallet->SetBroadcastTransactions(true); @@ -169,8 +171,8 @@ void TestGUI() // Send two transactions, and verify they are added to transaction list. TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel(); QCOMPARE(transactionTableModel->rowCount({}), 105); - uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, CKeyID(), 5 * COIN, false /* rbf */); - uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, CKeyID(), 10 * COIN, true /* rbf */); + uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, false /* rbf */); + uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, true /* rbf */); QCOMPARE(transactionTableModel->rowCount({}), 107); QVERIFY(FindTx(*transactionTableModel, txid1).isValid()); QVERIFY(FindTx(*transactionTableModel, txid2).isValid()); diff --git a/src/random.cpp b/src/random.cpp index 1aa78a9034..de26e6de1a 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -237,6 +237,34 @@ static void SeedHardwareSlow(CSHA512& hasher) noexcept { #endif } +/** Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */ +static void Strengthen(const unsigned char (&seed)[32], int microseconds, CSHA512& hasher) noexcept +{ + CSHA512 inner_hasher; + inner_hasher.Write(seed, sizeof(seed)); + + // Hash loop + unsigned char buffer[64]; + int64_t stop = GetTimeMicros() + microseconds; + do { + for (int i = 0; i < 1000; ++i) { + inner_hasher.Finalize(buffer); + inner_hasher.Reset(); + inner_hasher.Write(buffer, sizeof(buffer)); + } + // Benchmark operation and feed it into outer hasher. + int64_t perf = GetPerformanceCounter(); + hasher.Write((const unsigned char*)&perf, sizeof(perf)); + } while (GetTimeMicros() < stop); + + // Produce output from inner state and feed it to outer hasher. + inner_hasher.Finalize(buffer); + hasher.Write(buffer, sizeof(buffer)); + // Try to clean up. + inner_hasher.Reset(); + memory_cleanse(buffer, sizeof(buffer)); +} + static void RandAddSeedPerfmon(CSHA512& hasher) { #ifdef WIN32 @@ -529,7 +557,23 @@ static void SeedSlow(CSHA512& hasher) noexcept SeedTimestamp(hasher); } -static void SeedSleep(CSHA512& hasher) +/** Extract entropy from rng, strengthen it, and feed it into hasher. */ +static void SeedStrengthen(CSHA512& hasher, RNGState& rng) noexcept +{ + static std::atomic<int64_t> last_strengthen{0}; + int64_t last_time = last_strengthen.load(); + int64_t current_time = GetTimeMicros(); + if (current_time > last_time + 60000000) { // Only run once a minute + // Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher. + unsigned char strengthen_seed[32]; + rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false); + // Strengthen it for 10ms (100ms on first run), and feed it into hasher. + Strengthen(strengthen_seed, last_time == 0 ? 100000 : 10000, hasher); + last_strengthen = current_time; + } +} + +static void SeedSleep(CSHA512& hasher, RNGState& rng) { // Everything that the 'fast' seeder includes SeedFast(hasher); @@ -545,9 +589,12 @@ static void SeedSleep(CSHA512& hasher) // Windows performance monitor data (once every 10 minutes) RandAddSeedPerfmon(hasher); + + // Strengthen every minute + SeedStrengthen(hasher, rng); } -static void SeedStartup(CSHA512& hasher) noexcept +static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept { #ifdef WIN32 RAND_screen(); @@ -561,6 +608,9 @@ static void SeedStartup(CSHA512& hasher) noexcept // Windows performance monitor data. RandAddSeedPerfmon(hasher); + + // Strengthen + SeedStrengthen(hasher, rng); } enum class RNGLevel { @@ -585,7 +635,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level) SeedSlow(hasher); break; case RNGLevel::SLEEP: - SeedSleep(hasher); + SeedSleep(hasher, rng); break; } @@ -593,7 +643,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level) if (!rng.MixExtract(out, num, std::move(hasher), false)) { // On the first invocation, also seed with SeedStartup(). CSHA512 startup_hasher; - SeedStartup(startup_hasher); + SeedStartup(startup_hasher, rng); rng.MixExtract(out, num, std::move(startup_hasher), true); } @@ -652,7 +702,7 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len) if (requires_seed) RandomSeed(); std::vector<unsigned char> ret(len); if (len > 0) { - rng.Output(&ret[0], len); + rng.Keystream(&ret[0], len); } return ret; } diff --git a/src/random.h b/src/random.h index 1c035f87ba..75d037738d 100644 --- a/src/random.h +++ b/src/random.h @@ -43,6 +43,7 @@ * - RandAddSeedSleep() seeds everything that fast seeding includes, but additionally: * - A high-precision timestamp before and after sleeping 1ms. * - (On Windows) Once every 10 minutes, performance monitoring data from the OS. + - - Once every minute, strengthen the entropy for 10 ms using repeated SHA512. * These just exploit the fact the system is idle to improve the quality of the RNG * slightly. * @@ -51,6 +52,7 @@ * - 256 bits from the hardware RNG (rdseed or rdrand) when available. * - (On Windows) Performance monitoring data from the OS. * - (On Windows) Through OpenSSL, the screen contents. + * - Strengthen the entropy for 100 ms using repeated SHA512. * * When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and * (up to) the first 32 bytes of H are produced as output, while the last 32 bytes @@ -111,7 +113,7 @@ private: if (requires_seed) { RandomSeed(); } - rng.Output(bytebuf, sizeof(bytebuf)); + rng.Keystream(bytebuf, sizeof(bytebuf)); bytebuf_size = sizeof(bytebuf); } diff --git a/src/rest.cpp b/src/rest.cpp index baad3b2ce9..ab409947d3 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -141,13 +141,13 @@ static bool rest_headers(HTTPRequest* req, headers.reserve(count); { LOCK(cs_main); - tip = chainActive.Tip(); + tip = ::ChainActive().Tip(); const CBlockIndex* pindex = LookupBlockIndex(hash); - while (pindex != nullptr && chainActive.Contains(pindex)) { + while (pindex != nullptr && ::ChainActive().Contains(pindex)) { headers.push_back(pindex); if (headers.size() == (unsigned long)count) break; - pindex = chainActive.Next(pindex); + pindex = ::ChainActive().Next(pindex); } } @@ -209,7 +209,7 @@ static bool rest_block(HTTPRequest* req, CBlockIndex* tip = nullptr; { LOCK(cs_main); - tip = chainActive.Tip(); + tip = ::ChainActive().Tip(); pblockindex = LookupBlockIndex(hash); if (!pblockindex) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); @@ -522,7 +522,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) // serialize data // use exact same output as mentioned in Bip64 CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); - ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; + ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs; std::string ssGetUTXOResponseString = ssGetUTXOResponse.str(); req->WriteHeader("Content-Type", "application/octet-stream"); @@ -532,7 +532,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) case RetFormat::HEX: { CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); - ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs; + ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs; std::string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n"; req->WriteHeader("Content-Type", "text/plain"); @@ -545,8 +545,8 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) // pack in some essentials // use more or less the same output as mentioned in Bip64 - objGetUTXOResponse.pushKV("chainHeight", chainActive.Height()); - objGetUTXOResponse.pushKV("chaintipHash", chainActive.Tip()->GetBlockHash().GetHex()); + objGetUTXOResponse.pushKV("chainHeight", ::ChainActive().Height()); + objGetUTXOResponse.pushKV("chaintipHash", ::ChainActive().Tip()->GetBlockHash().GetHex()); objGetUTXOResponse.pushKV("bitmap", bitmapStringRepresentation); UniValue utxos(UniValue::VARR); @@ -590,10 +590,10 @@ static bool rest_blockhash_by_height(HTTPRequest* req, CBlockIndex* pblockindex = nullptr; { LOCK(cs_main); - if (blockheight > chainActive.Height()) { + if (blockheight > ::ChainActive().Height()) { return RESTERR(req, HTTP_NOT_FOUND, "Block height out of range"); } - pblockindex = chainActive[blockheight]; + pblockindex = ::ChainActive()[blockheight]; } switch (rf) { case RetFormat::BINARY: { diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f140999622..56018caf24 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -28,6 +28,7 @@ #include <sync.h> #include <txdb.h> #include <txmempool.h> +#include <undo.h> #include <util/strencodings.h> #include <util/system.h> #include <util/validation.h> @@ -182,7 +183,7 @@ static UniValue getblockcount(const JSONRPCRequest& request) }.ToString()); LOCK(cs_main); - return chainActive.Height(); + return ::ChainActive().Height(); } static UniValue getbestblockhash(const JSONRPCRequest& request) @@ -202,7 +203,7 @@ static UniValue getbestblockhash(const JSONRPCRequest& request) }.ToString()); LOCK(cs_main); - return chainActive.Tip()->GetBlockHash().GetHex(); + return ::ChainActive().Tip()->GetBlockHash().GetHex(); } void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex) @@ -381,7 +382,7 @@ static UniValue getdifficulty(const JSONRPCRequest& request) }.ToString()); LOCK(cs_main); - return GetDifficulty(chainActive.Tip()); + return GetDifficulty(::ChainActive().Tip()); } static std::string EntryDescriptionString() @@ -485,7 +486,10 @@ UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose) const uint256& hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); entryToJSON(pool, info, e); - o.pushKV(hash.ToString(), info); + // Mempool has unique entries so there is no advantage in using + // UniValue::pushKV, which checks if the key already exists in O(N). + // UniValue::__pushKV is used instead which currently is O(1). + o.__pushKV(hash.ToString(), info); } return o; } else { @@ -732,10 +736,10 @@ static UniValue getblockhash(const JSONRPCRequest& request) LOCK(cs_main); int nHeight = request.params[0].get_int(); - if (nHeight < 0 || nHeight > chainActive.Height()) + if (nHeight < 0 || nHeight > ::ChainActive().Height()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); - CBlockIndex* pblockindex = chainActive[nHeight]; + CBlockIndex* pblockindex = ::ChainActive()[nHeight]; return pblockindex->GetBlockHash().GetHex(); } @@ -791,7 +795,7 @@ static UniValue getblockheader(const JSONRPCRequest& request) { LOCK(cs_main); pblockindex = LookupBlockIndex(hash); - tip = chainActive.Tip(); + tip = ::ChainActive().Tip(); } if (!pblockindex) { @@ -828,6 +832,20 @@ static CBlock GetBlockChecked(const CBlockIndex* pblockindex) return block; } +static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) +{ + CBlockUndo blockUndo; + if (IsBlockPruned(pblockindex)) { + throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)"); + } + + if (!UndoReadFromDisk(blockUndo, pblockindex)) { + throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk"); + } + + return blockUndo; +} + static UniValue getblock(const JSONRPCRequest& request) { const RPCHelpMan help{"getblock", @@ -904,7 +922,7 @@ static UniValue getblock(const JSONRPCRequest& request) { LOCK(cs_main); pblockindex = LookupBlockIndex(hash); - tip = chainActive.Tip(); + tip = ::ChainActive().Tip(); if (!pblockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); @@ -1026,7 +1044,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) // too low to be a block time (corresponds to timestamp from Sep 2001). if (heightParam > 1000000000) { // Add a 2 hour buffer to include blocks which might have had old timestamps - CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0); + CBlockIndex* pindex = ::ChainActive().FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0); if (!pindex) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp."); } @@ -1034,7 +1052,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) } unsigned int height = (unsigned int) heightParam; - unsigned int chainHeight = (unsigned int) chainActive.Height(); + unsigned int chainHeight = (unsigned int) ::ChainActive().Height(); if (chainHeight < Params().PruneAfterHeight()) throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning."); else if (height > chainHeight) @@ -1333,10 +1351,10 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) LOCK(cs_main); - const CBlockIndex* tip = chainActive.Tip(); + const CBlockIndex* tip = ::ChainActive().Tip(); UniValue obj(UniValue::VOBJ); obj.pushKV("chain", Params().NetworkIDString()); - obj.pushKV("blocks", (int)chainActive.Height()); + obj.pushKV("blocks", (int)::ChainActive().Height()); obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1); obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); obj.pushKV("difficulty", (double)GetDifficulty(tip)); @@ -1433,11 +1451,11 @@ static UniValue getchaintips(const JSONRPCRequest& request) LOCK(cs_main); /* - * Idea: the set of chain tips is chainActive.tip, plus orphan blocks which do not have another orphan building off of them. + * Idea: the set of chain tips is ::ChainActive().tip, plus orphan blocks which do not have another orphan building off of them. * Algorithm: * - Make one pass through mapBlockIndex, picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers. * - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip. - * - add chainActive.Tip() + * - add ::ChainActive().Tip() */ std::set<const CBlockIndex*, CompareBlocksByHeight> setTips; std::set<const CBlockIndex*> setOrphans; @@ -1445,7 +1463,7 @@ static UniValue getchaintips(const JSONRPCRequest& request) for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex) { - if (!chainActive.Contains(item.second)) { + if (!::ChainActive().Contains(item.second)) { setOrphans.insert(item.second); setPrevs.insert(item.second->pprev); } @@ -1459,7 +1477,7 @@ static UniValue getchaintips(const JSONRPCRequest& request) } // Always report the currently active tip. - setTips.insert(chainActive.Tip()); + setTips.insert(::ChainActive().Tip()); /* Construct the output array. */ UniValue res(UniValue::VARR); @@ -1469,11 +1487,11 @@ static UniValue getchaintips(const JSONRPCRequest& request) obj.pushKV("height", block->nHeight); obj.pushKV("hash", block->phashBlock->GetHex()); - const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight; + const int branchLen = block->nHeight - ::ChainActive().FindFork(block)->nHeight; obj.pushKV("branchlen", branchLen); std::string status; - if (chainActive.Contains(block)) { + if (::ChainActive().Contains(block)) { // This block is part of the currently active chain. status = "active"; } else if (block->nStatus & BLOCK_FAILED_MASK) { @@ -1694,7 +1712,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) if (request.params[1].isNull()) { LOCK(cs_main); - pindex = chainActive.Tip(); + pindex = ::ChainActive().Tip(); } else { uint256 hash(ParseHashV(request.params[1], "blockhash")); LOCK(cs_main); @@ -1702,7 +1720,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - if (!chainActive.Contains(pindex)) { + if (!::ChainActive().Contains(pindex)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain"); } } @@ -1799,8 +1817,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) { const RPCHelpMan help{"getblockstats", "\nCompute per block statistics for a given window. All amounts are in satoshis.\n" - "It won't work for some heights with pruning.\n" - "It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.\n", + "It won't work for some heights with pruning.\n", { {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}}, {"stats", RPCArg::Type::ARR, /* default */ "all values", "Values to plot (see result below)", @@ -1863,7 +1880,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) CBlockIndex* pindex; if (request.params[0].isNum()) { const int height = request.params[0].get_int(); - const int current_tip = chainActive.Height(); + const int current_tip = ::ChainActive().Height(); if (height < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height)); } @@ -1871,14 +1888,14 @@ static UniValue getblockstats(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip)); } - pindex = chainActive[height]; + pindex = ::ChainActive()[height]; } else { const uint256 hash(ParseHashV(request.params[0], "hash_or_height")); pindex = LookupBlockIndex(hash); if (!pindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); } - if (!chainActive.Contains(pindex)) { + if (!::ChainActive().Contains(pindex)) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Block is not in chain %s", Params().NetworkIDString())); } } @@ -1895,6 +1912,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) } const CBlock block = GetBlockChecked(pindex); + const CBlockUndo blockUndo = GetUndoChecked(pindex); const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default) const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0; @@ -1908,10 +1926,6 @@ static UniValue getblockstats(const JSONRPCRequest& request) const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate"); const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight"); - if (loop_inputs && !g_txindex) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more of the selected stats requires -txindex enabled"); - } - CAmount maxfee = 0; CAmount maxfeerate = 0; CAmount minfee = MAX_MONEY; @@ -1932,7 +1946,8 @@ static UniValue getblockstats(const JSONRPCRequest& request) std::vector<std::pair<CAmount, int64_t>> feerate_array; std::vector<int64_t> txsize_array; - for (const auto& tx : block.vtx) { + for (size_t i = 0; i < block.vtx.size(); ++i) { + const auto& tx = block.vtx.at(i); outputs += tx->vout.size(); CAmount tx_total_out = 0; @@ -1976,14 +1991,9 @@ static UniValue getblockstats(const JSONRPCRequest& request) if (loop_inputs) { CAmount tx_total_in = 0; - for (const CTxIn& in : tx->vin) { - CTransactionRef tx_in; - uint256 hashBlock; - if (!GetTransaction(in.prevout.hash, tx_in, Params().GetConsensus(), hashBlock)) { - throw JSONRPCError(RPC_INTERNAL_ERROR, std::string("Unexpected internal error (tx index seems corrupt)")); - } - - CTxOut prevoutput = tx_in->vout[in.prevout.n]; + const auto& txundo = blockUndo.vtxundo.at(i - 1); + for (const Coin& coin: txundo.vprevout) { + const CTxOut& prevoutput = coin.out; tx_total_in += prevoutput.nValue; utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; @@ -2244,8 +2254,7 @@ UniValue scantxoutset(const JSONRPCRequest& request) desc_str = desc_uni.get_str(); UniValue range_uni = find_value(scanobject, "range"); if (!range_uni.isNull()) { - range = ParseRange(range_uni); - if (range.first < 0 || (range.second >> 31) != 0 || range.second >= range.first + 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range"); + range = ParseDescriptorRange(range_uni); } } else { throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object"); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 4de738a756..1831562100 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -40,10 +40,10 @@ * If 'height' is nonnegative, compute the estimate at the time when a given block was found. */ static UniValue GetNetworkHashPS(int lookup, int height) { - CBlockIndex *pb = chainActive.Tip(); + CBlockIndex *pb = ::ChainActive().Tip(); - if (height >= 0 && height < chainActive.Height()) - pb = chainActive[height]; + if (height >= 0 && height < ::ChainActive().Height()) + pb = ::ChainActive()[height]; if (pb == nullptr || !pb->nHeight) return 0; @@ -109,7 +109,7 @@ static UniValue generateBlocks(const CScript& coinbase_script, int nGenerate, ui { // Don't keep cs_main locked LOCK(cs_main); - nHeight = chainActive.Height(); + nHeight = ::ChainActive().Height(); nHeightEnd = nHeight+nGenerate; } unsigned int nExtraNonce = 0; @@ -122,7 +122,7 @@ static UniValue generateBlocks(const CScript& coinbase_script, int nGenerate, ui CBlock *pblock = &pblocktemplate->block; { LOCK(cs_main); - IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); + IncrementExtraNonce(pblock, ::ChainActive().Tip(), nExtraNonce); } while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { ++pblock->nNonce; @@ -210,10 +210,10 @@ static UniValue getmininginfo(const JSONRPCRequest& request) LOCK(cs_main); UniValue obj(UniValue::VOBJ); - obj.pushKV("blocks", (int)chainActive.Height()); + obj.pushKV("blocks", (int)::ChainActive().Height()); if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight); if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs); - obj.pushKV("difficulty", (double)GetDifficulty(chainActive.Tip())); + obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip())); obj.pushKV("networkhashps", getnetworkhashps(request)); obj.pushKV("pooledtx", (uint64_t)mempool.size()); obj.pushKV("chain", Params().NetworkIDString()); @@ -409,7 +409,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) return "duplicate-inconclusive"; } - CBlockIndex* const pindexPrev = chainActive.Tip(); + CBlockIndex* const pindexPrev = ::ChainActive().Tip(); // TestBlockValidity only supports blocks built on the current Tip if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; @@ -465,7 +465,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) else { // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier - hashWatchedChain = chainActive.Tip()->GetBlockHash(); + hashWatchedChain = ::ChainActive().Tip()->GetBlockHash(); nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; } @@ -503,7 +503,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) static CBlockIndex* pindexPrev; static int64_t nStart; static std::unique_ptr<CBlockTemplate> pblocktemplate; - if (pindexPrev != chainActive.Tip() || + if (pindexPrev != ::ChainActive().Tip() || (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) { // Clear pindexPrev so future calls make a new block, despite any failures from here on @@ -511,7 +511,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) // Store the pindexBest used before CreateNewBlock, to avoid races nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrevNew = chainActive.Tip(); + CBlockIndex* pindexPrevNew = ::ChainActive().Tip(); nStart = GetTime(); // Create new block @@ -646,7 +646,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) result.pushKV("transactions", transactions); result.pushKV("coinbaseaux", aux); result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue); - result.pushKV("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)); + result.pushKV("longpollid", ::ChainActive().Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)); result.pushKV("target", hashTarget.GetHex()); result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1); result.pushKV("mutable", aMutable); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index bfb559f0db..7008a83143 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -24,6 +24,7 @@ #include <warnings.h> #include <stdint.h> +#include <tuple> #ifdef HAVE_MALLOC_INFO #include <malloc.h> #endif @@ -215,18 +216,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request) int64_t range_end = 0; if (request.params.size() >= 2 && !request.params[1].isNull()) { - auto range = ParseRange(request.params[1]); - if (range.first < 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0"); - } - if ((range.second >> 31) != 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high"); - } - if (range.second >= range.first + 1000000) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large"); - } - range_begin = range.first; - range_end = range.second; + std::tie(range_begin, range_end) = ParseDescriptorRange(request.params[1]); } FlatSigningProvider key_provider; @@ -307,8 +297,8 @@ static UniValue verifymessage(const JSONRPCRequest& request) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } - const CKeyID *keyID = boost::get<CKeyID>(&destination); - if (!keyID) { + const PKHash *pkhash = boost::get<PKHash>(&destination); + if (!pkhash) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); } @@ -326,7 +316,7 @@ static UniValue verifymessage(const JSONRPCRequest& request) if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) return false; - return (pubkey.GetID() == *keyID); + return (pubkey.GetID() == *pkhash); } static UniValue signmessagewithprivkey(const JSONRPCRequest& request) diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index e8cdce623c..e49c3e031f 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -496,7 +496,7 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) obj.pushKV("protocolversion",PROTOCOL_VERSION); if(g_connman) obj.pushKV("localservices", strprintf("%016x", g_connman->GetLocalServices())); - obj.pushKV("localrelay", fRelayTxes); + obj.pushKV("localrelay", g_relay_txes); obj.pushKV("timeoffset", GetTimeOffset()); if (g_connman) { obj.pushKV("networkactive", g_connman->GetNetworkActive()); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 78d7bbc80c..b3926786db 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -64,8 +64,8 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry.pushKV("blockhash", hashBlock.GetHex()); CBlockIndex* pindex = LookupBlockIndex(hashBlock); if (pindex) { - if (chainActive.Contains(pindex)) { - entry.pushKV("confirmations", 1 + chainActive.Height() - pindex->nHeight); + if (::ChainActive().Contains(pindex)) { + entry.pushKV("confirmations", 1 + ::ChainActive().Height() - pindex->nHeight); entry.pushKV("time", pindex->GetBlockTime()); entry.pushKV("blocktime", pindex->GetBlockTime()); } @@ -184,7 +184,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) if (!blockindex) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found"); } - in_active_chain = chainActive.Contains(blockindex); + in_active_chain = ::ChainActive().Contains(blockindex); } bool f_txindex_ready = false; @@ -274,7 +274,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) for (const auto& tx : setTxids) { const Coin& coin = AccessByTxid(*pcoinsTip, tx); if (!coin.IsSpent()) { - pblockindex = chainActive[coin.nHeight]; + pblockindex = ::ChainActive()[coin.nHeight]; break; } } @@ -348,7 +348,7 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) LOCK(cs_main); const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash()); - if (!pindex || !chainActive.Contains(pindex) || pindex->nTx == 0) { + if (!pindex || !::ChainActive().Contains(pindex) || pindex->nTx == 0) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); } @@ -572,7 +572,7 @@ static UniValue decodescript(const JSONRPCRequest& request) if (type.isStr() && type.get_str() != "scripthash") { // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH, // don't return the address for a P2SH of the P2SH. - r.pushKV("p2sh", EncodeDestination(CScriptID(script))); + r.pushKV("p2sh", EncodeDestination(ScriptHash(script))); // 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") { @@ -599,7 +599,7 @@ static UniValue decodescript(const JSONRPCRequest& request) segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script)); } ScriptPubKeyToUniv(segwitScr, sr, /* fIncludeHex */ true); - sr.pushKV("p2sh-segwit", EncodeDestination(CScriptID(segwitScr))); + sr.pushKV("p2sh-segwit", EncodeDestination(ScriptHash(segwitScr))); r.pushKV("segwit", sr); } } diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 1a87c9f935..9cdb22001f 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -8,6 +8,8 @@ #include <tinyformat.h> #include <util/strencodings.h> +#include <tuple> + InitInterfaces* g_rpc_interfaces = nullptr; void RPCTypeCheck(const UniValue& params, @@ -181,7 +183,7 @@ public: return UniValue(UniValue::VOBJ); } - UniValue operator()(const CKeyID& keyID) const + UniValue operator()(const PKHash& keyID) const { UniValue obj(UniValue::VOBJ); obj.pushKV("isscript", false); @@ -189,7 +191,7 @@ public: return obj; } - UniValue operator()(const CScriptID& scriptID) const + UniValue operator()(const ScriptHash& scriptID) const { UniValue obj(UniValue::VOBJ); obj.pushKV("isscript", true); @@ -654,7 +656,7 @@ std::string RPCArg::ToString(const bool oneline) const assert(false); } -std::pair<int64_t, int64_t> ParseRange(const UniValue& value) +static std::pair<int64_t, int64_t> ParseRange(const UniValue& value) { if (value.isNum()) { return {0, value.get_int64()}; @@ -667,3 +669,19 @@ std::pair<int64_t, int64_t> ParseRange(const UniValue& value) } throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified as end or as [begin,end]"); } + +std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value) +{ + int64_t low, high; + std::tie(low, high) = ParseRange(value); + if (low < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0"); + } + if ((high >> 31) != 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high"); + } + if (high >= low + 1000000) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large"); + } + return {low, high}; +} diff --git a/src/rpc/util.h b/src/rpc/util.h index b5b5789253..e4fa8fc3d7 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -81,7 +81,7 @@ RPCErrorCode RPCErrorFromTransactionError(TransactionError terr); UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string = ""); //! Parse a JSON range specified as int64, or [int64, int64] -std::pair<int64_t, int64_t> ParseRange(const UniValue& value); +std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value); struct RPCArg { enum class Type { diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index a333d4d4ac..9be87fabb0 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -514,7 +514,7 @@ protected: { CKeyID id = keys[0].GetID(); out.pubkeys.emplace(id, keys[0]); - return Singleton(GetScriptForDestination(id)); + return Singleton(GetScriptForDestination(PKHash(id))); } public: PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {} @@ -544,12 +544,12 @@ protected: CKeyID id = keys[0].GetID(); out.pubkeys.emplace(id, keys[0]); ret.emplace_back(GetScriptForRawPubKey(keys[0])); // P2PK - ret.emplace_back(GetScriptForDestination(id)); // P2PKH + ret.emplace_back(GetScriptForDestination(PKHash(id))); // P2PKH if (keys[0].IsCompressed()) { CScript p2wpkh = GetScriptForDestination(WitnessV0KeyHash(id)); out.scripts.emplace(CScriptID(p2wpkh), p2wpkh); ret.emplace_back(p2wpkh); - ret.emplace_back(GetScriptForDestination(CScriptID(p2wpkh))); // P2SH-P2WPKH + ret.emplace_back(GetScriptForDestination(ScriptHash(p2wpkh))); // P2SH-P2WPKH } return ret; } @@ -572,7 +572,7 @@ public: class SHDescriptor final : public DescriptorImpl { protected: - std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(CScriptID(*script))); } + std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(ScriptHash(*script))); } public: SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {} }; diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 51bd2d6e9f..75fc2e84f1 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -90,7 +90,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, // This also applies to the P2WSH case. break; } - ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0)); + ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0)); break; } case TX_PUBKEYHASH: diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 31bfd04b0f..91a301bcdf 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -19,6 +19,10 @@ unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} +ScriptHash::ScriptHash(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {} + +PKHash::PKHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {} + WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in) { CSHA256().Write(in.data(), in.size()).Finalize(begin()); @@ -162,17 +166,17 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) if (!pubKey.IsValid()) return false; - addressRet = pubKey.GetID(); + addressRet = PKHash(pubKey); return true; } else if (whichType == TX_PUBKEYHASH) { - addressRet = CKeyID(uint160(vSolutions[0])); + addressRet = PKHash(uint160(vSolutions[0])); return true; } else if (whichType == TX_SCRIPTHASH) { - addressRet = CScriptID(uint160(vSolutions[0])); + addressRet = ScriptHash(uint160(vSolutions[0])); return true; } else if (whichType == TX_WITNESS_V0_KEYHASH) { WitnessV0KeyHash hash; @@ -217,7 +221,7 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std:: if (!pubKey.IsValid()) continue; - CTxDestination address = pubKey.GetID(); + CTxDestination address = PKHash(pubKey); addressRet.push_back(address); } @@ -250,13 +254,13 @@ public: return false; } - bool operator()(const CKeyID &keyID) const { + bool operator()(const PKHash &keyID) const { script->clear(); *script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG; return true; } - bool operator()(const CScriptID &scriptID) const { + bool operator()(const ScriptHash &scriptID) const { script->clear(); *script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL; return true; diff --git a/src/script/standard.h b/src/script/standard.h index f16068c413..e45e2d92cc 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -73,6 +73,22 @@ public: friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; } }; +struct PKHash : public uint160 +{ + PKHash() : uint160() {} + explicit PKHash(const uint160& hash) : uint160(hash) {} + explicit PKHash(const CPubKey& pubkey); + using uint160::uint160; +}; + +struct ScriptHash : public uint160 +{ + ScriptHash() : uint160() {} + explicit ScriptHash(const uint160& hash) : uint160(hash) {} + explicit ScriptHash(const CScript& script); + using uint160::uint160; +}; + struct WitnessV0ScriptHash : public uint256 { WitnessV0ScriptHash() : uint256() {} @@ -113,14 +129,14 @@ struct WitnessUnknown /** * A txout script template with a specific destination. It is either: * * CNoDestination: no destination set - * * CKeyID: TX_PUBKEYHASH destination (P2PKH) - * * CScriptID: TX_SCRIPTHASH destination (P2SH) + * * PKHash: TX_PUBKEYHASH destination (P2PKH) + * * ScriptHash: TX_SCRIPTHASH destination (P2SH) * * WitnessV0ScriptHash: TX_WITNESS_V0_SCRIPTHASH destination (P2WSH) * * WitnessV0KeyHash: TX_WITNESS_V0_KEYHASH destination (P2WPKH) * * WitnessUnknown: TX_WITNESS_UNKNOWN destination (P2W???) * A CTxDestination is the internal data type encoded in a bitcoin address */ -typedef boost::variant<CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination; +typedef boost::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination; /** Check whether a CTxDestination is a CNoDestination. */ bool IsValidDestination(const CTxDestination& dest); diff --git a/src/sync.cpp b/src/sync.cpp index e7c0a6f9bc..c2767b200a 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -2,6 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + #include <sync.h> #include <tinyformat.h> diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index db0b973463..7ba483173c 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -125,9 +125,9 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup) std::vector<BlockFilter> filters; std::vector<uint256> filter_hashes; - for (const CBlockIndex* block_index = chainActive.Genesis(); + for (const CBlockIndex* block_index = ::ChainActive().Genesis(); block_index != nullptr; - block_index = chainActive.Next(block_index)) { + block_index = ::ChainActive().Next(block_index)) { BOOST_CHECK(!filter_index.LookupFilter(block_index, filter)); BOOST_CHECK(!filter_index.LookupFilterHeader(block_index, filter_header)); BOOST_CHECK(!filter_index.LookupFilterRange(block_index->nHeight, block_index, filters)); @@ -153,9 +153,9 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup) { LOCK(cs_main); const CBlockIndex* block_index; - for (block_index = chainActive.Genesis(); + for (block_index = ::ChainActive().Genesis(); block_index != nullptr; - block_index = chainActive.Next(block_index)) { + block_index = ::ChainActive().Next(block_index)) { CheckFilterLookups(filter_index, block_index, last_header); } } @@ -164,9 +164,9 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup) const CBlockIndex* tip; { LOCK(cs_main); - tip = chainActive.Tip(); + tip = ::ChainActive().Tip(); } - CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); + CScript coinbase_script_pub_key = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey())); std::vector<std::shared_ptr<CBlock>> chainA, chainB; BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainA)); BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainB)); @@ -250,7 +250,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup) { LOCK(cs_main); - tip = chainActive.Tip(); + tip = ::ChainActive().Tip(); } BOOST_CHECK(filter_index.LookupFilterRange(0, tip, filters)); BOOST_CHECK(filter_index.LookupFilterHashRange(0, tip, filter_hashes)); diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 232c077c68..665975ca67 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -485,7 +485,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization) BOOST_CHECK_EQUAL(cc1.fCoinBase, false); BOOST_CHECK_EQUAL(cc1.nHeight, 203998U); BOOST_CHECK_EQUAL(cc1.out.nValue, CAmount{60000000000}); - BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35")))))); + BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35")))))); // Good example CDataStream ss2(ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"), SER_DISK, CLIENT_VERSION); @@ -494,7 +494,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization) BOOST_CHECK_EQUAL(cc2.fCoinBase, true); BOOST_CHECK_EQUAL(cc2.nHeight, 120891U); BOOST_CHECK_EQUAL(cc2.out.nValue, 110397); - BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4")))))); + BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4")))))); // Smallest possible example CDataStream ss3(ParseHex("000006"), SER_DISK, CLIENT_VERSION); diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 0d05b6514f..35911e507f 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -5,12 +5,13 @@ #include <crypto/aes.h> #include <crypto/chacha20.h> #include <crypto/poly1305.h> +#include <crypto/hkdf_sha256_32.h> +#include <crypto/hmac_sha256.h> +#include <crypto/hmac_sha512.h> #include <crypto/ripemd160.h> #include <crypto/sha1.h> #include <crypto/sha256.h> #include <crypto/sha512.h> -#include <crypto/hmac_sha256.h> -#include <crypto/hmac_sha512.h> #include <random.h> #include <util/strencodings.h> #include <test/setup_common.h> @@ -125,17 +126,36 @@ static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, b } } -static void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout) +static void TestChaCha20(const std::string &hex_message, const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout) { std::vector<unsigned char> key = ParseHex(hexkey); + std::vector<unsigned char> m = ParseHex(hex_message); ChaCha20 rng(key.data(), key.size()); rng.SetIV(nonce); rng.Seek(seek); std::vector<unsigned char> out = ParseHex(hexout); std::vector<unsigned char> outres; outres.resize(out.size()); - rng.Output(outres.data(), outres.size()); + assert(hex_message.empty() || m.size() == out.size()); + + // perform the ChaCha20 round(s), if message is provided it will output the encrypted ciphertext otherwise the keystream + if (!hex_message.empty()) { + rng.Crypt(m.data(), outres.data(), outres.size()); + } else { + rng.Keystream(outres.data(), outres.size()); + } BOOST_CHECK(out == outres); + if (!hex_message.empty()) { + // Manually XOR with the keystream and compare the output + rng.SetIV(nonce); + rng.Seek(seek); + std::vector<unsigned char> only_keystream(outres.size()); + rng.Keystream(only_keystream.data(), only_keystream.size()); + for (size_t i = 0; i != m.size(); i++) { + outres[i] = m[i] ^ only_keystream[i]; + } + BOOST_CHECK(out == outres); + } } static void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag) @@ -149,6 +169,22 @@ static void TestPoly1305(const std::string &hexmessage, const std::string &hexke BOOST_CHECK(tag == tagres); } +static void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &salt_hex, const std::string &info_hex, const std::string &okm_check_hex) { + std::vector<unsigned char> initial_key_material = ParseHex(ikm_hex); + std::vector<unsigned char> salt = ParseHex(salt_hex); + std::vector<unsigned char> info = ParseHex(info_hex); + + + // our implementation only supports strings for the "info" and "salt", stringify them + std::string salt_stringified(reinterpret_cast<char*>(salt.data()), salt.size()); + std::string info_stringified(reinterpret_cast<char*>(info.data()), info.size()); + + CHKDF_HMAC_SHA256_L32 hkdf32(initial_key_material.data(), initial_key_material.size(), salt_stringified); + unsigned char out[32]; + hkdf32.Expand32(info_stringified, out); + BOOST_CHECK(HexStr(out, out + 32) == okm_check_hex); +} + static std::string LongTestString() { std::string ret; for (int i=0; i<200000; i++) { @@ -420,25 +456,37 @@ BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) { BOOST_AUTO_TEST_CASE(chacha20_testvector) { // Test vector from RFC 7539 - TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1, + + // test encryption + TestChaCha20("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756" + "c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e" + "20776f756c642062652069742e", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1, + "6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d" + "624e65152ab8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74" + "a35be6b40b8eedf2785e42874d" + ); + + // test keystream output + TestChaCha20("", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1, "224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cb" "a40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a" "832c89c167eacd901d7e2bf363"); // Test vectors from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7 - TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0, 0, + TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 0, 0, "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b" "8f41518a11cc387b669b2ee6586"); - TestChaCha20("0000000000000000000000000000000000000000000000000000000000000001", 0, 0, + TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000001", 0, 0, "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d79" "2b1c43fea817e9ad275ae546963"); - TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0, + TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0, "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b52770" "62eb7a0433e445f41e3"); - TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 1, 0, + TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 1, 0, "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc4" "97a0b466e7d6bbdb0041b2f586b"); - TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0, + TestChaCha20("", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0, "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3b" "e59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc1" "18be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5" @@ -517,6 +565,26 @@ BOOST_AUTO_TEST_CASE(poly1305_testvector) "13000000000000000000000000000000"); } +BOOST_AUTO_TEST_CASE(hkdf_hmac_sha256_l32_tests) +{ + // Use rfc5869 test vectors but trucated to 32 bytes (our implementation only support length 32) + TestHKDF_SHA256_32( + /* IKM */ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + /* salt */ "000102030405060708090a0b0c", + /* info */ "f0f1f2f3f4f5f6f7f8f9", + /* expected OKM */ "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf"); + TestHKDF_SHA256_32( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c"); + TestHKDF_SHA256_32( + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "", + "", + "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d"); +} + BOOST_AUTO_TEST_CASE(countbits_tests) { FastRandomContext ctx; diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index bcb9a7c181..d47f395c15 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -90,8 +90,8 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) // This test requires that we have a chain with non-zero work. { LOCK(cs_main); - BOOST_CHECK(chainActive.Tip() != nullptr); - BOOST_CHECK(chainActive.Tip()->nChainWork > 0); + BOOST_CHECK(::ChainActive().Tip() != nullptr); + BOOST_CHECK(::ChainActive().Tip()->nChainWork > 0); } // Test starts here @@ -381,7 +381,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vin[0].scriptSig << OP_1; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); AddOrphanTx(MakeTransactionRef(tx), i); } @@ -397,7 +397,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vin[0].prevout.hash = txPrev->GetHash(); tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL)); AddOrphanTx(MakeTransactionRef(tx), i); @@ -411,7 +411,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) CMutableTransaction tx; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; - tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); tx.vin.resize(2777); for (unsigned int j = 0; j < tx.vin.size(); j++) { diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index e816546e62..1b95105eab 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -68,10 +68,10 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(!key2C.VerifyPubKey(pubkey2)); BOOST_CHECK(key2C.VerifyPubKey(pubkey2C)); - BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID())); - BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID())); - BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID())); - BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID())); + BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(PKHash(pubkey1))); + BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(PKHash(pubkey2))); + BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(PKHash(pubkey1C))); + BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(PKHash(pubkey2C))); for (int n=0; n<16; n++) { @@ -188,4 +188,36 @@ BOOST_AUTO_TEST_CASE(key_signature_tests) BOOST_CHECK(found_small); } +BOOST_AUTO_TEST_CASE(key_key_negation) +{ + // create a dummy hash for signature comparison + unsigned char rnd[8]; + std::string str = "Bitcoin key verification\n"; + GetRandBytes(rnd, sizeof(rnd)); + uint256 hash; + CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin()); + + // import the static test key + CKey key = DecodeSecret(strSecret1C); + + // create a signature + std::vector<unsigned char> vch_sig; + std::vector<unsigned char> vch_sig_cmp; + key.Sign(hash, vch_sig); + + // negate the key twice + BOOST_CHECK(key.GetPubKey().data()[0] == 0x03); + key.Negate(); + // after the first negation, the signature must be different + key.Sign(hash, vch_sig_cmp); + BOOST_CHECK(vch_sig_cmp != vch_sig); + BOOST_CHECK(key.GetPubKey().data()[0] == 0x02); + key.Negate(); + // after the second negation, we should have the original key and thus the + // same signature + key.Sign(hash, vch_sig_cmp); + BOOST_CHECK(vch_sig_cmp == vch_sig); + BOOST_CHECK(key.GetPubKey().data()[0] == 0x03); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 6ed4359059..4321d7d16e 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -8,15 +8,15 @@ #include <consensus/merkle.h> #include <consensus/tx_verify.h> #include <consensus/validation.h> -#include <validation.h> #include <miner.h> #include <policy/policy.h> #include <pubkey.h> #include <script/standard.h> #include <txmempool.h> #include <uint256.h> -#include <util/system.h> #include <util/strencodings.h> +#include <util/system.h> +#include <validation.h> #include <test/setup_common.h> @@ -82,11 +82,11 @@ struct { {2, 0xbbbeb305}, {2, 0xfe1c810a}, }; -static CBlockIndex CreateBlockIndex(int nHeight) +static CBlockIndex CreateBlockIndex(int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { CBlockIndex index; index.nHeight = nHeight; - index.pprev = chainActive.Tip(); + index.pprev = ::ChainActive().Tip(); return index; } @@ -231,17 +231,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { LOCK(cs_main); pblock->nVersion = 1; - pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1; + pblock->nTime = ::ChainActive().Tip()->GetMedianTimePast()+1; CMutableTransaction txCoinbase(*pblock->vtx[0]); txCoinbase.nVersion = 1; txCoinbase.vin[0].scriptSig = CScript(); txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce); - txCoinbase.vin[0].scriptSig.push_back(chainActive.Height()); + txCoinbase.vin[0].scriptSig.push_back(::ChainActive().Height()); txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this) txCoinbase.vout[0].scriptPubKey = CScript(); pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase)); if (txFirst.size() == 0) - baseheight = chainActive.Height(); + baseheight = ::ChainActive().Height(); if (txFirst.size() < 4) txFirst.push_back(pblock->vtx[0]); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); @@ -367,29 +367,29 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.clear(); // subsidy changing - int nHeight = chainActive.Height(); + int nHeight = ::ChainActive().Height(); // Create an actual 209999-long block chain (without valid blocks). - while (chainActive.Tip()->nHeight < 209999) { - CBlockIndex* prev = chainActive.Tip(); + while (::ChainActive().Tip()->nHeight < 209999) { + CBlockIndex* prev = ::ChainActive().Tip(); CBlockIndex* next = new CBlockIndex(); next->phashBlock = new uint256(InsecureRand256()); pcoinsTip->SetBestBlock(next->GetBlockHash()); next->pprev = prev; next->nHeight = prev->nHeight + 1; next->BuildSkip(); - chainActive.SetTip(next); + ::ChainActive().SetTip(next); } BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); // Extend to a 210000-long block chain. - while (chainActive.Tip()->nHeight < 210000) { - CBlockIndex* prev = chainActive.Tip(); + while (::ChainActive().Tip()->nHeight < 210000) { + CBlockIndex* prev = ::ChainActive().Tip(); CBlockIndex* next = new CBlockIndex(); next->phashBlock = new uint256(InsecureRand256()); pcoinsTip->SetBestBlock(next->GetBlockHash()); next->pprev = prev; next->nHeight = prev->nHeight + 1; next->BuildSkip(); - chainActive.SetTip(next); + ::ChainActive().SetTip(next); } BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); @@ -399,7 +399,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].scriptSig = CScript() << OP_1; tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE; script = CScript() << OP_0; - tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); + tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script)); hash = tx.GetHash(); mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; @@ -412,16 +412,16 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.clear(); // Delete the dummy blocks again. - while (chainActive.Tip()->nHeight > nHeight) { - CBlockIndex* del = chainActive.Tip(); - chainActive.SetTip(del->pprev); + while (::ChainActive().Tip()->nHeight > nHeight) { + CBlockIndex* del = ::ChainActive().Tip(); + ::ChainActive().SetTip(del->pprev); pcoinsTip->SetBestBlock(del->pprev->GetBlockHash()); delete del->phashBlock; delete del; } // non-final txs in mempool - SetMockTime(chainActive.Tip()->GetMedianTimePast()+1); + SetMockTime(::ChainActive().Tip()->GetMedianTimePast()+1); int flags = LOCKTIME_VERIFY_SEQUENCE|LOCKTIME_MEDIAN_TIME_PAST; // height map std::vector<int> prevheights; @@ -433,7 +433,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vin[0].prevout.hash = txFirst[0]->GetHash(); // only 1 transaction tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; - tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1; // txFirst[0] is the 2nd block + tx.vin[0].nSequence = ::ChainActive().Tip()->nHeight + 1; // txFirst[0] is the 2nd block prevheights[0] = baseheight + 1; tx.vout.resize(1); tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE; @@ -443,11 +443,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail - BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Sequence locks pass on 2nd block + BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, &prevheights, CreateBlockIndex(::ChainActive().Tip()->nHeight + 2))); // Sequence locks pass on 2nd block // relative time locked tx.vin[0].prevout.hash = txFirst[1]->GetHash(); - tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((chainActive.Tip()->GetMedianTimePast()+1-chainActive[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block + tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((::ChainActive().Tip()->GetMedianTimePast()+1-::ChainActive()[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block prevheights[0] = baseheight + 2; hash = tx.GetHash(); mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); @@ -455,36 +455,36 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) - chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast - BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 1))); // Sequence locks pass 512 seconds later + ::ChainActive().Tip()->GetAncestor(::ChainActive().Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast + BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, &prevheights, CreateBlockIndex(::ChainActive().Tip()->nHeight + 1))); // Sequence locks pass 512 seconds later for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) - chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -= 512; //undo tricked MTP + ::ChainActive().Tip()->GetAncestor(::ChainActive().Tip()->nHeight - i)->nTime -= 512; //undo tricked MTP // absolute height locked tx.vin[0].prevout.hash = txFirst[2]->GetHash(); tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1; prevheights[0] = baseheight + 3; - tx.nLockTime = chainActive.Tip()->nHeight + 1; + tx.nLockTime = ::ChainActive().Tip()->nHeight + 1; hash = tx.GetHash(); mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTx(CTransaction(tx), flags)); // Locktime fails BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass - BOOST_CHECK(IsFinalTx(CTransaction(tx), chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast())); // Locktime passes on 2nd block + BOOST_CHECK(IsFinalTx(CTransaction(tx), ::ChainActive().Tip()->nHeight + 2, ::ChainActive().Tip()->GetMedianTimePast())); // Locktime passes on 2nd block // absolute time locked tx.vin[0].prevout.hash = txFirst[3]->GetHash(); - tx.nLockTime = chainActive.Tip()->GetMedianTimePast(); + tx.nLockTime = ::ChainActive().Tip()->GetMedianTimePast(); prevheights.resize(1); prevheights[0] = baseheight + 4; hash = tx.GetHash(); mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx)); BOOST_CHECK(!CheckFinalTx(CTransaction(tx), flags)); // Locktime fails BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass - BOOST_CHECK(IsFinalTx(CTransaction(tx), chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later + BOOST_CHECK(IsFinalTx(CTransaction(tx), ::ChainActive().Tip()->nHeight + 2, ::ChainActive().Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later // mempool-dependent transactions (not added) tx.vin[0].prevout.hash = hash; - prevheights[0] = chainActive.Tip()->nHeight + 1; + prevheights[0] = ::ChainActive().Tip()->nHeight + 1; tx.nLockTime = 0; tx.vin[0].nSequence = 0; BOOST_CHECK(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes @@ -505,14 +505,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3U); // However if we advance height by 1 and time by 512, all of them should be mined for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) - chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast - chainActive.Tip()->nHeight++; - SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1); + ::ChainActive().Tip()->GetAncestor(::ChainActive().Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast + ::ChainActive().Tip()->nHeight++; + SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U); - chainActive.Tip()->nHeight--; + ::ChainActive().Tip()->nHeight--; SetMockTime(0); mempool.clear(); diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index 0ce5f09e42..9c4606f1b3 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -69,14 +69,14 @@ BOOST_AUTO_TEST_CASE(sign) // different keys, straight/P2SH, pubkey/pubkeyhash CScript standardScripts[4]; standardScripts[0] << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; - standardScripts[1] = GetScriptForDestination(key[1].GetPubKey().GetID()); + standardScripts[1] = GetScriptForDestination(PKHash(key[1].GetPubKey())); standardScripts[2] << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; - standardScripts[3] = GetScriptForDestination(key[2].GetPubKey().GetID()); + standardScripts[3] = GetScriptForDestination(PKHash(key[2].GetPubKey())); CScript evalScripts[4]; for (int i = 0; i < 4; i++) { BOOST_CHECK(keystore.AddCScript(standardScripts[i])); - evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i])); + evalScripts[i] = GetScriptForDestination(ScriptHash(standardScripts[i])); } CMutableTransaction txFrom; // Funding transaction: @@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(norecurse) CScript invalidAsScript; invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE; - CScript p2sh = GetScriptForDestination(CScriptID(invalidAsScript)); + CScript p2sh = GetScriptForDestination(ScriptHash(invalidAsScript)); CScript scriptSig; scriptSig << Serialize(invalidAsScript); @@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE(norecurse) // Try to recur, and verification should succeed because // the inner HASH160 <> EQUAL should only check the hash: - CScript p2sh2 = GetScriptForDestination(CScriptID(p2sh)); + CScript p2sh2 = GetScriptForDestination(ScriptHash(p2sh)); CScript scriptSig2; scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh); @@ -165,7 +165,7 @@ BOOST_AUTO_TEST_CASE(set) } CScript inner[4]; - inner[0] = GetScriptForDestination(key[0].GetPubKey().GetID()); + inner[0] = GetScriptForDestination(PKHash(key[0].GetPubKey())); inner[1] = GetScriptForMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+2)); inner[2] = GetScriptForMultisig(1, std::vector<CPubKey>(keys.begin(), keys.begin()+2)); inner[3] = GetScriptForMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+3)); @@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(set) CScript outer[4]; for (int i = 0; i < 4; i++) { - outer[i] = GetScriptForDestination(CScriptID(inner[i])); + outer[i] = GetScriptForDestination(ScriptHash(inner[i])); BOOST_CHECK(keystore.AddCScript(inner[i])); } @@ -253,7 +253,7 @@ BOOST_AUTO_TEST_CASE(switchover) CScript scriptSig; scriptSig << Serialize(notValid); - CScript fund = GetScriptForDestination(CScriptID(notValid)); + CScript fund = GetScriptForDestination(ScriptHash(notValid)); // Validation should succeed under old rules (hash is correct): @@ -284,11 +284,11 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txFrom.vout.resize(7); // First three are standard: - CScript pay1 = GetScriptForDestination(key[0].GetPubKey().GetID()); + CScript pay1 = GetScriptForDestination(PKHash(key[0].GetPubKey())); BOOST_CHECK(keystore.AddCScript(pay1)); CScript pay1of3 = GetScriptForMultisig(1, keys); - txFrom.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(pay1)); // P2SH (OP_CHECKSIG) + txFrom.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(pay1)); // P2SH (OP_CHECKSIG) txFrom.vout[0].nValue = 1000; txFrom.vout[1].scriptPubKey = pay1; // ordinary OP_CHECKSIG txFrom.vout[1].nValue = 2000; @@ -303,7 +303,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) oneAndTwo << OP_2 << ToByteVector(key[3].GetPubKey()) << ToByteVector(key[4].GetPubKey()) << ToByteVector(key[5].GetPubKey()); oneAndTwo << OP_3 << OP_CHECKMULTISIG; BOOST_CHECK(keystore.AddCScript(oneAndTwo)); - txFrom.vout[3].scriptPubKey = GetScriptForDestination(CScriptID(oneAndTwo)); + txFrom.vout[3].scriptPubKey = GetScriptForDestination(ScriptHash(oneAndTwo)); txFrom.vout[3].nValue = 4000; // vout[4] is max sigops: @@ -312,24 +312,24 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) fifteenSigops << ToByteVector(key[i%3].GetPubKey()); fifteenSigops << OP_15 << OP_CHECKMULTISIG; BOOST_CHECK(keystore.AddCScript(fifteenSigops)); - txFrom.vout[4].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops)); + txFrom.vout[4].scriptPubKey = GetScriptForDestination(ScriptHash(fifteenSigops)); txFrom.vout[4].nValue = 5000; // vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS CScript sixteenSigops; sixteenSigops << OP_16 << OP_CHECKMULTISIG; BOOST_CHECK(keystore.AddCScript(sixteenSigops)); - txFrom.vout[5].scriptPubKey = GetScriptForDestination(CScriptID(sixteenSigops)); + txFrom.vout[5].scriptPubKey = GetScriptForDestination(ScriptHash(sixteenSigops)); txFrom.vout[5].nValue = 5000; CScript twentySigops; twentySigops << OP_CHECKMULTISIG; BOOST_CHECK(keystore.AddCScript(twentySigops)); - txFrom.vout[6].scriptPubKey = GetScriptForDestination(CScriptID(twentySigops)); + txFrom.vout[6].scriptPubKey = GetScriptForDestination(ScriptHash(twentySigops)); txFrom.vout[6].nValue = 6000; AddCoins(coins, CTransaction(txFrom), 0); CMutableTransaction txTo; txTo.vout.resize(1); - txTo.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); + txTo.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[1].GetPubKey())); txTo.vin.resize(5); for (int i = 0; i < 5; i++) @@ -352,7 +352,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) CMutableTransaction txToNonStd1; txToNonStd1.vout.resize(1); - txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); + txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[1].GetPubKey())); txToNonStd1.vout[0].nValue = 1000; txToNonStd1.vin.resize(1); txToNonStd1.vin[0].prevout.n = 5; @@ -364,7 +364,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) CMutableTransaction txToNonStd2; txToNonStd2.vout.resize(1); - txToNonStd2.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID()); + txToNonStd2.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[1].GetPubKey())); txToNonStd2.vout[0].nValue = 1000; txToNonStd2.vin.resize(1); txToNonStd2.vin[0].prevout.n = 6; diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 36a2b1bee5..9f50083335 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -179,23 +179,23 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) s.clear(); s << ToByteVector(pubkey) << OP_CHECKSIG; BOOST_CHECK(ExtractDestination(s, address)); - BOOST_CHECK(boost::get<CKeyID>(&address) && - *boost::get<CKeyID>(&address) == pubkey.GetID()); + BOOST_CHECK(boost::get<PKHash>(&address) && + *boost::get<PKHash>(&address) == PKHash(pubkey)); // TX_PUBKEYHASH s.clear(); s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; BOOST_CHECK(ExtractDestination(s, address)); - BOOST_CHECK(boost::get<CKeyID>(&address) && - *boost::get<CKeyID>(&address) == pubkey.GetID()); + BOOST_CHECK(boost::get<PKHash>(&address) && + *boost::get<PKHash>(&address) == PKHash(pubkey)); // TX_SCRIPTHASH CScript redeemScript(s); // initialize with leftover P2PKH script s.clear(); s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; BOOST_CHECK(ExtractDestination(s, address)); - BOOST_CHECK(boost::get<CScriptID>(&address) && - *boost::get<CScriptID>(&address) == CScriptID(redeemScript)); + BOOST_CHECK(boost::get<ScriptHash>(&address) && + *boost::get<ScriptHash>(&address) == ScriptHash(redeemScript)); // TX_MULTISIG s.clear(); @@ -255,8 +255,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TX_PUBKEY); BOOST_CHECK_EQUAL(addresses.size(), 1U); BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) && - *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID()); + BOOST_CHECK(boost::get<PKHash>(&addresses[0]) && + *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); // TX_PUBKEYHASH s.clear(); @@ -265,8 +265,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH); BOOST_CHECK_EQUAL(addresses.size(), 1U); BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) && - *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID()); + BOOST_CHECK(boost::get<PKHash>(&addresses[0]) && + *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); // TX_SCRIPTHASH CScript redeemScript(s); // initialize with leftover P2PKH script @@ -276,8 +276,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH); BOOST_CHECK_EQUAL(addresses.size(), 1U); BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(boost::get<CScriptID>(&addresses[0]) && - *boost::get<CScriptID>(&addresses[0]) == CScriptID(redeemScript)); + BOOST_CHECK(boost::get<ScriptHash>(&addresses[0]) && + *boost::get<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript)); // TX_MULTISIG s.clear(); @@ -289,10 +289,10 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); BOOST_CHECK_EQUAL(addresses.size(), 2U); BOOST_CHECK_EQUAL(nRequired, 2); - BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) && - *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID()); - BOOST_CHECK(boost::get<CKeyID>(&addresses[1]) && - *boost::get<CKeyID>(&addresses[1]) == pubkeys[1].GetID()); + BOOST_CHECK(boost::get<PKHash>(&addresses[0]) && + *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); + BOOST_CHECK(boost::get<PKHash>(&addresses[1]) && + *boost::get<PKHash>(&addresses[1]) == PKHash(pubkeys[1])); // TX_NULL_DATA s.clear(); @@ -311,17 +311,17 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) CScript expected, result; - // CKeyID + // PKHash expected.clear(); expected << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; - result = GetScriptForDestination(pubkeys[0].GetID()); + result = GetScriptForDestination(PKHash(pubkeys[0])); BOOST_CHECK(result == expected); // CScriptID CScript redeemScript(result); expected.clear(); expected << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; - result = GetScriptForDestination(CScriptID(redeemScript)); + result = GetScriptForDestination(ScriptHash(redeemScript)); BOOST_CHECK(result == expected); // CNoDestination @@ -421,7 +421,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) // P2PKH compressed { CBasicKeyStore keystore; - scriptPubKey = GetScriptForDestination(pubkeys[0].GetID()); + scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0])); // Keystore does not have key result = IsMine(keystore, scriptPubKey); @@ -436,7 +436,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) // P2PKH uncompressed { CBasicKeyStore keystore; - scriptPubKey = GetScriptForDestination(uncompressedPubkey.GetID()); + scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey)); // Keystore does not have key result = IsMine(keystore, scriptPubKey); @@ -452,8 +452,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) { CBasicKeyStore keystore; - CScript redeemScript = GetScriptForDestination(pubkeys[0].GetID()); - scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); + CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0])); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); // Keystore does not have redeemScript or key result = IsMine(keystore, scriptPubKey); @@ -474,9 +474,9 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) { CBasicKeyStore keystore; - CScript redeemscript_inner = GetScriptForDestination(pubkeys[0].GetID()); - CScript redeemscript = GetScriptForDestination(CScriptID(redeemscript_inner)); - scriptPubKey = GetScriptForDestination(CScriptID(redeemscript)); + CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0])); + CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner)); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript)); BOOST_CHECK(keystore.AddCScript(redeemscript)); BOOST_CHECK(keystore.AddCScript(redeemscript_inner)); @@ -490,8 +490,8 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) { CBasicKeyStore keystore; - CScript redeemscript = GetScriptForDestination(pubkeys[0].GetID()); - CScript witnessscript = GetScriptForDestination(CScriptID(redeemscript)); + CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0])); + CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript)); scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript)); BOOST_CHECK(keystore.AddCScript(witnessscript)); @@ -506,7 +506,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) { CBasicKeyStore keystore; - CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID())); + CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0]))); scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript)); BOOST_CHECK(keystore.AddCScript(witnessscript)); @@ -520,7 +520,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) { CBasicKeyStore keystore; - CScript witnessscript_inner = GetScriptForDestination(pubkeys[0].GetID()); + CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0])); CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner)); scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript)); @@ -537,7 +537,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) CBasicKeyStore keystore; BOOST_CHECK(keystore.AddKey(keys[0])); - scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID())); + scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0]))); // Keystore implicitly has key and P2SH redeemScript BOOST_CHECK(keystore.AddCScript(scriptPubKey)); @@ -550,7 +550,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) CBasicKeyStore keystore; BOOST_CHECK(keystore.AddKey(uncompressedKey)); - scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(uncompressedPubkey.GetID())); + scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(uncompressedPubkey))); // Keystore has key, but no P2SH redeemScript result = IsMine(keystore, scriptPubKey); @@ -598,7 +598,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) BOOST_CHECK(keystore.AddKey(keys[1])); CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]}); - scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); // Keystore has no redeemScript result = IsMine(keystore, scriptPubKey); @@ -664,7 +664,7 @@ BOOST_AUTO_TEST_CASE(script_standard_IsMine) CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]}); CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript)); - scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); + scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); // Keystore has no witnessScript, P2SH redeemScript, or keys result = IsMine(keystore, scriptPubKey); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 588ae55a69..4798909e2f 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1211,7 +1211,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_CHECK(keystore.AddKey(key)); } - CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID())); + CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(PKHash(keys[0].GetPubKey()))); CMutableTransaction txTo = BuildSpendingTransaction(CScript(), CScriptWitness(), CTransaction(txFrom)); CScript& scriptPubKey = txFrom.vout[0].scriptPubKey; SignatureData scriptSig; @@ -1237,7 +1237,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) // P2SH, single-signature case: CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; BOOST_CHECK(keystore.AddCScript(pkSingle)); - scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); + scriptPubKey = GetScriptForDestination(ScriptHash(pkSingle)); BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL)); scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]); combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty); diff --git a/src/test/setup_common.cpp b/src/test/setup_common.cpp index 6b671b2400..5b454da52b 100644 --- a/src/test/setup_common.cpp +++ b/src/test/setup_common.cpp @@ -151,7 +151,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& { LOCK(cs_main); unsigned int extraNonce = 0; - IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); + IncrementExtraNonce(&block, ::ChainActive().Tip(), extraNonce); } while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 4efa023fbb..5c12ec13d2 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount) BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3U); BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21U); - CScript p2sh = GetScriptForDestination(CScriptID(s1)); + CScript p2sh = GetScriptForDestination(ScriptHash(s1)); CScript scriptSig; scriptSig << OP_0 << Serialize(s1); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount) BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3U); BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20U); - p2sh = GetScriptForDestination(CScriptID(s2)); + p2sh = GetScriptForDestination(ScriptHash(s2)); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0U); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0U); CScript scriptSig2; @@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) // Multisig nested in P2SH { CScript redeemScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY; - CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); + CScript scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); CScript scriptSig = CScript() << OP_0 << OP_0 << ToByteVector(redeemScript); BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CScriptWitness()); @@ -185,7 +185,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) { CScript p2pk = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; CScript scriptSig = GetScriptForWitness(p2pk); - CScript scriptPubKey = GetScriptForDestination(CScriptID(scriptSig)); + CScript scriptPubKey = GetScriptForDestination(ScriptHash(scriptSig)); scriptSig = CScript() << ToByteVector(scriptSig); CScriptWitness scriptWitness; scriptWitness.stack.push_back(std::vector<unsigned char>(0)); @@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost) { CScript witnessScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY; CScript redeemScript = GetScriptForWitness(witnessScript); - CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); + CScript scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); CScript scriptSig = CScript() << ToByteVector(redeemScript); CScriptWitness scriptWitness; scriptWitness.stack.push_back(std::vector<unsigned char>(0)); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 6242fdabd1..f5ff18c055 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -311,9 +311,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) dummyTransactions[1].vout.resize(2); dummyTransactions[1].vout[0].nValue = 21*CENT; - dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); + dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey())); dummyTransactions[1].vout[1].nValue = 22*CENT; - dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); + dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey())); AddCoins(coinsRet, CTransaction(dummyTransactions[1]), 0); return dummyTransactions; @@ -562,8 +562,8 @@ BOOST_AUTO_TEST_CASE(test_witness) CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); // P2SH pay-to-compressed-pubkey. - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey1)), output1, input1); - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey2)), output2, input2); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey1)), output1, input1); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey2)), output2, input2); ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1); CheckWithFlag(output1, input1, 0, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); @@ -587,8 +587,8 @@ BOOST_AUTO_TEST_CASE(test_witness) CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); // P2SH witness pay-to-compressed-pubkey (v0). - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1))), output1, input1); - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2))), output2, input2); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey1))), output1, input1); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey2))), output2, input2); ReplaceRedeemScript(input2.vin[0].scriptSig, GetScriptForWitness(scriptPubkey1)); CheckWithFlag(output1, input1, 0, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); @@ -612,8 +612,8 @@ BOOST_AUTO_TEST_CASE(test_witness) CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false); // P2SH pay-to-uncompressed-pubkey. - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey1L)), output1, input1); - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey2L)), output2, input2); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey1L)), output1, input1); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey2L)), output2, input2); ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1L); CheckWithFlag(output1, input1, 0, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); @@ -629,8 +629,8 @@ BOOST_AUTO_TEST_CASE(test_witness) CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2, false); // Signing disabled for P2SH witness pay-to-uncompressed-pubkey (v1). - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1, false); - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2, false); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey1L))), output1, input1, false); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey2L))), output2, input2, false); // Normal 2-of-2 multisig CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false); @@ -642,10 +642,10 @@ BOOST_AUTO_TEST_CASE(test_witness) CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); // P2SH 2-of-2 multisig - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptMulti)), output1, input1, false); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptMulti)), output1, input1, false); CheckWithFlag(output1, input1, 0, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, false); - CreateCreditAndSpend(keystore2, GetScriptForDestination(CScriptID(scriptMulti)), output2, input2, false); + CreateCreditAndSpend(keystore2, GetScriptForDestination(ScriptHash(scriptMulti)), output2, input2, false); CheckWithFlag(output2, input2, 0, true); CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, false); BOOST_CHECK(*output1 == *output2); @@ -666,10 +666,10 @@ BOOST_AUTO_TEST_CASE(test_witness) CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true); // P2SH witness 2-of-2 multisig - CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptMulti))), output1, input1, false); + CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptMulti))), output1, input1, false); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false); - CreateCreditAndSpend(keystore2, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptMulti))), output2, input2, false); + CreateCreditAndSpend(keystore2, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptMulti))), output2, input2, false); CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, true); CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false); BOOST_CHECK(*output1 == *output2); @@ -695,7 +695,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) t.vout[0].nValue = 90*CENT; CKey key; key.MakeNewKey(true); - t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); + t.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey())); std::string reason; BOOST_CHECK(IsStandardTx(CTransaction(t), reason)); diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp index 9d62b471c1..19561d4f67 100644 --- a/src/test/txindex_tests.cpp +++ b/src/test/txindex_tests.cpp @@ -56,7 +56,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup) // Check that new transactions in new blocks make it into the index. for (int i = 0; i < 10; i++) { - CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); + CScript coinbase_script_pub_key = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey())); std::vector<CMutableTransaction> no_txns; const CBlock& block = CreateAndProcessBlock(no_txns, coinbase_script_pub_key); const CTransaction& txn = *block.vtx[0]; diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 01018043b1..fe30d5f3a7 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -66,18 +66,27 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) // Test 1: block with both of those transactions should be rejected. block = CreateAndProcessBlock(spends, scriptPubKey); - BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + } // Test 2: ... and should be rejected if spend1 is in the memory pool BOOST_CHECK(ToMemPool(spends[0])); block = CreateAndProcessBlock(spends, scriptPubKey); - BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + } mempool.clear(); // Test 3: ... and should be rejected if spend2 is in the memory pool BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(spends, scriptPubKey); - BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash()); + } mempool.clear(); // Final sanity test: first spend in mempool, second in block, that's OK: @@ -85,7 +94,10 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) oneSpend.push_back(spends[0]); BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(oneSpend, scriptPubKey); - BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); + { + LOCK(cs_main); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash()); + } // spends[1] should have been removed from the mempool when the // block with spends[0] is accepted: BOOST_CHECK_EQUAL(mempool.size(), 0U); @@ -151,8 +163,8 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) } CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; - CScript p2sh_scriptPubKey = GetScriptForDestination(CScriptID(p2pk_scriptPubKey)); - CScript p2pkh_scriptPubKey = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); + CScript p2sh_scriptPubKey = GetScriptForDestination(ScriptHash(p2pk_scriptPubKey)); + CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey())); CScript p2wpkh_scriptPubKey = GetScriptForWitness(p2pkh_scriptPubKey); CBasicKeyStore keystore; @@ -220,7 +232,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey); LOCK(cs_main); - BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); + BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash()); BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash()); // Test P2SH: construct a transaction that is valid without P2SH, and diff --git a/src/test/util.cpp b/src/test/util.cpp index 05d3a97a59..64ecc6623a 100644 --- a/src/test/util.cpp +++ b/src/test/util.cpp @@ -84,7 +84,8 @@ std::shared_ptr<CBlock> PrepareBlock(const CScript& coinbase_scriptPubKey) .CreateNewBlock(coinbase_scriptPubKey) ->block); - block->nTime = ::chainActive.Tip()->GetMedianTimePast() + 1; + LOCK(cs_main); + block->nTime = ::ChainActive().Tip()->GetMedianTimePast() + 1; block->hashMerkleRoot = BlockMerkleRoot(*block); return block; diff --git a/src/test/util.h b/src/test/util.h index 8ba647ec3f..f90cb0d623 100644 --- a/src/test/util.h +++ b/src/test/util.h @@ -34,5 +34,37 @@ std::string getnewaddress(CWallet& w); /** Returns the generated coin */ CTxIn generatetoaddress(const std::string& address); +/** + * Increment a string. Useful to enumerate all fixed length strings with + * characters in [min_char, max_char]. + */ +template <typename CharType, size_t StringLength> +bool NextString(CharType (&string)[StringLength], CharType min_char, CharType max_char) +{ + for (CharType& elem : string) { + bool has_next = elem != max_char; + elem = elem < min_char || elem >= max_char ? min_char : CharType(elem + 1); + if (has_next) return true; + } + return false; +} + +/** + * Iterate over string values and call function for each string without + * successive duplicate characters. + */ +template <typename CharType, size_t StringLength, typename Fn> +void ForEachNoDup(CharType (&string)[StringLength], CharType min_char, CharType max_char, Fn&& fn) { + for (bool has_next = true; has_next; has_next = NextString(string, min_char, max_char)) { + int prev = -1; + bool skip_string = false; + for (CharType c : string) { + if (c == prev) skip_string = true; + if (skip_string || c < min_char || c > max_char) break; + prev = c; + } + if (!skip_string) fn(); + } +} #endif // BITCOIN_TEST_UTIL_H diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 0f1834240d..51dd25ed1c 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -7,6 +7,7 @@ #include <clientversion.h> #include <primitives/transaction.h> #include <sync.h> +#include <test/util.h> #include <util/strencodings.h> #include <util/moneystr.h> #include <test/setup_common.h> @@ -580,7 +581,7 @@ BOOST_AUTO_TEST_CASE(util_GetChainName) // Test different ways settings can be merged, and verify results. This test can // be used to confirm that updates to settings code don't change behavior -// unintentially. +// unintentionally. // // The test covers: // @@ -600,20 +601,22 @@ BOOST_AUTO_TEST_CASE(util_GetChainName) // outside a network section, and non-network specific settings like "-server" // that aren't sensitive to the network. // -struct SettingsMergeTestingSetup : public BasicTestingSetup { +struct ArgsMergeTestingSetup : public BasicTestingSetup { //! Max number of actions to sequence together. Can decrease this when //! debugging to make test results easier to understand. static constexpr int MAX_ACTIONS = 3; - enum Action { SET = 0, NEGATE, SECTION_SET, SECTION_NEGATE, END }; + enum Action { NONE, SET, NEGATE, SECTION_SET, SECTION_NEGATE }; using ActionList = Action[MAX_ACTIONS]; //! Enumerate all possible test configurations. template <typename Fn> void ForEachMergeSetup(Fn&& fn) { - ForEachActionList([&](const ActionList& arg_actions) { - ForEachActionList([&](const ActionList& conf_actions) { + ActionList arg_actions = {}; + ForEachNoDup(arg_actions, SET, SECTION_NEGATE, [&] { + ActionList conf_actions = {}; + ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] { for (bool soft_set : {false, true}) { for (bool force_set : {false, true}) { for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) { @@ -629,36 +632,6 @@ struct SettingsMergeTestingSetup : public BasicTestingSetup { }); } - //! Enumerate interesting combinations of actions. - template <typename Fn> - void ForEachActionList(Fn&& fn) - { - ActionList actions = {SET}; - for (bool done = false; !done;) { - int prev_action = -1; - bool skip_actions = false; - for (Action action : actions) { - if ((prev_action == END && action != END) || (prev_action != END && action == prev_action)) { - // To cut down list of enumerated settings, skip enumerating - // settings with ignored actions after an END, and settings that - // repeat the same action twice in a row. - skip_actions = true; - break; - } - prev_action = action; - } - if (!skip_actions) fn(actions); - done = true; - for (Action& action : actions) { - action = Action(action < END ? action + 1 : 0); - if (action) { - done = false; - break; - } - } - } - } - //! Translate actions into a list of <key>=<value> setting strings. std::vector<std::string> GetValues(const ActionList& actions, const std::string& section, @@ -668,7 +641,7 @@ struct SettingsMergeTestingSetup : public BasicTestingSetup { std::vector<std::string> values; int suffix = 0; for (Action action : actions) { - if (action == END) break; + if (action == NONE) break; std::string prefix; if (action == SECTION_SET || action == SECTION_NEGATE) prefix = section + "."; if (action == SET || action == SECTION_SET) { @@ -687,12 +660,12 @@ struct SettingsMergeTestingSetup : public BasicTestingSetup { // Regression test covering different ways config settings can be merged. The // test parses and merges settings, representing the results as strings that get // compared against an expected hash. To debug, the result strings can be dumped -// to a file (see below). -BOOST_FIXTURE_TEST_CASE(util_SettingsMerge, SettingsMergeTestingSetup) +// to a file (see comments below). +BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup) { CHash256 out_sha; FILE* out_file = nullptr; - if (const char* out_path = getenv("SETTINGS_MERGE_TEST_OUT")) { + if (const char* out_path = getenv("ARGS_MERGE_TEST_OUT")) { out_file = fsbridge::fopen(out_path, "w"); if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed"); } @@ -706,7 +679,7 @@ BOOST_FIXTURE_TEST_CASE(util_SettingsMerge, SettingsMergeTestingSetup) desc += network; parser.m_network = network; - const std::string& name = net_specific ? "server" : "wallet"; + const std::string& name = net_specific ? "wallet" : "server"; const std::string key = "-" + name; parser.AddArg(key, name, false, OptionsCategory::OPTIONS); if (net_specific) parser.SetNetworkOnlyArg(key); @@ -794,14 +767,116 @@ BOOST_FIXTURE_TEST_CASE(util_SettingsMerge, SettingsMergeTestingSetup) // If check below fails, should manually dump the results with: // - // SETTINGS_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_SettingsMerge + // ARGS_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ArgsMerge // // And verify diff against previous results to make sure the changes are expected. // // Results file is formatted like: // // <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output> - BOOST_CHECK_EQUAL(out_sha_hex, "80964e17fbd3c5569d3c824d032e28e2d319ef57494735b0e76eb7aad9957f2c"); + BOOST_CHECK_EQUAL(out_sha_hex, "b835eef5977d69114eb039a976201f8c7121f34fe2b7ea2b73cafb516e5c9dc8"); +} + +// Similar test as above, but for ArgsManager::GetChainName function. +struct ChainMergeTestingSetup : public BasicTestingSetup { + static constexpr int MAX_ACTIONS = 2; + + enum Action { NONE, ENABLE_TEST, DISABLE_TEST, NEGATE_TEST, ENABLE_REG, DISABLE_REG, NEGATE_REG }; + using ActionList = Action[MAX_ACTIONS]; + + //! Enumerate all possible test configurations. + template <typename Fn> + void ForEachMergeSetup(Fn&& fn) + { + ActionList arg_actions = {}; + ForEachNoDup(arg_actions, ENABLE_TEST, NEGATE_REG, [&] { + ActionList conf_actions = {}; + ForEachNoDup(conf_actions, ENABLE_TEST, NEGATE_REG, [&] { fn(arg_actions, conf_actions); }); + }); + } +}; + +BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup) +{ + CHash256 out_sha; + FILE* out_file = nullptr; + if (const char* out_path = getenv("CHAIN_MERGE_TEST_OUT")) { + out_file = fsbridge::fopen(out_path, "w"); + if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed"); + } + + ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions) { + TestArgsManager parser; + LOCK(parser.cs_args); + parser.AddArg("-regtest", "regtest", false, OptionsCategory::OPTIONS); + parser.AddArg("-testnet", "testnet", false, OptionsCategory::OPTIONS); + + auto arg = [](Action action) { return action == ENABLE_TEST ? "-testnet=1" : + action == DISABLE_TEST ? "-testnet=0" : + action == NEGATE_TEST ? "-notestnet=1" : + action == ENABLE_REG ? "-regtest=1" : + action == DISABLE_REG ? "-regtest=0" : + action == NEGATE_REG ? "-noregtest=1" : nullptr; }; + + std::string desc; + std::vector<const char*> argv = {"ignored"}; + for (Action action : arg_actions) { + const char* argstr = arg(action); + if (!argstr) break; + argv.push_back(argstr); + desc += " "; + desc += argv.back(); + } + std::string error; + BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error)); + BOOST_CHECK_EQUAL(error, ""); + + std::string conf; + for (Action action : conf_actions) { + const char* argstr = arg(action); + if (!argstr) break; + desc += " "; + desc += argstr + 1; + conf += argstr + 1; + } + std::istringstream conf_stream(conf); + BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error)); + BOOST_CHECK_EQUAL(error, ""); + + desc += " || "; + try { + desc += parser.GetChainName(); + } catch (const std::runtime_error& e) { + desc += "error: "; + desc += e.what(); + } + desc += "\n"; + + out_sha.Write((const unsigned char*)desc.data(), desc.size()); + if (out_file) { + BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size()); + } + }); + + if (out_file) { + if (fclose(out_file)) throw std::system_error(errno, std::generic_category(), "fclose failed"); + out_file = nullptr; + } + + unsigned char out_sha_bytes[CSHA256::OUTPUT_SIZE]; + out_sha.Finalize(out_sha_bytes); + std::string out_sha_hex = HexStr(std::begin(out_sha_bytes), std::end(out_sha_bytes)); + + // If check below fails, should manually dump the results with: + // + // CHAIN_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ChainMerge + // + // And verify diff against previous results to make sure the changes are expected. + // + // Results file is formatted like: + // + // <input> || <output> + BOOST_CHECK_EQUAL(out_sha_hex, "b284f4b4a15dd6bf8c06213a69a004b1960388e1d9917173927db52ac220927f"); } BOOST_AUTO_TEST_CASE(util_FormatMoney) diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 4d54aa9b2c..5dee034b20 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering) const CBlockIndex* initial_tip = nullptr; { LOCK(cs_main); - initial_tip = chainActive.Tip(); + initial_tip = ::ChainActive().Tip(); } TestSubscriber sub(initial_tip->GetBlockHash()); RegisterValidationInterface(&sub); @@ -181,7 +181,8 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering) UnregisterValidationInterface(&sub); - BOOST_CHECK_EQUAL(sub.m_expected_tip, chainActive.Tip()->GetBlockHash()); + LOCK(cs_main); + BOOST_CHECK_EQUAL(sub.m_expected_tip, ::ChainActive().Tip()->GetBlockHash()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txmempool.h b/src/txmempool.h index 3ada47a28e..ce0b762336 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -496,7 +496,7 @@ public: * By design, it is guaranteed that: * * 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool - * that is consistent with current chain tip (`chainActive` and + * that is consistent with current chain tip (`::ChainActive()` and * `pcoinsTip`) and is fully populated. Fully populated means that if the * current active chain is missing transactions that were present in a * previously active chain, all the missing transactions will have been diff --git a/src/util/threadnames.cpp b/src/util/threadnames.cpp index 7b0d744aec..b221b0c975 100644 --- a/src/util/threadnames.cpp +++ b/src/util/threadnames.cpp @@ -9,6 +9,11 @@ #include <atomic> #include <thread> +#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) +#include <pthread.h> +#include <pthread_np.h> +#endif + #include <util/threadnames.h> #ifdef HAVE_SYS_PRCTL_H diff --git a/src/validation.cpp b/src/validation.cpp index ba9d6184ee..b2d84f4c95 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -157,14 +157,16 @@ private: CCriticalSection m_cs_chainstate; public: - CChain chainActive; + //! The current chain of blockheaders we consult and build on. + //! @see CChain, CBlockIndex. + CChain m_chain; BlockMap mapBlockIndex GUARDED_BY(cs_main); std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked; CBlockIndex *pindexBestInvalid = nullptr; bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock); + bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) LOCKS_EXCLUDED(cs_main); /** * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure @@ -183,11 +185,11 @@ public: // Manual block validity manipulation: bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); - bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex); + bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool ReplayBlocks(const CChainParams& params, CCoinsView* view); - bool RewindBlockIndex(const CChainParams& params); + bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main); bool LoadGenesisBlock(const CChainParams& chainparams); void PruneBlockIndexCandidates(); @@ -218,6 +220,8 @@ private: void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main); } g_chainstate; +CChain& ChainActive() { return g_chainstate.m_chain; } + /** * Mutex to guard access to validation specific variables, such as reading * or changing the chainstate. @@ -231,7 +235,6 @@ private: RecursiveMutex cs_main; BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex; -CChain& chainActive = g_chainstate.chainActive; CBlockIndex *pindexBestHeader = nullptr; Mutex g_best_block_mutex; std::condition_variable g_best_block_cv; @@ -336,13 +339,13 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // scheduled, so no flags are set. flags = std::max(flags, 0); - // CheckFinalTx() uses chainActive.Height()+1 to evaluate + // CheckFinalTx() uses ::ChainActive().Height()+1 to evaluate // nLockTime because when IsFinalTx() is called within // CBlock::AcceptBlock(), the height of the block *being* // evaluated is what is used. Thus if we want to know if a // transaction can be part of the *next* block, we need to call - // IsFinalTx() with one more than chainActive.Height(). - const int nBlockHeight = chainActive.Height() + 1; + // IsFinalTx() with one more than ::ChainActive().Height(). + const int nBlockHeight = ::ChainActive().Height() + 1; // BIP113 requires that time-locked transactions have nLockTime set to // less than the median time of the previous block they're contained in. @@ -350,7 +353,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // chain tip, so we use that to calculate the median time passed to // IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set. const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) - ? chainActive.Tip()->GetMedianTimePast() + ? ::ChainActive().Tip()->GetMedianTimePast() : GetAdjustedTime(); return IsFinalTx(tx, nBlockHeight, nBlockTime); @@ -363,9 +366,9 @@ bool TestLockPointValidity(const LockPoints* lp) // If there are relative lock times then the maxInputBlock will be set // If there are no relative lock times, the LockPoints don't depend on the chain if (lp->maxInputBlock) { - // Check whether chainActive is an extension of the block at which the LockPoints + // Check whether ::ChainActive() is an extension of the block at which the LockPoints // calculation was valid. If not LockPoints are no longer valid - if (!chainActive.Contains(lp->maxInputBlock)) { + if (!::ChainActive().Contains(lp->maxInputBlock)) { return false; } } @@ -379,17 +382,17 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag AssertLockHeld(cs_main); AssertLockHeld(pool.cs); - CBlockIndex* tip = chainActive.Tip(); + CBlockIndex* tip = ::ChainActive().Tip(); assert(tip != nullptr); CBlockIndex index; index.pprev = tip; - // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate + // CheckSequenceLocks() uses ::ChainActive().Height()+1 to evaluate // height based locks because when SequenceLocks() is called within // ConnectBlock(), the height of the block *being* // evaluated is what is used. // Thus if we want to know if a transaction can be part of the - // *next* block, we need to use one more than chainActive.Height() + // *next* block, we need to use one more than ::ChainActive().Height() index.nHeight = tip->nHeight + 1; std::pair<int, int64_t> lockPair; @@ -399,7 +402,7 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag lockPair.second = lp->time; } else { - // pcoinsTip contains the UTXO set for chainActive.Tip() + // pcoinsTip contains the UTXO set for ::ChainActive().Tip() CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool); std::vector<int> prevheights; prevheights.resize(tx.vin.size()); @@ -466,9 +469,9 @@ static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main) AssertLockHeld(cs_main); if (IsInitialBlockDownload()) return false; - if (chainActive.Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE)) + if (::ChainActive().Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE)) return false; - if (chainActive.Height() < pindexBestHeader->nHeight - 1) + if (::ChainActive().Height() < pindexBestHeader->nHeight - 1) return false; return true; } @@ -520,7 +523,7 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, mempool.UpdateTransactionsFromBlock(vHashUpdate); // We also need to remove any now-immature transactions - mempool.removeForReorg(pcoinsTip.get(), chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + mempool.removeForReorg(pcoinsTip.get(), ::ChainActive().Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); // Re-limit mempool size, in case we added any transactions LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); } @@ -727,7 +730,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool } } - CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, chainActive.Height(), + CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, ::ChainActive().Height(), fSpendsCoinbase, nSigOpsCost, lp); unsigned int nSize = entry.GetTxSize(); @@ -924,7 +927,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // There is a similar check in CreateNewBlock() to prevent creating // invalid blocks (using TestBlockValidity), however allowing such // transactions into the mempool can be exploited as a DoS attack. - unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(chainActive.Tip(), chainparams.GetConsensus()); + unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(::ChainActive().Tip(), chainparams.GetConsensus()); if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, currentBlockScriptVerifyFlags, true, txdata)) { return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); @@ -1178,11 +1181,11 @@ bool IsInitialBlockDownload() return false; if (fImporting || fReindex) return true; - if (chainActive.Tip() == nullptr) + if (::ChainActive().Tip() == nullptr) return true; - if (chainActive.Tip()->nChainWork < nMinimumChainWork) + if (::ChainActive().Tip()->nChainWork < nMinimumChainWork) return true; - if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge)) + if (::ChainActive().Tip()->GetBlockTime() < (GetTime() - nMaxTipAge)) return true; LogPrintf("Leaving InitialBlockDownload (latching to false)\n"); latchToFalse.store(true, std::memory_order_relaxed); @@ -1219,10 +1222,10 @@ static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main) // If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it) // of our head, drop it - if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72) + if (pindexBestForkTip && ::ChainActive().Height() - pindexBestForkTip->nHeight >= 72) pindexBestForkTip = nullptr; - if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6))) + if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6))) { if (!GetfLargeWorkForkFound() && pindexBestForkBase) { @@ -1255,7 +1258,7 @@ static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) E AssertLockHeld(cs_main); // If we are on a fork that is sufficiently large, set a warning flag CBlockIndex* pfork = pindexNewForkTip; - CBlockIndex* plonger = chainActive.Tip(); + CBlockIndex* plonger = ::ChainActive().Tip(); while (pfork && pfork != plonger) { while (plonger && plonger->nHeight > pfork->nHeight) @@ -1274,7 +1277,7 @@ static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) E // the 7-block condition and from this always have the most-likely-to-cause-warning fork if (pfork && (!pindexBestForkTip || pindexNewForkTip->nHeight > pindexBestForkTip->nHeight) && pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && - chainActive.Height() - pindexNewForkTip->nHeight < 72) + ::ChainActive().Height() - pindexNewForkTip->nHeight < 72) { pindexBestForkTip = pindexNewForkTip; pindexBestForkBase = pfork; @@ -1291,10 +1294,10 @@ void static InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(c LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime())); - CBlockIndex *tip = chainActive.Tip(); + CBlockIndex *tip = ::ChainActive().Tip(); assert (tip); LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__, - tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0), + tip->GetBlockHash().ToString(), ::ChainActive().Height(), log(tip->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(tip->GetBlockTime())); CheckForkWarningConditions(); } @@ -2193,7 +2196,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState & } if (full_flush_completed) { // Update best block in wallet (so we can detect restored wallets). - GetMainSignals().ChainStateFlushed(chainActive.GetLocator()); + GetMainSignals().ChainStateFlushed(::ChainActive().GetLocator()); } } catch (const std::runtime_error& e) { return AbortNode(state, std::string("System error while flushing: ") + e.what()); @@ -2285,7 +2288,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar } -/** Disconnect chainActive's tip. +/** Disconnect m_chain's tip. * After calling, the mempool will be in an inconsistent state, with * transactions from disconnected blocks being added to disconnectpool. You * should make the mempool consistent again by calling UpdateMempoolForReorg. @@ -2297,7 +2300,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar */ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool) { - CBlockIndex *pindexDelete = chainActive.Tip(); + CBlockIndex *pindexDelete = m_chain.Tip(); assert(pindexDelete); // Read block from disk. std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); @@ -2332,7 +2335,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha } } - chainActive.SetTip(pindexDelete->pprev); + m_chain.SetTip(pindexDelete->pprev); UpdateTip(pindexDelete->pprev, chainparams); // Let wallets know transactions went from 1-confirmed to @@ -2410,14 +2413,14 @@ public: }; /** - * Connect a new block to chainActive. pblock is either nullptr or a pointer to a CBlock + * Connect a new block to m_chain. pblock is either nullptr or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. * * The block is added to connectTrace if connection succeeds. */ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) { - assert(pindexNew->pprev == chainActive.Tip()); + assert(pindexNew->pprev == m_chain.Tip()); // Read block from disk. int64_t nTime1 = GetTimeMicros(); std::shared_ptr<const CBlock> pthisBlock; @@ -2458,8 +2461,8 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp // Remove conflicting transactions from the mempool.; mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight); disconnectpool.removeForBlock(blockConnecting.vtx); - // Update chainActive & related variables. - chainActive.SetTip(pindexNew); + // Update m_chain & related variables. + m_chain.SetTip(pindexNew); UpdateTip(pindexNew, chainparams); int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; @@ -2490,7 +2493,7 @@ CBlockIndex* CChainState::FindMostWorkChain() { // Just going until the active chain is an optimization, as we know all blocks in it are valid already. CBlockIndex *pindexTest = pindexNew; bool fInvalidAncestor = false; - while (pindexTest && !chainActive.Contains(pindexTest)) { + while (pindexTest && !m_chain.Contains(pindexTest)) { assert(pindexTest->HaveTxsDownloaded() || pindexTest->nHeight == 0); // Pruned nodes may have entries in setBlockIndexCandidates for @@ -2533,7 +2536,7 @@ void CChainState::PruneBlockIndexCandidates() { // Note that we can't delete the current block itself, as we may need to return to it later in case a // reorganization to a better block fails. std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin(); - while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) { + while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, m_chain.Tip())) { setBlockIndexCandidates.erase(it++); } // Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates. @@ -2548,13 +2551,13 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar { AssertLockHeld(cs_main); - const CBlockIndex *pindexOldTip = chainActive.Tip(); - const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); + const CBlockIndex *pindexOldTip = m_chain.Tip(); + const CBlockIndex *pindexFork = m_chain.FindFork(pindexMostWork); // Disconnect active blocks which are no longer in the best chain. bool fBlocksDisconnected = false; DisconnectedBlockTransactions disconnectpool; - while (chainActive.Tip() && chainActive.Tip() != pindexFork) { + while (m_chain.Tip() && m_chain.Tip() != pindexFork) { if (!DisconnectTip(state, chainparams, &disconnectpool)) { // This is likely a fatal error, but keep the mempool consistent, // just in case. Only remove from the mempool in this case. @@ -2602,7 +2605,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar } } else { PruneBlockIndexCandidates(); - if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { + if (!pindexOldTip || m_chain.Tip()->nChainWork > pindexOldTip->nChainWork) { // We're in a better position than we were. Return temporarily to release the lock. fContinue = false; break; @@ -2648,7 +2651,7 @@ static void NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) { } } -static void LimitValidationInterfaceQueue() { +static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) { AssertLockNotHeld(cs_main); if (GetMainSignals().CallbacksPending() > 10) { @@ -2694,7 +2697,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& { LOCK(cs_main); - CBlockIndex* starting_tip = chainActive.Tip(); + CBlockIndex* starting_tip = m_chain.Tip(); bool blocks_connected = false; do { // We absolutely may not unlock cs_main until we've made forward progress @@ -2706,7 +2709,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& } // Whether we have anything to do at all. - if (pindexMostWork == nullptr || pindexMostWork == chainActive.Tip()) { + if (pindexMostWork == nullptr || pindexMostWork == m_chain.Tip()) { break; } @@ -2720,16 +2723,16 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& // Wipe cache, we may need another branch now. pindexMostWork = nullptr; } - pindexNewTip = chainActive.Tip(); + pindexNewTip = m_chain.Tip(); for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) { assert(trace.pblock && trace.pindex); GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs); } - } while (!chainActive.Tip() || (starting_tip && CBlockIndexWorkComparator()(chainActive.Tip(), starting_tip))); + } while (!m_chain.Tip() || (starting_tip && CBlockIndexWorkComparator()(m_chain.Tip(), starting_tip))); if (!blocks_connected) return true; - const CBlockIndex* pindexFork = chainActive.FindFork(starting_tip); + const CBlockIndex* pindexFork = m_chain.FindFork(starting_tip); bool fInitialDownload = IsInitialBlockDownload(); // Notify external listeners about the new tip. @@ -2771,15 +2774,15 @@ bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& par { { LOCK(cs_main); - if (pindex->nChainWork < chainActive.Tip()->nChainWork) { + if (pindex->nChainWork < m_chain.Tip()->nChainWork) { // Nothing to do, this block is not at the tip. return true; } - if (chainActive.Tip()->nChainWork > nLastPreciousChainwork) { + if (m_chain.Tip()->nChainWork > nLastPreciousChainwork) { // The chain has been extended since the last call, reset the counter. nBlockReverseSequenceId = -1; } - nLastPreciousChainwork = chainActive.Tip()->nChainWork; + nLastPreciousChainwork = m_chain.Tip()->nChainWork; setBlockIndexCandidates.erase(pindex); pindex->nSequenceId = nBlockReverseSequenceId; if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) { @@ -2813,11 +2816,11 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c LimitValidationInterfaceQueue(); LOCK(cs_main); - if (!chainActive.Contains(pindex)) break; + if (!m_chain.Contains(pindex)) break; pindex_was_in_chain = true; - CBlockIndex *invalid_walk_tip = chainActive.Tip(); + CBlockIndex *invalid_walk_tip = m_chain.Tip(); - // ActivateBestChain considers blocks already in chainActive + // ActivateBestChain considers blocks already in m_chain // unconditionally valid already, so force disconnect away from it. DisconnectedBlockTransactions disconnectpool; bool ret = DisconnectTip(state, chainparams, &disconnectpool); @@ -2828,7 +2831,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c // keeping the mempool up to date is probably futile anyway). UpdateMempoolForReorg(disconnectpool, /* fAddToMempool = */ (++disconnected <= 10) && ret); if (!ret) return false; - assert(invalid_walk_tip->pprev == chainActive.Tip()); + assert(invalid_walk_tip->pprev == m_chain.Tip()); // We immediately mark the disconnected blocks as invalid. // This prevents a case where pruned nodes may fail to invalidateblock @@ -2853,7 +2856,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c { LOCK(cs_main); - if (chainActive.Contains(to_mark_failed)) { + if (m_chain.Contains(to_mark_failed)) { // If the to-be-marked invalid block is in the active chain, something is interfering and we can't proceed. return false; } @@ -2868,7 +2871,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c // add it again. BlockMap::iterator it = mapBlockIndex.begin(); while (it != mapBlockIndex.end()) { - if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) { + if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, m_chain.Tip())) { setBlockIndexCandidates.insert(it->second); } it++; @@ -2899,7 +2902,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) { it->second->nStatus &= ~BLOCK_FAILED_MASK; setDirtyBlockIndex.insert(it->second); - if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) { + if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && setBlockIndexCandidates.value_comp()(m_chain.Tip(), it->second)) { setBlockIndexCandidates.insert(it->second); } if (it->second == pindexBestInvalid) { @@ -2991,7 +2994,7 @@ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pi LOCK(cs_nBlockSequenceId); pindex->nSequenceId = nBlockSequenceId++; } - if (chainActive.Tip() == nullptr || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) { + if (m_chain.Tip() == nullptr || !setBlockIndexCandidates.value_comp()(pindex, m_chain.Tip())) { setBlockIndexCandidates.insert(pindex); } std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex); @@ -3221,7 +3224,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc } //! Returns last CBlockIndex* that is a checkpoint -static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) +static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { const MapCheckpoints& checkpoints = data.mapCheckpoints; @@ -3245,7 +3248,7 @@ static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) * in ConnectBlock(). * Note that -reindex-chainstate skips the validation that happens here! */ -static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) +static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { assert(pindexPrev != nullptr); const int nHeight = pindexPrev->nHeight + 1; @@ -3511,13 +3514,13 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali // process an unrequested block if it's new and has enough work to // advance our tip, and isn't too many blocks ahead. bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA; - bool fHasMoreOrSameWork = (chainActive.Tip() ? pindex->nChainWork >= chainActive.Tip()->nChainWork : true); + bool fHasMoreOrSameWork = (m_chain.Tip() ? pindex->nChainWork >= m_chain.Tip()->nChainWork : true); // Blocks that are too out-of-order needlessly limit the effectiveness of // pruning, because pruning will not delete block files that contain any // blocks which are too close in height to the tip. Apply this test // regardless of whether pruning is enabled; it should generally be safe to // not process unrequested blocks. - bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP)); + bool fTooFarAhead = (pindex->nHeight > int(m_chain.Height() + MIN_BLOCKS_TO_KEEP)); // TODO: Decouple this function from the block download logic by removing fRequested // This requires some new chain data structure to efficiently look up if a @@ -3551,7 +3554,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali // Header is valid/has work, merkle tree and segwit merkle tree are good...RELAY NOW // (but if it does not build on our best tip, let the SendMessages loop relay it) - if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev) + if (!IsInitialBlockDownload() && m_chain.Tip() == pindex->pprev) GetMainSignals().NewPoWValidBlock(pindex, pblock); // Write block to history file @@ -3612,7 +3615,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) { AssertLockHeld(cs_main); - assert(pindexPrev && pindexPrev == chainActive.Tip()); + assert(pindexPrev && pindexPrev == ::ChainActive().Tip()); CCoinsViewCache viewNew(pcoinsTip.get()); uint256 block_hash(block.GetHash()); CBlockIndex indexDummy(block); @@ -3701,11 +3704,11 @@ static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPr assert(fPruneMode && nManualPruneHeight > 0); LOCK2(cs_main, cs_LastBlockFile); - if (chainActive.Tip() == nullptr) + if (::ChainActive().Tip() == nullptr) return; // last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip) - unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP); + unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, ::ChainActive().Tip()->nHeight - MIN_BLOCKS_TO_KEEP); int count=0; for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { if (vinfoBlockFile[fileNumber].nSize == 0 || vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) @@ -3745,14 +3748,14 @@ void PruneBlockFilesManual(int nManualPruneHeight) static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight) { LOCK2(cs_main, cs_LastBlockFile); - if (chainActive.Tip() == nullptr || nPruneTarget == 0) { + if (::ChainActive().Tip() == nullptr || nPruneTarget == 0) { return; } - if ((uint64_t)chainActive.Tip()->nHeight <= nPruneAfterHeight) { + if ((uint64_t)::ChainActive().Tip()->nHeight <= nPruneAfterHeight) { return; } - unsigned int nLastBlockWeCanPrune = chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP; + unsigned int nLastBlockWeCanPrune = ::ChainActive().Tip()->nHeight - MIN_BLOCKS_TO_KEEP; uint64_t nCurrentUsage = CalculateCurrentUsage(); // We don't check to prune until after we've allocated new space for files // So we should leave a buffer under our target to account for another allocation @@ -3948,33 +3951,23 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_RE bool LoadChainTip(const CChainParams& chainparams) { AssertLockHeld(cs_main); + assert(!pcoinsTip->GetBestBlock().IsNull()); // Never called when the coins view is empty - if (chainActive.Tip() && chainActive.Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true; - - if (pcoinsTip->GetBestBlock().IsNull() && mapBlockIndex.size() == 1) { - // In case we just added the genesis block, connect it now, so - // that we always have a chainActive.Tip() when we return. - LogPrintf("%s: Connecting genesis block...\n", __func__); - CValidationState state; - if (!ActivateBestChain(state, chainparams)) { - LogPrintf("%s: failed to activate chain (%s)\n", __func__, FormatStateMessage(state)); - return false; - } - } + if (::ChainActive().Tip() && ::ChainActive().Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true; // Load pointer to end of best chain CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock()); if (!pindex) { return false; } - chainActive.SetTip(pindex); + ::ChainActive().SetTip(pindex); g_chainstate.PruneBlockIndexCandidates(); LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n", - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), - FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()), - GuessVerificationProgress(chainparams.TxData(), chainActive.Tip())); + ::ChainActive().Tip()->GetBlockHash().ToString(), ::ChainActive().Height(), + FormatISO8601DateTime(::ChainActive().Tip()->GetBlockTime()), + GuessVerificationProgress(chainparams.TxData(), ::ChainActive().Tip())); return true; } @@ -3991,12 +3984,12 @@ CVerifyDB::~CVerifyDB() bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) { LOCK(cs_main); - if (chainActive.Tip() == nullptr || chainActive.Tip()->pprev == nullptr) + if (::ChainActive().Tip() == nullptr || ::ChainActive().Tip()->pprev == nullptr) return true; // Verify blocks in the best chain - if (nCheckDepth <= 0 || nCheckDepth > chainActive.Height()) - nCheckDepth = chainActive.Height(); + if (nCheckDepth <= 0 || nCheckDepth > ::ChainActive().Height()) + nCheckDepth = ::ChainActive().Height(); nCheckLevel = std::max(0, std::min(4, nCheckLevel)); LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); CCoinsViewCache coins(coinsview); @@ -4006,16 +3999,16 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, CValidationState state; int reportDone = 0; LogPrintf("[0%%]..."); /* Continued */ - for (pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { + for (pindex = ::ChainActive().Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { boost::this_thread::interruption_point(); - const int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); + const int percentageDone = std::max(1, std::min(99, (int)(((double)(::ChainActive().Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); if (reportDone < percentageDone/10) { // report every 10% step LogPrintf("[%d%%]...", percentageDone); /* Continued */ reportDone = percentageDone/10; } uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false); - if (pindex->nHeight <= chainActive.Height()-nCheckDepth) + if (pindex->nHeight <= ::ChainActive().Height()-nCheckDepth) break; if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) { // If pruning, only go back as far as we have data. @@ -4057,23 +4050,23 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, return true; } if (pindexFailure) - return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); + return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", ::ChainActive().Height() - pindexFailure->nHeight + 1, nGoodTransactions); // store block count as we move pindex at check level >= 4 - int block_count = chainActive.Height() - pindex->nHeight; + int block_count = ::ChainActive().Height() - pindex->nHeight; // check level 4: try reconnecting blocks if (nCheckLevel >= 4) { - while (pindex != chainActive.Tip()) { + while (pindex != ::ChainActive().Tip()) { boost::this_thread::interruption_point(); - const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))); + const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(::ChainActive().Height() - pindex->nHeight)) / (double)nCheckDepth * 50))); if (reportDone < percentageDone/10) { // report every 10% step LogPrintf("[%d%%]...", percentageDone); /* Continued */ reportDone = percentageDone/10; } uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false); - pindex = chainActive.Next(pindex); + pindex = ::ChainActive().Next(pindex); CBlock block; if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); @@ -4183,7 +4176,7 @@ bool ReplayBlocks(const CChainParams& params, CCoinsView* view) { void CChainState::EraseBlockData(CBlockIndex* index) { AssertLockHeld(cs_main); - assert(!chainActive.Contains(index)); // Make sure this block isn't active + assert(!m_chain.Contains(index)); // Make sure this block isn't active // Reduce validity index->nStatus = std::min<unsigned int>(index->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | (index->nStatus & ~BLOCK_VALID_MASK); @@ -4217,7 +4210,7 @@ void CChainState::EraseBlockData(CBlockIndex* index) bool CChainState::RewindBlockIndex(const CChainParams& params) { - // Note that during -reindex-chainstate we are called with an empty chainActive! + // Note that during -reindex-chainstate we are called with an empty m_chain! // First erase all post-segwit blocks without witness not in the main chain, // as this can we done without costly DisconnectTip calls. Active @@ -4225,7 +4218,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params) { LOCK(cs_main); for (const auto& entry : mapBlockIndex) { - if (IsWitnessEnabled(entry.second->pprev, params.GetConsensus()) && !(entry.second->nStatus & BLOCK_OPT_WITNESS) && !chainActive.Contains(entry.second)) { + if (IsWitnessEnabled(entry.second->pprev, params.GetConsensus()) && !(entry.second->nStatus & BLOCK_OPT_WITNESS) && !m_chain.Contains(entry.second)) { EraseBlockData(entry.second); } } @@ -4236,17 +4229,17 @@ bool CChainState::RewindBlockIndex(const CChainParams& params) int nHeight = 1; { LOCK(cs_main); - while (nHeight <= chainActive.Height()) { + while (nHeight <= m_chain.Height()) { // Although SCRIPT_VERIFY_WITNESS is now generally enforced on all // blocks in ConnectBlock, we don't need to go back and // re-download/re-verify blocks from before segwit actually activated. - if (IsWitnessEnabled(chainActive[nHeight - 1], params.GetConsensus()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) { + if (IsWitnessEnabled(m_chain[nHeight - 1], params.GetConsensus()) && !(m_chain[nHeight]->nStatus & BLOCK_OPT_WITNESS)) { break; } nHeight++; } - tip = chainActive.Tip(); + tip = m_chain.Tip(); } // nHeight is now the height of the first insufficiently-validated block, or tipheight + 1 @@ -4256,7 +4249,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params) { LOCK(cs_main); // Make sure nothing changed from under us (this won't happen because RewindBlockIndex runs before importing/network are active) - assert(tip == chainActive.Tip()); + assert(tip == m_chain.Tip()); if (tip == nullptr || tip->nHeight < nHeight) break; if (fPruneMode && !(tip->nStatus & BLOCK_HAVE_DATA)) { // If pruning, don't try rewinding past the HAVE_DATA point; @@ -4276,9 +4269,9 @@ bool CChainState::RewindBlockIndex(const CChainParams& params) // We do this after actual disconnecting, otherwise we'll end up writing the lack of data // to disk before writing the chainstate, resulting in a failure to continue if interrupted. // Note: If we encounter an insufficiently validated block that - // is on chainActive, it must be because we are a pruning node, and + // is on m_chain, it must be because we are a pruning node, and // this block or some successor doesn't HAVE_DATA, so we were unable to - // rewind all the way. Blocks remaining on chainActive at this point + // rewind all the way. Blocks remaining on m_chain at this point // must not have their validity reduced. EraseBlockData(tip); @@ -4296,9 +4289,9 @@ bool CChainState::RewindBlockIndex(const CChainParams& params) { LOCK(cs_main); - if (chainActive.Tip() != nullptr) { + if (m_chain.Tip() != nullptr) { // We can't prune block index candidates based on our tip if we have - // no tip due to chainActive being empty! + // no tip due to m_chain being empty! PruneBlockIndexCandidates(); CheckBlockIndex(params.GetConsensus()); @@ -4313,8 +4306,8 @@ bool RewindBlockIndex(const CChainParams& params) { return false; } - if (chainActive.Tip() != nullptr) { - // FlushStateToDisk can possibly read chainActive. Be conservative + if (::ChainActive().Tip() != nullptr) { + // FlushStateToDisk can possibly read ::ChainActive(). Be conservative // and skip it here, we're about to -reindex-chainstate anyway, so // it'll get called a bunch real soon. CValidationState state; @@ -4339,7 +4332,7 @@ void CChainState::UnloadBlockIndex() { void UnloadBlockIndex() { LOCK(cs_main); - chainActive.SetTip(nullptr); + ::ChainActive().SetTip(nullptr); pindexBestInvalid = nullptr; pindexBestHeader = nullptr; mempool.clear(); @@ -4389,7 +4382,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams) LOCK(cs_main); // Check whether we're already initialized by checking for genesis in - // mapBlockIndex. Note that we can't use chainActive here, since it is + // mapBlockIndex. Note that we can't use m_chain here, since it is // set based on the coins db, not the block index db, which is the only // thing loaded at this point. if (mapBlockIndex.count(chainparams.GenesisBlock().GetHash())) @@ -4546,8 +4539,8 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams) // During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain, // so we have the genesis block in mapBlockIndex but no active chain. (A few of the tests when - // iterating the block tree require that chainActive has been initialized.) - if (chainActive.Height() < 0) { + // iterating the block tree require that m_chain has been initialized.) + if (m_chain.Height() < 0) { assert(mapBlockIndex.size() <= 1); return; } @@ -4591,7 +4584,7 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams) if (pindex->pprev == nullptr) { // Genesis block checks. assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match. - assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block. + assert(pindex == m_chain.Genesis()); // The current active chain's genesis block must be this block. } if (!pindex->HaveTxsDownloaded()) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock) // VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred). @@ -4620,13 +4613,13 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams) // Checks for not-invalid blocks. assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents. } - if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && pindexFirstNeverProcessed == nullptr) { + if (!CBlockIndexWorkComparator()(pindex, m_chain.Tip()) && pindexFirstNeverProcessed == nullptr) { if (pindexFirstInvalid == nullptr) { // If this block sorts at least as good as the current tip and // is valid and we have all data for its parents, it must be in - // setBlockIndexCandidates. chainActive.Tip() must also be there + // setBlockIndexCandidates. m_chain.Tip() must also be there // even if some data has been pruned. - if (pindexFirstMissing == nullptr || pindex == chainActive.Tip()) { + if (pindexFirstMissing == nullptr || pindex == m_chain.Tip()) { assert(setBlockIndexCandidates.count(pindex)); } // If some parent is missing, then it could be that this block was in @@ -4660,11 +4653,11 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams) // - it has a descendant that at some point had more work than the // tip, and // - we tried switching to that descendant but were missing - // data for some intermediate block between chainActive and the + // data for some intermediate block between m_chain and the // tip. - // So if this block is itself better than chainActive.Tip() and it wasn't in + // So if this block is itself better than m_chain.Tip() and it wasn't in // setBlockIndexCandidates, then it must be in mapBlocksUnlinked. - if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && setBlockIndexCandidates.count(pindex) == 0) { + if (!CBlockIndexWorkComparator()(pindex, m_chain.Tip()) && setBlockIndexCandidates.count(pindex) == 0) { if (pindexFirstInvalid == nullptr) { assert(foundInUnlinked); } @@ -4735,19 +4728,19 @@ CBlockFileInfo* GetBlockFileInfo(size_t n) ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos) { LOCK(cs_main); - return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache); + return VersionBitsState(::ChainActive().Tip(), params, pos, versionbitscache); } BIP9Stats VersionBitsTipStatistics(const Consensus::Params& params, Consensus::DeploymentPos pos) { LOCK(cs_main); - return VersionBitsStatistics(chainActive.Tip(), params, pos); + return VersionBitsStatistics(::ChainActive().Tip(), params, pos); } int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos) { LOCK(cs_main); - return VersionBitsStateSinceHeight(chainActive.Tip(), params, pos, versionbitscache); + return VersionBitsStateSinceHeight(::ChainActive().Tip(), params, pos, versionbitscache); } static const uint64_t MEMPOOL_DUMP_VERSION = 1; diff --git a/src/validation.h b/src/validation.h index 7ab6adaf33..ad978f0e05 100644 --- a/src/validation.h +++ b/src/validation.h @@ -176,7 +176,7 @@ extern bool fHavePruned; extern bool fPruneMode; /** Number of MiB of block files that we're trying to stay below. */ extern uint64_t nPruneTarget; -/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */ +/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ::ChainActive().Tip() will not be pruned. */ static const unsigned int MIN_BLOCKS_TO_KEEP = 288; /** Minimum blocks required to signal NODE_NETWORK_LIMITED */ static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288; @@ -393,7 +393,7 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params); /** When there are blocks in the active chain with missing data, rewind the chainstate and remove them from the block index */ -bool RewindBlockIndex(const CChainParams& params); +bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main); /** Update uncommitted block structures (currently: only the witness reserved value). This is safe for submitted blocks. */ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams); @@ -412,7 +412,7 @@ public: /** Replay blocks that aren't fully applied to the database. */ bool ReplayBlocks(const CChainParams& params, CCoinsView* view); -inline CBlockIndex* LookupBlockIndex(const uint256& hash) +inline CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); BlockMap::const_iterator it = mapBlockIndex.find(hash); @@ -430,13 +430,13 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main); /** Mark a block as invalid. */ -bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex); +bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); /** Remove invalidity status from a block and its descendants. */ void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); -/** The currently-connected chain of blocks (protected by cs_main). */ -extern CChain& chainActive; +/** @returns the most-work chain. */ +CChain& ChainActive(); /** Global variable that points to the coins database (protected by cs_main) */ extern std::unique_ptr<CCoinsViewDB> pcoinsdbview; diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index 9257b272bc..12ba032dff 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index a255177e36..dd56ea10ab 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 6a326bfd97..546e3d54eb 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -407,13 +407,6 @@ bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& er LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(nullptr, nullptr, nullptr)); LogPrintf("Using wallet %s\n", file_path.string()); - // Wallet file must be a plain filename without a directory - if (walletFile != fs::basename(walletFile) + fs::extension(walletFile)) - { - errorStr = strprintf(_("Wallet %s resides outside wallet directory %s"), walletFile, walletDir.string()); - return false; - } - if (!env->Open(true /* retry */)) { errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir); return false; diff --git a/src/wallet/db.h b/src/wallet/db.h index 762fb83a2f..b3856fbaf9 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index 78db4df5e5..15ddd5cb97 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h index f9cbfc5f68..0c4e1cb7dd 100644 --- a/src/wallet/feebumper.h +++ b/src/wallet/feebumper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp index d9ae18ed60..59d05a771a 100644 --- a/src/wallet/fees.cpp +++ b/src/wallet/fees.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 47ef01bfd1..0b8afd5a5d 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 79c5f439df..54aa12dba8 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/load.h b/src/wallet/load.h index 9bb6f2166e..81f078fd10 100644 --- a/src/wallet/load.h +++ b/src/wallet/load.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/psbtwallet.cpp b/src/wallet/psbtwallet.cpp index 1b17b09763..ce4788dee1 100644 --- a/src/wallet/psbtwallet.cpp +++ b/src/wallet/psbtwallet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index c339e111ba..3861b5524f 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -22,6 +22,7 @@ #include <wallet/rpcwallet.h> #include <stdint.h> +#include <tuple> #include <boost/algorithm/string.hpp> #include <boost/date_time/posix_time/posix_time.hpp> @@ -157,8 +158,11 @@ UniValue importprivkey(const JSONRPCRequest& request) if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); - if (fRescan && pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode"); + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned"); } if (fRescan && !reserver.reserve()) { @@ -252,7 +256,7 @@ static void ImportScript(CWallet* const pwallet, const CScript& script, const st if (!pwallet->HaveCScript(id) && !pwallet->AddCScript(script)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet"); } - ImportAddress(pwallet, id, strLabel); + ImportAddress(pwallet, ScriptHash(id), strLabel); } else { CTxDestination destination; if (ExtractDestination(script, destination)) { @@ -314,8 +318,11 @@ UniValue importaddress(const JSONRPCRequest& request) if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); - if (fRescan && pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode"); + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -507,8 +514,11 @@ UniValue importpubkey(const JSONRPCRequest& request) if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); - if (fRescan && pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode"); + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -573,8 +583,11 @@ UniValue importwallet(const JSONRPCRequest& request) }, }.ToString()); - if (pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode"); + if (pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -661,17 +674,17 @@ UniValue importwallet(const JSONRPCRequest& request) assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); if (pwallet->HaveKey(keyid)) { - pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid)); + pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(PKHash(keyid))); continue; } - pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid)); + pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(PKHash(keyid))); if (!pwallet->AddKeyPubKey(key, pubkey)) { fGood = false; continue; } pwallet->mapKeyMetadata[keyid].nCreateTime = time; if (has_label) - pwallet->SetAddressBook(keyid, label, "receive"); + pwallet->SetAddressBook(PKHash(keyid), label, "receive"); nTimeBegin = std::min(nTimeBegin, time); progress++; } @@ -807,19 +820,16 @@ UniValue dumpwallet(const JSONRPCRequest& request) if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); - std::map<CTxDestination, int64_t> mapKeyBirth; + std::map<CKeyID, int64_t> mapKeyBirth; const std::map<CKeyID, int64_t>& mapKeyPool = pwallet->GetAllReserveKeys(); pwallet->GetKeyBirthTimes(*locked_chain, mapKeyBirth); std::set<CScriptID> scripts = pwallet->GetCScripts(); - // TODO: include scripts in GetKeyBirthTimes() output instead of separate // sort time/key pairs std::vector<std::pair<int64_t, CKeyID> > vKeyBirth; for (const auto& entry : mapKeyBirth) { - if (const CKeyID* keyID = boost::get<CKeyID>(&entry.first)) { // set and test - vKeyBirth.push_back(std::make_pair(entry.second, *keyID)); - } + vKeyBirth.push_back(std::make_pair(entry.second, entry.first)); } mapKeyBirth.clear(); std::sort(vKeyBirth.begin(), vKeyBirth.end()); @@ -870,7 +880,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) for (const CScriptID &scriptid : scripts) { CScript script; std::string create_time = "0"; - std::string address = EncodeDestination(scriptid); + std::string address = EncodeDestination(ScriptHash(scriptid)); // get birth times for scripts with metadata auto it = pwallet->m_script_metadata.find(scriptid); if (it != pwallet->m_script_metadata.end()) { @@ -1144,12 +1154,7 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID if (!data.exists("range")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range"); } - auto range = ParseRange(data["range"]); - range_start = range.first; - range_end = range.second; - if (range_start < 0 || (range_end >> 31) != 0 || range_end - range_start >= 1000000) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid descriptor range specified"); - } + std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]); } const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 626cdccfee..96a74a338a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -550,13 +550,14 @@ static UniValue signmessage(const JSONRPCRequest& request) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } - const CKeyID *keyID = boost::get<CKeyID>(&dest); - if (!keyID) { + const PKHash *pkhash = boost::get<PKHash>(&dest); + if (!pkhash) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); } CKey key; - if (!pwallet->GetKey(*keyID, key)) { + CKeyID keyID(*pkhash); + if (!pwallet->GetKey(keyID, key)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); } @@ -2640,26 +2641,29 @@ static UniValue loadwallet(const JSONRPCRequest& request) static UniValue createwallet(const JSONRPCRequest& request) { - if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) { - throw std::runtime_error( - RPCHelpMan{"createwallet", - "\nCreates and loads a new wallet.\n", - { - {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."}, - {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."}, - {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."}, - }, - RPCResult{ + const RPCHelpMan help{ + "createwallet", + "\nCreates and loads a new wallet.\n", + { + {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."}, + {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."}, + {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."}, + {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."}, + }, + RPCResult{ "{\n" " \"name\" : <wallet_name>, (string) The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path.\n" " \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n" "}\n" - }, - RPCExamples{ - HelpExampleCli("createwallet", "\"testwallet\"") + }, + RPCExamples{ + HelpExampleCli("createwallet", "\"testwallet\"") + HelpExampleRpc("createwallet", "\"testwallet\"") - }, - }.ToString()); + }, + }; + + if (request.fHelp || !help.IsValidNumArgs(request.params.size())) { + throw std::runtime_error(help.ToString()); } std::string error; std::string warning; @@ -2669,7 +2673,20 @@ static UniValue createwallet(const JSONRPCRequest& request) flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; } + bool create_blank = false; // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted if (!request.params[2].isNull() && request.params[2].get_bool()) { + create_blank = true; + flags |= WALLET_FLAG_BLANK_WALLET; + } + SecureString passphrase; + passphrase.reserve(100); + if (!request.params[3].isNull()) { + passphrase = request.params[3].get_str().c_str(); + if (passphrase.empty()) { + // Empty string is invalid + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Cannot encrypt a wallet with a blank password"); + } + // Born encrypted wallets need to be blank first so that wallet creation doesn't make any unencrypted keys flags |= WALLET_FLAG_BLANK_WALLET; } @@ -2687,6 +2704,29 @@ static UniValue createwallet(const JSONRPCRequest& request) if (!wallet) { throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed."); } + + // Encrypt the wallet if there's a passphrase + if (!passphrase.empty() && !(flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + if (!wallet->EncryptWallet(passphrase)) { + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet created but failed to encrypt."); + } + + if (!create_blank) { + // Unlock the wallet + if (!wallet->Unlock(passphrase)) { + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet was encrypted but could not be unlocked"); + } + + // Set a seed for the wallet + CPubKey master_pub_key = wallet->GenerateNewSeed(); + wallet->SetHDSeed(master_pub_key); + wallet->NewKeyPool(); + + // Relock the wallet + wallet->Lock(); + } + } + AddWallet(wallet); wallet->postInitProcess(); @@ -2897,7 +2937,7 @@ static UniValue listunspent(const JSONRPCRequest& request) } if (scriptPubKey.IsPayToScriptHash()) { - const CScriptID& hash = boost::get<CScriptID>(address); + const CScriptID& hash = CScriptID(boost::get<ScriptHash>(address)); CScript redeemScript; if (pwallet->GetCScript(hash, redeemScript)) { entry.pushKV("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())); @@ -3537,8 +3577,9 @@ public: UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); } - UniValue operator()(const CKeyID& keyID) const + UniValue operator()(const PKHash& pkhash) const { + CKeyID keyID(pkhash); UniValue obj(UniValue::VOBJ); CPubKey vchPubKey; if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) { @@ -3548,8 +3589,9 @@ public: return obj; } - UniValue operator()(const CScriptID& scriptID) const + UniValue operator()(const ScriptHash& scripthash) const { + CScriptID scriptID(scripthash); UniValue obj(UniValue::VOBJ); CScript subscript; if (pwallet && pwallet->GetCScript(scriptID, subscript)) { @@ -4137,7 +4179,7 @@ static const CRPCCommand commands[] = { "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", "blank"} }, + { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase"} }, { "wallet", "dumpprivkey", &dumpprivkey, {"address"} }, { "wallet", "dumpwallet", &dumpwallet, {"filename"} }, { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h index 90617472cc..1c0523c90b 100644 --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index 34b9770e8b..9e7f0ed773 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp index d9b07af329..e4950af4e5 100644 --- a/src/wallet/test/db_tests.cpp +++ b/src/wallet/test/db_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h index 0f2d9fbd3d..e2b7075085 100644 --- a/src/wallet/test/init_test_fixture.h +++ b/src/wallet/test/init_test_fixture.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp index e1c53c83e2..9e5208b453 100644 --- a/src/wallet/test/init_tests.cpp +++ b/src/wallet/test/init_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp index f774cb4ad1..4753c7f313 100644 --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp index acc61c984f..2f41813234 100644 --- a/src/wallet/test/wallet_crypto_tests.cpp +++ b/src/wallet/test/wallet_crypto_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index 6526e69eea..e352c81519 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h index 1017e61700..c1dbecdf8c 100644 --- a/src/wallet/test/wallet_test_fixture.h +++ b/src/wallet/test/wallet_test_fixture.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 3cdbde33c3..62630c011a 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -12,12 +12,12 @@ #include <consensus/validation.h> #include <interfaces/chain.h> +#include <policy/policy.h> #include <rpc/server.h> #include <test/setup_common.h> #include <validation.h> #include <wallet/coincontrol.h> #include <wallet/test/wallet_test_fixture.h> -#include <policy/policy.h> #include <boost/test/unit_test.hpp> #include <univalue.h> @@ -36,16 +36,15 @@ static void AddKey(CWallet& wallet, const CKey& key) BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) { - auto chain = interfaces::MakeChain(); - // Cap last block file size, and mine new block in a new block file. - CBlockIndex* oldTip = chainActive.Tip(); + CBlockIndex* oldTip = ::ChainActive().Tip(); GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE; CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); - CBlockIndex* newTip = chainActive.Tip(); + CBlockIndex* newTip = ::ChainActive().Tip(); - LockAnnotation lock(::cs_main); + auto chain = interfaces::MakeChain(); auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); // Verify ScanForWalletTransactions accommodates a null start block. { @@ -116,16 +115,15 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) { - auto chain = interfaces::MakeChain(); - // Cap last block file size, and mine new block in a new block file. - CBlockIndex* oldTip = chainActive.Tip(); + CBlockIndex* oldTip = ::ChainActive().Tip(); GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE; CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); - CBlockIndex* newTip = chainActive.Tip(); + CBlockIndex* newTip = ::ChainActive().Tip(); - LockAnnotation lock(::cs_main); + auto chain = interfaces::MakeChain(); auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); // Prune the older block file. PruneOneBlockFile(oldTip->GetBlockPos().nFile); @@ -177,11 +175,9 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) // than or equal to key birthday. BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) { - auto chain = interfaces::MakeChain(); - // Create two blocks with same timestamp to verify that importwallet rescan // will pick up both blocks, not just the first. - const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5; + const int64_t BLOCK_TIME = ::ChainActive().Tip()->GetBlockTimeMax() + 5; SetMockTime(BLOCK_TIME); m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); @@ -192,7 +188,9 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) SetMockTime(KEY_TIME); m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); + auto chain = interfaces::MakeChain(); auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); std::string backup_file = (SetDataDir("importwallet_rescan") / "wallet.backup").string(); @@ -245,11 +243,15 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup) { auto chain = interfaces::MakeChain(); + CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy()); CWalletTx wtx(&wallet, m_coinbase_txns.back()); + auto locked_chain = chain->lock(); + LockAnnotation lock(::cs_main); LOCK(wallet.cs_wallet); - wtx.hashBlock = chainActive.Tip()->GetBlockHash(); + + wtx.hashBlock = ::ChainActive().Tip()->GetBlockHash(); wtx.nIndex = 0; // Call GetImmatureCredit() once before adding the key to the wallet to @@ -322,7 +324,7 @@ BOOST_AUTO_TEST_CASE(ComputeTimeSmart) BOOST_AUTO_TEST_CASE(LoadReceiveRequests) { - CTxDestination dest = CKeyID(); + CTxDestination dest = PKHash(); LOCK(m_wallet.cs_wallet); m_wallet.AddDestData(dest, "misc", "val_misc"); m_wallet.AddDestData(dest, "rr0", "val_rr0"); @@ -346,10 +348,10 @@ public: AddKey(*wallet, coinbaseKey); WalletRescanReserver reserver(wallet.get()); reserver.reserve(); - CWallet::ScanResult result = wallet->ScanForWalletTransactions(chainActive.Genesis()->GetBlockHash(), {} /* stop_block */, reserver, false /* update */); + CWallet::ScanResult result = wallet->ScanForWalletTransactions(::ChainActive().Genesis()->GetBlockHash(), {} /* stop_block */, reserver, false /* update */); BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS); - BOOST_CHECK_EQUAL(result.last_scanned_block, chainActive.Tip()->GetBlockHash()); - BOOST_CHECK_EQUAL(*result.last_scanned_height, chainActive.Height()); + BOOST_CHECK_EQUAL(result.last_scanned_block, ::ChainActive().Tip()->GetBlockHash()); + BOOST_CHECK_EQUAL(*result.last_scanned_height, ::ChainActive().Height()); BOOST_CHECK(result.last_failed_block.IsNull()); } @@ -366,7 +368,10 @@ public: int changePos = -1; std::string error; CCoinControl dummy; - BOOST_CHECK(wallet->CreateTransaction(*m_locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy)); + { + auto locked_chain = m_chain->lock(); + BOOST_CHECK(wallet->CreateTransaction(*locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy)); + } CValidationState state; BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, state)); CMutableTransaction blocktx; @@ -375,15 +380,16 @@ public: blocktx = CMutableTransaction(*wallet->mapWallet.at(tx->GetHash()).tx); } CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); + + LOCK(cs_main); LOCK(wallet->cs_wallet); auto it = wallet->mapWallet.find(tx->GetHash()); BOOST_CHECK(it != wallet->mapWallet.end()); - it->second.SetMerkleBranch(chainActive.Tip()->GetBlockHash(), 1); + it->second.SetMerkleBranch(::ChainActive().Tip()->GetBlockHash(), 1); return it->second; } std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain(); - std::unique_ptr<interfaces::Chain::Lock> m_locked_chain = m_chain->assumeLocked(); // Temporary. Removed in upcoming lock cleanup std::unique_ptr<CWallet> wallet; }; @@ -395,11 +401,12 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) // address. std::map<CTxDestination, std::vector<COutput>> list; { - LOCK2(cs_main, wallet->cs_wallet); - list = wallet->ListCoins(*m_locked_chain); + auto locked_chain = m_chain->lock(); + LOCK(wallet->cs_wallet); + list = wallet->ListCoins(*locked_chain); } BOOST_CHECK_EQUAL(list.size(), 1U); - BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress); + BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U); // Check initial balance from one mature coinbase transaction. @@ -411,18 +418,20 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) // pubkey. AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */}); { - LOCK2(cs_main, wallet->cs_wallet); - list = wallet->ListCoins(*m_locked_chain); + auto locked_chain = m_chain->lock(); + LOCK(wallet->cs_wallet); + list = wallet->ListCoins(*locked_chain); } BOOST_CHECK_EQUAL(list.size(), 1U); - BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress); + BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); // Lock both coins. Confirm number of available coins drops to 0. { - LOCK2(cs_main, wallet->cs_wallet); + auto locked_chain = m_chain->lock(); + LOCK(wallet->cs_wallet); std::vector<COutput> available; - wallet->AvailableCoins(*m_locked_chain, available); + wallet->AvailableCoins(*locked_chain, available); BOOST_CHECK_EQUAL(available.size(), 2U); } for (const auto& group : list) { @@ -432,19 +441,21 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) } } { - LOCK2(cs_main, wallet->cs_wallet); + auto locked_chain = m_chain->lock(); + LOCK(wallet->cs_wallet); std::vector<COutput> available; - wallet->AvailableCoins(*m_locked_chain, available); + wallet->AvailableCoins(*locked_chain, available); BOOST_CHECK_EQUAL(available.size(), 0U); } // Confirm ListCoins still returns same result as before, despite coins // being locked. { - LOCK2(cs_main, wallet->cs_wallet); - list = wallet->ListCoins(*m_locked_chain); + auto locked_chain = m_chain->lock(); + LOCK(wallet->cs_wallet); + list = wallet->ListCoins(*locked_chain); } BOOST_CHECK_EQUAL(list.size(), 1U); - BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress); + BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1a9e640a8a..260617c666 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -306,7 +306,7 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& secret, const C // check if we need to remove from watch-only CScript script; - script = GetScriptForDestination(pubkey.GetID()); + script = GetScriptForDestination(PKHash(pubkey)); if (HaveWatchOnly(script)) { RemoveWatchOnly(script); } @@ -449,7 +449,7 @@ bool CWallet::LoadCScript(const CScript& redeemScript) * these. Do not add them to the wallet and warn. */ if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) { - std::string strAddr = EncodeDestination(CScriptID(redeemScript)); + std::string strAddr = EncodeDestination(ScriptHash(redeemScript)); WalletLogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr); return true; } @@ -1288,7 +1288,7 @@ void CWallet::UpdatedBlockTip() void CWallet::BlockUntilSyncedToCurrentChain() { AssertLockNotHeld(cs_wallet); // Skip the queue-draining stuff if we know we're caught up with - // chainActive.Tip(), otherwise put a callback in the validation interface queue and wait + // ::ChainActive().Tip(), otherwise put a callback in the validation interface queue and wait // for the queue to drain enough to execute it (indicating we are caught up // at least with the time we entered this function). uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed); @@ -3711,7 +3711,7 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const /** @} */ // end of Actions -void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CTxDestination, int64_t>& mapKeyBirth) const { +void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CKeyID, int64_t>& mapKeyBirth) const { AssertLockHeld(cs_wallet); mapKeyBirth.clear(); @@ -4074,7 +4074,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, return nullptr; } - auto locked_chain = chain.assumeLocked(); // Temporary. Removed in upcoming lock cleanup + auto locked_chain = chain.lock(); walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { // Make it impossible to disable private keys after creation @@ -4209,10 +4209,13 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, if (tip_height && *tip_height != rescan_height) { - //We can't rescan beyond non-pruned blocks, stop and throw an error - //this might happen if a user uses an old wallet within a pruned node - // or if he ran -disablewallet for a longer time, then decided to re-enable - if (chain.getPruneMode()) { + // We can't rescan beyond non-pruned blocks, stop and throw an error. + // This might happen if a user uses an old wallet within a pruned node + // or if they ran -disablewallet for a longer time, then decided to re-enable + if (chain.havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will load the wallet, + // but fail the rescan with a generic error. int block_height = *tip_height; while (block_height > 0 && locked_chain->haveBlockOnDisk(block_height - 1) && rescan_height != block_height) { --block_height; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 30ea51c8a2..5e3bbe2f37 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -141,14 +141,61 @@ enum WalletFlags : uint64_t { static constexpr uint64_t g_known_wallet_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET | WALLET_FLAG_KEY_ORIGIN_METADATA; -/** A key pool entry */ +/** A key from a CWallet's keypool + * + * The wallet holds one (for pre HD-split wallets) or several keypools. These + * are sets of keys that have not yet been used to provide addresses or receive + * change. + * + * The Bitcoin Core wallet was originally a collection of unrelated private + * keys with their associated addresses. If a non-HD wallet generated a + * key/address, gave that address out and then restored a backup from before + * that key's generation, then any funds sent to that address would be + * lost definitively. + * + * The keypool was implemented to avoid this scenario (commit: 10384941). The + * wallet would generate a set of keys (100 by default). When a new public key + * was required, either to give out as an address or to use in a change output, + * it would be drawn from the keypool. The keypool would then be topped up to + * maintain 100 keys. This ensured that as long as the wallet hadn't used more + * than 100 keys since the previous backup, all funds would be safe, since a + * restored wallet would be able to scan for all owned addresses. + * + * A keypool also allowed encrypted wallets to give out addresses without + * having to be decrypted to generate a new private key. + * + * With the introduction of HD wallets (commit: f1902510), the keypool + * essentially became an address look-ahead pool. Restoring old backups can no + * longer definitively lose funds as long as the addresses used were from the + * wallet's HD seed (since all private keys can be rederived from the seed). + * However, if many addresses were used since the backup, then the wallet may + * not know how far ahead in the HD chain to look for its addresses. The + * keypool is used to implement a 'gap limit'. The keypool maintains a set of + * keys (by default 1000) ahead of the last used key and scans for the + * addresses of those keys. This avoids the risk of not seeing transactions + * involving the wallet's addresses, or of re-using the same address. + * + * The HD-split wallet feature added a second keypool (commit: 02592f4c). There + * is an external keypool (for addresses to hand out) and an internal keypool + * (for change addresses). + * + * Keypool keys are stored in the wallet/keystore's keymap. The keypool data is + * stored as sets of indexes in the wallet (setInternalKeyPool, + * setExternalKeyPool and set_pre_split_keypool), and a map from the key to the + * index (m_pool_key_to_index). The CKeyPool object is used to + * serialize/deserialize the pool data to/from the database. + */ class CKeyPool { public: + //! The time at which the key was generated. Set in AddKeypoolPubKeyWithDB int64_t nTime; + //! The public key CPubKey vchPubKey; - bool fInternal; // for change outputs - bool m_pre_split; // For keys generated before keypool split upgrade + //! Whether this keypool entry is in the internal keypool (for change outputs) + bool fInternal; + //! Whether this key was generated for a keypool before the wallet was upgraded to HD-split + bool m_pre_split; CKeyPool(); CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn); @@ -187,6 +234,57 @@ public: } }; +/** A wrapper to reserve a key from a wallet keypool + * + * CReserveKey is used to reserve a key from the keypool. It is passed around + * during the CreateTransaction/CommitTransaction procedure. + * + * Instantiating a CReserveKey does not reserve a keypool key. To do so, + * GetReservedKey() needs to be called on the object. Once a key has been + * reserved, call KeepKey() on the CReserveKey object to make sure it is not + * returned to the keypool. Call ReturnKey() to return the key to the keypool + * so it can be re-used (for example, if the key was used in a new transaction + * and that transaction was not completed and needed to be aborted). + * + * If a key is reserved and KeepKey() is not called, then the key will be + * returned to the keypool when the CReserveObject goes out of scope. + */ +class CReserveKey +{ +protected: + //! The wallet to reserve the keypool key from + CWallet* pwallet; + //! The index of the key in the keypool + int64_t nIndex{-1}; + //! The public key + CPubKey vchPubKey; + //! Whether this is from the internal (change output) keypool + bool fInternal{false}; + +public: + //! Construct a CReserveKey object. This does NOT reserve a key from the keypool yet + explicit CReserveKey(CWallet* pwalletIn) + { + pwallet = pwalletIn; + } + + CReserveKey(const CReserveKey&) = delete; + CReserveKey& operator=(const CReserveKey&) = delete; + + //! Destructor. If a key has been reserved and not KeepKey'ed, it will be returned to the keypool + ~CReserveKey() + { + ReturnKey(); + } + + //! Reserve a key from the keypool + bool GetReservedKey(CPubKey &pubkey, bool internal = false); + //! Return a key to the keypool + void ReturnKey(); + //! Keep the key. Do not return it to the keypool when this object goes out of scope + void KeepKey(); +}; + /** Address book data */ class CAddressBookData { @@ -875,7 +973,7 @@ public: bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); - void GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CTxDestination, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + void GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CKeyID, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); unsigned int ComputeTimeSmart(const CWalletTx& wtx) const; /** @@ -1201,34 +1299,6 @@ public: */ void MaybeResendWalletTxs(); -/** A key allocated from the key pool. */ -class CReserveKey -{ -protected: - CWallet* pwallet; - int64_t nIndex{-1}; - CPubKey vchPubKey; - bool fInternal{false}; - -public: - explicit CReserveKey(CWallet* pwalletIn) - { - pwallet = pwalletIn; - } - - CReserveKey(const CReserveKey&) = delete; - CReserveKey& operator=(const CReserveKey&) = delete; - - ~CReserveKey() - { - ReturnKey(); - } - - void ReturnKey(); - bool GetReservedKey(CPubKey &pubkey, bool internal = false); - void KeepKey(); -}; - /** RAII object to check and reserve a wallet rescan */ class WalletRescanReserver { diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 3122cd6fa4..ece97e2a75 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index 1ff1e8b840..5c1b086703 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h index 5b06fd1792..da848a747b 100644 --- a/src/wallet/wallettool.h +++ b/src/wallet/wallettool.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index b227a15556..04c2407a89 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. |