aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci/test/00_setup_env_native_fuzz_with_valgrind.sh2
-rwxr-xr-xci/test/00_setup_env_native_valgrind.sh2
-rwxr-xr-xci/test/06_script_b.sh6
-rw-r--r--configure.ac3
-rw-r--r--contrib/guix/manifest.scm3
-rwxr-xr-xcontrib/signet/miner101
-rw-r--r--contrib/valgrind.supp21
-rw-r--r--depends/packages/expat.mk9
-rw-r--r--depends/packages/qt.mk3
-rw-r--r--depends/patches/qt/fast_fixed_dtoa_no_optimize.patch20
-rw-r--r--src/.clang-tidy2
-rw-r--r--src/Makefile.am5
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/addrman.cpp149
-rw-r--r--src/addrman.h25
-rw-r--r--src/addrman_impl.h42
-rw-r--r--src/bench/addrman.cpp2
-rw-r--r--src/bench/checkblock.cpp1
-rw-r--r--src/bitcoin-chainstate.cpp29
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/bitcoin-tx.cpp2
-rw-r--r--src/bitcoin-util.cpp2
-rw-r--r--src/bitcoin-wallet.cpp2
-rw-r--r--src/bitcoind.cpp2
-rw-r--r--src/blockfilter.cpp2
-rw-r--r--src/chain.cpp7
-rw-r--r--src/chain.h24
-rw-r--r--src/chainparams.cpp2
-rw-r--r--src/compat/compat.h (renamed from src/compat.h)46
-rw-r--r--src/crypto/muhash.cpp4
-rw-r--r--src/dbwrapper.cpp19
-rw-r--r--src/dbwrapper.h16
-rw-r--r--src/external_signer.cpp2
-rw-r--r--src/hash.cpp4
-rw-r--r--src/hash.h36
-rw-r--r--src/httpserver.cpp2
-rw-r--r--src/i2p.cpp2
-rw-r--r--src/i2p.h2
-rw-r--r--src/index/base.cpp68
-rw-r--r--src/index/base.h28
-rw-r--r--src/index/blockfilterindex.cpp50
-rw-r--r--src/index/blockfilterindex.h12
-rw-r--r--src/index/coinstatsindex.cpp69
-rw-r--r--src/index/coinstatsindex.h10
-rw-r--r--src/index/txindex.cpp17
-rw-r--r--src/index/txindex.h4
-rw-r--r--src/init.cpp157
-rw-r--r--src/interfaces/chain.h31
-rw-r--r--src/kernel/chain.cpp26
-rw-r--r--src/kernel/chain.h19
-rw-r--r--src/kernel/checks.cpp11
-rw-r--r--src/kernel/checks.h10
-rw-r--r--src/kernel/coinstats.cpp24
-rw-r--r--src/kernel/coinstats.h6
-rw-r--r--src/mapport.cpp2
-rw-r--r--src/net.cpp33
-rw-r--r--src/net.h2
-rw-r--r--src/net_processing.cpp17
-rw-r--r--src/netaddress.h2
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/netbase.h2
-rw-r--r--src/node/blockstorage.cpp2
-rw-r--r--src/node/chainstate.cpp114
-rw-r--r--src/node/chainstate.h85
-rw-r--r--src/node/interfaces.cpp46
-rw-r--r--src/policy/fees.cpp16
-rw-r--r--src/policy/fees.h6
-rw-r--r--src/primitives/transaction.cpp7
-rw-r--r--src/primitives/transaction.h14
-rw-r--r--src/protocol.h11
-rw-r--r--src/psbt.h9
-rw-r--r--src/pubkey.cpp6
-rw-r--r--src/qt/bitcoingui.cpp8
-rw-r--r--src/qt/main.cpp2
-rw-r--r--src/qt/optionsdialog.cpp1
-rw-r--r--src/random.cpp2
-rw-r--r--src/random.h17
-rw-r--r--src/randomenv.cpp2
-rw-r--r--src/rpc/blockchain.cpp30
-rw-r--r--src/rpc/blockchain.h2
-rw-r--r--src/rpc/fees.cpp2
-rw-r--r--src/rpc/mempool.cpp1
-rw-r--r--src/rpc/mining.cpp4
-rw-r--r--src/rpc/net.cpp24
-rw-r--r--src/rpc/node.cpp6
-rw-r--r--src/rpc/rawtransaction.cpp32
-rw-r--r--src/script/interpreter.cpp32
-rw-r--r--src/script/interpreter.h6
-rw-r--r--src/script/sign.cpp2
-rw-r--r--src/script/standard.cpp8
-rw-r--r--src/serialize.h23
-rw-r--r--src/streams.h69
-rw-r--r--src/test/addrman_tests.cpp26
-rw-r--r--src/test/blockfilter_index_tests.cpp11
-rw-r--r--src/test/coinstatsindex_tests.cpp13
-rw-r--r--src/test/flatfile_tests.cpp12
-rw-r--r--src/test/fuzz/addrman.cpp18
-rw-r--r--src/test/fuzz/autofile.cpp4
-rw-r--r--src/test/fuzz/chain.cpp3
-rw-r--r--src/test/fuzz/parse_univalue.cpp2
-rw-r--r--src/test/fuzz/policy_estimator.cpp2
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp2
-rw-r--r--src/test/fuzz/tx_pool.cpp10
-rw-r--r--src/test/fuzz/txorphan.cpp2
-rw-r--r--src/test/fuzz/util.cpp5
-rw-r--r--src/test/fuzz/util.h14
-rw-r--r--src/test/fuzz/utxo_snapshot.cpp4
-rw-r--r--src/test/net_tests.cpp2
-rw-r--r--src/test/netbase_tests.cpp18
-rw-r--r--src/test/random_tests.cpp10
-rw-r--r--src/test/rbf_tests.cpp230
-rw-r--r--src/test/script_tests.cpp26
-rw-r--r--src/test/sock_tests.cpp2
-rw-r--r--src/test/system_tests.cpp5
-rw-r--r--src/test/txindex_tests.cpp5
-rw-r--r--src/test/util/chainstate.h6
-rw-r--r--src/test/util/net.h2
-rw-r--r--src/test/util/setup_common.cpp35
-rw-r--r--src/test/validation_chainstatemanager_tests.cpp10
-rw-r--r--src/threadinterrupt.cpp12
-rw-r--r--src/threadinterrupt.h5
-rw-r--r--src/timedata.h8
-rw-r--r--src/torcontrol.cpp2
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txdb.h1
-rw-r--r--src/univalue/include/univalue.h40
-rw-r--r--src/util/asmap.cpp2
-rw-r--r--src/util/message.cpp2
-rw-r--r--src/util/sock.cpp2
-rw-r--r--src/util/sock.h2
-rw-r--r--src/util/system.cpp2
-rw-r--r--src/util/system.h2
-rw-r--r--src/util/time.cpp2
-rw-r--r--src/util/time.h3
-rw-r--r--src/validation.cpp5
-rw-r--r--src/validation.h4
-rw-r--r--src/wallet/bdb.cpp1
-rw-r--r--src/wallet/dump.cpp4
-rw-r--r--src/wallet/receive.cpp58
-rw-r--r--src/wallet/receive.h6
-rw-r--r--src/wallet/rpc/addresses.cpp28
-rw-r--r--src/wallet/rpc/backup.cpp40
-rw-r--r--src/wallet/rpc/coins.cpp16
-rw-r--r--src/wallet/rpc/encrypt.cpp14
-rw-r--r--src/wallet/rpc/signmessage.cpp2
-rw-r--r--src/wallet/rpc/spend.cpp20
-rw-r--r--src/wallet/rpc/transactions.cpp18
-rw-r--r--src/wallet/rpc/wallet.cpp14
-rw-r--r--src/wallet/test/fuzz/notifications.cpp18
-rw-r--r--src/wallet/test/wallet_tests.cpp6
-rw-r--r--src/wallet/wallet.cpp23
-rw-r--r--src/wallet/wallet.h4
-rwxr-xr-xtest/functional/feature_addrman.py2
-rwxr-xr-xtest/functional/feature_taproot.py10
-rwxr-xr-xtest/functional/rpc_psbt.py56
-rwxr-xr-xtest/functional/test_framework/messages.py14
-rw-r--r--test/functional/test_framework/psbt.py131
-rw-r--r--test/functional/test_framework/util.py8
-rwxr-xr-xtest/functional/wallet_address_types.py28
-rwxr-xr-xtest/lint/lint-circular-dependencies.py3
160 files changed, 1696 insertions, 1198 deletions
diff --git a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
index 9477fb2d9f..97c530e19e 100755
--- a/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
+++ b/ci/test/00_setup_env_native_fuzz_with_valgrind.sh
@@ -16,5 +16,5 @@ export RUN_FUZZ_TESTS=true
export FUZZ_TESTS_CONFIG="--valgrind"
export GOAL="install"
# Temporarily pin dwarf 4, until valgrind can understand clang's dwarf 5
-export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang CXX=clang++ CXXFLAGS='-fdebug-default-version=4'"
+export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer CC=clang CXX=clang++ CFLAGS='-gdwarf-4' CXXFLAGS='-gdwarf-4'"
export CCACHE_SIZE=200M
diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh
index 7b714dff5c..d8c08fca39 100755
--- a/ci/test/00_setup_env_native_valgrind.sh
+++ b/ci/test/00_setup_env_native_valgrind.sh
@@ -14,4 +14,4 @@ export NO_DEPENDS=1
export TEST_RUNNER_EXTRA="--nosandbox --exclude feature_init,rpc_bind,feature_bind_extra" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547
export GOAL="install"
# Temporarily pin dwarf 4, until valgrind can understand clang's dwarf 5
-export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no CC=clang CXX=clang++ CXXFLAGS='-fdebug-default-version=4'" # TODO enable GUI
+export BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=no CC=clang CXX=clang++ CFLAGS='-gdwarf-4' CXXFLAGS='-gdwarf-4'" # TODO enable GUI
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index 77358f93d9..84b7ebe3fd 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -40,14 +40,18 @@ if [ "${RUN_TIDY}" = "true" ]; then
export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST/"
CI_EXEC "python3 ${DIR_IWYU}/include-what-you-use/iwyu_tool.py"\
" src/compat"\
+ " src/dbwrapper.cpp"\
" src/init"\
- " src/kernel/mempool_persist.cpp"\
+ " src/kernel"\
+ " src/node/chainstate.cpp"\
" src/policy/feerate.cpp"\
" src/policy/packages.cpp"\
" src/policy/settings.cpp"\
+ " src/primitives/transaction.cpp"\
" src/rpc/fees.cpp"\
" src/rpc/signmessage.cpp"\
" src/test/fuzz/txorphan.cpp"\
+ " src/threadinterrupt.cpp"\
" src/util/bip32.cpp"\
" src/util/bytevectorhash.cpp"\
" src/util/error.cpp"\
diff --git a/configure.ac b/configure.ac
index 0cd88543c6..90e7f18515 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1978,6 +1978,9 @@ AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py])
AC_CONFIG_LINKS([test/fuzz/test_runner.py:test/fuzz/test_runner.py])
AC_CONFIG_LINKS([test/util/test_runner.py:test/util/test_runner.py])
AC_CONFIG_LINKS([test/util/rpcauth-test.py:test/util/rpcauth-test.py])
+AC_CONFIG_LINKS([src/qt/Makefile:src/qt/Makefile])
+AC_CONFIG_LINKS([src/qt/test/Makefile:src/qt/test/Makefile])
+AC_CONFIG_LINKS([src/test/Makefile:src/test/Makefile])
dnl boost's m4 checks do something really nasty: they export these vars. As a
dnl result, they leak into secp256k1's configure and crazy things happen.
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 12b563eac2..7471f08a2b 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -607,8 +607,7 @@ inspecting signatures in Mach-O binaries.")
((string-contains target "-linux-")
(list (cond ((string-contains target "riscv64-")
(make-bitcoin-cross-toolchain target
- #:base-libc (make-glibc-without-werror glibc-2.27/bitcoin-patched)
- #:base-kernel-headers base-linux-kernel-headers))
+ #:base-libc (make-glibc-without-werror glibc-2.27/bitcoin-patched)))
(else
(make-bitcoin-cross-toolchain target)))))
((string-contains target "darwin")
diff --git a/contrib/signet/miner b/contrib/signet/miner
index 61415cb2dd..fdcd20ae3b 100755
--- a/contrib/signet/miner
+++ b/contrib/signet/miner
@@ -4,7 +4,6 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import argparse
-import base64
import json
import logging
import math
@@ -15,14 +14,13 @@ import sys
import time
import subprocess
-from io import BytesIO
-
PATH_BASE_CONTRIB_SIGNET = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
PATH_BASE_TEST_FUNCTIONAL = os.path.abspath(os.path.join(PATH_BASE_CONTRIB_SIGNET, "..", "..", "test", "functional"))
sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL)
from test_framework.blocktools import get_witness_script, script_BIP34_coinbase_height # noqa: E402
-from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_hex, deser_string, ser_compact_size, ser_string, ser_uint256, tx_from_hex # noqa: E402
+from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, from_binary, from_hex, ser_string, ser_uint256, tx_from_hex # noqa: E402
+from test_framework.psbt import PSBT, PSBTMap, PSBT_GLOBAL_UNSIGNED_TX, PSBT_IN_FINAL_SCRIPTSIG, PSBT_IN_FINAL_SCRIPTWITNESS, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_SIGHASH_TYPE # noqa: E402
from test_framework.script import CScriptOp # noqa: E402
logging.basicConfig(
@@ -34,89 +32,6 @@ SIGNET_HEADER = b"\xec\xc7\xda\xa2"
PSBT_SIGNET_BLOCK = b"\xfc\x06signetb" # proprietary PSBT global field holding the block being signed
RE_MULTIMINER = re.compile("^(\d+)(-(\d+))?/(\d+)$")
-# #### some helpers that could go into test_framework
-
-# like from_hex, but without the hex part
-def FromBinary(cls, stream):
- """deserialize a binary stream (or bytes object) into an object"""
- # handle bytes object by turning it into a stream
- was_bytes = isinstance(stream, bytes)
- if was_bytes:
- stream = BytesIO(stream)
- obj = cls()
- obj.deserialize(stream)
- if was_bytes:
- assert len(stream.read()) == 0
- return obj
-
-class PSBTMap:
- """Class for serializing and deserializing PSBT maps"""
-
- def __init__(self, map=None):
- self.map = map if map is not None else {}
-
- def deserialize(self, f):
- m = {}
- while True:
- k = deser_string(f)
- if len(k) == 0:
- break
- v = deser_string(f)
- if len(k) == 1:
- k = k[0]
- assert k not in m
- m[k] = v
- self.map = m
-
- def serialize(self):
- m = b""
- for k,v in self.map.items():
- if isinstance(k, int) and 0 <= k and k <= 255:
- k = bytes([k])
- m += ser_compact_size(len(k)) + k
- m += ser_compact_size(len(v)) + v
- m += b"\x00"
- return m
-
-class PSBT:
- """Class for serializing and deserializing PSBTs"""
-
- def __init__(self):
- self.g = PSBTMap()
- self.i = []
- self.o = []
- self.tx = None
-
- def deserialize(self, f):
- assert f.read(5) == b"psbt\xff"
- self.g = FromBinary(PSBTMap, f)
- assert 0 in self.g.map
- self.tx = FromBinary(CTransaction, self.g.map[0])
- self.i = [FromBinary(PSBTMap, f) for _ in self.tx.vin]
- self.o = [FromBinary(PSBTMap, f) for _ in self.tx.vout]
- return self
-
- def serialize(self):
- assert isinstance(self.g, PSBTMap)
- assert isinstance(self.i, list) and all(isinstance(x, PSBTMap) for x in self.i)
- assert isinstance(self.o, list) and all(isinstance(x, PSBTMap) for x in self.o)
- assert 0 in self.g.map
- tx = FromBinary(CTransaction, self.g.map[0])
- assert len(tx.vin) == len(self.i)
- assert len(tx.vout) == len(self.o)
-
- psbt = [x.serialize() for x in [self.g] + self.i + self.o]
- return b"psbt\xff" + b"".join(psbt)
-
- def to_base64(self):
- return base64.b64encode(self.serialize()).decode("utf8")
-
- @classmethod
- def from_base64(cls, b64psbt):
- return FromBinary(cls, base64.b64decode(b64psbt))
-
-# #####
-
def create_coinbase(height, value, spk):
cb = CTransaction()
cb.vin = [CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), 0xffffffff)]
@@ -159,11 +74,11 @@ def signet_txs(block, challenge):
def do_createpsbt(block, signme, spendme):
psbt = PSBT()
- psbt.g = PSBTMap( {0: signme.serialize(),
+ psbt.g = PSBTMap( {PSBT_GLOBAL_UNSIGNED_TX: signme.serialize(),
PSBT_SIGNET_BLOCK: block.serialize()
} )
- psbt.i = [ PSBTMap( {0: spendme.serialize(),
- 3: bytes([1,0,0,0])})
+ psbt.i = [ PSBTMap( {PSBT_IN_NON_WITNESS_UTXO: spendme.serialize(),
+ PSBT_IN_SIGHASH_TYPE: bytes([1,0,0,0])})
]
psbt.o = [ PSBTMap() ]
return psbt.to_base64()
@@ -175,10 +90,10 @@ def do_decode_psbt(b64psbt):
assert len(psbt.tx.vout) == 1
assert PSBT_SIGNET_BLOCK in psbt.g.map
- scriptSig = psbt.i[0].map.get(7, b"")
- scriptWitness = psbt.i[0].map.get(8, b"\x00")
+ scriptSig = psbt.i[0].map.get(PSBT_IN_FINAL_SCRIPTSIG, b"")
+ scriptWitness = psbt.i[0].map.get(PSBT_IN_FINAL_SCRIPTWITNESS, b"\x00")
- return FromBinary(CBlock, psbt.g.map[PSBT_SIGNET_BLOCK]), ser_string(scriptSig) + scriptWitness
+ return from_binary(CBlock, psbt.g.map[PSBT_SIGNET_BLOCK]), ser_string(scriptSig) + scriptWitness
def finish_block(block, signet_solution, grind_cmd):
block.vtx[0].vout[-1].scriptPubKey += CScriptOp.encode_op_pushdata(SIGNET_HEADER + signet_solution)
diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp
index 6efe49254b..d6856b4274 100644
--- a/contrib/valgrind.supp
+++ b/contrib/valgrind.supp
@@ -65,12 +65,6 @@
obj:*/libdb_cxx-*.so
}
{
- Suppress leaks on init
- Memcheck:Leak
- ...
- fun:_Z11AppInitMainR11NodeContext
-}
-{
Suppress leaks on shutdown
Memcheck:Leak
...
@@ -83,21 +77,6 @@
obj:/usr/lib64/libgdk-3.so.0.2404.7
}
{
- Suppress leveldb warning (leveldb::InitModule()) - https://github.com/google/leveldb/issues/113
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:_Znwm
- fun:_ZN7leveldbL10InitModuleEv
-}
-{
- Suppress leveldb warning (leveldb::Env::Default()) - https://github.com/google/leveldb/issues/113
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:_Znwm
- ...
- fun:_ZN7leveldbL14InitDefaultEnvEv
-}
-{
Suppress leveldb leak
Memcheck:Leak
match-leak-kinds: reachable
diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk
index 349319138e..bb203d06f8 100644
--- a/depends/packages/expat.mk
+++ b/depends/packages/expat.mk
@@ -1,15 +1,18 @@
package=expat
-$(package)_version=2.4.1
+$(package)_version=2.4.8
$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_$(subst .,_,$($(package)_version))/
$(package)_file_name=$(package)-$($(package)_version).tar.xz
-$(package)_sha256_hash=cf032d0dba9b928636548e32b327a2d66b1aab63c4f4a13dd132c2d1d2f2fb6a
+$(package)_sha256_hash=f79b8f904b749e3e0d20afeadecf8249c55b2e32d4ebb089ae378df479dcaf25
+# -D_DEFAULT_SOURCE defines __USE_MISC, which exposes additional
+# definitions in endian.h, which are required for a working
+# endianess check in configure when building with -flto.
define $(package)_set_vars
$(package)_config_opts=--disable-shared --without-docbook --without-tests --without-examples
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
$(package)_config_opts += --without-xmlwf
$(package)_config_opts_linux=--with-pic
- $(package)_cflags += -fno-lto
+ $(package)_cppflags += -D_DEFAULT_SOURCE
endef
define $(package)_config_cmds
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index d46ca9ff9c..bddc9b4871 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -21,6 +21,7 @@ $(package)_patches += fix_limits_header.patch
$(package)_patches += use_android_ndk23.patch
$(package)_patches += rcc_hardcode_timestamp.patch
$(package)_patches += duplicate_lcqpafonts.patch
+$(package)_patches += fast_fixed_dtoa_no_optimize.patch
$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix)
$(package)_qttranslations_sha256_hash=5d7869f670a135ad0986e266813b9dd5bbae2b09577338f9cdf8904d4af52db0
@@ -176,6 +177,7 @@ $(package)_config_opts_mingw32 += "QMAKE_CFLAGS = '$($(package)_cflags) $($(pack
$(package)_config_opts_mingw32 += "QMAKE_CXX = '$($(package)_cxx)'"
$(package)_config_opts_mingw32 += "QMAKE_CXXFLAGS = '$($(package)_cxxflags) $($(package)_cppflags)'"
$(package)_config_opts_mingw32 += "QMAKE_LFLAGS = '$($(package)_ldflags)'"
+$(package)_config_opts_mingw32 += "QMAKE_LIB = '$($(package)_ar) rc'"
$(package)_config_opts_mingw32 += -device-option CROSS_COMPILE="$(host)-"
$(package)_config_opts_mingw32 += -pch
@@ -251,6 +253,7 @@ define $(package)_preprocess_cmds
patch -p1 -i $($(package)_patch_dir)/use_android_ndk23.patch && \
patch -p1 -i $($(package)_patch_dir)/rcc_hardcode_timestamp.patch && \
patch -p1 -i $($(package)_patch_dir)/duplicate_lcqpafonts.patch && \
+ patch -p1 -i $($(package)_patch_dir)/fast_fixed_dtoa_no_optimize.patch && \
mkdir -p qtbase/mkspecs/macx-clang-linux &&\
cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\
cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \
diff --git a/depends/patches/qt/fast_fixed_dtoa_no_optimize.patch b/depends/patches/qt/fast_fixed_dtoa_no_optimize.patch
new file mode 100644
index 0000000000..d4d6539f56
--- /dev/null
+++ b/depends/patches/qt/fast_fixed_dtoa_no_optimize.patch
@@ -0,0 +1,20 @@
+Modify the optimisation flags for FastFixedDtoa.
+This fixes a non-determinism issue in the asm produced for
+this function when cross-compiling on x86_64 and aarch64 for
+the arm-linux-gnueabihf HOST.
+
+--- a/qtbase/src/3rdparty/double-conversion/fixed-dtoa.h
++++ b/qtbase/src/3rdparty/double-conversion/fixed-dtoa.h
+@@ -48,9 +48,12 @@ namespace double_conversion {
+ //
+ // This method only works for some parameters. If it can't handle the input it
+ // returns false. The output is null-terminated when the function succeeds.
++#pragma GCC push_options
++#pragma GCC optimize ("-O1")
+ bool FastFixedDtoa(double v, int fractional_count,
+ Vector<char> buffer, int* length, int* decimal_point);
+
++#pragma GCC pop_options
+ } // namespace double_conversion
+
+ #endif // DOUBLE_CONVERSION_FIXED_DTOA_H_
diff --git a/src/.clang-tidy b/src/.clang-tidy
index df2a080075..b9371b147b 100644
--- a/src/.clang-tidy
+++ b/src/.clang-tidy
@@ -5,6 +5,7 @@ misc-unused-using-decls,
modernize-use-default-member-init,
modernize-use-nullptr,
readability-redundant-declaration,
+readability-redundant-string-init,
'
WarningsAsErrors: '
bugprone-argument-comment,
@@ -12,4 +13,5 @@ misc-unused-using-decls,
modernize-use-default-member-init,
modernize-use-nullptr,
readability-redundant-declaration,
+readability-redundant-string-init,
'
diff --git a/src/Makefile.am b/src/Makefile.am
index 02ec5c098e..23bc180095 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -133,9 +133,9 @@ BITCOIN_CORE_H = \
clientversion.h \
coins.h \
common/bloom.h \
- compat.h \
compat/assumptions.h \
compat/byteswap.h \
+ compat/compat.h \
compat/cpuid.h \
compat/endian.h \
compressor.h \
@@ -171,6 +171,7 @@ BITCOIN_CORE_H = \
interfaces/ipc.h \
interfaces/node.h \
interfaces/wallet.h \
+ kernel/chain.h \
kernel/chainstatemanager_opts.h \
kernel/checks.h \
kernel/coinstats.h \
@@ -365,6 +366,7 @@ libbitcoin_node_a_SOURCES = \
index/coinstatsindex.cpp \
index/txindex.cpp \
init.cpp \
+ kernel/chain.cpp \
kernel/checks.cpp \
kernel/coinstats.cpp \
kernel/context.cpp \
@@ -882,6 +884,7 @@ libbitcoinkernel_la_SOURCES = \
flatfile.cpp \
fs.cpp \
hash.cpp \
+ kernel/chain.cpp \
kernel/checks.cpp \
kernel/coinstats.cpp \
kernel/context.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index e05cc7bdd6..f52964b033 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -117,6 +117,7 @@ BITCOIN_TESTS =\
test/prevector_tests.cpp \
test/raii_event_tests.cpp \
test/random_tests.cpp \
+ test/rbf_tests.cpp \
test/rest_tests.cpp \
test/reverselock_tests.cpp \
test/rpc_tests.cpp \
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 204bb544c5..857ad73b2f 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -29,19 +29,19 @@ static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP{64};
/** Maximum number of times an address can occur in the new table */
static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS{8};
/** How old addresses can maximally be */
-static constexpr int64_t ADDRMAN_HORIZON_DAYS{30};
+static constexpr auto ADDRMAN_HORIZON{30 * 24h};
/** After how many failed attempts we give up on a new node */
static constexpr int32_t ADDRMAN_RETRIES{3};
/** How many successive failures are allowed ... */
static constexpr int32_t ADDRMAN_MAX_FAILURES{10};
-/** ... in at least this many days */
-static constexpr int64_t ADDRMAN_MIN_FAIL_DAYS{7};
+/** ... in at least this duration */
+static constexpr auto ADDRMAN_MIN_FAIL{7 * 24h};
/** How recent a successful connection should be before we allow an address to be evicted from tried */
-static constexpr int64_t ADDRMAN_REPLACEMENT_HOURS{4};
+static constexpr auto ADDRMAN_REPLACEMENT{4h};
/** The maximum number of tried addr collisions to store */
static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10};
-/** The maximum time we'll spend trying to resolve a tried table collision, in seconds */
-static constexpr int64_t ADDRMAN_TEST_WINDOW{40*60}; // 40 minutes
+/** The maximum time we'll spend trying to resolve a tried table collision */
+static constexpr auto ADDRMAN_TEST_WINDOW{40min};
int AddrInfo::GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const
{
@@ -64,36 +64,39 @@ int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) con
return hash1 % ADDRMAN_BUCKET_SIZE;
}
-bool AddrInfo::IsTerrible(int64_t nNow) const
+bool AddrInfo::IsTerrible(NodeSeconds now) const
{
- if (nNow - nLastTry <= 60) { // never remove things tried in the last minute
+ if (now - m_last_try <= 1min) { // never remove things tried in the last minute
return false;
}
- if (nTime > nNow + 10 * 60) // came in a flying DeLorean
+ if (nTime > now + 10min) { // came in a flying DeLorean
return true;
+ }
- if (nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) { // not seen in recent history
+ if (now - nTime > ADDRMAN_HORIZON) { // not seen in recent history
return true;
}
- if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
+ if (TicksSinceEpoch<std::chrono::seconds>(m_last_success) == 0 && nAttempts >= ADDRMAN_RETRIES) { // tried N times and never a success
return true;
+ }
- if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
+ if (now - m_last_success > ADDRMAN_MIN_FAIL && nAttempts >= ADDRMAN_MAX_FAILURES) { // N successive failures in the last week
return true;
+ }
return false;
}
-double AddrInfo::GetChance(int64_t nNow) const
+double AddrInfo::GetChance(NodeSeconds now) const
{
double fChance = 1.0;
- int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
// deprioritize very recent attempts away
- if (nSinceLastTry < 60 * 10)
+ if (now - m_last_try < 10min) {
fChance *= 0.01;
+ }
// deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
fChance *= pow(0.66, std::min(nAttempts, 8));
@@ -540,7 +543,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
info.fInTried = true;
}
-bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
+bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty)
{
AssertLockHeld(cs);
@@ -552,15 +555,15 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
// Do not set a penalty for a source's self-announcement
if (addr == source) {
- nTimePenalty = 0;
+ time_penalty = 0s;
}
if (pinfo) {
// periodically update nTime
- bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
- int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
- if (pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty) {
- pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
+ const bool currently_online{AdjustedTime() - addr.nTime < 24h};
+ const auto update_interval{currently_online ? 1h : 24h};
+ if (pinfo->nTime < addr.nTime - update_interval - time_penalty) {
+ pinfo->nTime = std::max(NodeSeconds{0s}, addr.nTime - time_penalty);
}
// add services
@@ -587,7 +590,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
return false;
} else {
pinfo = Create(addr, source, &nId);
- pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
+ pinfo->nTime = std::max(NodeSeconds{0s}, pinfo->nTime - time_penalty);
nNew++;
}
@@ -617,13 +620,13 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
return fInsert;
}
-bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
+bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, NodeSeconds time)
{
AssertLockHeld(cs);
int nId;
- nLastGood = nTime;
+ m_last_good = time;
AddrInfo* pinfo = Find(addr, &nId);
@@ -633,8 +636,8 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
AddrInfo& info = *pinfo;
// update info
- info.nLastSuccess = nTime;
- info.nLastTry = nTime;
+ info.m_last_success = time;
+ info.m_last_try = time;
info.nAttempts = 0;
// nTime is not updated here, to avoid leaking information about
// currently-connected peers.
@@ -671,11 +674,11 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
}
}
-bool AddrManImpl::Add_(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty)
+bool AddrManImpl::Add_(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{
int added{0};
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) {
- added += AddSingle(*it, source, nTimePenalty) ? 1 : 0;
+ added += AddSingle(*it, source, time_penalty) ? 1 : 0;
}
if (added > 0) {
LogPrint(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToString(), nTried, nNew);
@@ -683,7 +686,7 @@ bool AddrManImpl::Add_(const std::vector<CAddress> &vAddr, const CNetAddr& sourc
return added > 0;
}
-void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
+void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, NodeSeconds time)
{
AssertLockHeld(cs);
@@ -696,14 +699,14 @@ void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, int64_t nTi
AddrInfo& info = *pinfo;
// update info
- info.nLastTry = nTime;
- if (fCountFailure && info.nLastCountAttempt < nLastGood) {
- info.nLastCountAttempt = nTime;
+ info.m_last_try = time;
+ if (fCountFailure && info.m_last_count_attempt < m_last_good) {
+ info.m_last_count_attempt = time;
info.nAttempts++;
}
}
-std::pair<CAddress, int64_t> AddrManImpl::Select_(bool newOnly) const
+std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool newOnly) const
{
AssertLockHeld(cs);
@@ -736,7 +739,7 @@ std::pair<CAddress, int64_t> AddrManImpl::Select_(bool newOnly) const
// With probability GetChance() * fChanceFactor, return the entry.
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
LogPrint(BCLog::ADDRMAN, "Selected %s from tried\n", info.ToString());
- return {info, info.nLastTry};
+ return {info, info.m_last_try};
}
// Otherwise start over with a (likely) different bucket, and increased chance factor.
fChanceFactor *= 1.2;
@@ -764,7 +767,7 @@ std::pair<CAddress, int64_t> AddrManImpl::Select_(bool newOnly) const
// With probability GetChance() * fChanceFactor, return the entry.
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
LogPrint(BCLog::ADDRMAN, "Selected %s from new\n", info.ToString());
- return {info, info.nLastTry};
+ return {info, info.m_last_try};
}
// Otherwise start over with a (likely) different bucket, and increased chance factor.
fChanceFactor *= 1.2;
@@ -785,7 +788,7 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct
}
// gather a list of random nodes, skipping those of low quality
- const int64_t now{GetAdjustedTime()};
+ const auto now{AdjustedTime()};
std::vector<CAddress> addresses;
for (unsigned int n = 0; n < vRandom.size(); n++) {
if (addresses.size() >= nNodes)
@@ -810,7 +813,7 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct
return addresses;
}
-void AddrManImpl::Connected_(const CService& addr, int64_t nTime)
+void AddrManImpl::Connected_(const CService& addr, NodeSeconds time)
{
AssertLockHeld(cs);
@@ -823,9 +826,10 @@ void AddrManImpl::Connected_(const CService& addr, int64_t nTime)
AddrInfo& info = *pinfo;
// update info
- int64_t nUpdateInterval = 20 * 60;
- if (nTime - info.nTime > nUpdateInterval)
- info.nTime = nTime;
+ const auto update_interval{20min};
+ if (time - info.nTime > update_interval) {
+ info.nTime = time;
+ }
}
void AddrManImpl::SetServices_(const CService& addr, ServiceFlags nServices)
@@ -870,22 +874,22 @@ void AddrManImpl::ResolveCollisions_()
int id_old = vvTried[tried_bucket][tried_bucket_pos];
AddrInfo& info_old = mapInfo[id_old];
- const auto current_time{GetAdjustedTime()};
+ const auto current_time{AdjustedTime()};
// Has successfully connected in last X hours
- if (current_time - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
+ if (current_time - info_old.m_last_success < ADDRMAN_REPLACEMENT) {
erase_collision = true;
- } else if (current_time - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
+ } else if (current_time - info_old.m_last_try < ADDRMAN_REPLACEMENT) { // attempted to connect and failed in last X hours
// Give address at least 60 seconds to successfully connect
- if (current_time - info_old.nLastTry > 60) {
+ if (current_time - info_old.m_last_try > 60s) {
LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
// Replaces an existing address already in the tried table with the new address
Good_(info_new, false, current_time);
erase_collision = true;
}
- } else if (current_time - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
+ } else if (current_time - info_new.m_last_success > ADDRMAN_TEST_WINDOW) {
// If the collision hasn't resolved in some reasonable amount of time,
// just evict the old entry -- we must not be able to
// connect to it for some reason.
@@ -894,7 +898,7 @@ void AddrManImpl::ResolveCollisions_()
erase_collision = true;
}
} else { // Collision is not actually a collision anymore
- Good_(info_new, false, GetAdjustedTime());
+ Good_(info_new, false, AdjustedTime());
erase_collision = true;
}
}
@@ -907,7 +911,7 @@ void AddrManImpl::ResolveCollisions_()
}
}
-std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
+std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision_()
{
AssertLockHeld(cs);
@@ -932,7 +936,7 @@ std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
- return {info_old, info_old.nLastTry};
+ return {info_old, info_old.m_last_try};
}
std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& addr)
@@ -990,8 +994,9 @@ int AddrManImpl::CheckAddrman() const
int n = entry.first;
const AddrInfo& info = entry.second;
if (info.fInTried) {
- if (!info.nLastSuccess)
+ if (!TicksSinceEpoch<std::chrono::seconds>(info.m_last_success)) {
return -1;
+ }
if (info.nRefCount)
return -2;
setTried.insert(n);
@@ -1008,10 +1013,12 @@ int AddrManImpl::CheckAddrman() const
}
if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
return -14;
- if (info.nLastTry < 0)
+ if (info.m_last_try < NodeSeconds{0s}) {
return -6;
- if (info.nLastSuccess < 0)
+ }
+ if (info.m_last_success < NodeSeconds{0s}) {
return -8;
+ }
}
if (setTried.size() != (size_t)nTried)
@@ -1067,29 +1074,29 @@ size_t AddrManImpl::size() const
return vRandom.size();
}
-bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
+bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{
LOCK(cs);
Check();
- auto ret = Add_(vAddr, source, nTimePenalty);
+ auto ret = Add_(vAddr, source, time_penalty);
Check();
return ret;
}
-bool AddrManImpl::Good(const CService& addr, int64_t nTime)
+bool AddrManImpl::Good(const CService& addr, NodeSeconds time)
{
LOCK(cs);
Check();
- auto ret = Good_(addr, /*test_before_evict=*/true, nTime);
+ auto ret = Good_(addr, /*test_before_evict=*/true, time);
Check();
return ret;
}
-void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
+void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
{
LOCK(cs);
Check();
- Attempt_(addr, fCountFailure, nTime);
+ Attempt_(addr, fCountFailure, time);
Check();
}
@@ -1101,7 +1108,7 @@ void AddrManImpl::ResolveCollisions()
Check();
}
-std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision()
+std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision()
{
LOCK(cs);
Check();
@@ -1110,7 +1117,7 @@ std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision()
return ret;
}
-std::pair<CAddress, int64_t> AddrManImpl::Select(bool newOnly) const
+std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool newOnly) const
{
LOCK(cs);
Check();
@@ -1128,11 +1135,11 @@ std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct,
return addresses;
}
-void AddrManImpl::Connected(const CService& addr, int64_t nTime)
+void AddrManImpl::Connected(const CService& addr, NodeSeconds time)
{
LOCK(cs);
Check();
- Connected_(addr, nTime);
+ Connected_(addr, time);
Check();
}
@@ -1184,19 +1191,19 @@ size_t AddrMan::size() const
return m_impl->size();
}
-bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
+bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{
- return m_impl->Add(vAddr, source, nTimePenalty);
+ return m_impl->Add(vAddr, source, time_penalty);
}
-bool AddrMan::Good(const CService& addr, int64_t nTime)
+bool AddrMan::Good(const CService& addr, NodeSeconds time)
{
- return m_impl->Good(addr, nTime);
+ return m_impl->Good(addr, time);
}
-void AddrMan::Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
+void AddrMan::Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
{
- m_impl->Attempt(addr, fCountFailure, nTime);
+ m_impl->Attempt(addr, fCountFailure, time);
}
void AddrMan::ResolveCollisions()
@@ -1204,12 +1211,12 @@ void AddrMan::ResolveCollisions()
m_impl->ResolveCollisions();
}
-std::pair<CAddress, int64_t> AddrMan::SelectTriedCollision()
+std::pair<CAddress, NodeSeconds> AddrMan::SelectTriedCollision()
{
return m_impl->SelectTriedCollision();
}
-std::pair<CAddress, int64_t> AddrMan::Select(bool newOnly) const
+std::pair<CAddress, NodeSeconds> AddrMan::Select(bool newOnly) const
{
return m_impl->Select(newOnly);
}
@@ -1219,9 +1226,9 @@ std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std
return m_impl->GetAddr(max_addresses, max_pct, network);
}
-void AddrMan::Connected(const CService& addr, int64_t nTime)
+void AddrMan::Connected(const CService& addr, NodeSeconds time)
{
- m_impl->Connected(addr, nTime);
+ m_impl->Connected(addr, time);
}
void AddrMan::SetServices(const CService& addr, ServiceFlags nServices)
diff --git a/src/addrman.h b/src/addrman.h
index a0063e8a9c..b70c6a48ad 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -11,6 +11,7 @@
#include <protocol.h>
#include <streams.h>
#include <timedata.h>
+#include <util/time.h>
#include <cstdint>
#include <memory>
@@ -107,23 +108,23 @@ public:
*
* @param[in] vAddr Address records to attempt to add.
* @param[in] source The address of the node that sent us these addr records.
- * @param[in] nTimePenalty A "time penalty" to apply to the address record's nTime. If a peer
+ * @param[in] time_penalty A "time penalty" to apply to the address record's nTime. If a peer
* sends us an address record with nTime=n, then we'll add it to our
- * addrman with nTime=(n - nTimePenalty).
+ * addrman with nTime=(n - time_penalty).
* @return true if at least one address is successfully added. */
- bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty = 0);
+ bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty = 0s);
/**
* Mark an address record as accessible and attempt to move it to addrman's tried table.
*
* @param[in] addr Address record to attempt to move to tried table.
- * @param[in] nTime The time that we were last connected to this peer.
+ * @param[in] time The time that we were last connected to this peer.
* @return true if the address is successfully moved from the new table to the tried table.
*/
- bool Good(const CService& addr, int64_t nTime = GetAdjustedTime());
+ bool Good(const CService& addr, NodeSeconds time = AdjustedTime());
//! Mark an entry as connection attempted to.
- void Attempt(const CService& addr, bool fCountFailure, int64_t nTime = GetAdjustedTime());
+ void Attempt(const CService& addr, bool fCountFailure, NodeSeconds time = AdjustedTime());
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
void ResolveCollisions();
@@ -133,18 +134,18 @@ public:
* attempting to evict.
*
* @return CAddress The record for the selected tried peer.
- * int64_t The last time we attempted to connect to that peer.
+ * seconds The last time we attempted to connect to that peer.
*/
- std::pair<CAddress, int64_t> SelectTriedCollision();
+ std::pair<CAddress, NodeSeconds> SelectTriedCollision();
/**
* Choose an address to connect to.
*
* @param[in] newOnly Whether to only select addresses from the new table.
* @return CAddress The record for the selected peer.
- * int64_t The last time we attempted to connect to that peer.
+ * seconds The last time we attempted to connect to that peer.
*/
- std::pair<CAddress, int64_t> Select(bool newOnly = false) const;
+ std::pair<CAddress, NodeSeconds> Select(bool newOnly = false) const;
/**
* Return all or many randomly selected addresses, optionally by network.
@@ -166,9 +167,9 @@ public:
* not leak information about currently connected peers.
*
* @param[in] addr The address of the peer we were connected to
- * @param[in] nTime The time that we were last connected to this peer
+ * @param[in] time The time that we were last connected to this peer
*/
- void Connected(const CService& addr, int64_t nTime = GetAdjustedTime());
+ void Connected(const CService& addr, NodeSeconds time = AdjustedTime());
//! Update an entry's service bits.
void SetServices(const CService& addr, ServiceFlags nServices);
diff --git a/src/addrman_impl.h b/src/addrman_impl.h
index 9d98cdde54..a73a026940 100644
--- a/src/addrman_impl.h
+++ b/src/addrman_impl.h
@@ -11,7 +11,9 @@
#include <protocol.h>
#include <serialize.h>
#include <sync.h>
+#include <timedata.h>
#include <uint256.h>
+#include <util/time.h>
#include <cstdint>
#include <optional>
@@ -38,16 +40,16 @@ class AddrInfo : public CAddress
{
public:
//! last try whatsoever by us (memory only)
- int64_t nLastTry{0};
+ NodeSeconds m_last_try{0s};
//! last counted attempt (memory only)
- int64_t nLastCountAttempt{0};
+ NodeSeconds m_last_count_attempt{0s};
//! where knowledge about this address first came from
CNetAddr source;
//! last successful connection by us
- int64_t nLastSuccess{0};
+ NodeSeconds m_last_success{0s};
//! connection attempts since last successful attempt
int nAttempts{0};
@@ -64,7 +66,7 @@ public:
SERIALIZE_METHODS(AddrInfo, obj)
{
READWRITEAS(CAddress, obj);
- READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
+ READWRITE(obj.source, Using<ChronoFormatter<int64_t>>(obj.m_last_success), obj.nAttempts);
}
AddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
@@ -91,10 +93,10 @@ public:
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
//! Determine whether the statistics about this entry are bad enough so that it can just be deleted
- bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
+ bool IsTerrible(NodeSeconds now = AdjustedTime()) const;
//! Calculate the relative chance this entry should be given when selecting nodes to connect to
- double GetChance(int64_t nNow = GetAdjustedTime()) const;
+ double GetChance(NodeSeconds now = AdjustedTime()) const;
};
class AddrManImpl
@@ -112,26 +114,26 @@ public:
size_t size() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
- bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
+ bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
- bool Good(const CService& addr, int64_t nTime)
+ bool Good(const CService& addr, NodeSeconds time)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
- void Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
+ void Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
void ResolveCollisions() EXCLUSIVE_LOCKS_REQUIRED(!cs);
- std::pair<CAddress, int64_t> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs);
+ std::pair<CAddress, NodeSeconds> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs);
- std::pair<CAddress, int64_t> Select(bool newOnly) const
+ std::pair<CAddress, NodeSeconds> Select(bool newOnly) const
EXCLUSIVE_LOCKS_REQUIRED(!cs);
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
EXCLUSIVE_LOCKS_REQUIRED(!cs);
- void Connected(const CService& addr, int64_t nTime)
+ void Connected(const CService& addr, NodeSeconds time)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
void SetServices(const CService& addr, ServiceFlags nServices)
@@ -202,7 +204,7 @@ private:
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
//! last time Good was called (memory only). Initially set to 1 so that "never" is strictly worse.
- int64_t nLastGood GUARDED_BY(cs){1};
+ NodeSeconds m_last_good GUARDED_BY(cs){1s};
//! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
std::set<int> m_tried_collisions;
@@ -233,25 +235,25 @@ private:
/** Attempt to add a single address to addrman's new table.
* @see AddrMan::Add() for parameters. */
- bool AddSingle(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ bool AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
- bool Good_(const CService& addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ bool Good_(const CService& addr, bool test_before_evict, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
- bool Add_(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ bool Add_(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
- void Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ void Attempt_(const CService& addr, bool fCountFailure, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
- std::pair<CAddress, int64_t> Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ std::pair<CAddress, NodeSeconds> Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs);
std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
- void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ void Connected_(const CService& addr, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
void SetServices_(const CService& addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
- std::pair<CAddress, int64_t> SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
+ std::pair<CAddress, NodeSeconds> SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
std::optional<AddressPosition> FindAddressEntry_(const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(cs);
diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp
index 76300f4db8..2600b03022 100644
--- a/src/bench/addrman.cpp
+++ b/src/bench/addrman.cpp
@@ -43,7 +43,7 @@ static void CreateAddresses()
CAddress ret(CService(addr, port), NODE_NETWORK);
- ret.nTime = GetAdjustedTime();
+ ret.nTime = AdjustedTime();
return ret;
};
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index 52e5cb743f..53aa470042 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -8,6 +8,7 @@
#include <chainparams.h>
#include <consensus/validation.h>
#include <streams.h>
+#include <util/system.h>
#include <validation.h>
// These are the two major time-sinks which happen after we have fully received
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index d53e917aba..4656cb23e7 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -18,6 +18,7 @@
#include <consensus/validation.h>
#include <core_io.h>
#include <node/blockstorage.h>
+#include <node/caches.h>
#include <node/chainstate.h>
#include <scheduler.h>
#include <script/sigcache.h>
@@ -83,27 +84,19 @@ int main(int argc, char* argv[])
};
ChainstateManager chainman{chainman_opts};
- auto rv = node::LoadChainstate(false,
- std::ref(chainman),
- nullptr,
- false,
- false,
- 2 << 20,
- 2 << 22,
- (450 << 20) - (2 << 20) - (2 << 22),
- false,
- false,
- []() { return false; });
- if (rv.has_value()) {
+ node::CacheSizes cache_sizes;
+ cache_sizes.block_tree_db = 2 << 20;
+ cache_sizes.coins_db = 2 << 22;
+ cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22);
+ node::ChainstateLoadOptions options;
+ options.check_interrupt = [] { return false; };
+ auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
+ if (status != node::ChainstateLoadStatus::SUCCESS) {
std::cerr << "Failed to load Chain state from your datadir." << std::endl;
goto epilogue;
} else {
- auto maybe_verify_error = node::VerifyLoadedChainstate(std::ref(chainman),
- false,
- false,
- DEFAULT_CHECKBLOCKS,
- DEFAULT_CHECKLEVEL);
- if (maybe_verify_error.has_value()) {
+ std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options);
+ if (status != node::ChainstateLoadStatus::SUCCESS) {
std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl;
goto epilogue;
}
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 0db2b75384..7cc956ebda 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -9,7 +9,7 @@
#include <chainparamsbase.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <compat/stdin.h>
#include <policy/feerate.h>
#include <rpc/client.h>
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index e0d5c6e5dc..b006353cb0 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -8,7 +8,7 @@
#include <clientversion.h>
#include <coins.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <core_io.h>
diff --git a/src/bitcoin-util.cpp b/src/bitcoin-util.cpp
index 1739804edb..fb184c0486 100644
--- a/src/bitcoin-util.cpp
+++ b/src/bitcoin-util.cpp
@@ -11,7 +11,7 @@
#include <chainparams.h>
#include <chainparamsbase.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <core_io.h>
#include <streams.h>
#include <util/system.h>
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index 7bec3292a1..a7d49452b0 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -9,7 +9,7 @@
#include <chainparams.h>
#include <chainparamsbase.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <interfaces/init.h>
#include <key.h>
#include <logging.h>
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index be894e192e..85ba88f6ab 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -9,7 +9,7 @@
#include <chainparams.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/init.h>
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index 1ad6872143..0ff79bb3ca 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -148,7 +148,7 @@ bool GCSFilter::MatchAny(const ElementSet& elements) const
const std::string& BlockFilterTypeName(BlockFilterType filter_type)
{
- static std::string unknown_retval = "";
+ static std::string unknown_retval;
auto it = g_filter_types.find(filter_type);
return it != g_filter_types.end() ? it->second : unknown_retval;
}
diff --git a/src/chain.cpp b/src/chain.cpp
index b8158f7b0b..0f898bafd5 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chain.h>
+#include <tinyformat.h>
#include <util/time.h>
std::string CBlockFileInfo::ToString() const
@@ -11,6 +12,12 @@ std::string CBlockFileInfo::ToString() const
return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, FormatISO8601Date(nTimeFirst), FormatISO8601Date(nTimeLast));
}
+std::string CBlockIndex::ToString() const
+{
+ return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
+ pprev, nHeight, hashMerkleRoot.ToString(), GetBlockHash().ToString());
+}
+
void CChain::SetTip(CBlockIndex *pindex) {
if (pindex == nullptr) {
vChain.clear();
diff --git a/src/chain.h b/src/chain.h
index ecc2ae732f..627a3dfab2 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -11,7 +11,6 @@
#include <flatfile.h>
#include <primitives/block.h>
#include <sync.h>
-#include <tinyformat.h>
#include <uint256.h>
#include <vector>
@@ -263,6 +262,7 @@ public:
uint256 GetBlockHash() const
{
+ assert(phashBlock != nullptr);
return *phashBlock;
}
@@ -301,13 +301,7 @@ public:
return pbegin[(pend - pbegin) / 2];
}
- std::string ToString() const
- {
- return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
- pprev, nHeight,
- hashMerkleRoot.ToString(),
- GetBlockHash().ToString());
- }
+ std::string ToString() const;
//! Check whether this block index entry is valid up to the passed validity level.
bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const
@@ -402,7 +396,7 @@ public:
READWRITE(obj.nNonce);
}
- uint256 GetBlockHash() const
+ uint256 ConstructBlockHash() const
{
CBlockHeader block;
block.nVersion = nVersion;
@@ -414,16 +408,8 @@ public:
return block.GetHash();
}
-
- std::string ToString() const
- {
- std::string str = "CDiskBlockIndex(";
- str += CBlockIndex::ToString();
- str += strprintf("\n hashBlock=%s, hashPrev=%s)",
- GetBlockHash().ToString(),
- hashPrev.ToString());
- return str;
- }
+ uint256 GetBlockHash() = delete;
+ std::string ToString() = delete;
};
/** An in-memory indexed chain of blocks. */
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 7a7c72ea25..dd7b93234d 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -352,7 +352,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
// message start is defined as the first 4 bytes of the sha256d of the block script
- CHashWriter h(SER_DISK, 0);
+ HashWriter h{};
h << consensus.signet_challenge;
uint256 hash = h.GetHash();
memcpy(pchMessageStart, hash.begin(), 4);
diff --git a/src/compat.h b/src/compat/compat.h
index 0a44b98b4e..a8e5552c0a 100644
--- a/src/compat.h
+++ b/src/compat/compat.h
@@ -3,21 +3,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_COMPAT_H
-#define BITCOIN_COMPAT_H
+#ifndef BITCOIN_COMPAT_COMPAT_H
+#define BITCOIN_COMPAT_COMPAT_H
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
+// Windows defines FD_SETSIZE to 64 (see _fd_types.h in mingw-w64),
+// which is too small for our usage, but allows us to redefine it safely.
+// We redefine it to be 1024, to match glibc, see typesizes.h.
#ifdef WIN32
#ifdef FD_SETSIZE
-#undef FD_SETSIZE // prevent redefinition compiler warning
+#undef FD_SETSIZE
#endif
-#define FD_SETSIZE 1024 // max number of fds in fd_set
+#define FD_SETSIZE 1024
#include <winsock2.h>
#include <ws2tcpip.h>
-#include <stdint.h>
+#include <cstdint>
#else
#include <fcntl.h>
#include <sys/mman.h>
@@ -34,49 +37,54 @@
#include <unistd.h>
#endif
+// We map Linux / BSD error functions and codes, to the equivalent
+// Windows definitions, and use the WSA* names throughout our code.
+// Note that glibc defines EWOULDBLOCK as EAGAIN (see errno.h).
#ifndef WIN32
typedef unsigned int SOCKET;
-#include <errno.h>
+#include <cerrno>
#define WSAGetLastError() errno
#define WSAEINVAL EINVAL
-#define WSAEALREADY EALREADY
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAEAGAIN EAGAIN
#define WSAEMSGSIZE EMSGSIZE
#define WSAEINTR EINTR
#define WSAEINPROGRESS EINPROGRESS
#define WSAEADDRINUSE EADDRINUSE
-#define WSAENOTSOCK EBADF
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR -1
#else
-#ifndef WSAEAGAIN
+// WSAEAGAIN doesn't exist on Windows
#ifdef EAGAIN
#define WSAEAGAIN EAGAIN
#else
#define WSAEAGAIN WSAEWOULDBLOCK
#endif
#endif
-#endif
+// Windows doesn't define S_IRUSR or S_IWUSR. We define both
+// here, with the same values as glibc (see stat.h).
#ifdef WIN32
#ifndef S_IRUSR
#define S_IRUSR 0400
#define S_IWUSR 0200
#endif
-#else
+#endif
+
+// Windows defines MAX_PATH as it's maximum path length.
+// We define MAX_PATH for use on non-Windows systems.
+#ifndef WIN32
#define MAX_PATH 1024
#endif
+
+// ssize_t is POSIX, and not present when using MSVC.
#ifdef _MSC_VER
-#if !defined(ssize_t)
-#ifdef _WIN64
-typedef int64_t ssize_t;
-#else
-typedef int32_t ssize_t;
-#endif
-#endif
+#include <BaseTsd.h>
+typedef SSIZE_T ssize_t;
#endif
+// The type of the option value passed to getsockopt & setsockopt
+// differs between Windows and non-Windows.
#ifndef WIN32
typedef void* sockopt_arg_type;
#else
@@ -119,4 +127,4 @@ bool static inline IsSelectableSocket(const SOCKET& s) {
#define MSG_DONTWAIT 0
#endif
-#endif // BITCOIN_COMPAT_H
+#endif // BITCOIN_COMPAT_COMPAT_H
diff --git a/src/crypto/muhash.cpp b/src/crypto/muhash.cpp
index 57ed357645..7d14b7938e 100644
--- a/src/crypto/muhash.cpp
+++ b/src/crypto/muhash.cpp
@@ -298,7 +298,7 @@ void Num3072::ToBytes(unsigned char (&out)[BYTE_SIZE]) {
Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
unsigned char tmp[Num3072::BYTE_SIZE];
- uint256 hashed_in = (CHashWriter(SER_DISK, 0) << in).GetSHA256();
+ uint256 hashed_in{(HashWriter{} << in).GetSHA256()};
ChaCha20(hashed_in.data(), hashed_in.size()).Keystream(tmp, Num3072::BYTE_SIZE);
Num3072 out{tmp};
@@ -318,7 +318,7 @@ void MuHash3072::Finalize(uint256& out) noexcept
unsigned char data[Num3072::BYTE_SIZE];
m_numerator.ToBytes(data);
- out = (CHashWriter(SER_DISK, 0) << data).GetSHA256();
+ out = (HashWriter{} << data).GetSHA256();
}
MuHash3072& MuHash3072::operator*=(const MuHash3072& mul) noexcept
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index d4a8e4f35a..4dbc839941 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -4,15 +4,28 @@
#include <dbwrapper.h>
-#include <memory>
+#include <fs.h>
+#include <logging.h>
#include <random.h>
+#include <tinyformat.h>
+#include <util/strencodings.h>
+#include <util/system.h>
+#include <algorithm>
+#include <cassert>
+#include <cstdarg>
+#include <cstdint>
+#include <cstdio>
#include <leveldb/cache.h>
+#include <leveldb/db.h>
#include <leveldb/env.h>
#include <leveldb/filter_policy.h>
#include <leveldb/helpers/memenv/memenv.h>
-#include <stdint.h>
-#include <algorithm>
+#include <leveldb/iterator.h>
+#include <leveldb/options.h>
+#include <leveldb/status.h>
+#include <memory>
+#include <optional>
class CBitcoinLevelDBLogger : public leveldb::Logger {
public:
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index cef8426d61..665eaa0e98 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -7,14 +7,26 @@
#include <clientversion.h>
#include <fs.h>
+#include <logging.h>
#include <serialize.h>
#include <span.h>
#include <streams.h>
-#include <util/strencodings.h>
-#include <util/system.h>
+#include <cstddef>
+#include <cstdint>
+#include <exception>
#include <leveldb/db.h>
+#include <leveldb/iterator.h>
+#include <leveldb/options.h>
+#include <leveldb/slice.h>
+#include <leveldb/status.h>
#include <leveldb/write_batch.h>
+#include <stdexcept>
+#include <string>
+#include <vector>
+namespace leveldb {
+class Env;
+}
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
diff --git a/src/external_signer.cpp b/src/external_signer.cpp
index d125fe479b..6bab0a856c 100644
--- a/src/external_signer.cpp
+++ b/src/external_signer.cpp
@@ -49,7 +49,7 @@ bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalS
if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true;
}
if (duplicate) break;
- std::string name = "";
+ std::string name;
const UniValue& model_field = find_value(signer, "model");
if (model_field.isStr() && model_field.getValStr() != "") {
name += model_field.getValStr();
diff --git a/src/hash.cpp b/src/hash.cpp
index f58b29e3ba..111b707964 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -86,9 +86,9 @@ uint256 SHA256Uint256(const uint256& input)
return result;
}
-CHashWriter TaggedHash(const std::string& tag)
+HashWriter TaggedHash(const std::string& tag)
{
- CHashWriter writer(SER_GETHASH, 0);
+ HashWriter writer{};
uint256 taghash;
CSHA256().Write((const unsigned char*)tag.data(), tag.size()).Finalize(taghash.begin());
writer << taghash << taghash;
diff --git a/src/hash.h b/src/hash.h
index 0ccef2105f..b1ff3acc7d 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -96,20 +96,12 @@ inline uint160 Hash160(const T1& in1)
}
/** A writer stream (for serialization) that computes a 256-bit hash. */
-class CHashWriter
+class HashWriter
{
private:
CSHA256 ctx;
- const int nType;
- const int nVersion;
public:
-
- CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}
-
- int GetType() const { return nType; }
- int GetVersion() const { return nVersion; }
-
void write(Span<const std::byte> src)
{
ctx.Write(UCharCast(src.data()), src.size());
@@ -144,6 +136,26 @@ public:
return ReadLE64(result.begin());
}
+ template <typename T>
+ HashWriter& operator<<(const T& obj)
+ {
+ ::Serialize(*this, obj);
+ return *this;
+ }
+};
+
+class CHashWriter : public HashWriter
+{
+private:
+ const int nType;
+ const int nVersion;
+
+public:
+ CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}
+
+ int GetType() const { return nType; }
+ int GetVersion() const { return nVersion; }
+
template<typename T>
CHashWriter& operator<<(const T& obj) {
// Serialize to this stream
@@ -203,12 +215,12 @@ unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vData
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
-/** Return a CHashWriter primed for tagged hashes (as specified in BIP 340).
+/** Return a HashWriter primed for tagged hashes (as specified in BIP 340).
*
* The returned object will have SHA256(tag) written to it twice (= 64 bytes).
* A tagged hash can be computed by feeding the message into this object, and
- * then calling CHashWriter::GetSHA256().
+ * then calling HashWriter::GetSHA256().
*/
-CHashWriter TaggedHash(const std::string& tag);
+HashWriter TaggedHash(const std::string& tag);
#endif // BITCOIN_HASH_H
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index b8f69b038c..8e00a6278f 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -9,7 +9,7 @@
#include <httpserver.h>
#include <chainparamsbase.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <netbase.h>
#include <node/interface_ui.h>
#include <rpc/protocol.h> // For HTTP status codes
diff --git a/src/i2p.cpp b/src/i2p.cpp
index 8611984555..c45bcc15d2 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <compat/endian.h>
#include <crypto/sha256.h>
#include <fs.h>
diff --git a/src/i2p.h b/src/i2p.h
index 433fcc3a08..eb0a10103d 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_I2P_H
#define BITCOIN_I2P_H
-#include <compat.h>
+#include <compat/compat.h>
#include <fs.h>
#include <netaddress.h>
#include <sync.h>
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 323547900d..1ebe89ef7c 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -4,11 +4,15 @@
#include <chainparams.h>
#include <index/base.h>
+#include <interfaces/chain.h>
+#include <kernel/chain.h>
#include <node/blockstorage.h>
+#include <node/context.h>
#include <node/interface_ui.h>
#include <shutdown.h>
#include <tinyformat.h>
#include <util/syscall_sandbox.h>
+#include <util/system.h>
#include <util/thread.h>
#include <util/translation.h>
#include <validation.h> // For g_chainman
@@ -31,6 +35,15 @@ static void FatalError(const char* fmt, const Args&... args)
StartShutdown();
}
+CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash)
+{
+ CBlockLocator locator;
+ bool found = chain.findBlock(block_hash, interfaces::FoundBlock().locator(locator));
+ assert(found);
+ assert(!locator.IsNull());
+ return locator;
+}
+
BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate) :
CDBWrapper(path, n_cache_size, f_memory, f_wipe, f_obfuscate)
{}
@@ -49,6 +62,9 @@ void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator
batch.Write(DB_BEST_BLOCK, locator);
}
+BaseIndex::BaseIndex(std::unique_ptr<interfaces::Chain> chain)
+ : m_chain{std::move(chain)} {}
+
BaseIndex::~BaseIndex()
{
Interrupt();
@@ -69,6 +85,10 @@ bool BaseIndex::Init()
} else {
SetBestBlockIndex(m_chainstate->FindForkInGlobalIndex(locator));
}
+
+ // Note: this will latch to true immediately if the user starts up with an empty
+ // datadir and an index enabled. If this is the case, indexation will happen solely
+ // via `BlockConnected` signals until, possibly, the next restart.
m_synced = m_best_block_index.load() == active_chain.Tip();
if (!m_synced) {
bool prune_violation = false;
@@ -175,12 +195,15 @@ void BaseIndex::ThreadSync()
}
CBlock block;
+ interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex);
if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
FatalError("%s: Failed to read block %s from disk",
__func__, pindex->GetBlockHash().ToString());
return;
+ } else {
+ block_info.data = &block;
}
- if (!WriteBlock(block, pindex)) {
+ if (!CustomAppend(block_info)) {
FatalError("%s: Failed to write block %s to index database",
__func__, pindex->GetBlockHash().ToString());
return;
@@ -197,22 +220,20 @@ void BaseIndex::ThreadSync()
bool BaseIndex::Commit()
{
- CDBBatch batch(GetDB());
- if (!CommitInternal(batch) || !GetDB().WriteBatch(batch)) {
- return error("%s: Failed to commit latest %s state", __func__, GetName());
- }
- return true;
-}
-
-bool BaseIndex::CommitInternal(CDBBatch& batch)
-{
- LOCK(cs_main);
// Don't commit anything if we haven't indexed any block yet
// (this could happen if init is interrupted).
- if (m_best_block_index == nullptr) {
- return false;
+ bool ok = m_best_block_index != nullptr;
+ if (ok) {
+ CDBBatch batch(GetDB());
+ ok = CustomCommit(batch);
+ if (ok) {
+ GetDB().WriteBestBlock(batch, GetLocator(*m_chain, m_best_block_index.load()->GetBlockHash()));
+ ok = GetDB().WriteBatch(batch);
+ }
+ }
+ if (!ok) {
+ return error("%s: Failed to commit latest %s state", __func__, GetName());
}
- GetDB().WriteBestBlock(batch, m_chainstate->m_chain.GetLocator(m_best_block_index));
return true;
}
@@ -221,6 +242,10 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
assert(current_tip == m_best_block_index);
assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
+ if (!CustomRewind({current_tip->GetBlockHash(), current_tip->nHeight}, {new_tip->GetBlockHash(), new_tip->nHeight})) {
+ return false;
+ }
+
// In the case of a reorg, ensure persisted block locator is not stale.
// Pruning has a minimum of 288 blocks-to-keep and getting the index
// out of sync may be possible but a users fault.
@@ -268,8 +293,8 @@ void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const
return;
}
}
-
- if (WriteBlock(*block, pindex)) {
+ interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex, block.get());
+ if (CustomAppend(block_info)) {
SetBestBlockIndex(pindex);
} else {
FatalError("%s: Failed to write block %s to index",
@@ -346,13 +371,18 @@ void BaseIndex::Interrupt()
m_interrupt();
}
-bool BaseIndex::Start(CChainState& active_chainstate)
+bool BaseIndex::Start()
{
- m_chainstate = &active_chainstate;
+ // m_chainstate member gives indexing code access to node internals. It is
+ // removed in followup https://github.com/bitcoin/bitcoin/pull/24230
+ m_chainstate = &m_chain->context()->chainman->ActiveChainstate();
// Need to register this ValidationInterface before running Init(), so that
// callbacks are not missed if Init sets m_synced to true.
RegisterValidationInterface(this);
- if (!Init()) {
+ if (!Init()) return false;
+
+ const CBlockIndex* index = m_best_block_index.load();
+ if (!CustomInit(index ? std::make_optional(interfaces::BlockKey{index->GetBlockHash(), index->nHeight}) : std::nullopt)) {
return false;
}
diff --git a/src/index/base.h b/src/index/base.h
index a8f6a18c8d..5a484377e7 100644
--- a/src/index/base.h
+++ b/src/index/base.h
@@ -6,12 +6,16 @@
#define BITCOIN_INDEX_BASE_H
#include <dbwrapper.h>
+#include <interfaces/chain.h>
#include <threadinterrupt.h>
#include <validationinterface.h>
class CBlock;
class CBlockIndex;
class CChainState;
+namespace interfaces {
+class Chain;
+} // namespace interfaces
struct IndexSummary {
std::string name;
@@ -51,6 +55,10 @@ private:
/// Whether the index is in sync with the main chain. The flag is flipped
/// from false to true once, after which point this starts processing
/// ValidationInterface notifications to stay in sync.
+ ///
+ /// Note that this will latch to true *immediately* upon startup if
+ /// `m_chainstate->m_chain` is empty, which will be the case upon startup
+ /// with an empty datadir if, e.g., `-txindex=1` is specified.
std::atomic<bool> m_synced{false};
/// The last block in the chain that the index is in sync with.
@@ -59,6 +67,9 @@ private:
std::thread m_thread_sync;
CThreadInterrupt m_interrupt;
+ /// Read best block locator and check that data needed to sync has not been pruned.
+ bool Init();
+
/// Sync the index with the block index starting from the current best block.
/// Intended to be run in its own thread, m_thread_sync, and can be
/// interrupted with m_interrupt. Once the index gets in sync, the m_synced
@@ -76,30 +87,32 @@ private:
/// getting corrupted.
bool Commit();
+ /// Loop over disconnected blocks and call CustomRewind.
+ bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip);
+
virtual bool AllowPrune() const = 0;
protected:
+ std::unique_ptr<interfaces::Chain> m_chain;
CChainState* m_chainstate{nullptr};
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override;
void ChainStateFlushed(const CBlockLocator& locator) override;
- const CBlockIndex* CurrentIndex() { return m_best_block_index.load(); };
-
/// Initialize internal state from the database and block index.
- [[nodiscard]] virtual bool Init();
+ [[nodiscard]] virtual bool CustomInit(const std::optional<interfaces::BlockKey>& block) { return true; }
/// Write update index entries for a newly connected block.
- virtual bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) { return true; }
+ [[nodiscard]] virtual bool CustomAppend(const interfaces::BlockInfo& block) { return true; }
/// Virtual method called internally by Commit that can be overridden to atomically
/// commit more index state.
- virtual bool CommitInternal(CDBBatch& batch);
+ virtual bool CustomCommit(CDBBatch& batch) { return true; }
/// Rewind index to an earlier chain tip during a chain reorg. The tip must
/// be an ancestor of the current best block.
- virtual bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip);
+ [[nodiscard]] virtual bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) { return true; }
virtual DB& GetDB() const = 0;
@@ -110,6 +123,7 @@ protected:
void SetBestBlockIndex(const CBlockIndex* block);
public:
+ BaseIndex(std::unique_ptr<interfaces::Chain> chain);
/// Destructor interrupts sync thread if running and blocks until it exits.
virtual ~BaseIndex();
@@ -124,7 +138,7 @@ public:
/// Start initializes the sync state and registers the instance as a
/// ValidationInterface so that it stays in sync with blockchain updates.
- [[nodiscard]] bool Start(CChainState& active_chainstate);
+ [[nodiscard]] bool Start();
/// Stops the instance from staying in sync with blockchain updates.
void Stop();
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index e7fad8eb64..f4837f3456 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -9,6 +9,7 @@
#include <index/blockfilterindex.h>
#include <node/blockstorage.h>
#include <util/system.h>
+#include <validation.h>
using node::UndoReadFromDisk;
@@ -94,9 +95,9 @@ struct DBHashKey {
static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes;
-BlockFilterIndex::BlockFilterIndex(BlockFilterType filter_type,
+BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory, bool f_wipe)
- : m_filter_type(filter_type)
+ : BaseIndex(std::move(chain)), m_filter_type(filter_type)
{
const std::string& filter_name = BlockFilterTypeName(filter_type);
if (filter_name.empty()) throw std::invalid_argument("unknown filter_type");
@@ -109,7 +110,7 @@ BlockFilterIndex::BlockFilterIndex(BlockFilterType filter_type,
m_filter_fileseq = std::make_unique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE);
}
-bool BlockFilterIndex::Init()
+bool BlockFilterIndex::CustomInit(const std::optional<interfaces::BlockKey>& block)
{
if (!m_db->Read(DB_FILTER_POS, m_next_filter_pos)) {
// Check that the cause of the read failure is that the key does not exist. Any other errors
@@ -124,15 +125,15 @@ bool BlockFilterIndex::Init()
m_next_filter_pos.nFile = 0;
m_next_filter_pos.nPos = 0;
}
- return BaseIndex::Init();
+ return true;
}
-bool BlockFilterIndex::CommitInternal(CDBBatch& batch)
+bool BlockFilterIndex::CustomCommit(CDBBatch& batch)
{
const FlatFilePos& pos = m_next_filter_pos;
// Flush current filter file to disk.
- CAutoFile file(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION);
+ AutoFile file{m_filter_fileseq->Open(pos)};
if (file.IsNull()) {
return error("%s: Failed to open filter file %d", __func__, pos.nFile);
}
@@ -141,12 +142,12 @@ bool BlockFilterIndex::CommitInternal(CDBBatch& batch)
}
batch.Write(DB_FILTER_POS, pos);
- return BaseIndex::CommitInternal(batch);
+ return true;
}
bool BlockFilterIndex::ReadFilterFromDisk(const FlatFilePos& pos, const uint256& hash, BlockFilter& filter) const
{
- CAutoFile filein(m_filter_fileseq->Open(pos, true), SER_DISK, CLIENT_VERSION);
+ AutoFile filein{m_filter_fileseq->Open(pos, true)};
if (filein.IsNull()) {
return false;
}
@@ -178,7 +179,7 @@ size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter&
// If writing the filter would overflow the file, flush and move to the next one.
if (pos.nPos + data_size > MAX_FLTR_FILE_SIZE) {
- CAutoFile last_file(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION);
+ AutoFile last_file{m_filter_fileseq->Open(pos)};
if (last_file.IsNull()) {
LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile);
return 0;
@@ -204,7 +205,7 @@ size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter&
return 0;
}
- CAutoFile fileout(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION);
+ AutoFile fileout{m_filter_fileseq->Open(pos)};
if (fileout.IsNull()) {
LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile);
return 0;
@@ -214,22 +215,25 @@ size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter&
return data_size;
}
-bool BlockFilterIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
+bool BlockFilterIndex::CustomAppend(const interfaces::BlockInfo& block)
{
CBlockUndo block_undo;
uint256 prev_header;
- if (pindex->nHeight > 0) {
+ if (block.height > 0) {
+ // pindex variable gives indexing code access to node internals. It
+ // will be removed in upcoming commit
+ const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
if (!UndoReadFromDisk(block_undo, pindex)) {
return false;
}
std::pair<uint256, DBVal> read_out;
- if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
+ if (!m_db->Read(DBHeightKey(block.height - 1), read_out)) {
return false;
}
- uint256 expected_block_hash = pindex->pprev->GetBlockHash();
+ uint256 expected_block_hash = *Assert(block.prev_hash);
if (read_out.first != expected_block_hash) {
return error("%s: previous block header belongs to unexpected block %s; expected %s",
__func__, read_out.first.ToString(), expected_block_hash.ToString());
@@ -238,18 +242,18 @@ bool BlockFilterIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex
prev_header = read_out.second.header;
}
- BlockFilter filter(m_filter_type, block, block_undo);
+ BlockFilter filter(m_filter_type, *Assert(block.data), block_undo);
size_t bytes_written = WriteFilterToDisk(m_next_filter_pos, filter);
if (bytes_written == 0) return false;
std::pair<uint256, DBVal> value;
- value.first = pindex->GetBlockHash();
+ value.first = block.hash;
value.second.hash = filter.GetHash();
value.second.header = filter.ComputeHeader(prev_header);
value.second.pos = m_next_filter_pos;
- if (!m_db->Write(DBHeightKey(pindex->nHeight), value)) {
+ if (!m_db->Write(DBHeightKey(block.height), value)) {
return false;
}
@@ -283,17 +287,15 @@ static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
return true;
}
-bool BlockFilterIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
+bool BlockFilterIndex::CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip)
{
- assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
-
CDBBatch batch(*m_db);
std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
// During a reorg, we need to copy all filters for blocks that are getting disconnected from the
// height index to the hash index so we can still find them when the height index entries are
// overwritten.
- if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip->nHeight, current_tip->nHeight)) {
+ if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip.height, current_tip.height)) {
return false;
}
@@ -303,7 +305,7 @@ bool BlockFilterIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex*
batch.Write(DB_FILTER_POS, m_next_filter_pos);
if (!m_db->WriteBatch(batch)) return false;
- return BaseIndex::Rewind(current_tip, new_tip);
+ return true;
}
static bool LookupOne(const CDBWrapper& db, const CBlockIndex* block_index, DBVal& result)
@@ -467,12 +469,12 @@ void ForEachBlockFilterIndex(std::function<void (BlockFilterIndex&)> fn)
for (auto& entry : g_filter_indexes) fn(entry.second);
}
-bool InitBlockFilterIndex(BlockFilterType filter_type,
+bool InitBlockFilterIndex(std::function<std::unique_ptr<interfaces::Chain>()> make_chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory, bool f_wipe)
{
auto result = g_filter_indexes.emplace(std::piecewise_construct,
std::forward_as_tuple(filter_type),
- std::forward_as_tuple(filter_type,
+ std::forward_as_tuple(make_chain(), filter_type,
n_cache_size, f_memory, f_wipe));
return result.second;
}
diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h
index fef8b573e8..968eccb6b3 100644
--- a/src/index/blockfilterindex.h
+++ b/src/index/blockfilterindex.h
@@ -41,13 +41,13 @@ private:
bool AllowPrune() const override { return true; }
protected:
- bool Init() override;
+ bool CustomInit(const std::optional<interfaces::BlockKey>& block) override;
- bool CommitInternal(CDBBatch& batch) override;
+ bool CustomCommit(CDBBatch& batch) override;
- bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
+ bool CustomAppend(const interfaces::BlockInfo& block) override;
- bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip) override;
+ bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) override;
BaseIndex::DB& GetDB() const override { return *m_db; }
@@ -55,7 +55,7 @@ protected:
public:
/** Constructs the index, which becomes available to be queried. */
- explicit BlockFilterIndex(BlockFilterType filter_type,
+ explicit BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
BlockFilterType GetFilterType() const { return m_filter_type; }
@@ -88,7 +88,7 @@ void ForEachBlockFilterIndex(std::function<void (BlockFilterIndex&)> fn);
* Initialize a block filter index for the given type if one does not already exist. Returns true if
* a new index is created and false if one has already been initialized.
*/
-bool InitBlockFilterIndex(BlockFilterType filter_type,
+bool InitBlockFilterIndex(std::function<std::unique_ptr<interfaces::Chain>()> make_chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
/**
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp
index 687e330fe0..b9029e946a 100644
--- a/src/index/coinstatsindex.cpp
+++ b/src/index/coinstatsindex.cpp
@@ -10,6 +10,7 @@
#include <serialize.h>
#include <txdb.h>
#include <undo.h>
+#include <util/system.h>
#include <validation.h>
using kernel::CCoinsStats;
@@ -102,7 +103,8 @@ struct DBHashKey {
std::unique_ptr<CoinStatsIndex> g_coin_stats_index;
-CoinStatsIndex::CoinStatsIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
+CoinStatsIndex::CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe)
+ : BaseIndex(std::move(chain))
{
fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"};
fs::create_directories(path);
@@ -110,24 +112,27 @@ CoinStatsIndex::CoinStatsIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
m_db = std::make_unique<CoinStatsIndex::DB>(path / "db", n_cache_size, f_memory, f_wipe);
}
-bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
+bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
{
CBlockUndo block_undo;
- const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
+ const CAmount block_subsidy{GetBlockSubsidy(block.height, Params().GetConsensus())};
m_total_subsidy += block_subsidy;
// Ignore genesis block
- if (pindex->nHeight > 0) {
+ if (block.height > 0) {
+ // pindex variable gives indexing code access to node internals. It
+ // will be removed in upcoming commit
+ const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
if (!UndoReadFromDisk(block_undo, pindex)) {
return false;
}
std::pair<uint256, DBVal> read_out;
- if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
+ if (!m_db->Read(DBHeightKey(block.height - 1), read_out)) {
return false;
}
- uint256 expected_block_hash{pindex->pprev->GetBlockHash()};
+ uint256 expected_block_hash{*Assert(block.prev_hash)};
if (read_out.first != expected_block_hash) {
LogPrintf("WARNING: previous block header belongs to unexpected block %s; expected %s\n",
read_out.first.ToString(), expected_block_hash.ToString());
@@ -139,12 +144,13 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
}
// TODO: Deduplicate BIP30 related code
- bool is_bip30_block{(pindex->nHeight == 91722 && pindex->GetBlockHash() == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) ||
- (pindex->nHeight == 91812 && pindex->GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"))};
+ bool is_bip30_block{(block.height == 91722 && block.hash == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) ||
+ (block.height == 91812 && block.hash == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"))};
// Add the new utxos created from the block
- for (size_t i = 0; i < block.vtx.size(); ++i) {
- const auto& tx{block.vtx.at(i)};
+ assert(block.data);
+ for (size_t i = 0; i < block.data->vtx.size(); ++i) {
+ const auto& tx{block.data->vtx.at(i)};
// Skip duplicate txid coinbase transactions (BIP30).
if (is_bip30_block && tx->IsCoinBase()) {
@@ -155,7 +161,7 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
for (uint32_t j = 0; j < tx->vout.size(); ++j) {
const CTxOut& out{tx->vout[j]};
- Coin coin{out, pindex->nHeight, tx->IsCoinBase()};
+ Coin coin{out, block.height, tx->IsCoinBase()};
COutPoint outpoint{tx->GetHash(), j};
// Skip unspendable coins
@@ -211,7 +217,7 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
std::pair<uint256, DBVal> value;
- value.first = pindex->GetBlockHash();
+ value.first = block.hash;
value.second.transaction_output_count = m_transaction_output_count;
value.second.bogo_size = m_bogo_size;
value.second.total_amount = m_total_amount;
@@ -231,7 +237,7 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
// Intentionally do not update DB_MUHASH here so it stays in sync with
// DB_BEST_BLOCK, and the index is not corrupted if there is an unclean shutdown.
- return m_db->Write(DBHeightKey(pindex->nHeight), value);
+ return m_db->Write(DBHeightKey(block.height), value);
}
static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
@@ -260,17 +266,15 @@ static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
return true;
}
-bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
+bool CoinStatsIndex::CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip)
{
- assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
-
CDBBatch batch(*m_db);
std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
// During a reorg, we need to copy all hash digests for blocks that are
// getting disconnected from the height index to the hash index so we can
// still find them when the height index entries are overwritten.
- if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip->nHeight, current_tip->nHeight)) {
+ if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip.height, current_tip.height)) {
return false;
}
@@ -278,7 +282,8 @@ bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* n
{
LOCK(cs_main);
- const CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip->GetBlockHash())};
+ const CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip.hash)};
+ const CBlockIndex* new_tip_index{m_chainstate->m_blockman.LookupBlockIndex(new_tip.hash)};
const auto& consensus_params{Params().GetConsensus()};
do {
@@ -292,29 +297,29 @@ bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* n
ReverseBlock(block, iter_tip);
iter_tip = iter_tip->GetAncestor(iter_tip->nHeight - 1);
- } while (new_tip != iter_tip);
+ } while (new_tip_index != iter_tip);
}
- return BaseIndex::Rewind(current_tip, new_tip);
+ return true;
}
-static bool LookUpOne(const CDBWrapper& db, const CBlockIndex* block_index, DBVal& result)
+static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockKey& block, DBVal& result)
{
// First check if the result is stored under the height index and the value
// there matches the block hash. This should be the case if the block is on
// the active chain.
std::pair<uint256, DBVal> read_out;
- if (!db.Read(DBHeightKey(block_index->nHeight), read_out)) {
+ if (!db.Read(DBHeightKey(block.height), read_out)) {
return false;
}
- if (read_out.first == block_index->GetBlockHash()) {
+ if (read_out.first == block.hash) {
result = std::move(read_out.second);
return true;
}
// If value at the height index corresponds to an different block, the
// result will be stored in the hash index.
- return db.Read(DBHashKey(block_index->GetBlockHash()), result);
+ return db.Read(DBHashKey(block.hash), result);
}
std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex* block_index) const
@@ -323,7 +328,7 @@ std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex* block_
stats.index_used = true;
DBVal entry;
- if (!LookUpOne(*m_db, block_index, entry)) {
+ if (!LookUpOne(*m_db, {block_index->GetBlockHash(), block_index->nHeight}, entry)) {
return std::nullopt;
}
@@ -344,7 +349,7 @@ std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex* block_
return stats;
}
-bool CoinStatsIndex::Init()
+bool CoinStatsIndex::CustomInit(const std::optional<interfaces::BlockKey>& block)
{
if (!m_db->Read(DB_MUHASH, m_muhash)) {
// Check that the cause of the read failure is that the key does not
@@ -356,13 +361,9 @@ bool CoinStatsIndex::Init()
}
}
- if (!BaseIndex::Init()) return false;
-
- const CBlockIndex* pindex{CurrentIndex()};
-
- if (pindex) {
+ if (block) {
DBVal entry;
- if (!LookUpOne(*m_db, pindex, entry)) {
+ if (!LookUpOne(*m_db, *block, entry)) {
return error("%s: Cannot read current %s state; index may be corrupted",
__func__, GetName());
}
@@ -391,12 +392,12 @@ bool CoinStatsIndex::Init()
return true;
}
-bool CoinStatsIndex::CommitInternal(CDBBatch& batch)
+bool CoinStatsIndex::CustomCommit(CDBBatch& batch)
{
// DB_MUHASH should always be committed in a batch together with DB_BEST_BLOCK
// to prevent an inconsistent state of the DB.
batch.Write(DB_MUHASH, m_muhash);
- return BaseIndex::CommitInternal(batch);
+ return true;
}
// Reverse a single block as part of a reorg
diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h
index cae052d913..c4af223388 100644
--- a/src/index/coinstatsindex.h
+++ b/src/index/coinstatsindex.h
@@ -39,13 +39,13 @@ private:
bool AllowPrune() const override { return true; }
protected:
- bool Init() override;
+ bool CustomInit(const std::optional<interfaces::BlockKey>& block) override;
- bool CommitInternal(CDBBatch& batch) override;
+ bool CustomCommit(CDBBatch& batch) override;
- bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
+ bool CustomAppend(const interfaces::BlockInfo& block) override;
- bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip) override;
+ bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) override;
BaseIndex::DB& GetDB() const override { return *m_db; }
@@ -53,7 +53,7 @@ protected:
public:
// Constructs the index, which becomes available to be queried.
- explicit CoinStatsIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
+ explicit CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
// Look up stats for a specific block using CBlockIndex
std::optional<kernel::CCoinsStats> LookUpStats(const CBlockIndex* block_index) const;
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 97c11c4383..b719aface8 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -48,23 +48,22 @@ bool TxIndex::DB::WriteTxs(const std::vector<std::pair<uint256, CDiskTxPos>>& v_
return WriteBatch(batch);
}
-TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
- : m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
+TxIndex::TxIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe)
+ : BaseIndex(std::move(chain)), m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
{}
TxIndex::~TxIndex() = default;
-bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
+bool TxIndex::CustomAppend(const interfaces::BlockInfo& block)
{
// Exclude genesis block transaction because outputs are not spendable.
- if (pindex->nHeight == 0) return true;
+ if (block.height == 0) return true;
- CDiskTxPos pos{
- WITH_LOCK(::cs_main, return pindex->GetBlockPos()),
- GetSizeOfCompactSize(block.vtx.size())};
+ assert(block.data);
+ CDiskTxPos pos({block.file_number, block.data_pos}, GetSizeOfCompactSize(block.data->vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos>> vPos;
- vPos.reserve(block.vtx.size());
- for (const auto& tx : block.vtx) {
+ vPos.reserve(block.data->vtx.size());
+ for (const auto& tx : block.data->vtx) {
vPos.emplace_back(tx->GetHash(), pos);
pos.nTxOffset += ::GetSerializeSize(*tx, CLIENT_VERSION);
}
diff --git a/src/index/txindex.h b/src/index/txindex.h
index ec339abaa1..be240c4582 100644
--- a/src/index/txindex.h
+++ b/src/index/txindex.h
@@ -23,7 +23,7 @@ private:
bool AllowPrune() const override { return false; }
protected:
- bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
+ bool CustomAppend(const interfaces::BlockInfo& block) override;
BaseIndex::DB& GetDB() const override;
@@ -31,7 +31,7 @@ protected:
public:
/// Constructs the index, which becomes available to be queried.
- explicit TxIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
+ explicit TxIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
// Destructor is declared because this class contains a unique_ptr to an incomplete type.
virtual ~TxIndex() override;
diff --git a/src/init.cpp b/src/init.cpp
index 5ed1def4db..a94bbe6460 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -108,8 +108,6 @@ using kernel::DumpMempool;
using node::CacheSizes;
using node::CalculateCacheSizes;
-using node::ChainstateLoadVerifyError;
-using node::ChainstateLoadingError;
using node::DEFAULT_PERSIST_MEMPOOL;
using node::DEFAULT_PRINTPRIORITY;
using node::DEFAULT_STOPAFTERBLOCKIMPORT;
@@ -1098,21 +1096,8 @@ static bool LockDataDirectory(bool probeOnly)
bool AppInitSanityChecks(const kernel::Context& kernel)
{
// ********************************************************* Step 4: sanity checks
- auto maybe_error = kernel::SanityChecks(kernel);
-
- if (maybe_error.has_value()) {
- switch (maybe_error.value()) {
- case kernel::SanityCheckError::ERROR_ECC:
- InitError(Untranslated("Elliptic curve cryptography sanity check failure. Aborting."));
- break;
- case kernel::SanityCheckError::ERROR_RANDOM:
- InitError(Untranslated("OS cryptographic RNG sanity check failure. Aborting."));
- break;
- case kernel::SanityCheckError::ERROR_CHRONO:
- InitError(Untranslated("Clock epoch mismatch. Aborting."));
- break;
- } // no default case, so the compiler can warn about missing cases
-
+ if (auto error = kernel::SanityChecks(kernel)) {
+ InitError(*error);
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME));
}
@@ -1452,112 +1437,54 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
node.chainman = std::make_unique<ChainstateManager>(chainman_opts);
ChainstateManager& chainman = *node.chainman;
- const bool fReset = fReindex;
- bilingual_str strLoadError;
+ node::ChainstateLoadOptions options;
+ options.mempool = Assert(node.mempool.get());
+ options.reindex = node::fReindex;
+ options.reindex_chainstate = fReindexChainState;
+ options.prune = node::fPruneMode;
+ options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
+ options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
+ options.check_interrupt = ShutdownRequested;
+ options.coins_error_cb = [] {
+ uiInterface.ThreadSafeMessageBox(
+ _("Error reading from database, shutting down."),
+ "", CClientUIInterface::MSG_ERROR);
+ };
uiInterface.InitMessage(_("Loading block index…").translated);
const int64_t load_block_index_start_time = GetTimeMillis();
- std::optional<ChainstateLoadingError> maybe_load_error;
- try {
- maybe_load_error = LoadChainstate(fReset,
- chainman,
- Assert(node.mempool.get()),
- fPruneMode,
- fReindexChainState,
- cache_sizes.block_tree_db,
- cache_sizes.coins_db,
- cache_sizes.coins,
- /*block_tree_db_in_memory=*/false,
- /*coins_db_in_memory=*/false,
- /*shutdown_requested=*/ShutdownRequested,
- /*coins_error_cb=*/[]() {
- uiInterface.ThreadSafeMessageBox(
- _("Error reading from database, shutting down."),
- "", CClientUIInterface::MSG_ERROR);
- });
- } catch (const std::exception& e) {
- LogPrintf("%s\n", e.what());
- maybe_load_error = ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED;
- }
- if (maybe_load_error.has_value()) {
- switch (maybe_load_error.value()) {
- case ChainstateLoadingError::ERROR_LOADING_BLOCK_DB:
- strLoadError = _("Error loading block database");
- break;
- case ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK:
- // If the loaded chain has a wrong genesis, bail out immediately
- // (we're likely using a testnet datadir, or the other way around).
- return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
- case ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX:
- strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
- break;
- case ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED:
- strLoadError = _("Error initializing block database");
- break;
- case ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED:
- return InitError(_("Unsupported chainstate database format found. "
- "Please restart with -reindex-chainstate. This will "
- "rebuild the chainstate database."));
- case ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED:
- strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
- break;
- case ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED:
- strLoadError = _("Error initializing block database");
- break;
- case ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED:
- strLoadError = _("Error opening block database");
- break;
- case ChainstateLoadingError::ERROR_BLOCKS_WITNESS_INSUFFICIENTLY_VALIDATED:
- strLoadError = strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."),
- chainman.GetConsensus().SegwitHeight);
- break;
- case ChainstateLoadingError::SHUTDOWN_PROBED:
- break;
- }
- } else {
- std::optional<ChainstateLoadVerifyError> maybe_verify_error;
+ auto catch_exceptions = [](auto&& f) {
try {
- uiInterface.InitMessage(_("Verifying blocks…").translated);
- auto check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
- if (chainman.m_blockman.m_have_pruned && check_blocks > MIN_BLOCKS_TO_KEEP) {
- LogPrintfCategory(BCLog::PRUNE, "pruned datadir may not have more than %d blocks; only checking available blocks\n",
- MIN_BLOCKS_TO_KEEP);
- }
- maybe_verify_error = VerifyLoadedChainstate(chainman,
- fReset,
- fReindexChainState,
- check_blocks,
- args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL));
+ return f();
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());
- maybe_verify_error = ChainstateLoadVerifyError::ERROR_GENERIC_FAILURE;
+ return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error opening block database"));
}
- if (maybe_verify_error.has_value()) {
- switch (maybe_verify_error.value()) {
- case ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE:
- strLoadError = _("The block database contains a block which appears to be from the future. "
- "This may be due to your computer's date and time being set incorrectly. "
- "Only rebuild the block database if you are sure that your computer's date and time are correct");
- break;
- case ChainstateLoadVerifyError::ERROR_CORRUPTED_BLOCK_DB:
- strLoadError = _("Corrupted block database detected");
- break;
- case ChainstateLoadVerifyError::ERROR_GENERIC_FAILURE:
- strLoadError = _("Error opening block database");
- break;
- }
- } else {
+ };
+ auto [status, error] = catch_exceptions([&]{ return LoadChainstate(chainman, cache_sizes, options); });
+ if (status == node::ChainstateLoadStatus::SUCCESS) {
+ uiInterface.InitMessage(_("Verifying blocks…").translated);
+ if (chainman.m_blockman.m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) {
+ LogPrintfCategory(BCLog::PRUNE, "pruned datadir may not have more than %d blocks; only checking available blocks\n",
+ MIN_BLOCKS_TO_KEEP);
+ }
+ std::tie(status, error) = catch_exceptions([&]{ return VerifyLoadedChainstate(chainman, options);});
+ if (status == node::ChainstateLoadStatus::SUCCESS) {
fLoaded = true;
LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time);
}
}
+ if (status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB) {
+ return InitError(error);
+ }
+
if (!fLoaded && !ShutdownRequested()) {
// first suggest a reindex
- if (!fReset) {
+ if (!options.reindex) {
bool fRet = uiInterface.ThreadSafeQuestion(
- strLoadError + Untranslated(".\n\n") + _("Do you want to rebuild the block database now?"),
- strLoadError.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
+ error + Untranslated(".\n\n") + _("Do you want to rebuild the block database now?"),
+ error.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
if (fRet) {
fReindex = true;
@@ -1567,7 +1494,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
return false;
}
} else {
- return InitError(strLoadError);
+ return InitError(error);
}
}
}
@@ -1593,22 +1520,22 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
return InitError(*error);
}
- g_txindex = std::make_unique<TxIndex>(cache_sizes.tx_index, false, fReindex);
- if (!g_txindex->Start(chainman.ActiveChainstate())) {
+ g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, fReindex);
+ if (!g_txindex->Start()) {
return false;
}
}
for (const auto& filter_type : g_enabled_filter_types) {
- InitBlockFilterIndex(filter_type, cache_sizes.filter_index, false, fReindex);
- if (!GetBlockFilterIndex(filter_type)->Start(chainman.ActiveChainstate())) {
+ InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, fReindex);
+ if (!GetBlockFilterIndex(filter_type)->Start()) {
return false;
}
}
if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
- g_coin_stats_index = std::make_unique<CoinStatsIndex>(/* cache size */ 0, false, fReindex);
- if (!g_coin_stats_index->Start(chainman.ActiveChainstate())) {
+ g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /* cache size */ 0, false, fReindex);
+ if (!g_coin_stats_index->Start()) {
return false;
}
}
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index ff994b8edc..5fc0e540a9 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -18,6 +18,7 @@
class ArgsManager;
class CBlock;
+class CBlockUndo;
class CFeeRate;
class CRPCCommand;
class CScheduler;
@@ -37,6 +38,12 @@ namespace interfaces {
class Handler;
class Wallet;
+//! Hash/height pair to help track and identify blocks.
+struct BlockKey {
+ uint256 hash;
+ int height = -1;
+};
+
//! Helper for findBlock to selectively return pieces of block data. If block is
//! found, data will be returned by setting specified output variables. If block
//! is not found, output variables will keep their previous values.
@@ -50,6 +57,8 @@ public:
FoundBlock& mtpTime(int64_t& mtp_time) { m_mtp_time = &mtp_time; return *this; }
//! Return whether block is in the active (most-work) chain.
FoundBlock& inActiveChain(bool& in_active_chain) { m_in_active_chain = &in_active_chain; return *this; }
+ //! Return locator if block is in the active chain.
+ FoundBlock& locator(CBlockLocator& locator) { m_locator = &locator; return *this; }
//! Return next block in the active chain if current block is in the active chain.
FoundBlock& nextBlock(const FoundBlock& next_block) { m_next_block = &next_block; return *this; }
//! Read block data from disk. If the block exists but doesn't have data
@@ -62,11 +71,25 @@ public:
int64_t* m_max_time = nullptr;
int64_t* m_mtp_time = nullptr;
bool* m_in_active_chain = nullptr;
+ CBlockLocator* m_locator = nullptr;
const FoundBlock* m_next_block = nullptr;
CBlock* m_data = nullptr;
mutable bool found = false;
};
+//! Block data sent with blockConnected, blockDisconnected notifications.
+struct BlockInfo {
+ const uint256& hash;
+ const uint256* prev_hash = nullptr;
+ int height = -1;
+ int file_number = -1;
+ unsigned data_pos = 0;
+ const CBlock* data = nullptr;
+ const CBlockUndo* undo_data = nullptr;
+
+ BlockInfo(const uint256& hash LIFETIMEBOUND) : hash(hash) {}
+};
+
//! Interface giving clients (wallet processes, maybe other analysis tools in
//! the future) ability to access to the chain state, receive notifications,
//! estimate fees, and submit transactions.
@@ -239,8 +262,8 @@ public:
virtual ~Notifications() {}
virtual void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {}
virtual void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {}
- virtual void blockConnected(const CBlock& block, int height) {}
- virtual void blockDisconnected(const CBlock& block, int height) {}
+ virtual void blockConnected(const BlockInfo& block) {}
+ virtual void blockDisconnected(const BlockInfo& block) {}
virtual void updatedBlockTip() {}
virtual void chainStateFlushed(const CBlockLocator& locator) {}
};
@@ -290,6 +313,10 @@ public:
//! Return true if an assumed-valid chain is in use.
virtual bool hasAssumedValidChain() = 0;
+
+ //! Get internal node context. Useful for testing, but not
+ //! accessible across processes.
+ virtual node::NodeContext* context() { return nullptr; }
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
diff --git a/src/kernel/chain.cpp b/src/kernel/chain.cpp
new file mode 100644
index 0000000000..82e77125d7
--- /dev/null
+++ b/src/kernel/chain.cpp
@@ -0,0 +1,26 @@
+// Copyright (c) 2022 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 <chain.h>
+#include <interfaces/chain.h>
+#include <sync.h>
+#include <uint256.h>
+
+class CBlock;
+
+namespace kernel {
+interfaces::BlockInfo MakeBlockInfo(const CBlockIndex* index, const CBlock* data)
+{
+ interfaces::BlockInfo info{index ? *index->phashBlock : uint256::ZERO};
+ if (index) {
+ info.prev_hash = index->pprev ? index->pprev->phashBlock : nullptr;
+ info.height = index->nHeight;
+ LOCK(::cs_main);
+ info.file_number = index->nFile;
+ info.data_pos = index->nDataPos;
+ }
+ info.data = data;
+ return info;
+}
+} // namespace kernel
diff --git a/src/kernel/chain.h b/src/kernel/chain.h
new file mode 100644
index 0000000000..f0750f8266
--- /dev/null
+++ b/src/kernel/chain.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2022 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_KERNEL_CHAIN_H
+#define BITCOIN_KERNEL_CHAIN_H
+
+class CBlock;
+class CBlockIndex;
+namespace interfaces {
+struct BlockInfo;
+} // namespace interfaces
+
+namespace kernel {
+//! Return data from block index.
+interfaces::BlockInfo MakeBlockInfo(const CBlockIndex* block_index, const CBlock* data = nullptr);
+} // namespace kernel
+
+#endif // BITCOIN_KERNEL_CHAIN_H
diff --git a/src/kernel/checks.cpp b/src/kernel/checks.cpp
index 2a1dd3bfa2..4c303c172c 100644
--- a/src/kernel/checks.cpp
+++ b/src/kernel/checks.cpp
@@ -7,21 +7,24 @@
#include <key.h>
#include <random.h>
#include <util/time.h>
+#include <util/translation.h>
+
+#include <memory>
namespace kernel {
-std::optional<SanityCheckError> SanityChecks(const Context&)
+std::optional<bilingual_str> SanityChecks(const Context&)
{
if (!ECC_InitSanityCheck()) {
- return SanityCheckError::ERROR_ECC;
+ return Untranslated("Elliptic curve cryptography sanity check failure. Aborting.");
}
if (!Random_SanityCheck()) {
- return SanityCheckError::ERROR_RANDOM;
+ return Untranslated("OS cryptographic RNG sanity check failure. Aborting.");
}
if (!ChronoSanityCheck()) {
- return SanityCheckError::ERROR_CHRONO;
+ return Untranslated("Clock epoch mismatch. Aborting.");
}
return std::nullopt;
diff --git a/src/kernel/checks.h b/src/kernel/checks.h
index 80b207f607..3eb14824fb 100644
--- a/src/kernel/checks.h
+++ b/src/kernel/checks.h
@@ -7,20 +7,16 @@
#include <optional>
+struct bilingual_str;
+
namespace kernel {
struct Context;
-enum class SanityCheckError {
- ERROR_ECC,
- ERROR_RANDOM,
- ERROR_CHRONO,
-};
-
/**
* Ensure a usable environment with all necessary library support.
*/
-std::optional<SanityCheckError> SanityChecks(const Context&);
+std::optional<bilingual_str> SanityChecks(const Context&);
}
diff --git a/src/kernel/coinstats.cpp b/src/kernel/coinstats.cpp
index f380871627..06a4b8c974 100644
--- a/src/kernel/coinstats.cpp
+++ b/src/kernel/coinstats.cpp
@@ -4,16 +4,32 @@
#include <kernel/coinstats.h>
+#include <chain.h>
#include <coins.h>
#include <crypto/muhash.h>
#include <hash.h>
+#include <node/blockstorage.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
#include <serialize.h>
+#include <span.h>
+#include <streams.h>
+#include <sync.h>
+#include <tinyformat.h>
#include <uint256.h>
+#include <util/check.h>
#include <util/overflow.h>
#include <util/system.h>
#include <validation.h>
+#include <version.h>
+#include <cassert>
+#include <iosfwd>
+#include <iterator>
#include <map>
+#include <memory>
+#include <string>
+#include <utility>
namespace kernel {
@@ -52,7 +68,7 @@ CDataStream TxOutSer(const COutPoint& outpoint, const Coin& coin) {
//! It is also possible, though very unlikely, that a change in this
//! construction could cause a previously invalid (and potentially malicious)
//! UTXO snapshot to be considered valid.
-static void ApplyHash(CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
+static void ApplyHash(HashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
{
for (auto it = outputs.begin(); it != outputs.end(); ++it) {
if (it == outputs.begin()) {
@@ -143,7 +159,7 @@ std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsV
bool success = [&]() -> bool {
switch (hash_type) {
case(CoinStatsHashType::HASH_SERIALIZED): {
- CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
+ HashWriter ss{};
return ComputeUTXOStats(view, stats, ss, interruption_point);
}
case(CoinStatsHashType::MUHASH): {
@@ -164,7 +180,7 @@ std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsV
}
// The legacy hash serializes the hashBlock
-static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats)
+static void PrepareHash(HashWriter& ss, const CCoinsStats& stats)
{
ss << stats.hashBlock;
}
@@ -172,7 +188,7 @@ static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats)
static void PrepareHash(MuHash3072& muhash, CCoinsStats& stats) {}
static void PrepareHash(std::nullptr_t, CCoinsStats& stats) {}
-static void FinalizeHash(CHashWriter& ss, CCoinsStats& stats)
+static void FinalizeHash(HashWriter& ss, CCoinsStats& stats)
{
stats.hashSerialized = ss.GetHash();
}
diff --git a/src/kernel/coinstats.h b/src/kernel/coinstats.h
index a15957233f..b7c1328e93 100644
--- a/src/kernel/coinstats.h
+++ b/src/kernel/coinstats.h
@@ -5,16 +5,18 @@
#ifndef BITCOIN_KERNEL_COINSTATS_H
#define BITCOIN_KERNEL_COINSTATS_H
-#include <chain.h>
-#include <coins.h>
#include <consensus/amount.h>
#include <streams.h>
#include <uint256.h>
#include <cstdint>
#include <functional>
+#include <optional>
class CCoinsView;
+class Coin;
+class COutPoint;
+class CScript;
namespace node {
class BlockManager;
} // namespace node
diff --git a/src/mapport.cpp b/src/mapport.cpp
index 235e6f904c..6262e51879 100644
--- a/src/mapport.cpp
+++ b/src/mapport.cpp
@@ -19,7 +19,7 @@
#include <util/thread.h>
#ifdef USE_NATPMP
-#include <compat.h>
+#include <compat/compat.h>
#include <natpmp.h>
#endif // USE_NATPMP
diff --git a/src/net.cpp b/src/net.cpp
index 2c4a1e4bae..c4aaac4986 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -13,7 +13,7 @@
#include <addrman.h>
#include <banman.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <consensus/consensus.h>
#include <crypto/sha256.h>
#include <node/eviction.h>
@@ -85,8 +85,8 @@ static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000; // "many" vs "few" pe
/** The default timeframe for -maxuploadtarget. 1 day. */
static constexpr std::chrono::seconds MAX_UPLOAD_TIMEFRAME{60 * 60 * 24};
-// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
-#define FEELER_SLEEP_WINDOW 1
+// A random time period (0 to 1 seconds) is added to feeler connections to prevent synchronization.
+static constexpr auto FEELER_SLEEP_WINDOW{1s};
/** Used to pass flags to the Bind() function */
enum BindFlags {
@@ -187,7 +187,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
// it'll get a pile of addresses with newer timestamps.
// Seed nodes are given a random 'last seen time' of between one and two
// weeks ago.
- const int64_t nOneWeek = 7*24*60*60;
+ const auto one_week{7 * 24h};
std::vector<CAddress> vSeedsOut;
FastRandomContext rng;
CDataStream s(vSeedsIn, SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
@@ -195,7 +195,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
CService endpoint;
s >> endpoint;
CAddress addr{endpoint, GetDesirableServiceFlags(NODE_NONE)};
- addr.nTime = GetTime() - rng.randrange(nOneWeek) - nOneWeek;
+ addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - one_week, -one_week);
LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToString());
vSeedsOut.push_back(addr);
}
@@ -452,10 +452,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
}
}
- /// debug print
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "trying connection %s lastseen=%.1fhrs\n",
- pszDest ? pszDest : addrConnect.ToString(),
- pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime) / 3600.0);
+ pszDest ? pszDest : addrConnect.ToString(),
+ Ticks<HoursDouble>(pszDest ? 0h : AdjustedTime() - addrConnect.nTime));
// Resolve
const uint16_t default_port{pszDest != nullptr ? Params().GetDefaultPort(pszDest) :
@@ -1469,9 +1468,8 @@ void CConnman::ThreadDNSAddressSeed()
unsigned int nMaxIPs = 256; // Limits number of IPs learned from a DNS seed
if (LookupHost(host, vIPs, nMaxIPs, true)) {
for (const CNetAddr& ip : vIPs) {
- int nOneDay = 24*3600;
CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
- addr.nTime = GetTime() - 3*nOneDay - rng.randrange(4*nOneDay); // use a random age between 3 and 7 days old
+ addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
vAdd.push_back(addr);
found++;
}
@@ -1568,6 +1566,7 @@ int CConnman::GetExtraBlockRelayCount() const
void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_OPEN_CONNECTION);
+ FastRandomContext rng;
// Connect to specific addresses
if (!connect.empty())
{
@@ -1736,7 +1735,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
addrman.ResolveCollisions();
- int64_t nANow = GetAdjustedTime();
+ const auto nANow{AdjustedTime()};
int nTries = 0;
while (!interruptNet)
{
@@ -1759,7 +1758,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
break;
CAddress addr;
- int64_t addr_last_try{0};
+ NodeSeconds addr_last_try{0s};
if (fFeeler) {
// First, try to get a tried table collision address. This returns
@@ -1799,8 +1798,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
continue;
// only consider very recently tried nodes after 30 failed attempts
- if (nANow - addr_last_try < 600 && nTries < 30)
+ if (nANow - addr_last_try < 10min && nTries < 30) {
continue;
+ }
// for non-feelers, require all the services we'll want,
// for feelers, only require they be a full node (only because most
@@ -1821,12 +1821,11 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
}
if (addrConnect.IsValid()) {
-
if (fFeeler) {
// Add small amount of random noise before connection to avoid synchronization.
- int randsleep = GetRand<int>(FEELER_SLEEP_WINDOW * 1000);
- if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep)))
+ if (!interruptNet.sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) {
return;
+ }
LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString());
}
@@ -2825,7 +2824,7 @@ void CaptureMessageToFile(const CAddress& addr,
fs::create_directories(base_path);
fs::path path = base_path / (is_incoming ? "msgs_recv.dat" : "msgs_sent.dat");
- CAutoFile f(fsbridge::fopen(path, "ab"), SER_DISK, CLIENT_VERSION);
+ AutoFile f{fsbridge::fopen(path, "ab")};
ser_writedata64(f, now.count());
f.write(MakeByteSpan(msg_type));
diff --git a/src/net.h b/src/net.h
index f3be7e8dff..2036e9078c 100644
--- a/src/net.h
+++ b/src/net.h
@@ -8,7 +8,7 @@
#include <chainparams.h>
#include <common/bloom.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <node/connection_types.h>
#include <consensus/amount.h>
#include <crypto/siphash.h>
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 74d1bf44d2..7507b8ebca 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -29,6 +29,7 @@
#include <scheduler.h>
#include <streams.h>
#include <sync.h>
+#include <timedata.h>
#include <tinyformat.h>
#include <txmempool.h>
#include <txorphanage.h>
@@ -2929,7 +2930,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// indicate to the peer that we will participate in addr relay.
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
{
- CAddress addr{GetLocalAddress(pfrom.addr), peer->m_our_services, (uint32_t)GetAdjustedTime()};
+ CAddress addr{GetLocalAddress(pfrom.addr), peer->m_our_services, AdjustedTime()};
FastRandomContext insecure_rand;
if (addr.IsRoutable())
{
@@ -3134,8 +3135,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Store the new addresses
std::vector<CAddress> vAddrOk;
- int64_t nNow = GetAdjustedTime();
- int64_t nSince = nNow - 10 * 60;
+ const auto current_a_time{AdjustedTime()};
// Update/increment addr rate limiting bucket.
const auto current_time{GetTime<std::chrono::microseconds>()};
@@ -3171,8 +3171,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (!MayHaveUsefulAddressDB(addr.nServices) && !HasAllDesirableServiceFlags(addr.nServices))
continue;
- if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
- addr.nTime = nNow - 5 * 24 * 60 * 60;
+ if (addr.nTime <= NodeSeconds{100000000s} || addr.nTime > current_a_time + 10min) {
+ addr.nTime = current_a_time - 5 * 24h;
+ }
AddAddressKnown(*peer, addr);
if (m_banman && (m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr))) {
// Do not process banned/discouraged addresses beyond remembering we received them
@@ -3180,7 +3181,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
++num_proc;
bool fReachable = IsReachable(addr);
- if (addr.nTime > nSince && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) {
+ if (addr.nTime > current_a_time - 10min && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) {
// Relay to a limited number of other nodes
RelayAddress(pfrom.GetId(), addr, fReachable);
}
@@ -3193,7 +3194,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
LogPrint(BCLog::NET, "Received addr: %u addresses (%u processed, %u rate-limited) from peer=%d\n",
vAddr.size(), num_proc, num_rate_limit, pfrom.GetId());
- m_addrman.Add(vAddrOk, pfrom.addr, 2 * 60 * 60);
+ m_addrman.Add(vAddrOk, pfrom.addr, 2h);
if (vAddr.size() < 1000) peer->m_getaddr_sent = false;
// AddrFetch: Require multiple addresses to avoid disconnecting on self-announcements
@@ -4685,7 +4686,7 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
peer.m_addr_known->reset();
}
if (std::optional<CService> local_service = GetLocalAddrForPeer(node)) {
- CAddress local_addr{*local_service, peer.m_our_services, (uint32_t)GetAdjustedTime()};
+ CAddress local_addr{*local_service, peer.m_our_services, AdjustedTime()};
FastRandomContext insecure_rand;
PushAddress(peer, local_addr, insecure_rand);
}
diff --git a/src/netaddress.h b/src/netaddress.h
index 47ba045334..e52beb783d 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -9,7 +9,7 @@
#include <config/bitcoin-config.h>
#endif
-#include <compat.h>
+#include <compat/compat.h>
#include <crypto/siphash.h>
#include <prevector.h>
#include <random.h>
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 030f462ed9..4b8d2f8d0c 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -5,7 +5,7 @@
#include <netbase.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <sync.h>
#include <tinyformat.h>
#include <util/sock.h>
diff --git a/src/netbase.h b/src/netbase.h
index bf7522210d..fadc8b418e 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -9,7 +9,7 @@
#include <config/bitcoin-config.h>
#endif
-#include <compat.h>
+#include <compat/compat.h>
#include <netaddress.h>
#include <serialize.h>
#include <util/sock.h>
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 103f4f0d7f..bac05f6be2 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -471,7 +471,7 @@ static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const
fileout << blockundo;
// calculate & write checksum
- CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
+ HashWriter hasher{};
hasher << hashBlock;
hasher << blockundo;
fileout << hasher.GetHash();
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index 54ba5b7966..ad9293f172 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -4,66 +4,75 @@
#include <node/chainstate.h>
+#include <chain.h>
+#include <coins.h>
#include <consensus/params.h>
#include <node/blockstorage.h>
+#include <node/caches.h>
+#include <sync.h>
+#include <threadsafety.h>
+#include <tinyformat.h>
+#include <txdb.h>
+#include <uint256.h>
+#include <util/time.h>
+#include <util/translation.h>
#include <validation.h>
+#include <algorithm>
+#include <atomic>
+#include <cassert>
+#include <memory>
+#include <vector>
+
namespace node {
-std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
- ChainstateManager& chainman,
- CTxMemPool* mempool,
- bool fPruneMode,
- bool fReindexChainState,
- int64_t nBlockTreeDBCache,
- int64_t nCoinDBCache,
- int64_t nCoinCacheUsage,
- bool block_tree_db_in_memory,
- bool coins_db_in_memory,
- std::function<bool()> shutdown_requested,
- std::function<void()> coins_error_cb)
+ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes,
+ const ChainstateLoadOptions& options)
{
auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
- return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
+ return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
};
LOCK(cs_main);
- chainman.InitializeChainstate(mempool);
- chainman.m_total_coinstip_cache = nCoinCacheUsage;
- chainman.m_total_coinsdb_cache = nCoinDBCache;
+ chainman.InitializeChainstate(options.mempool);
+ chainman.m_total_coinstip_cache = cache_sizes.coins;
+ chainman.m_total_coinsdb_cache = cache_sizes.coins_db;
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
// new CBlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
pblocktree.reset();
- pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, block_tree_db_in_memory, fReset));
+ pblocktree.reset(new CBlockTreeDB(cache_sizes.block_tree_db, options.block_tree_db_in_memory, options.reindex));
- if (fReset) {
+ if (options.reindex) {
pblocktree->WriteReindexing(true);
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
- if (fPruneMode)
+ if (options.prune) {
CleanupBlockRevFiles();
+ }
}
- if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
+ if (options.check_interrupt && options.check_interrupt()) return {ChainstateLoadStatus::INTERRUPTED, {}};
// LoadBlockIndex will load m_have_pruned if we've ever removed a
// block file from disk.
- // Note that it also sets fReindex based on the disk flag!
- // From here on out fReindex and fReset mean something different!
+ // Note that it also sets fReindex global based on the disk flag!
+ // From here on, fReindex and options.reindex values may be different!
if (!chainman.LoadBlockIndex()) {
- if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
- return ChainstateLoadingError::ERROR_LOADING_BLOCK_DB;
+ if (options.check_interrupt && options.check_interrupt()) return {ChainstateLoadStatus::INTERRUPTED, {}};
+ return {ChainstateLoadStatus::FAILURE, _("Error loading block database")};
}
if (!chainman.BlockIndex().empty() &&
!chainman.m_blockman.LookupBlockIndex(chainman.GetConsensus().hashGenesisBlock)) {
- return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK;
+ // If the loaded chain has a wrong genesis, bail out immediately
+ // (we're likely using a testnet datadir, or the other way around).
+ return {ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB, _("Incorrect or no genesis block found. Wrong datadir for network?")};
}
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
// in the past, but is now trying to run unpruned.
- if (chainman.m_blockman.m_have_pruned && !fPruneMode) {
- return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
+ if (chainman.m_blockman.m_have_pruned && !options.prune) {
+ return {ChainstateLoadStatus::FAILURE, _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain")};
}
// At this point blocktree args are consistent with what's on disk.
@@ -71,7 +80,7 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
// (otherwise we use the one already on disk).
// This is called again in ThreadImport after the reindex completes.
if (!fReindex && !chainman.ActiveChainstate().LoadGenesisBlock()) {
- return ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED;
+ return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")};
}
// At this point we're either in reindex or we've loaded a useful
@@ -79,57 +88,56 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
for (CChainState* chainstate : chainman.GetAll()) {
chainstate->InitCoinsDB(
- /*cache_size_bytes=*/nCoinDBCache,
- /*in_memory=*/coins_db_in_memory,
- /*should_wipe=*/fReset || fReindexChainState);
+ /*cache_size_bytes=*/cache_sizes.coins_db,
+ /*in_memory=*/options.coins_db_in_memory,
+ /*should_wipe=*/options.reindex || options.reindex_chainstate);
- if (coins_error_cb) {
- chainstate->CoinsErrorCatcher().AddReadErrCallback(coins_error_cb);
+ if (options.coins_error_cb) {
+ chainstate->CoinsErrorCatcher().AddReadErrCallback(options.coins_error_cb);
}
// Refuse to load unsupported database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (chainstate->CoinsDB().NeedsUpgrade()) {
- return ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED;
+ return {ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB, _("Unsupported chainstate database format found. "
+ "Please restart with -reindex-chainstate. This will "
+ "rebuild the chainstate database.")};
}
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!chainstate->ReplayBlocks()) {
- return ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED;
+ return {ChainstateLoadStatus::FAILURE, _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.")};
}
// The on-disk coinsdb is now in a good state, create the cache
- chainstate->InitCoinsCache(nCoinCacheUsage);
+ chainstate->InitCoinsCache(cache_sizes.coins);
assert(chainstate->CanFlushToDisk());
if (!is_coinsview_empty(chainstate)) {
// LoadChainTip initializes the chain based on CoinsTip()'s best block
if (!chainstate->LoadChainTip()) {
- return ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED;
+ return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")};
}
assert(chainstate->m_chain.Tip() != nullptr);
}
}
- if (!fReset) {
+ if (!options.reindex) {
auto chainstates{chainman.GetAll()};
if (std::any_of(chainstates.begin(), chainstates.end(),
[](const CChainState* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {
- return ChainstateLoadingError::ERROR_BLOCKS_WITNESS_INSUFFICIENTLY_VALIDATED;
- }
+ return {ChainstateLoadStatus::FAILURE, strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."),
+ chainman.GetConsensus().SegwitHeight)};
+ };
}
- return std::nullopt;
+ return {ChainstateLoadStatus::SUCCESS, {}};
}
-std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManager& chainman,
- bool fReset,
- bool fReindexChainState,
- int check_blocks,
- int check_level)
+ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options)
{
auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
- return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
+ return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
};
LOCK(cs_main);
@@ -138,18 +146,20 @@ std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManage
if (!is_coinsview_empty(chainstate)) {
const CBlockIndex* tip = chainstate->m_chain.Tip();
if (tip && tip->nTime > GetTime() + MAX_FUTURE_BLOCK_TIME) {
- return ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE;
+ return {ChainstateLoadStatus::FAILURE, _("The block database contains a block which appears to be from the future. "
+ "This may be due to your computer's date and time being set incorrectly. "
+ "Only rebuild the block database if you are sure that your computer's date and time are correct")};
}
if (!CVerifyDB().VerifyDB(
*chainstate, chainman.GetConsensus(), chainstate->CoinsDB(),
- check_level,
- check_blocks)) {
- return ChainstateLoadVerifyError::ERROR_CORRUPTED_BLOCK_DB;
+ options.check_level,
+ options.check_blocks)) {
+ return {ChainstateLoadStatus::FAILURE, _("Corrupted block database detected")};
}
}
}
- return std::nullopt;
+ return {ChainstateLoadStatus::SUCCESS, {}};
}
} // namespace node
diff --git a/src/node/chainstate.h b/src/node/chainstate.h
index ff7935e8e0..2289310ece 100644
--- a/src/node/chainstate.h
+++ b/src/node/chainstate.h
@@ -5,30 +5,41 @@
#ifndef BITCOIN_NODE_CHAINSTATE_H
#define BITCOIN_NODE_CHAINSTATE_H
+#include <util/translation.h>
+#include <validation.h>
+
#include <cstdint>
#include <functional>
-#include <optional>
+#include <tuple>
-class ChainstateManager;
class CTxMemPool;
-namespace Consensus {
-struct Params;
-} // namespace Consensus
namespace node {
-enum class ChainstateLoadingError {
- ERROR_LOADING_BLOCK_DB,
- ERROR_BAD_GENESIS_BLOCK,
- ERROR_PRUNED_NEEDS_REINDEX,
- ERROR_LOAD_GENESIS_BLOCK_FAILED,
- ERROR_CHAINSTATE_UPGRADE_FAILED,
- ERROR_REPLAYBLOCKS_FAILED,
- ERROR_LOADCHAINTIP_FAILED,
- ERROR_GENERIC_BLOCKDB_OPEN_FAILED,
- ERROR_BLOCKS_WITNESS_INSUFFICIENTLY_VALIDATED,
- SHUTDOWN_PROBED,
+
+struct CacheSizes;
+
+struct ChainstateLoadOptions {
+ CTxMemPool* mempool{nullptr};
+ bool block_tree_db_in_memory{false};
+ bool coins_db_in_memory{false};
+ bool reindex{false};
+ bool reindex_chainstate{false};
+ bool prune{false};
+ int64_t check_blocks{DEFAULT_CHECKBLOCKS};
+ int64_t check_level{DEFAULT_CHECKLEVEL};
+ std::function<bool()> check_interrupt;
+ std::function<void()> coins_error_cb;
};
+//! Chainstate load status. Simple applications can just check for the success
+//! case, and treat other cases as errors. More complex applications may want to
+//! try reindexing in the generic failure case, and pass an interrupt callback
+//! and exit cleanly in the interrupted case.
+enum class ChainstateLoadStatus { SUCCESS, FAILURE, FAILURE_INCOMPATIBLE_DB, INTERRUPTED };
+
+//! Chainstate load status code and optional error string.
+using ChainstateLoadResult = std::tuple<ChainstateLoadStatus, bilingual_str>;
+
/** This sequence can have 4 types of outcomes:
*
* 1. Success
@@ -40,45 +51,11 @@ enum class ChainstateLoadingError {
* 4. Hard failure
* - a failure that definitively cannot be recovered from with a reindex
*
- * Currently, LoadChainstate returns a std::optional<ChainstateLoadingError>
- * which:
- *
- * - if has_value()
- * - Either "Soft failure", "Hard failure", or "Shutdown requested",
- * differentiable by the specific enumerator.
- *
- * Note that a return value of SHUTDOWN_PROBED means ONLY that "during
- * this sequence, when we explicitly checked shutdown_requested() at
- * arbitrary points, one of those calls returned true". Therefore, a
- * return value other than SHUTDOWN_PROBED does not guarantee that
- * shutdown hasn't been called indirectly.
- * - else
- * - Success!
+ * LoadChainstate returns a (status code, error string) tuple.
*/
-std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
- ChainstateManager& chainman,
- CTxMemPool* mempool,
- bool fPruneMode,
- bool fReindexChainState,
- int64_t nBlockTreeDBCache,
- int64_t nCoinDBCache,
- int64_t nCoinCacheUsage,
- bool block_tree_db_in_memory,
- bool coins_db_in_memory,
- std::function<bool()> shutdown_requested = nullptr,
- std::function<void()> coins_error_cb = nullptr);
-
-enum class ChainstateLoadVerifyError {
- ERROR_BLOCK_FROM_FUTURE,
- ERROR_CORRUPTED_BLOCK_DB,
- ERROR_GENERIC_FAILURE,
-};
-
-std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManager& chainman,
- bool fReset,
- bool fReindexChainState,
- int check_blocks,
- int check_level);
+ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes,
+ const ChainstateLoadOptions& options);
+ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options);
} // namespace node
#endif // BITCOIN_NODE_CHAINSTATE_H
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 46e0efb9b6..46d45377fa 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -19,6 +19,7 @@
#include <netaddress.h>
#include <netbase.h>
#include <node/blockstorage.h>
+#include <kernel/chain.h>
#include <node/coin.h>
#include <node/context.h>
#include <node/transaction.h>
@@ -35,7 +36,6 @@
#include <shutdown.h>
#include <support/allocators/secure.h>
#include <sync.h>
-#include <timedata.h>
#include <txmempool.h>
#include <uint256.h>
#include <univalue.h>
@@ -401,6 +401,7 @@ bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<Rec
if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax();
if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast();
if (block.m_in_active_chain) *block.m_in_active_chain = active[index->nHeight] == index;
+ if (block.m_locator) { *block.m_locator = active.GetLocator(index); }
if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active);
if (block.m_data) {
REVERSE_LOCK(lock);
@@ -426,11 +427,11 @@ public:
}
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
{
- m_notifications->blockConnected(*block, index->nHeight);
+ m_notifications->blockConnected(kernel::MakeBlockInfo(index, block.get()));
}
void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
{
- m_notifications->blockDisconnected(*block, index->nHeight);
+ m_notifications->blockDisconnected(kernel::MakeBlockInfo(index, block.get()));
}
void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
{
@@ -507,7 +508,7 @@ public:
std::optional<int> getHeight() override
{
LOCK(::cs_main);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
+ const CChain& active = chainman().ActiveChain();
int height = active.Height();
if (height >= 0) {
return height;
@@ -517,7 +518,7 @@ public:
uint256 getBlockHash(int height) override
{
LOCK(::cs_main);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
+ const CChain& active = chainman().ActiveChain();
CBlockIndex* block = active[height];
assert(block);
return block->GetBlockHash();
@@ -525,14 +526,14 @@ public:
bool haveBlockOnDisk(int height) override
{
LOCK(::cs_main);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
+ const CChain& active = chainman().ActiveChain();
CBlockIndex* block = active[height];
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
}
CBlockLocator getTipLocator() override
{
LOCK(::cs_main);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
+ const CChain& active = chainman().ActiveChain();
return active.GetLocator();
}
CBlockLocator getActiveChainLocator(const uint256& block_hash) override
@@ -545,7 +546,7 @@ public:
std::optional<int> findLocatorFork(const CBlockLocator& locator) override
{
LOCK(::cs_main);
- const CChainState& active = Assert(m_node.chainman)->ActiveChainstate();
+ const CChainState& active = chainman().ActiveChainstate();
if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
return fork->nHeight;
}
@@ -554,20 +555,20 @@ public:
bool findBlock(const uint256& hash, const FoundBlock& block) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- return FillBlock(m_node.chainman->m_blockman.LookupBlockIndex(hash), block, lock, active);
+ const CChain& active = chainman().ActiveChain();
+ return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, active);
}
bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
+ const CChain& active = chainman().ActiveChain();
return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active);
}
bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- if (const CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash)) {
+ const CChain& active = chainman().ActiveChain();
+ if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) {
return FillBlock(ancestor, ancestor_out, lock, active);
}
@@ -577,18 +578,18 @@ public:
bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- const CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash);
- const CBlockIndex* ancestor = m_node.chainman->m_blockman.LookupBlockIndex(ancestor_hash);
+ const CChain& active = chainman().ActiveChain();
+ const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash);
+ const CBlockIndex* ancestor = chainman().m_blockman.LookupBlockIndex(ancestor_hash);
if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;
return FillBlock(ancestor, ancestor_out, lock, active);
}
bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- const CBlockIndex* block1 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash1);
- const CBlockIndex* block2 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash2);
+ const CChain& active = chainman().ActiveChain();
+ const CBlockIndex* block1 = chainman().m_blockman.LookupBlockIndex(block_hash1);
+ const CBlockIndex* block2 = chainman().m_blockman.LookupBlockIndex(block_hash2);
const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;
// Using & instead of && below to avoid short circuiting and leaving
// output uninitialized. Cast bool to int to avoid -Wbitwise-instead-of-logical
@@ -701,7 +702,7 @@ public:
bool havePruned() override
{
LOCK(::cs_main);
- return m_node.chainman->m_blockman.m_have_pruned;
+ return chainman().m_blockman.m_have_pruned;
}
bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
bool isInitialBlockDownload() override {
@@ -723,7 +724,7 @@ public:
{
if (!old_tip.IsNull()) {
LOCK(::cs_main);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
+ const CChain& active = chainman().ActiveChain();
if (old_tip == active.Tip()->GetBlockHash()) return;
}
SyncWithValidationInterfaceQueue();
@@ -777,9 +778,10 @@ public:
}
bool hasAssumedValidChain() override
{
- return Assert(m_node.chainman)->IsSnapshotActive();
+ return chainman().IsSnapshotActive();
}
+ NodeContext* context() override { return &m_node; }
NodeContext& m_node;
};
} // namespace
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 27a6ab221f..2b940be07e 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -161,13 +161,13 @@ public:
unsigned int GetMaxConfirms() const { return scale * confAvg.size(); }
/** Write state of estimation data to a file*/
- void Write(CAutoFile& fileout) const;
+ void Write(AutoFile& fileout) const;
/**
* Read saved state of estimation data from a file and replace all internal data structures and
* variables with this state.
*/
- void Read(CAutoFile& filein, int nFileVersion, size_t numBuckets);
+ void Read(AutoFile& filein, int nFileVersion, size_t numBuckets);
};
@@ -390,7 +390,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
return median;
}
-void TxConfirmStats::Write(CAutoFile& fileout) const
+void TxConfirmStats::Write(AutoFile& fileout) const
{
fileout << Using<EncodedDoubleFormatter>(decay);
fileout << scale;
@@ -400,7 +400,7 @@ void TxConfirmStats::Write(CAutoFile& fileout) const
fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
}
-void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets)
+void TxConfirmStats::Read(AutoFile& filein, int nFileVersion, size_t numBuckets)
{
// Read data file and do some very basic sanity checking
// buckets and bucketMap are not updated yet, so don't access them
@@ -546,7 +546,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath
longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
// If the fee estimation file is present, read recorded estimations
- CAutoFile est_file(fsbridge::fopen(m_estimation_filepath, "rb"), SER_DISK, CLIENT_VERSION);
+ AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "rb")};
if (est_file.IsNull() || !Read(est_file)) {
LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
}
@@ -904,13 +904,13 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
void CBlockPolicyEstimator::Flush() {
FlushUnconfirmed();
- CAutoFile est_file(fsbridge::fopen(m_estimation_filepath, "wb"), SER_DISK, CLIENT_VERSION);
+ AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "wb")};
if (est_file.IsNull() || !Write(est_file)) {
LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
}
}
-bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
+bool CBlockPolicyEstimator::Write(AutoFile& fileout) const
{
try {
LOCK(m_cs_fee_estimator);
@@ -935,7 +935,7 @@ bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
return true;
}
-bool CBlockPolicyEstimator::Read(CAutoFile& filein)
+bool CBlockPolicyEstimator::Read(AutoFile& filein)
{
try {
LOCK(m_cs_fee_estimator);
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 9ee5c2938a..e4628bf853 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -20,7 +20,7 @@
#include <string>
#include <vector>
-class CAutoFile;
+class AutoFile;
class CTxMemPoolEntry;
class TxConfirmStats;
@@ -220,11 +220,11 @@ public:
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Write estimation data to a file */
- bool Write(CAutoFile& fileout) const
+ bool Write(AutoFile& fileout) const
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Read estimation data from a file */
- bool Read(CAutoFile& filein)
+ bool Read(AutoFile& filein)
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool */
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index f7f6ae4480..ec48194ee9 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -7,10 +7,15 @@
#include <consensus/amount.h>
#include <hash.h>
+#include <script/script.h>
+#include <serialize.h>
#include <tinyformat.h>
+#include <uint256.h>
#include <util/strencodings.h>
+#include <version.h>
-#include <assert.h>
+#include <cassert>
+#include <stdexcept>
std::string COutPoint::ToString() const
{
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index fb98fb6868..f496ea022e 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -6,13 +6,21 @@
#ifndef BITCOIN_PRIMITIVES_TRANSACTION_H
#define BITCOIN_PRIMITIVES_TRANSACTION_H
-#include <stdint.h>
#include <consensus/amount.h>
+#include <prevector.h>
#include <script/script.h>
#include <serialize.h>
#include <uint256.h>
+#include <cstddef>
+#include <cstdint>
+#include <ios>
+#include <limits>
+#include <memory>
+#include <string>
#include <tuple>
+#include <utility>
+#include <vector>
/**
* A flag that is ORed into the protocol version to designate that a transaction
@@ -303,7 +311,7 @@ private:
public:
/** Convert a CMutableTransaction into a CTransaction. */
explicit CTransaction(const CMutableTransaction& tx);
- CTransaction(CMutableTransaction&& tx);
+ explicit CTransaction(CMutableTransaction&& tx);
template <typename Stream>
inline void Serialize(Stream& s) const {
@@ -368,7 +376,7 @@ struct CMutableTransaction
int32_t nVersion;
uint32_t nLockTime;
- CMutableTransaction();
+ explicit CMutableTransaction();
explicit CMutableTransaction(const CTransaction& tx);
template <typename Stream>
diff --git a/src/protocol.h b/src/protocol.h
index da2d24aff3..b85dc0d820 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -11,6 +11,7 @@
#include <serialize.h>
#include <streams.h>
#include <uint256.h>
+#include <util/time.h>
#include <cstdint>
#include <limits>
@@ -352,7 +353,7 @@ static inline bool MayHaveUsefulAddressDB(ServiceFlags services)
/** A CService with information about it as peer */
class CAddress : public CService
{
- static constexpr uint32_t TIME_INIT{100000000};
+ static constexpr std::chrono::seconds TIME_INIT{100000000};
/** Historically, CAddress disk serialization stored the CLIENT_VERSION, optionally OR'ed with
* the ADDRV2_FORMAT flag to indicate V2 serialization. The first field has since been
@@ -382,7 +383,7 @@ class CAddress : public CService
public:
CAddress() : CService{} {};
CAddress(CService ipIn, ServiceFlags nServicesIn) : CService{ipIn}, nServices{nServicesIn} {};
- CAddress(CService ipIn, ServiceFlags nServicesIn, uint32_t nTimeIn) : CService{ipIn}, nTime{nTimeIn}, nServices{nServicesIn} {};
+ CAddress(CService ipIn, ServiceFlags nServicesIn, NodeSeconds time) : CService{ipIn}, nTime{time}, nServices{nServicesIn} {};
SERIALIZE_METHODS(CAddress, obj)
{
@@ -415,7 +416,7 @@ public:
use_v2 = s.GetVersion() & ADDRV2_FORMAT;
}
- READWRITE(obj.nTime);
+ READWRITE(Using<LossyChronoFormatter<uint32_t>>(obj.nTime));
// nServices is serialized as CompactSize in V2; as uint64_t in V1.
if (use_v2) {
uint64_t services_tmp;
@@ -430,8 +431,8 @@ public:
SerReadWriteMany(os, ser_action, ReadWriteAsHelper<CService>(obj));
}
- //! Always included in serialization.
- uint32_t nTime{TIME_INIT};
+ //! Always included in serialization. The behavior is unspecified if the value is not representable as uint32_t.
+ NodeSeconds nTime{TIME_INIT};
//! Serialized as uint64_t in V1, and as CompactSize in V2.
ServiceFlags nServices{NODE_NONE};
diff --git a/src/psbt.h b/src/psbt.h
index a143a99988..eef7d7dd3b 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -866,6 +866,12 @@ struct PSBTOutput
s_tree >> depth;
s_tree >> leaf_ver;
s_tree >> script;
+ if (depth > TAPROOT_CONTROL_MAX_NODE_COUNT) {
+ throw std::ios_base::failure("Output Taproot tree has as leaf greater than Taproot maximum depth");
+ }
+ if ((leaf_ver & ~TAPROOT_LEAF_MASK) != 0) {
+ throw std::ios_base::failure("Output Taproot tree has a leaf with an invalid leaf version");
+ }
m_tap_tree->Add((int)depth, script, (int)leaf_ver, true /* track */);
}
if (!m_tap_tree->IsComplete()) {
@@ -887,6 +893,9 @@ struct PSBTOutput
s >> leaf_hashes;
size_t after_hashes = s.size();
size_t hashes_len = before_hashes - after_hashes;
+ if (hashes_len > value_len) {
+ throw std::ios_base::failure("Output Taproot BIP32 keypath has an invalid length");
+ }
size_t origin_len = value_len - hashes_len;
m_tap_bip32_paths.emplace(xonly, std::make_pair(leaf_hashes, DeserializeKeyOrigin(s, origin_len)));
break;
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index 324f681a0a..a4a1be6388 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -211,16 +211,16 @@ bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> si
return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), 32, &pubkey);
}
-static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak");
+static const HashWriter HASHER_TAPTWEAK{TaggedHash("TapTweak")};
uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const
{
if (merkle_root == nullptr) {
// We have no scripts. The actual tweak does not matter, but follow BIP341 here to
// allow for reproducible tweaking.
- return (CHashWriter(HASHER_TAPTWEAK) << m_keydata).GetSHA256();
+ return (HashWriter{HASHER_TAPTWEAK} << m_keydata).GetSHA256();
} else {
- return (CHashWriter(HASHER_TAPTWEAK) << m_keydata << *merkle_root).GetSHA256();
+ return (HashWriter{HASHER_TAPTWEAK} << m_keydata << *merkle_root).GetSHA256();
}
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index baad0fdd91..90f228803c 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -430,8 +430,12 @@ void BitcoinGUI::createActions()
if (backup_file.isEmpty()) return;
bool wallet_name_ok;
- //: Title of the Restore Wallet input dialog (where the wallet name is entered)
- QString wallet_name = QInputDialog::getText(this, tr("Restore Name"), tr("Wallet Name:"), QLineEdit::Normal, "", &wallet_name_ok);
+ /*: Title of pop-up window shown when the user is attempting to
++ restore a wallet. */
+ QString title = tr("Restore Wallet");
+ //: Label of the input field where the name of the wallet is entered.
+ QString label = tr("Wallet Name");
+ QString wallet_name = QInputDialog::getText(this, title, label, QLineEdit::Normal, "", &wallet_name_ok);
if (!wallet_name_ok || wallet_name.isEmpty()) return;
auto activity = new RestoreWalletActivity(m_wallet_controller, this);
diff --git a/src/qt/main.cpp b/src/qt/main.cpp
index 38b0ac71a3..e8f39584ad 100644
--- a/src/qt/main.cpp
+++ b/src/qt/main.cpp
@@ -4,7 +4,7 @@
#include <qt/bitcoin.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <util/translation.h>
#include <util/url.h>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 42c8b07763..2b6711ca40 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -19,6 +19,7 @@
#include <validation.h> // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
#include <netbase.h>
#include <txdb.h> // for -dbcache defaults
+#include <util/system.h>
#include <chrono>
diff --git a/src/random.cpp b/src/random.cpp
index fca4b5041a..f92e679a00 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -10,7 +10,7 @@
#include <crypto/sha512.h>
#include <support/cleanse.h>
#ifdef WIN32
-#include <compat.h> // for Windows API
+#include <compat/compat.h>
#include <wincrypt.h>
#endif
#include <logging.h>
diff --git a/src/random.h b/src/random.h
index b92c29f0be..5fe20c5f76 100644
--- a/src/random.h
+++ b/src/random.h
@@ -11,6 +11,7 @@
#include <span.h>
#include <uint256.h>
+#include <cassert>
#include <chrono>
#include <cstdint>
#include <limits>
@@ -236,13 +237,19 @@ public:
template <typename Tp>
Tp rand_uniform_delay(const Tp& time, typename Tp::duration range)
{
- using Dur = typename Tp::duration;
- Dur dur{range.count() > 0 ? /* interval [0..range) */ Dur{randrange(range.count())} :
- range.count() < 0 ? /* interval (range..0] */ -Dur{randrange(-range.count())} :
- /* interval [0..0] */ Dur{0}};
- return time + dur;
+ return time + rand_uniform_duration<Tp>(range);
}
+ /** Generate a uniform random duration in the range from 0 (inclusive) to range (exclusive). */
+ template <typename Chrono>
+ typename Chrono::duration rand_uniform_duration(typename Chrono::duration range) noexcept
+ {
+ using Dur = typename Chrono::duration;
+ return range.count() > 0 ? /* interval [0..range) */ Dur{randrange(range.count())} :
+ range.count() < 0 ? /* interval (range..0] */ -Dur{randrange(-range.count())} :
+ /* interval [0..0] */ Dur{0};
+ };
+
// Compatibility with the C++11 UniformRandomBitGenerator concept
typedef uint64_t result_type;
static constexpr uint64_t min() { return 0; }
diff --git a/src/randomenv.cpp b/src/randomenv.cpp
index c5dca346d6..9e58180b7a 100644
--- a/src/randomenv.cpp
+++ b/src/randomenv.cpp
@@ -15,7 +15,7 @@
#include <support/cleanse.h>
#include <util/time.h> // for GetTime()
#ifdef WIN32
-#include <compat.h> // for Windows API
+#include <compat/compat.h>
#endif
#include <algorithm>
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 52d5eaaa50..8f116a05ef 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -39,6 +39,7 @@
#include <univalue.h>
#include <util/check.h>
#include <util/strencodings.h>
+#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
@@ -396,7 +397,7 @@ static RPCHelpMan syncwithvalidationinterfacequeue()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
SyncWithValidationInterfaceQueue();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -613,11 +614,12 @@ const RPCResult getblock_vin{
{
{RPCResult::Type::BOOL, "generated", "Coinbase or not"},
{RPCResult::Type::NUM, "height", "The height of the prevout"},
- {RPCResult::Type::NUM, "value", "The value in " + CURRENCY_UNIT},
+ {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT},
{RPCResult::Type::OBJ, "scriptPubKey", "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
+ {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
{RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
{RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
}},
@@ -1014,9 +1016,9 @@ static RPCHelpMan gettxout()
{RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
{RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
{RPCResult::Type::OBJ, "scriptPubKey", "", {
- {RPCResult::Type::STR, "asm", "The asm"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
{RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
{RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
}},
@@ -1054,11 +1056,11 @@ static RPCHelpMan gettxout()
LOCK(mempool.cs);
CCoinsViewMemPool view(coins_view, mempool);
if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
- return NullUniValue;
+ return UniValue::VNULL;
}
} else {
if (!coins_view->GetCoin(out, coin)) {
- return NullUniValue;
+ return UniValue::VNULL;
}
}
@@ -1496,7 +1498,7 @@ static RPCHelpMan preciousblock()
throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -1537,7 +1539,7 @@ static RPCHelpMan invalidateblock()
throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -1577,7 +1579,7 @@ static RPCHelpMan reconsiderblock()
throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -2096,7 +2098,7 @@ static RPCHelpMan scantxoutset()
CoinsViewScanReserver reserver;
if (reserver.reserve()) {
// no scan in progress
- return NullUniValue;
+ return UniValue::VNULL;
}
result.pushKV("progress", g_scan_progress.load());
return result;
@@ -2306,7 +2308,7 @@ static RPCHelpMan dumptxoutset()
}
FILE* file{fsbridge::fopen(temppath, "wb")};
- CAutoFile afile{file, SER_DISK, CLIENT_VERSION};
+ AutoFile afile{file};
if (afile.IsNull()) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
@@ -2327,7 +2329,7 @@ static RPCHelpMan dumptxoutset()
UniValue CreateUTXOSnapshot(
NodeContext& node,
CChainState& chainstate,
- CAutoFile& afile,
+ AutoFile& afile,
const fs::path& path,
const fs::path& temppath)
{
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 5fbd9d5fd3..a332fd4892 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -55,7 +55,7 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES],
UniValue CreateUTXOSnapshot(
node::NodeContext& node,
CChainState& chainstate,
- CAutoFile& afile,
+ AutoFile& afile,
const fs::path& path,
const fs::path& tmppath);
diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp
index dd1a6441a0..41f386d443 100644
--- a/src/rpc/fees.cpp
+++ b/src/rpc/fees.cpp
@@ -6,7 +6,6 @@
#include <core_io.h>
#include <policy/feerate.h>
#include <policy/fees.h>
-#include <policy/policy.h>
#include <policy/settings.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
@@ -16,7 +15,6 @@
#include <txmempool.h>
#include <univalue.h>
#include <util/fees.h>
-#include <util/system.h>
#include <algorithm>
#include <array>
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index d59ff3f75c..0ae10b6c39 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -20,6 +20,7 @@
#include <txmempool.h>
#include <univalue.h>
#include <util/moneystr.h>
+#include <util/time.h>
using kernel::DumpMempool;
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index ea6db1e9a0..2902b35865 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -476,7 +476,7 @@ static RPCHelpMan prioritisetransaction()
static UniValue BIP22ValidationResult(const BlockValidationState& state)
{
if (state.IsValid())
- return NullUniValue;
+ return UniValue::VNULL;
if (state.IsError())
throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
@@ -1040,7 +1040,7 @@ static RPCHelpMan submitheader()
BlockValidationState state;
chainman.ProcessNewBlockHeaders({h}, state);
- if (state.IsValid()) return NullUniValue;
+ if (state.IsValid()) return UniValue::VNULL;
if (state.IsError()) {
throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 27eea824bc..059be61bb4 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -60,7 +60,7 @@ static RPCHelpMan getconnectioncount()
NodeContext& node = EnsureAnyNodeContext(request.context);
const CConnman& connman = EnsureConnman(node);
- return (int)connman.GetNodeCount(ConnectionDirection::Both);
+ return connman.GetNodeCount(ConnectionDirection::Both);
},
};
}
@@ -84,7 +84,7 @@ static RPCHelpMan ping()
// Request that each node send a ping during next message processing pass
peerman.SendPings();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -304,7 +304,7 @@ static RPCHelpMan addnode()
{
CAddress addr;
connman.OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL);
- return NullUniValue;
+ return UniValue::VNULL;
}
if (strCommand == "add")
@@ -320,7 +320,7 @@ static RPCHelpMan addnode()
}
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -423,7 +423,7 @@ static RPCHelpMan disconnectnode()
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -640,9 +640,9 @@ static RPCHelpMan getnetworkinfo()
obj.pushKV("timeoffset", GetTimeOffset());
if (node.connman) {
obj.pushKV("networkactive", node.connman->GetNetworkActive());
- obj.pushKV("connections", (int)node.connman->GetNodeCount(ConnectionDirection::Both));
- obj.pushKV("connections_in", (int)node.connman->GetNodeCount(ConnectionDirection::In));
- obj.pushKV("connections_out", (int)node.connman->GetNodeCount(ConnectionDirection::Out));
+ obj.pushKV("connections", node.connman->GetNodeCount(ConnectionDirection::Both));
+ obj.pushKV("connections_in", node.connman->GetNodeCount(ConnectionDirection::In));
+ obj.pushKV("connections_out", node.connman->GetNodeCount(ConnectionDirection::Out));
}
obj.pushKV("networks", GetNetworksInfo());
obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
@@ -745,7 +745,7 @@ static RPCHelpMan setban()
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously manually banned.");
}
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -819,7 +819,7 @@ static RPCHelpMan clearbanned()
node.banman->ClearBanned();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -894,7 +894,7 @@ static RPCHelpMan getnodeaddresses()
for (const CAddress& addr : vAddr) {
UniValue obj(UniValue::VOBJ);
- obj.pushKV("time", (int)addr.nTime);
+ obj.pushKV("time", int64_t{TicksSinceEpoch<std::chrono::seconds>(addr.nTime)});
obj.pushKV("services", (uint64_t)addr.nServices);
obj.pushKV("address", addr.ToStringIP());
obj.pushKV("port", addr.GetPort());
@@ -942,7 +942,7 @@ static RPCHelpMan addpeeraddress()
if (LookupHost(addr_string, net_addr, false)) {
CAddress address{{net_addr, port}, ServiceFlags{NODE_NETWORK | NODE_WITNESS}};
- address.nTime = GetAdjustedTime();
+ address.nTime = AdjustedTime();
// The source address is set equal to the address. This is equivalent to the peer
// announcing itself.
if (node.addrman->Add({address}, address)) {
diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp
index 5475662b82..605ebc15a7 100644
--- a/src/rpc/node.cpp
+++ b/src/rpc/node.cpp
@@ -65,7 +65,7 @@ static RPCHelpMan setmocktime()
}
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -85,7 +85,7 @@ static RPCHelpMan invokedisallowedsyscall()
throw std::runtime_error("invokedisallowedsyscall is used for testing only.");
}
TestDisallowedSandboxCall();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -118,7 +118,7 @@ static RPCHelpMan mockscheduler()
CHECK_NONFATAL(node_context->scheduler);
node_context->scheduler->MockForward(std::chrono::seconds(delta_seconds));
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 16105a85d5..9ec506b0fb 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -96,8 +96,8 @@ static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
{RPCResult::Type::NUM, "vout", /*optional=*/true, "The output number (if not coinbase transaction)"},
{RPCResult::Type::OBJ, "scriptSig", /*optional=*/true, "The script (if not coinbase transaction)",
{
- {RPCResult::Type::STR, "asm", "asm"},
- {RPCResult::Type::STR_HEX, "hex", "hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the signature script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw signature script bytes, hex-encoded"},
}},
{RPCResult::Type::ARR, "txinwitness", /*optional=*/true, "",
{
@@ -114,9 +114,9 @@ static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
{RPCResult::Type::NUM, "n", "index"},
{RPCResult::Type::OBJ, "scriptPubKey", "",
{
- {RPCResult::Type::STR, "asm", "the asm"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
{RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
- {RPCResult::Type::STR_HEX, "hex", "the hex"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
{RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
}},
@@ -692,9 +692,9 @@ const RPCResult decodepsbt_inputs{
{RPCResult::Type::NUM, "amount", "The value in " + CURRENCY_UNIT},
{RPCResult::Type::OBJ, "scriptPubKey", "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
{RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
{RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
}},
@@ -706,14 +706,14 @@ const RPCResult decodepsbt_inputs{
{RPCResult::Type::STR, "sighash", /*optional=*/true, "The sighash type to be used"},
{RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the redeem script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw redeem script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
{RPCResult::Type::OBJ, "witness_script", /*optional=*/true, "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the witness script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw witness script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
{RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "",
@@ -727,8 +727,8 @@ const RPCResult decodepsbt_inputs{
}},
{RPCResult::Type::OBJ, "final_scriptSig", /*optional=*/true, "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the final signature script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw final signature script bytes, hex-encoded"},
}},
{RPCResult::Type::ARR, "final_scriptwitness", /*optional=*/true, "",
{
@@ -812,14 +812,14 @@ const RPCResult decodepsbt_outputs{
{
{RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the redeem script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw redeem script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
{RPCResult::Type::OBJ, "witness_script", /*optional=*/true, "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the witness script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw witness script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
{RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "",
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 9f56301377..38bb11aad4 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1342,7 +1342,7 @@ public:
template <class T>
uint256 GetPrevoutsSHA256(const T& txTo)
{
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
for (const auto& txin : txTo.vin) {
ss << txin.prevout;
}
@@ -1353,7 +1353,7 @@ uint256 GetPrevoutsSHA256(const T& txTo)
template <class T>
uint256 GetSequencesSHA256(const T& txTo)
{
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
for (const auto& txin : txTo.vin) {
ss << txin.nSequence;
}
@@ -1364,7 +1364,7 @@ uint256 GetSequencesSHA256(const T& txTo)
template <class T>
uint256 GetOutputsSHA256(const T& txTo)
{
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
for (const auto& txout : txTo.vout) {
ss << txout;
}
@@ -1374,7 +1374,7 @@ uint256 GetOutputsSHA256(const T& txTo)
/** Compute the (single) SHA256 of the concatenation of all amounts spent by a tx. */
uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
{
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
for (const auto& txout : outputs_spent) {
ss << txout.nValue;
}
@@ -1384,7 +1384,7 @@ uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
/** Compute the (single) SHA256 of the concatenation of all scriptPubKeys spent by a tx. */
uint256 GetSpentScriptsSHA256(const std::vector<CTxOut>& outputs_spent)
{
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
for (const auto& txout : outputs_spent) {
ss << txout.scriptPubKey;
}
@@ -1458,9 +1458,9 @@ template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo,
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
-const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash");
-const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf");
-const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch");
+const HashWriter HASHER_TAPSIGHASH{TaggedHash("TapSighash")};
+const HashWriter HASHER_TAPLEAF{TaggedHash("TapLeaf")};
+const HashWriter HASHER_TAPBRANCH{TaggedHash("TapBranch")};
static bool HandleMissingData(MissingDataBehavior mdb)
{
@@ -1499,7 +1499,7 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons
return HandleMissingData(mdb);
}
- CHashWriter ss = HASHER_TAPSIGHASH;
+ HashWriter ss{HASHER_TAPSIGHASH};
// Epoch
static constexpr uint8_t EPOCH = 0;
@@ -1544,7 +1544,7 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons
if (output_type == SIGHASH_SINGLE) {
if (in_pos >= tx_to.vout.size()) return false;
if (!execdata.m_output_hash) {
- CHashWriter sha_single_output(SER_GETHASH, 0);
+ HashWriter sha_single_output{};
sha_single_output << tx_to.vout[in_pos];
execdata.m_output_hash = sha_single_output.GetSHA256();
}
@@ -1587,12 +1587,12 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
hashOutputs = cacheready ? cache->hashOutputs : SHA256Uint256(GetOutputsSHA256(txTo));
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
ss << txTo.vout[nIn];
hashOutputs = ss.GetHash();
}
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
// Version
ss << txTo.nVersion;
// Input prevouts/nSequence (none/all, depending on flags)
@@ -1627,7 +1627,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType);
// Serialize and hash
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
ss << txTmp << nHashType;
return ss.GetHash();
}
@@ -1827,7 +1827,7 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
uint256 ComputeTapleafHash(uint8_t leaf_version, const CScript& script)
{
- return (CHashWriter(HASHER_TAPLEAF) << leaf_version << script).GetSHA256();
+ return (HashWriter{HASHER_TAPLEAF} << leaf_version << script).GetSHA256();
}
uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint256& tapleaf_hash)
@@ -1839,7 +1839,7 @@ uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint25
const int path_len = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
uint256 k = tapleaf_hash;
for (int i = 0; i < path_len; ++i) {
- CHashWriter ss_branch{HASHER_TAPBRANCH};
+ HashWriter ss_branch{HASHER_TAPBRANCH};
Span node{Span{control}.subspan(TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE)};
if (std::lexicographical_compare(k.begin(), k.end(), node.begin(), node.end())) {
ss_branch << k << node;
@@ -1902,7 +1902,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
// Drop annex (this is non-standard; see IsWitnessStandard)
const valtype& annex = SpanPopBack(stack);
- execdata.m_annex_hash = (CHashWriter(SER_GETHASH, 0) << annex).GetSHA256();
+ execdata.m_annex_hash = (HashWriter{} << annex).GetSHA256();
execdata.m_annex_present = true;
} else {
execdata.m_annex_present = false;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index adf454aa15..f91578d684 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -233,9 +233,9 @@ static constexpr size_t TAPROOT_CONTROL_NODE_SIZE = 32;
static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128;
static constexpr size_t TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT;
-extern const CHashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre-fed to it.
-extern const CHashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
-extern const CHashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
+extern const HashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre-fed to it.
+extern const HashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
+extern const HashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
template <class T>
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index a3681d26cc..3b8071d9d1 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -165,7 +165,7 @@ static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatu
if (leaf_version != TAPROOT_LEAF_TAPSCRIPT) return false;
SigVersion sigversion = SigVersion::TAPSCRIPT;
- uint256 leaf_hash = (CHashWriter(HASHER_TAPLEAF) << uint8_t(leaf_version) << script).GetSHA256();
+ uint256 leaf_hash = (HashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();
// <xonly pubkey> OP_CHECKSIG
if (script.size() == 34 && script[33] == OP_CHECKSIG && script[0] == 0x20) {
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 5d80891485..b3f6a1b669 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -375,9 +375,9 @@ bool IsValidDestination(const CTxDestination& dest) {
}
/* Lexicographically sort a and b's hash, and compute parent hash. */
if (a.hash < b.hash) {
- ret.hash = (CHashWriter(HASHER_TAPBRANCH) << a.hash << b.hash).GetSHA256();
+ ret.hash = (HashWriter{HASHER_TAPBRANCH} << a.hash << b.hash).GetSHA256();
} else {
- ret.hash = (CHashWriter(HASHER_TAPBRANCH) << b.hash << a.hash).GetSHA256();
+ ret.hash = (HashWriter{HASHER_TAPBRANCH} << b.hash << a.hash).GetSHA256();
}
return ret;
}
@@ -452,7 +452,7 @@ TaprootBuilder& TaprootBuilder::Add(int depth, const CScript& script, int leaf_v
if (!IsValid()) return *this;
/* Construct NodeInfo object with leaf hash and (if track is true) also leaf information. */
NodeInfo node;
- node.hash = (CHashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();
+ node.hash = (HashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();
if (track) node.leaves.emplace_back(LeafInfo{script, leaf_version, {}});
/* Insert into the branch. */
Insert(std::move(node), depth);
@@ -610,7 +610,7 @@ std::optional<std::vector<std::tuple<int, CScript, int>>> InferTaprootTree(const
node.done = true;
stack.pop_back();
} else if (node.sub[0]->done && !node.sub[1]->done && !node.sub[1]->explored && !node.sub[1]->hash.IsNull() &&
- (CHashWriter{HASHER_TAPBRANCH} << node.sub[1]->hash << node.sub[1]->hash).GetSHA256() == node.hash) {
+ (HashWriter{HASHER_TAPBRANCH} << node.sub[1]->hash << node.sub[1]->hash).GetSHA256() == node.hash) {
// Whenever there are nodes with two identical subtrees under it, we run into a problem:
// the control blocks for the leaves underneath those will be identical as well, and thus
// they will all be matched to the same path in the tree. The result is that at the location
diff --git a/src/serialize.h b/src/serialize.h
index a1cce78451..89a9f32240 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -520,6 +520,29 @@ struct CompactSizeFormatter
}
};
+template <typename U, bool LOSSY = false>
+struct ChronoFormatter {
+ template <typename Stream, typename Tp>
+ void Unser(Stream& s, Tp& tp)
+ {
+ U u;
+ s >> u;
+ // Lossy deserialization does not make sense, so force Wnarrowing
+ tp = Tp{typename Tp::duration{typename Tp::duration::rep{u}}};
+ }
+ template <typename Stream, typename Tp>
+ void Ser(Stream& s, Tp tp)
+ {
+ if constexpr (LOSSY) {
+ s << U(tp.time_since_epoch().count());
+ } else {
+ s << U{tp.time_since_epoch().count()};
+ }
+ }
+};
+template <typename U>
+using LossyChronoFormatter = ChronoFormatter<U, true>;
+
class CompactSizeWriter
{
protected:
diff --git a/src/streams.h b/src/streams.h
index 96b7696f72..f14d347380 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -465,35 +465,28 @@ public:
};
-
/** Non-refcounted RAII wrapper for FILE*
*
* Will automatically close the file when it goes out of scope if not null.
* If you're returning the file pointer, return file.release().
* If you need to close the file early, use file.fclose() instead of fclose(file).
*/
-class CAutoFile
+class AutoFile
{
-private:
- const int nType;
- const int nVersion;
-
+protected:
FILE* file;
public:
- CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
- {
- file = filenew;
- }
+ explicit AutoFile(FILE* filenew) : file{filenew} {}
- ~CAutoFile()
+ ~AutoFile()
{
fclose();
}
// Disallow copies
- CAutoFile(const CAutoFile&) = delete;
- CAutoFile& operator=(const CAutoFile&) = delete;
+ AutoFile(const AutoFile&) = delete;
+ AutoFile& operator=(const AutoFile&) = delete;
void fclose()
{
@@ -504,14 +497,14 @@ public:
}
/** Get wrapped FILE* with transfer of ownership.
- * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
+ * @note This will invalidate the AutoFile object, and makes it the responsibility of the caller
* of this function to clean up the returned FILE*.
*/
FILE* release() { FILE* ret = file; file = nullptr; return ret; }
/** Get wrapped FILE* without transfer of ownership.
* @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
- * CAutoFile outlives use of the passed pointer.
+ * AutoFile outlives use of the passed pointer.
*/
FILE* Get() const { return file; }
@@ -522,40 +515,62 @@ public:
//
// Stream subset
//
- int GetType() const { return nType; }
- int GetVersion() const { return nVersion; }
-
void read(Span<std::byte> dst)
{
- if (!file)
- throw std::ios_base::failure("CAutoFile::read: file handle is nullptr");
+ if (!file) throw std::ios_base::failure("AutoFile::read: file handle is nullptr");
if (fread(dst.data(), 1, dst.size(), file) != dst.size()) {
- throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
+ throw std::ios_base::failure(feof(file) ? "AutoFile::read: end of file" : "AutoFile::read: fread failed");
}
}
void ignore(size_t nSize)
{
- if (!file)
- throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
+ if (!file) throw std::ios_base::failure("AutoFile::ignore: file handle is nullptr");
unsigned char data[4096];
while (nSize > 0) {
size_t nNow = std::min<size_t>(nSize, sizeof(data));
if (fread(data, 1, nNow, file) != nNow)
- throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
+ throw std::ios_base::failure(feof(file) ? "AutoFile::ignore: end of file" : "AutoFile::read: fread failed");
nSize -= nNow;
}
}
void write(Span<const std::byte> src)
{
- if (!file)
- throw std::ios_base::failure("CAutoFile::write: file handle is nullptr");
+ if (!file) throw std::ios_base::failure("AutoFile::write: file handle is nullptr");
if (fwrite(src.data(), 1, src.size(), file) != src.size()) {
- throw std::ios_base::failure("CAutoFile::write: write failed");
+ throw std::ios_base::failure("AutoFile::write: write failed");
}
}
+ template <typename T>
+ AutoFile& operator<<(const T& obj)
+ {
+ if (!file) throw std::ios_base::failure("AutoFile::operator<<: file handle is nullptr");
+ ::Serialize(*this, obj);
+ return *this;
+ }
+
+ template <typename T>
+ AutoFile& operator>>(T&& obj)
+ {
+ if (!file) throw std::ios_base::failure("AutoFile::operator>>: file handle is nullptr");
+ ::Unserialize(*this, obj);
+ return *this;
+ }
+};
+
+class CAutoFile : public AutoFile
+{
+private:
+ const int nType;
+ const int nVersion;
+
+public:
+ CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : AutoFile{filenew}, nType(nTypeIn), nVersion(nVersionIn) {}
+ int GetType() const { return nType; }
+ int GetVersion() const { return nVersion; }
+
template<typename T>
CAutoFile& operator<<(const T& obj)
{
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 12cf1176a6..b1372a3e98 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -225,7 +225,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
- int64_t start_time{GetAdjustedTime()};
+ const auto start_time{AdjustedTime()};
addr.nTime = start_time;
// test that multiplicity stays at 1 if nTime doesn't increase
@@ -244,7 +244,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
for (unsigned int i = 1; i < 400; ++i) {
std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
CNetAddr source{ResolveIP(addr_ip)};
- addr.nTime = start_time + i;
+ addr.nTime = start_time + std::chrono::seconds{i};
addrman->Add({addr}, source);
}
AddressPosition addr_pos_multi = addrman->FindAddressEntry(addr).value();
@@ -295,15 +295,15 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
- addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false
+ addr1.nTime = AdjustedTime(); // Set time so isTerrible = false
CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
- addr2.nTime = GetAdjustedTime();
+ addr2.nTime = AdjustedTime();
CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
- addr3.nTime = GetAdjustedTime();
+ addr3.nTime = AdjustedTime();
CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
- addr4.nTime = GetAdjustedTime();
+ addr4.nTime = AdjustedTime();
CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
- addr5.nTime = GetAdjustedTime();
+ addr5.nTime = AdjustedTime();
CNetAddr source1 = ResolveIP("250.1.2.1");
CNetAddr source2 = ResolveIP("250.2.3.3");
@@ -329,7 +329,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
// Ensure that for all addrs in addrman, isTerrible == false.
- addr.nTime = GetAdjustedTime();
+ addr.nTime = AdjustedTime();
addrman->Add({addr}, ResolveIP(strAddr));
if (i % 8 == 0)
addrman->Good(addr);
@@ -821,8 +821,8 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
// Ensure test of address fails, so that it is evicted.
// Update entry in tried by setting last good connection in the deep past.
- BOOST_CHECK(!addrman->Good(info, /*nTime=*/1));
- addrman->Attempt(info, /*fCountFailure=*/false, /*nTime=*/GetAdjustedTime() - 61);
+ BOOST_CHECK(!addrman->Good(info, NodeSeconds{1s}));
+ addrman->Attempt(info, /*fCountFailure=*/false, AdjustedTime() - 61s);
// Should swap 36 for 19.
addrman->ResolveCollisions();
@@ -966,7 +966,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
CNetAddr source{ResolveIP("252.2.2.2")};
CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
- int64_t start_time{GetAdjustedTime() - 10000};
+ const auto start_time{AdjustedTime() - 10000s};
addr.nTime = start_time;
BOOST_CHECK(addrman->Add({addr}, source));
BOOST_CHECK_EQUAL(addrman->size(), 1U);
@@ -978,7 +978,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
addrman->SetServices(addr_diff_port, NODE_NETWORK_LIMITED);
std::vector<CAddress> vAddr1{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
BOOST_CHECK_EQUAL(vAddr1.size(), 1U);
- BOOST_CHECK_EQUAL(vAddr1.at(0).nTime, start_time);
+ BOOST_CHECK(vAddr1.at(0).nTime == start_time);
BOOST_CHECK_EQUAL(vAddr1.at(0).nServices, NODE_NONE);
// Updating an addrman entry with the correct port is successful
@@ -986,7 +986,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
addrman->SetServices(addr, NODE_NETWORK_LIMITED);
std::vector<CAddress> vAddr2 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
BOOST_CHECK_EQUAL(vAddr2.size(), 1U);
- BOOST_CHECK(vAddr2.at(0).nTime >= start_time + 10000);
+ BOOST_CHECK(vAddr2.at(0).nTime >= start_time + 10000s);
BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED);
}
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index c31e4e51f7..1a182209b8 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -7,6 +7,7 @@
#include <consensus/merkle.h>
#include <consensus/validation.h>
#include <index/blockfilterindex.h>
+#include <interfaces/chain.h>
#include <node/miner.h>
#include <pow.h>
#include <script/standard.h>
@@ -110,7 +111,7 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex,
BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
{
- BlockFilterIndex filter_index(BlockFilterType::BASIC, 1 << 20, true);
+ BlockFilterIndex filter_index(interfaces::MakeChain(m_node), BlockFilterType::BASIC, 1 << 20, true);
uint256 last_header;
@@ -137,7 +138,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
// BlockUntilSyncedToCurrentChain should return false before index is started.
BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());
- BOOST_REQUIRE(filter_index.Start(m_node.chainman->ActiveChainstate()));
+ BOOST_REQUIRE(filter_index.Start());
// Allow filter index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000;
@@ -279,14 +280,14 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
BOOST_CHECK(filter_index == nullptr);
- BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
+ BOOST_CHECK(InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1 << 20, true, false));
filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
BOOST_CHECK(filter_index != nullptr);
BOOST_CHECK(filter_index->GetFilterType() == BlockFilterType::BASIC);
// Initialize returns false if index already exists.
- BOOST_CHECK(!InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
+ BOOST_CHECK(!InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1 << 20, true, false));
int iter_count = 0;
ForEachBlockFilterIndex([&iter_count](BlockFilterIndex& _index) { iter_count++; });
@@ -301,7 +302,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
BOOST_CHECK(filter_index == nullptr);
// Reinitialize index.
- BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
+ BOOST_CHECK(InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1 << 20, true, false));
DestroyAllBlockFilterIndexes();
diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp
index 1d9a037a66..c93d05a93b 100644
--- a/src/test/coinstatsindex_tests.cpp
+++ b/src/test/coinstatsindex_tests.cpp
@@ -4,6 +4,7 @@
#include <chainparams.h>
#include <index/coinstatsindex.h>
+#include <interfaces/chain.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
#include <util/time.h>
@@ -28,7 +29,7 @@ static void IndexWaitSynced(BaseIndex& index)
BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
{
- CoinStatsIndex coin_stats_index{1 << 20, true};
+ CoinStatsIndex coin_stats_index{interfaces::MakeChain(m_node), 1 << 20, true};
const CBlockIndex* block_index;
{
@@ -43,7 +44,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
// is started.
BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain());
- BOOST_REQUIRE(coin_stats_index.Start(m_node.chainman->ActiveChainstate()));
+ BOOST_REQUIRE(coin_stats_index.Start());
IndexWaitSynced(coin_stats_index);
@@ -87,8 +88,8 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
CChainState& chainstate = Assert(m_node.chainman)->ActiveChainstate();
const CChainParams& params = Params();
{
- CoinStatsIndex index{1 << 20};
- BOOST_REQUIRE(index.Start(chainstate));
+ CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
+ BOOST_REQUIRE(index.Start());
IndexWaitSynced(index);
std::shared_ptr<const CBlock> new_block;
CBlockIndex* new_block_index = nullptr;
@@ -113,9 +114,9 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
}
{
- CoinStatsIndex index{1 << 20};
+ CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
// Make sure the index can be loaded.
- BOOST_REQUIRE(index.Start(chainstate));
+ BOOST_REQUIRE(index.Start());
index.Stop();
}
}
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index d54d6b6471..605faa08e4 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -41,26 +41,26 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
// Write first line to file.
{
- CAutoFile file(seq.Open(FlatFilePos(0, pos1)), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(0, pos1))};
file << LIMITED_STRING(line1, 256);
}
// Attempt to append to file opened in read-only mode.
{
- CAutoFile file(seq.Open(FlatFilePos(0, pos2), true), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(0, pos2), true)};
BOOST_CHECK_THROW(file << LIMITED_STRING(line2, 256), std::ios_base::failure);
}
// Append second line to file.
{
- CAutoFile file(seq.Open(FlatFilePos(0, pos2)), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(0, pos2))};
file << LIMITED_STRING(line2, 256);
}
// Read text from file in read-only mode.
{
std::string text;
- CAutoFile file(seq.Open(FlatFilePos(0, pos1), true), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(0, pos1), true)};
file >> LIMITED_STRING(text, 256);
BOOST_CHECK_EQUAL(text, line1);
@@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
// Read text from file with position offset.
{
std::string text;
- CAutoFile file(seq.Open(FlatFilePos(0, pos2)), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(0, pos2))};
file >> LIMITED_STRING(text, 256);
BOOST_CHECK_EQUAL(text, line2);
@@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
// Ensure another file in the sequence has no data.
{
std::string text;
- CAutoFile file(seq.Open(FlatFilePos(1, pos2)), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(1, pos2))};
BOOST_CHECK_THROW(file >> LIMITED_STRING(text, 256), std::ios_base::failure);
}
}
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index af7a282781..7668940cbc 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -113,11 +113,11 @@ void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
for (size_t j = 0; j < num_addresses; ++j) {
const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK};
- const auto time_penalty = fast_random_context.randrange(100000001);
+ const std::chrono::seconds time_penalty{fast_random_context.randrange(100000001)};
addrman.Add({addr}, source, time_penalty);
if (n > 0 && addrman.size() % n == 0) {
- addrman.Good(addr, GetTime());
+ addrman.Good(addr, Now<NodeSeconds>());
}
// Add 10% of the addresses from more than one source.
@@ -161,7 +161,7 @@ public:
CSipHasher hasher(0, 0);
auto addr_key = a.GetKey();
auto source_key = a.source.GetAddrBytes();
- hasher.Write(a.nLastSuccess);
+ hasher.Write(TicksSinceEpoch<std::chrono::seconds>(a.m_last_success));
hasher.Write(a.nAttempts);
hasher.Write(a.nRefCount);
hasher.Write(a.fInTried);
@@ -175,8 +175,8 @@ public:
};
auto addrinfo_eq = [](const AddrInfo& lhs, const AddrInfo& rhs) {
- return std::tie(static_cast<const CService&>(lhs), lhs.source, lhs.nLastSuccess, lhs.nAttempts, lhs.nRefCount, lhs.fInTried) ==
- std::tie(static_cast<const CService&>(rhs), rhs.source, rhs.nLastSuccess, rhs.nAttempts, rhs.nRefCount, rhs.fInTried);
+ return std::tie(static_cast<const CService&>(lhs), lhs.source, lhs.m_last_success, lhs.nAttempts, lhs.nRefCount, lhs.fInTried) ==
+ std::tie(static_cast<const CService&>(rhs), rhs.source, rhs.m_last_success, rhs.nAttempts, rhs.nRefCount, rhs.fInTried);
};
using Addresses = std::unordered_set<AddrInfo, decltype(addrinfo_hasher), decltype(addrinfo_eq)>;
@@ -269,25 +269,25 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
}
const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
if (opt_net_addr) {
- addr_man.Add(addresses, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000));
+ addr_man.Add(addresses, *opt_net_addr, std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)});
}
},
[&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) {
- addr_man.Good(*opt_service, ConsumeTime(fuzzed_data_provider));
+ addr_man.Good(*opt_service, NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
}
},
[&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) {
- addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider));
+ addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
}
},
[&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) {
- addr_man.Connected(*opt_service, ConsumeTime(fuzzed_data_provider));
+ addr_man.Connected(*opt_service, NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
}
},
[&] {
diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp
index 3b410930ed..1a8957d090 100644
--- a/src/test/fuzz/autofile.cpp
+++ b/src/test/fuzz/autofile.cpp
@@ -18,7 +18,7 @@ FUZZ_TARGET(autofile)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
- CAutoFile auto_file = fuzzed_auto_file_provider.open();
+ AutoFile auto_file{fuzzed_auto_file_provider.open()};
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
CallOneOf(
fuzzed_data_provider,
@@ -53,8 +53,6 @@ FUZZ_TARGET(autofile)
});
}
(void)auto_file.Get();
- (void)auto_file.GetType();
- (void)auto_file.GetVersion();
(void)auto_file.IsNull();
if (fuzzed_data_provider.ConsumeBool()) {
FILE* f = auto_file.release();
diff --git a/src/test/fuzz/chain.cpp b/src/test/fuzz/chain.cpp
index 8c0ed32d51..01edb06138 100644
--- a/src/test/fuzz/chain.cpp
+++ b/src/test/fuzz/chain.cpp
@@ -23,7 +23,7 @@ FUZZ_TARGET(chain)
disk_block_index->phashBlock = &zero;
{
LOCK(::cs_main);
- (void)disk_block_index->GetBlockHash();
+ (void)disk_block_index->ConstructBlockHash();
(void)disk_block_index->GetBlockPos();
(void)disk_block_index->GetBlockTime();
(void)disk_block_index->GetBlockTimeMax();
@@ -31,7 +31,6 @@ FUZZ_TARGET(chain)
(void)disk_block_index->GetUndoPos();
(void)disk_block_index->HaveTxsDownloaded();
(void)disk_block_index->IsValid();
- (void)disk_block_index->ToString();
}
const CBlockHeader block_header = disk_block_index->GetBlockHeader();
diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp
index c7a76aa52f..0cc210f26f 100644
--- a/src/test/fuzz/parse_univalue.cpp
+++ b/src/test/fuzz/parse_univalue.cpp
@@ -26,7 +26,7 @@ FUZZ_TARGET_INIT(parse_univalue, initialize_parse_univalue)
return ParseNonRFCJSONValue(random_string);
} catch (const std::runtime_error&) {
valid = false;
- return NullUniValue;
+ return UniValue{};
}
}();
if (!valid) {
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 58c19a91cb..637ba503c6 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -76,7 +76,7 @@ FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
}
{
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
- CAutoFile fuzzed_auto_file = fuzzed_auto_file_provider.open();
+ AutoFile fuzzed_auto_file{fuzzed_auto_file_provider.open()};
block_policy_estimator.Write(fuzzed_auto_file);
block_policy_estimator.Read(fuzzed_auto_file);
}
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
index 77402c260a..436873c955 100644
--- a/src/test/fuzz/policy_estimator_io.cpp
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -26,7 +26,7 @@ FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
- CAutoFile fuzzed_auto_file = fuzzed_auto_file_provider.open();
+ AutoFile fuzzed_auto_file{fuzzed_auto_file_provider.open()};
// Re-using block_policy_estimator across runs to avoid costly creation of CBlockPolicyEstimator object.
static CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args)};
if (block_policy_estimator.Read(fuzzed_auto_file)) {
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 63fbf0516a..cfb112879a 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -136,7 +136,6 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};
MockTime(fuzzed_data_provider, chainstate);
- SetMempoolConstraints(*node.args, fuzzed_data_provider);
// All RBF-spendable outpoints
std::set<COutPoint> outpoints_rbf;
@@ -150,6 +149,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
// The sum of the values of all spendable outpoints
constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
+ SetMempoolConstraints(*node.args, fuzzed_data_provider);
CTxMemPool tx_pool_{MakeMempool(node)};
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
@@ -221,9 +221,6 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
MockTime(fuzzed_data_provider, chainstate);
}
if (fuzzed_data_provider.ConsumeBool()) {
- SetMempoolConstraints(*node.args, fuzzed_data_provider);
- }
- if (fuzzed_data_provider.ConsumeBool()) {
tx_pool.RollingFeeUpdate();
}
if (fuzzed_data_provider.ConsumeBool()) {
@@ -316,7 +313,6 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
auto& chainstate = node.chainman->ActiveChainstate();
MockTime(fuzzed_data_provider, chainstate);
- SetMempoolConstraints(*node.args, fuzzed_data_provider);
std::vector<uint256> txids;
for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
@@ -328,6 +324,7 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
txids.push_back(ConsumeUInt256(fuzzed_data_provider));
}
+ SetMempoolConstraints(*node.args, fuzzed_data_provider);
CTxMemPool tx_pool_{MakeMempool(node)};
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
@@ -339,9 +336,6 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
MockTime(fuzzed_data_provider, chainstate);
}
if (fuzzed_data_provider.ConsumeBool()) {
- SetMempoolConstraints(*node.args, fuzzed_data_provider);
- }
- if (fuzzed_data_provider.ConsumeBool()) {
tx_pool.RollingFeeUpdate();
}
if (fuzzed_data_provider.ConsumeBool()) {
diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp
index cc20f89bbf..3fc6cde84e 100644
--- a/src/test/fuzz/txorphan.cpp
+++ b/src/test/fuzz/txorphan.cpp
@@ -67,7 +67,7 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
for (uint32_t i = 0; i < num_out; i++) {
tx_mut.vout.emplace_back(CAmount{0}, CScript{});
}
- // restore previously poped outpoints
+ // restore previously popped outpoints
for (auto& in : tx_mut.vin) {
outpoints.push_back(in.prevout);
}
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index fabcea22c3..ba1a634e41 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -527,6 +527,11 @@ CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
return net_addr;
}
+CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}};
+}
+
FILE* FuzzedFileProvider::open()
{
SetFuzzedErrNo(m_fuzzed_data_provider);
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index 406e11c573..33d9ab3cc3 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -8,7 +8,7 @@
#include <arith_uint256.h>
#include <chainparamsbase.h>
#include <coins.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <merkleblock.h>
@@ -287,10 +287,7 @@ inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcep
return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
}
-inline CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
-}
+CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
template <bool ReturnUniquePtr = false>
auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
@@ -358,17 +355,16 @@ public:
class FuzzedAutoFileProvider
{
- FuzzedDataProvider& m_fuzzed_data_provider;
FuzzedFileProvider m_fuzzed_file_provider;
public:
- FuzzedAutoFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider}, m_fuzzed_file_provider{fuzzed_data_provider}
+ FuzzedAutoFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_file_provider{fuzzed_data_provider}
{
}
- CAutoFile open()
+ AutoFile open()
{
- return {m_fuzzed_file_provider.open(), m_fuzzed_data_provider.ConsumeIntegral<int>(), m_fuzzed_data_provider.ConsumeIntegral<int>()};
+ return AutoFile{m_fuzzed_file_provider.open()};
}
};
diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp
index 33496a457e..0b596492be 100644
--- a/src/test/fuzz/utxo_snapshot.cpp
+++ b/src/test/fuzz/utxo_snapshot.cpp
@@ -39,13 +39,13 @@ FUZZ_TARGET_INIT(utxo_snapshot, initialize_chain)
Assert(!chainman.SnapshotBlockhash());
{
- CAutoFile outfile{fsbridge::fopen(snapshot_path, "wb"), SER_DISK, CLIENT_VERSION};
+ AutoFile outfile{fsbridge::fopen(snapshot_path, "wb")};
const auto file_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
outfile << Span{file_data};
}
const auto ActivateFuzzedSnapshot{[&] {
- CAutoFile infile{fsbridge::fopen(snapshot_path, "rb"), SER_DISK, CLIENT_VERSION};
+ AutoFile infile{fsbridge::fopen(snapshot_path, "rb")};
SnapshotMetadata metadata;
try {
infile >> metadata;
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index f2eaa0179f..f6642d3218 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -4,7 +4,7 @@
#include <chainparams.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <cstdint>
#include <net.h>
#include <net_processing.h>
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 224dc88d0f..c2d2fa37b4 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -480,21 +480,21 @@ BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters)
// try a few edge cases for port, service flags and time.
static const std::vector<CAddress> fixture_addresses({
- CAddress(
+ CAddress{
CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0 /* port */),
NODE_NONE,
- 0x4966bc61U /* Fri Jan 9 02:54:25 UTC 2009 */
- ),
- CAddress(
+ NodeSeconds{0x4966bc61s}, /* Fri Jan 9 02:54:25 UTC 2009 */
+ },
+ CAddress{
CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0x00f1 /* port */),
NODE_NETWORK,
- 0x83766279U /* Tue Nov 22 11:22:33 UTC 2039 */
- ),
- CAddress(
+ NodeSeconds{0x83766279s}, /* Tue Nov 22 11:22:33 UTC 2039 */
+ },
+ CAddress{
CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0xf1f2 /* port */),
static_cast<ServiceFlags>(NODE_WITNESS | NODE_COMPACT_FILTERS | NODE_NETWORK_LIMITED),
- 0xffffffffU /* Sun Feb 7 06:28:15 UTC 2106 */
- )
+ NodeSeconds{0xffffffffs}, /* Sun Feb 7 06:28:15 UTC 2106 */
+ },
});
// fixture_addresses should equal to this when serialized in V1 format.
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
index 9b2760fd1c..96fb28dc9f 100644
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -53,6 +53,16 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50));
+ {
+ struct MicroClock {
+ using duration = std::chrono::microseconds;
+ };
+ FastRandomContext ctx{true};
+ // Check with clock type
+ BOOST_CHECK_EQUAL(47222, ctx.rand_uniform_duration<MicroClock>(1s).count());
+ // Check with time-point type
+ BOOST_CHECK_EQUAL(2782, ctx.rand_uniform_duration<SteadySeconds>(9h).count());
+ }
// Check that a nondeterministic ones are not
g_mock_deterministic_tests = false;
diff --git a/src/test/rbf_tests.cpp b/src/test/rbf_tests.cpp
new file mode 100644
index 0000000000..e597081afd
--- /dev/null
+++ b/src/test/rbf_tests.cpp
@@ -0,0 +1,230 @@
+// Copyright (c) 2021 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 <policy/rbf.h>
+#include <random.h>
+#include <txmempool.h>
+#include <util/system.h>
+#include <util/time.h>
+
+#include <test/util/setup_common.h>
+
+#include <boost/test/unit_test.hpp>
+#include <optional>
+#include <vector>
+
+BOOST_FIXTURE_TEST_SUITE(rbf_tests, TestingSetup)
+
+static inline CTransactionRef make_tx(const std::vector<CTransactionRef>& inputs,
+ const std::vector<CAmount>& output_values)
+{
+ CMutableTransaction tx = CMutableTransaction();
+ tx.vin.resize(inputs.size());
+ tx.vout.resize(output_values.size());
+ for (size_t i = 0; i < inputs.size(); ++i) {
+ tx.vin[i].prevout.hash = inputs[i]->GetHash();
+ tx.vin[i].prevout.n = 0;
+ // Add a witness so wtxid != txid
+ CScriptWitness witness;
+ witness.stack.push_back(std::vector<unsigned char>(i + 10));
+ tx.vin[i].scriptWitness = witness;
+ }
+ for (size_t i = 0; i < output_values.size(); ++i) {
+ tx.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx.vout[i].nValue = output_values[i];
+ }
+ return MakeTransactionRef(tx);
+}
+
+static void add_descendants(const CTransactionRef& tx, int32_t num_descendants, CTxMemPool& pool)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
+{
+ AssertLockHeld(::cs_main);
+ AssertLockHeld(pool.cs);
+ TestMemPoolEntryHelper entry;
+ // Assumes this isn't already spent in mempool
+ auto tx_to_spend = tx;
+ for (int32_t i{0}; i < num_descendants; ++i) {
+ auto next_tx = make_tx(/*inputs=*/{tx_to_spend}, /*output_values=*/{(50 - i) * CENT});
+ pool.addUnchecked(entry.FromTx(next_tx));
+ tx_to_spend = next_tx;
+ }
+}
+
+BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
+{
+ CTxMemPool& pool = *Assert(m_node.mempool);
+ LOCK2(::cs_main, pool.cs);
+ TestMemPoolEntryHelper entry;
+
+ const CAmount low_fee{CENT/100};
+ const CAmount normal_fee{CENT/10};
+ const CAmount high_fee{CENT};
+
+ // Create a parent tx1 and child tx2 with normal fees:
+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});
+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx1));
+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});
+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));
+
+ // Create a low-feerate parent tx3 and high-feerate child tx4 (cpfp)
+ const auto tx3 = make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {1099 * CENT});
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx3));
+ const auto tx4 = make_tx(/*inputs=*/ {tx3}, /*output_values=*/ {999 * CENT});
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx4));
+
+ // Create a parent tx5 and child tx6 where both have very low fees
+ const auto tx5 = make_tx(/*inputs=*/ {m_coinbase_txns[2]}, /*output_values=*/ {1099 * CENT});
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx5));
+ const auto tx6 = make_tx(/*inputs=*/ {tx3}, /*output_values=*/ {1098 * CENT});
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx6));
+ // Make tx6's modified fee much higher than its base fee. This should cause it to pass
+ // the fee-related checks despite being low-feerate.
+ pool.PrioritiseTransaction(tx6->GetHash(), 1 * COIN);
+
+ // Two independent high-feerate transactions, tx7 and tx8
+ const auto tx7 = make_tx(/*inputs=*/ {m_coinbase_txns[3]}, /*output_values=*/ {999 * CENT});
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx7));
+ const auto tx8 = make_tx(/*inputs=*/ {m_coinbase_txns[4]}, /*output_values=*/ {999 * CENT});
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx8));
+
+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();
+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();
+ const auto entry3 = pool.GetIter(tx3->GetHash()).value();
+ const auto entry4 = pool.GetIter(tx4->GetHash()).value();
+ const auto entry5 = pool.GetIter(tx5->GetHash()).value();
+ const auto entry6 = pool.GetIter(tx6->GetHash()).value();
+ const auto entry7 = pool.GetIter(tx7->GetHash()).value();
+ const auto entry8 = pool.GetIter(tx8->GetHash()).value();
+
+ BOOST_CHECK_EQUAL(entry1->GetFee(), normal_fee);
+ BOOST_CHECK_EQUAL(entry2->GetFee(), normal_fee);
+ BOOST_CHECK_EQUAL(entry3->GetFee(), low_fee);
+ BOOST_CHECK_EQUAL(entry4->GetFee(), high_fee);
+ BOOST_CHECK_EQUAL(entry5->GetFee(), low_fee);
+ BOOST_CHECK_EQUAL(entry6->GetFee(), low_fee);
+ BOOST_CHECK_EQUAL(entry7->GetFee(), high_fee);
+ BOOST_CHECK_EQUAL(entry8->GetFee(), high_fee);
+
+ CTxMemPool::setEntries set_12_normal{entry1, entry2};
+ CTxMemPool::setEntries set_34_cpfp{entry3, entry4};
+ CTxMemPool::setEntries set_56_low{entry5, entry6};
+ CTxMemPool::setEntries all_entries{entry1, entry2, entry3, entry4, entry5, entry6, entry7, entry8};
+ CTxMemPool::setEntries empty_set;
+
+ const auto unused_txid{GetRandHash()};
+
+ // Tests for PaysMoreThanConflicts
+ // These tests use feerate, not absolute fee.
+ BOOST_CHECK(PaysMoreThanConflicts(/*iters_conflicting=*/set_12_normal,
+ /*replacement_feerate=*/CFeeRate(entry1->GetModifiedFee() + 1, entry1->GetTxSize() + 2),
+ /*txid=*/unused_txid).has_value());
+ // Replacement must be strictly greater than the originals.
+ BOOST_CHECK(PaysMoreThanConflicts(set_12_normal, CFeeRate(entry1->GetModifiedFee(), entry1->GetTxSize()), unused_txid).has_value());
+ BOOST_CHECK(PaysMoreThanConflicts(set_12_normal, CFeeRate(entry1->GetModifiedFee() + 1, entry1->GetTxSize()), unused_txid) == std::nullopt);
+ // These tests use modified fees (including prioritisation), not base fees.
+ BOOST_CHECK(PaysMoreThanConflicts({entry5}, CFeeRate(entry5->GetModifiedFee() + 1, entry5->GetTxSize()), unused_txid) == std::nullopt);
+ BOOST_CHECK(PaysMoreThanConflicts({entry6}, CFeeRate(entry6->GetFee() + 1, entry6->GetTxSize()), unused_txid).has_value());
+ BOOST_CHECK(PaysMoreThanConflicts({entry6}, CFeeRate(entry6->GetModifiedFee() + 1, entry6->GetTxSize()), unused_txid) == std::nullopt);
+ // PaysMoreThanConflicts checks individual feerate, not ancestor feerate. This test compares
+ // replacement_feerate and entry4's feerate, which are the same. The replacement_feerate is
+ // considered too low even though entry4 has a low ancestor feerate.
+ BOOST_CHECK(PaysMoreThanConflicts(set_34_cpfp, CFeeRate(entry4->GetModifiedFee(), entry4->GetTxSize()), unused_txid).has_value());
+
+ // Tests for EntriesAndTxidsDisjoint
+ BOOST_CHECK(EntriesAndTxidsDisjoint(empty_set, {tx1->GetHash()}, unused_txid) == std::nullopt);
+ BOOST_CHECK(EntriesAndTxidsDisjoint(set_12_normal, {tx3->GetHash()}, unused_txid) == std::nullopt);
+ // EntriesAndTxidsDisjoint uses txids, not wtxids.
+ BOOST_CHECK(EntriesAndTxidsDisjoint({entry2}, {tx2->GetWitnessHash()}, unused_txid) == std::nullopt);
+ BOOST_CHECK(EntriesAndTxidsDisjoint({entry2}, {tx2->GetHash()}, unused_txid).has_value());
+ BOOST_CHECK(EntriesAndTxidsDisjoint(set_12_normal, {tx1->GetHash()}, unused_txid).has_value());
+ BOOST_CHECK(EntriesAndTxidsDisjoint(set_12_normal, {tx2->GetHash()}, unused_txid).has_value());
+ // EntriesAndTxidsDisjoint does not calculate descendants of iters_conflicting; it uses whatever
+ // the caller passed in. As such, no error is returned even though entry2 is a descendant of tx1.
+ BOOST_CHECK(EntriesAndTxidsDisjoint({entry2}, {tx1->GetHash()}, unused_txid) == std::nullopt);
+
+ // Tests for PaysForRBF
+ const CFeeRate incremental_relay_feerate{DEFAULT_INCREMENTAL_RELAY_FEE};
+ const CFeeRate higher_relay_feerate{2 * DEFAULT_INCREMENTAL_RELAY_FEE};
+ // Must pay at least as much as the original.
+ BOOST_CHECK(PaysForRBF(/*original_fees=*/high_fee,
+ /*replacement_fees=*/high_fee,
+ /*replacement_vsize=*/1,
+ /*relay_fee=*/CFeeRate(0),
+ /*txid=*/unused_txid)
+ == std::nullopt);
+ BOOST_CHECK(PaysForRBF(high_fee, high_fee - 1, 1, CFeeRate(0), unused_txid).has_value());
+ BOOST_CHECK(PaysForRBF(high_fee + 1, high_fee, 1, CFeeRate(0), unused_txid).has_value());
+ // Additional fees must cover the replacement's vsize at incremental relay fee
+ BOOST_CHECK(PaysForRBF(high_fee, high_fee + 1, 2, incremental_relay_feerate, unused_txid).has_value());
+ BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 2, incremental_relay_feerate, unused_txid) == std::nullopt);
+ BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 2, higher_relay_feerate, unused_txid).has_value());
+ BOOST_CHECK(PaysForRBF(high_fee, high_fee + 4, 2, higher_relay_feerate, unused_txid) == std::nullopt);
+ BOOST_CHECK(PaysForRBF(low_fee, high_fee, 99999999, incremental_relay_feerate, unused_txid).has_value());
+ BOOST_CHECK(PaysForRBF(low_fee, high_fee + 99999999, 99999999, incremental_relay_feerate, unused_txid) == std::nullopt);
+
+ // Tests for GetEntriesForConflicts
+ CTxMemPool::setEntries all_parents{entry1, entry3, entry5, entry7, entry8};
+ CTxMemPool::setEntries all_children{entry2, entry4, entry6};
+ const std::vector<CTransactionRef> parent_inputs({m_coinbase_txns[0], m_coinbase_txns[1], m_coinbase_txns[2],
+ m_coinbase_txns[3], m_coinbase_txns[4]});
+ const auto conflicts_with_parents = make_tx(parent_inputs, {50 * CENT});
+ CTxMemPool::setEntries all_conflicts;
+ BOOST_CHECK(GetEntriesForConflicts(/*tx=*/ *conflicts_with_parents.get(),
+ /*pool=*/ pool,
+ /*iters_conflicting=*/ all_parents,
+ /*all_conflicts=*/ all_conflicts) == std::nullopt);
+ BOOST_CHECK(all_conflicts == all_entries);
+ auto conflicts_size = all_conflicts.size();
+ all_conflicts.clear();
+
+ add_descendants(tx2, 23, pool);
+ BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
+ conflicts_size += 23;
+ BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
+ all_conflicts.clear();
+
+ add_descendants(tx4, 23, pool);
+ BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
+ conflicts_size += 23;
+ BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
+ all_conflicts.clear();
+
+ add_descendants(tx6, 23, pool);
+ BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
+ conflicts_size += 23;
+ BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
+ all_conflicts.clear();
+
+ add_descendants(tx7, 23, pool);
+ BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
+ conflicts_size += 23;
+ BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
+ BOOST_CHECK_EQUAL(all_conflicts.size(), 100);
+ all_conflicts.clear();
+
+ // Exceeds maximum number of conflicts.
+ add_descendants(tx8, 1, pool);
+ BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts).has_value());
+
+ // Tests for HasNoNewUnconfirmed
+ const auto spends_unconfirmed = make_tx({tx1}, {36 * CENT});
+ for (const auto& input : spends_unconfirmed->vin) {
+ // Spends unconfirmed inputs.
+ BOOST_CHECK(pool.exists(GenTxid::Txid(input.prevout.hash)));
+ }
+ BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),
+ /*pool=*/ pool,
+ /*iters_conflicting=*/ all_entries) == std::nullopt);
+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);
+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());
+
+ const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});
+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());
+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());
+
+ const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});
+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 05bb89ab55..9e7a376d6b 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1514,8 +1514,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_returns_true)
CScriptWitness wit;
scriptPubKey << OP_1;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << spendTx;
@@ -1537,8 +1537,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_index_err)
CScriptWitness wit;
scriptPubKey << OP_EQUAL;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << spendTx;
@@ -1560,8 +1560,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_size)
CScriptWitness wit;
scriptPubKey << OP_EQUAL;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << spendTx;
@@ -1583,8 +1583,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_serialization)
CScriptWitness wit;
scriptPubKey << OP_EQUAL;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << 0xffffffff;
@@ -1606,8 +1606,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_amount_required_err)
CScriptWitness wit;
scriptPubKey << OP_EQUAL;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << spendTx;
@@ -1629,8 +1629,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_invalid_flags)
CScriptWitness wit;
scriptPubKey << OP_EQUAL;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << spendTx;
@@ -1813,7 +1813,7 @@ BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors)
BOOST_CHECK_EQUAL(HexStr(sighash), input["intermediary"]["sigHash"].get_str());
// To verify the sigmsg, hash the expected sigmsg, and compare it with the (expected) sighash.
- BOOST_CHECK_EQUAL(HexStr((CHashWriter(HASHER_TAPSIGHASH) << Span{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
+ BOOST_CHECK_EQUAL(HexStr((HashWriter{HASHER_TAPSIGHASH} << Span{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
}
}
diff --git a/src/test/sock_tests.cpp b/src/test/sock_tests.cpp
index 01a402833d..8376ec1a68 100644
--- a/src/test/sock_tests.cpp
+++ b/src/test/sock_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <compat.h>
+#include <compat/compat.h>
#include <test/util/setup_common.h>
#include <threadinterrupt.h>
#include <util/sock.h>
diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp
index 3f5353b5a2..f160bb08a5 100644
--- a/src/test/system_tests.cpp
+++ b/src/test/system_tests.cpp
@@ -7,11 +7,6 @@
#include <univalue.h>
#ifdef ENABLE_EXTERNAL_SIGNER
-#if defined(WIN32) && !defined(__kernel_entry)
-// A workaround for boost 1.71 incompatibility with mingw-w64 compiler.
-// For details see https://github.com/bitcoin/bitcoin/pull/22348.
-#define __kernel_entry
-#endif
#if defined(__GNUC__)
// Boost 1.78 requires the following workaround.
// See: https://github.com/boostorg/process/issues/235
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index 15213f826b..62c7ddb673 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -4,6 +4,7 @@
#include <chainparams.h>
#include <index/txindex.h>
+#include <interfaces/chain.h>
#include <script/standard.h>
#include <test/util/setup_common.h>
#include <util/time.h>
@@ -15,7 +16,7 @@ BOOST_AUTO_TEST_SUITE(txindex_tests)
BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
{
- TxIndex txindex(1 << 20, true);
+ TxIndex txindex(interfaces::MakeChain(m_node), 1 << 20, true);
CTransactionRef tx_disk;
uint256 block_hash;
@@ -28,7 +29,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
// BlockUntilSyncedToCurrentChain should return false before txindex is started.
BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain());
- BOOST_REQUIRE(txindex.Start(m_node.chainman->ActiveChainstate()));
+ BOOST_REQUIRE(txindex.Start());
// Allow tx index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000;
diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h
index 5ac504c24f..13e0e684b8 100644
--- a/src/test/util/chainstate.h
+++ b/src/test/util/chainstate.h
@@ -16,7 +16,7 @@
#include <boost/test/unit_test.hpp>
-const auto NoMalleation = [](CAutoFile& file, node::SnapshotMetadata& meta){};
+const auto NoMalleation = [](AutoFile& file, node::SnapshotMetadata& meta){};
/**
* Create and activate a UTXO snapshot, optionally providing a function to
@@ -32,7 +32,7 @@ CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F ma
WITH_LOCK(::cs_main, height = node.chainman->ActiveHeight());
fs::path snapshot_path = root / fs::u8path(tfm::format("test_snapshot.%d.dat", height));
FILE* outfile{fsbridge::fopen(snapshot_path, "wb")};
- CAutoFile auto_outfile{outfile, SER_DISK, CLIENT_VERSION};
+ AutoFile auto_outfile{outfile};
UniValue result = CreateUTXOSnapshot(
node, node.chainman->ActiveChainstate(), auto_outfile, snapshot_path, snapshot_path);
@@ -42,7 +42,7 @@ CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F ma
// Read the written snapshot in and then activate it.
//
FILE* infile{fsbridge::fopen(snapshot_path, "rb")};
- CAutoFile auto_infile{infile, SER_DISK, CLIENT_VERSION};
+ AutoFile auto_infile{infile};
node::SnapshotMetadata metadata;
auto_infile >> metadata;
diff --git a/src/test/util/net.h b/src/test/util/net.h
index 7f61a03d27..ec6b4e6e88 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_TEST_UTIL_NET_H
#define BITCOIN_TEST_UTIL_NET_H
-#include <compat.h>
+#include <compat/compat.h>
#include <node/eviction.h>
#include <netaddress.h>
#include <net.h>
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 0fba9258f1..67984721a3 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -54,8 +54,6 @@
using node::BlockAssembler;
using node::CalculateCacheSizes;
-using node::fPruneMode;
-using node::fReindex;
using node::LoadChainstate;
using node::NodeContext;
using node::RegenerateCommitments;
@@ -218,25 +216,20 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
// instead of unit tests, but for now we need these here.
RegisterAllCoreRPCCommands(tableRPC);
- auto maybe_load_error = LoadChainstate(fReindex.load(),
- *Assert(m_node.chainman.get()),
- Assert(m_node.mempool.get()),
- fPruneMode,
- m_args.GetBoolArg("-reindex-chainstate", false),
- m_cache_sizes.block_tree_db,
- m_cache_sizes.coins_db,
- m_cache_sizes.coins,
- /*block_tree_db_in_memory=*/true,
- /*coins_db_in_memory=*/true);
- assert(!maybe_load_error.has_value());
-
- auto maybe_verify_error = VerifyLoadedChainstate(
- *Assert(m_node.chainman),
- fReindex.load(),
- m_args.GetBoolArg("-reindex-chainstate", false),
- m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS),
- m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL));
- assert(!maybe_verify_error.has_value());
+ node::ChainstateLoadOptions options;
+ options.mempool = Assert(m_node.mempool.get());
+ options.block_tree_db_in_memory = true;
+ options.coins_db_in_memory = true;
+ options.reindex = node::fReindex;
+ options.reindex_chainstate = m_args.GetBoolArg("-reindex-chainstate", false);
+ options.prune = node::fPruneMode;
+ options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
+ options.check_level = m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
+ auto [status, error] = LoadChainstate(*Assert(m_node.chainman), m_cache_sizes, options);
+ assert(status == node::ChainstateLoadStatus::SUCCESS);
+
+ std::tie(status, error) = VerifyLoadedChainstate(*Assert(m_node.chainman), options);
+ assert(status == node::ChainstateLoadStatus::SUCCESS);
BlockValidationState state;
if (!m_node.chainman->ActiveChainstate().ActivateBestChain(state)) {
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index 6dc522b421..14de96ff41 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -193,7 +193,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
// Should not load malleated snapshots
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
+ m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
// A UTXO is missing but count is correct
metadata.m_coins_count -= 1;
@@ -204,22 +204,22 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
auto_infile >> coin;
}));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
+ m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
// Coins count is larger than coins in file
metadata.m_coins_count += 1;
}));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
+ m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
// Coins count is smaller than coins in file
metadata.m_coins_count -= 1;
}));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
+ m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
// Wrong hash
metadata.m_base_blockhash = uint256::ZERO;
}));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
+ m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
// Wrong hash
metadata.m_base_blockhash = uint256::ONE;
}));
diff --git a/src/threadinterrupt.cpp b/src/threadinterrupt.cpp
index 340106ed99..e28b447c1d 100644
--- a/src/threadinterrupt.cpp
+++ b/src/threadinterrupt.cpp
@@ -28,18 +28,8 @@ void CThreadInterrupt::operator()()
cond.notify_all();
}
-bool CThreadInterrupt::sleep_for(std::chrono::milliseconds rel_time)
+bool CThreadInterrupt::sleep_for(Clock::duration rel_time)
{
WAIT_LOCK(mut, lock);
return !cond.wait_for(lock, rel_time, [this]() { return flag.load(std::memory_order_acquire); });
}
-
-bool CThreadInterrupt::sleep_for(std::chrono::seconds rel_time)
-{
- return sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(rel_time));
-}
-
-bool CThreadInterrupt::sleep_for(std::chrono::minutes rel_time)
-{
- return sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(rel_time));
-}
diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h
index 992016b4f6..363aab39ce 100644
--- a/src/threadinterrupt.h
+++ b/src/threadinterrupt.h
@@ -19,13 +19,12 @@
class CThreadInterrupt
{
public:
+ using Clock = std::chrono::steady_clock;
CThreadInterrupt();
explicit operator bool() const;
void operator()() EXCLUSIVE_LOCKS_REQUIRED(!mut);
void reset();
- bool sleep_for(std::chrono::milliseconds rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
- bool sleep_for(std::chrono::seconds rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
- bool sleep_for(std::chrono::minutes rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
+ bool sleep_for(Clock::duration rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
private:
std::condition_variable cond;
diff --git a/src/timedata.h b/src/timedata.h
index 2f039d5465..ed2d8639f7 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -5,9 +5,12 @@
#ifndef BITCOIN_TIMEDATA_H
#define BITCOIN_TIMEDATA_H
+#include <util/time.h>
+
#include <algorithm>
-#include <assert.h>
-#include <stdint.h>
+#include <cassert>
+#include <chrono>
+#include <cstdint>
#include <vector>
static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT = 70 * 60;
@@ -73,6 +76,7 @@ public:
/** Functions to keep track of adjusted P2P time */
int64_t GetTimeOffset();
int64_t GetAdjustedTime();
+inline NodeSeconds AdjustedTime() { return Now<NodeSeconds>() + std::chrono::seconds{GetTimeOffset()}; }
void AddTimeData(const CNetAddr& ip, int64_t nTime);
/**
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index d6e792a55f..3a21a79a34 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -7,7 +7,7 @@
#include <chainparams.h>
#include <chainparamsbase.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <crypto/hmac_sha256.h>
#include <net.h>
#include <netaddress.h>
diff --git a/src/txdb.cpp b/src/txdb.cpp
index c048c2d92a..bad3bb80a9 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -310,7 +310,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
CDiskBlockIndex diskindex;
if (pcursor->GetValue(diskindex)) {
// Construct block index object
- CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
+ CBlockIndex* pindexNew = insertBlockIndex(diskindex.ConstructBlockHash());
pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
pindexNew->nHeight = diskindex.nHeight;
pindexNew->nFile = diskindex.nFile;
diff --git a/src/txdb.h b/src/txdb.h
index faa543b412..a04596f7bb 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -8,6 +8,7 @@
#include <coins.h>
#include <dbwrapper.h>
+#include <sync.h>
#include <memory>
#include <optional>
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index dff544f96f..230a5fd096 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -24,27 +24,25 @@ public:
typ = initialType;
val = initialStr;
}
- UniValue(uint64_t val_) {
- setInt(val_);
- }
- UniValue(int64_t val_) {
- setInt(val_);
- }
- UniValue(bool val_) {
- setBool(val_);
- }
- UniValue(int val_) {
- setInt(val_);
- }
- UniValue(double val_) {
- setFloat(val_);
- }
- UniValue(const std::string& val_) {
- setStr(val_);
- }
- UniValue(const char *val_) {
- std::string s(val_);
- setStr(s);
+ template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
+ std::enable_if_t<std::is_floating_point_v<T> || // setFloat
+ std::is_same_v<bool, T> || // setBool
+ std::is_signed_v<T> || std::is_unsigned_v<T> || // setInt
+ std::is_constructible_v<std::string, T>, // setStr
+ bool> = true>
+ UniValue(Ref&& val)
+ {
+ if constexpr (std::is_floating_point_v<T>) {
+ setFloat(val);
+ } else if constexpr (std::is_same_v<bool, T>) {
+ setBool(val);
+ } else if constexpr (std::is_signed_v<T>) {
+ setInt(int64_t{val});
+ } else if constexpr (std::is_unsigned_v<T>) {
+ setInt(uint64_t{val});
+ } else {
+ setStr(std::string{std::forward<Ref>(val)});
+ }
}
void clear();
diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp
index b1db3b5f0d..33258d9962 100644
--- a/src/util/asmap.cpp
+++ b/src/util/asmap.cpp
@@ -198,7 +198,7 @@ std::vector<bool> DecodeAsmap(fs::path path)
{
std::vector<bool> bits;
FILE *filestr = fsbridge::fopen(path, "rb");
- CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
+ AutoFile file{filestr};
if (file.IsNull()) {
LogPrintf("Failed to open asmap file from disk\n");
return bits;
diff --git a/src/util/message.cpp b/src/util/message.cpp
index d395c4b0bc..028251a5a8 100644
--- a/src/util/message.cpp
+++ b/src/util/message.cpp
@@ -74,7 +74,7 @@ bool MessageSign(
uint256 MessageHash(const std::string& message)
{
- CHashWriter hasher(SER_GETHASH, 0);
+ HashWriter hasher{};
hasher << MESSAGE_MAGIC << message;
return hasher.GetHash();
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
index 2588575d81..125dbc7f18 100644
--- a/src/util/sock.cpp
+++ b/src/util/sock.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <compat.h>
+#include <compat/compat.h>
#include <logging.h>
#include <threadinterrupt.h>
#include <tinyformat.h>
diff --git a/src/util/sock.h b/src/util/sock.h
index b854609c22..38a7dc80d6 100644
--- a/src/util/sock.h
+++ b/src/util/sock.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_UTIL_SOCK_H
#define BITCOIN_UTIL_SOCK_H
-#include <compat.h>
+#include <compat/compat.h>
#include <threadinterrupt.h>
#include <util/time.h>
diff --git a/src/util/system.cpp b/src/util/system.cpp
index f6f2828fc8..ce45fb2ed4 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -740,7 +740,7 @@ std::string ArgsManager::GetHelpMessage() const
{
const bool show_debug = GetBoolArg("-help-debug", false);
- std::string usage = "";
+ std::string usage;
LOCK(cs_args);
for (const auto& arg_map : m_available_args) {
switch(arg_map.first) {
diff --git a/src/util/system.h b/src/util/system.h
index 04c66341d3..fa03e88920 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -14,7 +14,7 @@
#include <config/bitcoin-config.h>
#endif
-#include <compat.h>
+#include <compat/compat.h>
#include <compat/assumptions.h>
#include <fs.h>
#include <logging.h>
diff --git a/src/util/time.cpp b/src/util/time.cpp
index 2cafc55c69..f6d37347f8 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -7,7 +7,7 @@
#include <config/bitcoin-config.h>
#endif
-#include <compat.h>
+#include <compat/compat.h>
#include <tinyformat.h>
#include <util/time.h>
#include <util/check.h>
diff --git a/src/util/time.h b/src/util/time.h
index fc49f23ce3..4f9bde5d56 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_UTIL_TIME_H
#define BITCOIN_UTIL_TIME_H
-#include <compat.h>
+#include <compat/compat.h>
#include <chrono>
#include <cstdint>
@@ -55,6 +55,7 @@ constexpr int64_t count_seconds(std::chrono::seconds t) { return t.count(); }
constexpr int64_t count_milliseconds(std::chrono::milliseconds t) { return t.count(); }
constexpr int64_t count_microseconds(std::chrono::microseconds t) { return t.count(); }
+using HoursDouble = std::chrono::duration<double, std::chrono::hours::period>;
using SecondsDouble = std::chrono::duration<double, std::chrono::seconds::period>;
/**
diff --git a/src/validation.cpp b/src/validation.cpp
index c46eb36e5c..d64ef4df0b 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2266,7 +2266,6 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
m_blockman.m_dirty_blockindex.insert(pindex);
}
- assert(pindex->phashBlock);
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
@@ -4721,7 +4720,7 @@ const AssumeutxoData* ExpectedAssumeutxo(
}
bool ChainstateManager::ActivateSnapshot(
- CAutoFile& coins_file,
+ AutoFile& coins_file,
const SnapshotMetadata& metadata,
bool in_memory)
{
@@ -4816,7 +4815,7 @@ static void FlushSnapshotToDisk(CCoinsViewCache& coins_cache, bool snapshot_load
bool ChainstateManager::PopulateAndValidateSnapshot(
CChainState& snapshot_chainstate,
- CAutoFile& coins_file,
+ AutoFile& coins_file,
const SnapshotMetadata& metadata)
{
// It's okay to release cs_main before we're done using `coins_cache` because we know
diff --git a/src/validation.h b/src/validation.h
index a21d9e3a28..a44dbd9c7a 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -818,7 +818,7 @@ private:
//! Internal helper for ActivateSnapshot().
[[nodiscard]] bool PopulateAndValidateSnapshot(
CChainState& snapshot_chainstate,
- CAutoFile& coins_file,
+ AutoFile& coins_file,
const node::SnapshotMetadata& metadata);
/**
@@ -907,7 +907,7 @@ public:
//! - Move the new chainstate to `m_snapshot_chainstate` and make it our
//! ChainstateActive().
[[nodiscard]] bool ActivateSnapshot(
- CAutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory);
+ AutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory);
//! The most-work chain.
CChainState& ActiveChainstate() const;
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index dbd768a758..60715ff3c8 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <compat/compat.h>
#include <fs.h>
#include <wallet/bdb.h>
#include <wallet/db.h>
diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp
index d80c3e25b0..f7fee443d0 100644
--- a/src/wallet/dump.cpp
+++ b/src/wallet/dump.cpp
@@ -41,7 +41,7 @@ bool DumpWallet(const ArgsManager& args, CWallet& wallet, bilingual_str& error)
return false;
}
- CHashWriter hasher(0, 0);
+ HashWriter hasher{};
WalletDatabase& db = wallet.GetDatabase();
std::unique_ptr<DatabaseBatch> batch = db.MakeBatch();
@@ -132,7 +132,7 @@ bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::
std::ifstream dump_file{dump_path};
// Compute the checksum
- CHashWriter hasher(0, 0);
+ HashWriter hasher{};
uint256 checksum;
// Check the magic and version
diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp
index d3303c0b1f..944925d600 100644
--- a/src/wallet/receive.cpp
+++ b/src/wallet/receive.cpp
@@ -9,15 +9,12 @@
#include <wallet/wallet.h>
namespace wallet {
-isminetype InputIsMine(const CWallet& wallet, const CTxIn &txin)
+isminetype InputIsMine(const CWallet& wallet, const CTxIn& txin)
{
AssertLockHeld(wallet.cs_wallet);
- std::map<uint256, CWalletTx>::const_iterator mi = wallet.mapWallet.find(txin.prevout.hash);
- if (mi != wallet.mapWallet.end())
- {
- const CWalletTx& prev = (*mi).second;
- if (txin.prevout.n < prev.tx->vout.size())
- return wallet.IsMine(prev.tx->vout[txin.prevout.n]);
+ const CWalletTx* prev = wallet.GetWalletTx(txin.prevout.hash);
+ if (prev && txin.prevout.n < prev->tx->vout.size()) {
+ return wallet.IsMine(prev->tx->vout[txin.prevout.n]);
}
return ISMINE_NO;
}
@@ -25,20 +22,8 @@ isminetype InputIsMine(const CWallet& wallet, const CTxIn &txin)
bool AllInputsMine(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter)
{
LOCK(wallet.cs_wallet);
-
- for (const CTxIn& txin : tx.vin)
- {
- auto mi = wallet.mapWallet.find(txin.prevout.hash);
- if (mi == wallet.mapWallet.end())
- return false; // any unknown inputs can't be from us
-
- const CWalletTx& prev = (*mi).second;
-
- if (txin.prevout.n >= prev.tx->vout.size())
- return false; // invalid input!
-
- if (!(wallet.IsMine(prev.tx->vout[txin.prevout.n]) & filter))
- return false;
+ for (const CTxIn& txin : tx.vin) {
+ if (!(InputIsMine(wallet, txin) & filter)) return false;
}
return true;
}
@@ -111,10 +96,10 @@ CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx)
return nChange;
}
-static CAmount GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, const isminefilter& filter, bool recalculate = false)
+static CAmount GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, const isminefilter& filter)
{
auto& amount = wtx.m_amounts[type];
- if (recalculate || !amount.m_cached[filter]) {
+ if (!amount.m_cached[filter]) {
amount.Set(filter, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx, filter) : TxGetCredit(wallet, *wtx.tx, filter));
wtx.m_is_cache_empty = false;
}
@@ -160,29 +145,18 @@ CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx)
return wtx.nChangeCached;
}
-CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, bool fUseCache)
-{
- AssertLockHeld(wallet.cs_wallet);
-
- if (wallet.IsTxImmatureCoinBase(wtx) && wallet.IsTxInMainChain(wtx)) {
- return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache);
- }
-
- return 0;
-}
-
-CAmount CachedTxGetImmatureWatchOnlyCredit(const CWallet& wallet, const CWalletTx& wtx, const bool fUseCache)
+CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
{
AssertLockHeld(wallet.cs_wallet);
if (wallet.IsTxImmatureCoinBase(wtx) && wallet.IsTxInMainChain(wtx)) {
- return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache);
+ return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, filter);
}
return 0;
}
-CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, bool fUseCache, const isminefilter& filter)
+CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
{
AssertLockHeld(wallet.cs_wallet);
@@ -193,7 +167,7 @@ CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx,
if (wallet.IsTxImmatureCoinBase(wtx))
return 0;
- if (fUseCache && allow_cache && wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_cached[filter]) {
+ if (allow_cache && wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_cached[filter]) {
return wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_value[filter];
}
@@ -328,8 +302,8 @@ Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
const CWalletTx& wtx = entry.second;
const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)};
const int tx_depth{wallet.GetTxDepthInMainChain(wtx)};
- const CAmount tx_credit_mine{CachedTxGetAvailableCredit(wallet, wtx, /*fUseCache=*/true, ISMINE_SPENDABLE | reuse_filter)};
- const CAmount tx_credit_watchonly{CachedTxGetAvailableCredit(wallet, wtx, /*fUseCache=*/true, ISMINE_WATCH_ONLY | reuse_filter)};
+ const CAmount tx_credit_mine{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_SPENDABLE | reuse_filter)};
+ const CAmount tx_credit_watchonly{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_WATCH_ONLY | reuse_filter)};
if (is_trusted && tx_depth >= min_depth) {
ret.m_mine_trusted += tx_credit_mine;
ret.m_watchonly_trusted += tx_credit_watchonly;
@@ -338,8 +312,8 @@ Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
ret.m_mine_untrusted_pending += tx_credit_mine;
ret.m_watchonly_untrusted_pending += tx_credit_watchonly;
}
- ret.m_mine_immature += CachedTxGetImmatureCredit(wallet, wtx);
- ret.m_watchonly_immature += CachedTxGetImmatureWatchOnlyCredit(wallet, wtx);
+ ret.m_mine_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_SPENDABLE);
+ ret.m_watchonly_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_WATCH_ONLY);
}
}
return ret;
diff --git a/src/wallet/receive.h b/src/wallet/receive.h
index 1caef293f2..41a70b089a 100644
--- a/src/wallet/receive.h
+++ b/src/wallet/receive.h
@@ -29,11 +29,9 @@ CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const ism
//! filter decides which addresses will count towards the debit
CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter);
CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx);
-CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, bool fUseCache = true)
+CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
-CAmount CachedTxGetImmatureWatchOnlyCredit(const CWallet& wallet, const CWalletTx& wtx, const bool fUseCache = true)
- EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
-CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, bool fUseCache = true, const isminefilter& filter = ISMINE_SPENDABLE)
+CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter = ISMINE_SPENDABLE)
EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
struct COutputEntry
{
diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp
index 9428d049de..2a6eb96871 100644
--- a/src/wallet/rpc/addresses.cpp
+++ b/src/wallet/rpc/addresses.cpp
@@ -34,7 +34,7 @@ RPCHelpMan getnewaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -86,7 +86,7 @@ RPCHelpMan getrawchangeaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -131,7 +131,7 @@ RPCHelpMan setlabel()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -148,7 +148,7 @@ RPCHelpMan setlabel()
pwallet->SetAddressBook(dest, label, "send");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -181,7 +181,7 @@ RPCHelpMan listaddressgroupings()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -252,7 +252,7 @@ RPCHelpMan addmultisigaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
@@ -327,7 +327,7 @@ RPCHelpMan keypoolrefill()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
if (pwallet->IsLegacy() && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
@@ -350,7 +350,7 @@ RPCHelpMan keypoolrefill()
throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -374,14 +374,14 @@ RPCHelpMan newkeypool()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
spk_man.NewKeyPool();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -548,7 +548,7 @@ RPCHelpMan getaddressinfo()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -658,7 +658,7 @@ RPCHelpMan getaddressesbylabel()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -721,7 +721,7 @@ RPCHelpMan listlabels()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -763,7 +763,7 @@ RPCHelpMan walletdisplayaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- if (!wallet) return NullUniValue;
+ if (!wallet) return UniValue::VNULL;
CWallet* const pwallet = wallet.get();
LOCK(pwallet->cs_wallet);
diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp
index 62aba4f3f2..306053fd0c 100644
--- a/src/wallet/rpc/backup.cpp
+++ b/src/wallet/rpc/backup.cpp
@@ -124,7 +124,7 @@ RPCHelpMan importprivkey()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
@@ -140,7 +140,7 @@ RPCHelpMan importprivkey()
EnsureWalletIsUnlocked(*pwallet);
std::string strSecret = request.params[0].get_str();
- std::string strLabel = "";
+ std::string strLabel;
if (!request.params[1].isNull())
strLabel = request.params[1].get_str();
@@ -192,7 +192,7 @@ RPCHelpMan importprivkey()
RescanWallet(*pwallet, reserver);
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -229,7 +229,7 @@ RPCHelpMan importaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
EnsureLegacyScriptPubKeyMan(*pwallet, true);
@@ -299,7 +299,7 @@ RPCHelpMan importaddress()
}
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -317,7 +317,7 @@ RPCHelpMan importprunedfunds()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
CMutableTransaction tx;
if (!DecodeHexTx(tx, request.params[0].get_str())) {
@@ -352,7 +352,7 @@ RPCHelpMan importprunedfunds()
CTransactionRef tx_ref = MakeTransactionRef(tx);
if (pwallet->IsMine(*tx_ref)) {
pwallet->AddToWallet(std::move(tx_ref), TxStateConfirmed{merkleBlock.header.GetHash(), height, static_cast<int>(txnIndex)});
- return NullUniValue;
+ return UniValue::VNULL;
}
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction");
@@ -376,7 +376,7 @@ RPCHelpMan removeprunedfunds()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -393,7 +393,7 @@ RPCHelpMan removeprunedfunds()
throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet.");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -425,7 +425,7 @@ RPCHelpMan importpubkey()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
EnsureLegacyScriptPubKeyMan(*pwallet, true);
@@ -480,7 +480,7 @@ RPCHelpMan importpubkey()
}
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -506,7 +506,7 @@ RPCHelpMan importwallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
EnsureLegacyScriptPubKeyMan(*pwallet, true);
@@ -637,7 +637,7 @@ RPCHelpMan importwallet()
if (!fGood)
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys/scripts to wallet");
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -661,7 +661,7 @@ RPCHelpMan dumpprivkey()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
const LegacyScriptPubKeyMan& spk_man = EnsureConstLegacyScriptPubKeyMan(*pwallet);
@@ -711,7 +711,7 @@ RPCHelpMan dumpwallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
const CWallet& wallet = *pwallet;
const LegacyScriptPubKeyMan& spk_man = EnsureConstLegacyScriptPubKeyMan(wallet);
@@ -1328,7 +1328,7 @@ RPCHelpMan importmulti()
[&](const RPCHelpMan& self, const JSONRPCRequest& mainRequest) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(mainRequest);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
CWallet& wallet{*pwallet};
// Make sure the results are valid at least up to the most recent block
@@ -1636,7 +1636,7 @@ RPCHelpMan importdescriptors()
[&](const RPCHelpMan& self, const JSONRPCRequest& main_request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(main_request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
CWallet& wallet{*pwallet};
// Make sure the results are valid at least up to the most recent block
@@ -1771,7 +1771,7 @@ RPCHelpMan listdescriptors()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
- if (!wallet) return NullUniValue;
+ if (!wallet) return UniValue::VNULL;
if (!wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "listdescriptors is not available for non-descriptor wallets");
@@ -1840,7 +1840,7 @@ RPCHelpMan backupwallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1853,7 +1853,7 @@ RPCHelpMan backupwallet()
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp
index 8cb41bca18..d40d800f28 100644
--- a/src/wallet/rpc/coins.cpp
+++ b/src/wallet/rpc/coins.cpp
@@ -103,7 +103,7 @@ RPCHelpMan getreceivedbyaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -144,7 +144,7 @@ RPCHelpMan getreceivedbylabel()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -184,7 +184,7 @@ RPCHelpMan getbalance()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -223,7 +223,7 @@ RPCHelpMan getunconfirmedbalance()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -282,7 +282,7 @@ RPCHelpMan lockunspent()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -407,7 +407,7 @@ RPCHelpMan listlockunspent()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -459,7 +459,7 @@ RPCHelpMan getbalances()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
- if (!rpc_wallet) return NullUniValue;
+ if (!rpc_wallet) return UniValue::VNULL;
const CWallet& wallet = *rpc_wallet;
// Make sure the results are valid at least up to the most recent block
@@ -559,7 +559,7 @@ RPCHelpMan listunspent()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
int nMinDepth = 1;
if (!request.params[0].isNull()) {
diff --git a/src/wallet/rpc/encrypt.cpp b/src/wallet/rpc/encrypt.cpp
index 931c64ca06..a68f52a718 100644
--- a/src/wallet/rpc/encrypt.cpp
+++ b/src/wallet/rpc/encrypt.cpp
@@ -32,7 +32,7 @@ RPCHelpMan walletpassphrase()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- if (!wallet) return NullUniValue;
+ if (!wallet) return UniValue::VNULL;
CWallet* const pwallet = wallet.get();
int64_t nSleepTime;
@@ -98,7 +98,7 @@ RPCHelpMan walletpassphrase()
}
}, nSleepTime);
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -120,7 +120,7 @@ RPCHelpMan walletpassphrasechange()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -146,7 +146,7 @@ RPCHelpMan walletpassphrasechange()
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -173,7 +173,7 @@ RPCHelpMan walletlock()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -184,7 +184,7 @@ RPCHelpMan walletlock()
pwallet->Lock();
pwallet->nRelockTime = 0;
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -217,7 +217,7 @@ RPCHelpMan encryptwallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
diff --git a/src/wallet/rpc/signmessage.cpp b/src/wallet/rpc/signmessage.cpp
index 438d290030..ae4bd4fbc5 100644
--- a/src/wallet/rpc/signmessage.cpp
+++ b/src/wallet/rpc/signmessage.cpp
@@ -36,7 +36,7 @@ RPCHelpMan signmessage()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index c7b66179ca..e27cb1139e 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -261,7 +261,7 @@ RPCHelpMan sendtoaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -367,7 +367,7 @@ RPCHelpMan sendmany()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -422,7 +422,7 @@ RPCHelpMan settxfee()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -805,7 +805,7 @@ RPCHelpMan fundrawtransaction()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
@@ -895,7 +895,7 @@ RPCHelpMan signrawtransactionwithwallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
@@ -992,7 +992,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
[want_psbt](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) {
throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
@@ -1209,7 +1209,7 @@ RPCHelpMan send()
);
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
UniValue options{request.params[4].isNull() ? UniValue::VOBJ : request.params[4]};
InterpretFeeEstimationInstructions(/*conf_target=*/request.params[1], /*estimate_mode=*/request.params[2], /*fee_rate=*/request.params[3], options);
@@ -1314,7 +1314,7 @@ RPCHelpMan sendall()
);
std::shared_ptr<CWallet> const pwallet{GetWalletForJSONRPCRequest(request)};
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
@@ -1490,7 +1490,7 @@ RPCHelpMan walletprocesspsbt()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
const CWallet& wallet{*pwallet};
// Make sure the results are valid at least up to the most recent block
@@ -1617,7 +1617,7 @@ RPCHelpMan walletcreatefundedpsbt()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
CWallet& wallet{*pwallet};
// Make sure the results are valid at least up to the most recent block
diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp
index 0b52dcc001..9c8003d6d7 100644
--- a/src/wallet/rpc/transactions.cpp
+++ b/src/wallet/rpc/transactions.cpp
@@ -236,7 +236,7 @@ RPCHelpMan listreceivedbyaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -281,7 +281,7 @@ RPCHelpMan listreceivedbylabel()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -471,7 +471,7 @@ RPCHelpMan listtransactions()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -586,7 +586,7 @@ RPCHelpMan listsinceblock()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
const CWallet& wallet = *pwallet;
// Make sure the results are valid at least up to the most recent block
@@ -727,7 +727,7 @@ RPCHelpMan gettransaction()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -800,7 +800,7 @@ RPCHelpMan abandontransaction()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -817,7 +817,7 @@ RPCHelpMan abandontransaction()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -845,7 +845,7 @@ RPCHelpMan rescanblockchain()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
CWallet& wallet{*pwallet};
// Make sure the results are valid at least up to the most recent block
@@ -925,7 +925,7 @@ RPCHelpMan abortrescan()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
pwallet->AbortRescan();
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 4c44c333a6..0fe8871152 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -68,7 +68,7 @@ static RPCHelpMan getwalletinfo()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -241,7 +241,7 @@ static RPCHelpMan loadwallet()
static RPCHelpMan setwalletflag()
{
- std::string flags = "";
+ std::string flags;
for (auto& it : WALLET_FLAG_MAP)
if (it.second & MUTABLE_WALLET_FLAGS)
flags += (flags == "" ? "" : ", ") + it.first;
@@ -267,7 +267,7 @@ static RPCHelpMan setwalletflag()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
std::string flag_str = request.params[0].get_str();
bool value = request.params[1].isNull() || request.params[1].get_bool();
@@ -480,7 +480,7 @@ static RPCHelpMan sethdseed()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
@@ -521,7 +521,7 @@ static RPCHelpMan sethdseed()
spk_man.SetHDSeed(master_pub_key);
if (flush_key_pool) spk_man.NewKeyPool();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -532,7 +532,7 @@ static RPCHelpMan upgradewallet()
"\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n"
"New keys may be generated and a new wallet backup will need to be made.",
{
- {"version", RPCArg::Type::NUM, RPCArg::Default{FEATURE_LATEST}, "The version number to upgrade to. Default is the latest wallet version."}
+ {"version", RPCArg::Type::NUM, RPCArg::Default{int{FEATURE_LATEST}}, "The version number to upgrade to. Default is the latest wallet version."}
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -551,7 +551,7 @@ static RPCHelpMan upgradewallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
RPCTypeCheck(request.params, {UniValue::VNUM}, true);
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
index 816bef6148..5c173773e4 100644
--- a/src/wallet/test/fuzz/notifications.cpp
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -137,8 +137,13 @@ FUZZ_TARGET_INIT(wallet_notifications, initialize_setup)
block.vtx.emplace_back(MakeTransactionRef(tx));
}
// Mine block
- a.wallet->blockConnected(block, chain.size());
- b.wallet->blockConnected(block, chain.size());
+ const uint256& hash = block.GetHash();
+ interfaces::BlockInfo info{hash};
+ info.prev_hash = &block.hashPrevBlock;
+ info.height = chain.size();
+ info.data = &block;
+ a.wallet->blockConnected(info);
+ b.wallet->blockConnected(info);
// Store the coins for the next block
Coins coins_new;
for (const auto& tx : block.vtx) {
@@ -154,8 +159,13 @@ FUZZ_TARGET_INIT(wallet_notifications, initialize_setup)
auto& [coins, block]{chain.back()};
if (block.vtx.empty()) return; // Can only disconnect if the block was submitted first
// Disconnect block
- a.wallet->blockDisconnected(block, chain.size() - 1);
- b.wallet->blockDisconnected(block, chain.size() - 1);
+ const uint256& hash = block.GetHash();
+ interfaces::BlockInfo info{hash};
+ info.prev_hash = &block.hashPrevBlock;
+ info.height = chain.size() - 1;
+ info.data = &block;
+ a.wallet->blockDisconnected(info);
+ b.wallet->blockDisconnected(info);
chain.pop_back();
});
auto& [coins, first_block]{chain.front()};
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 1dc09e003b..81183aa738 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -360,13 +360,13 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
// Call GetImmatureCredit() once before adding the key to the wallet to
// cache the current immature credit amount, which is 0.
- BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 0);
+ BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx, ISMINE_SPENDABLE), 0);
// Invalidate the cached value, add the key, and make sure a new immature
// credit amount is calculated.
wtx.MarkDirty();
AddKey(wallet, coinbaseKey);
- BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 50*COIN);
+ BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx, ISMINE_SPENDABLE), 50*COIN);
}
static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
@@ -779,7 +779,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
promise.set_value();
SyncWithValidationInterfaceQueue();
// AddToWallet events for block_tx and mempool_tx events are counted a
- // second time as the notificaiton queue is processed
+ // second time as the notification queue is processed
BOOST_CHECK_EQUAL(addtx_count, 4);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 9af68000aa..54a3221e2d 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1314,30 +1314,31 @@ void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRe
}
}
-void CWallet::blockConnected(const CBlock& block, int height)
+void CWallet::blockConnected(const interfaces::BlockInfo& block)
{
- const uint256& block_hash = block.GetHash();
+ assert(block.data);
LOCK(cs_wallet);
- m_last_block_processed_height = height;
- m_last_block_processed = block_hash;
- for (size_t index = 0; index < block.vtx.size(); index++) {
- SyncTransaction(block.vtx[index], TxStateConfirmed{block_hash, height, static_cast<int>(index)});
- transactionRemovedFromMempool(block.vtx[index], MemPoolRemovalReason::BLOCK, 0 /* mempool_sequence */);
+ m_last_block_processed_height = block.height;
+ m_last_block_processed = block.hash;
+ for (size_t index = 0; index < block.data->vtx.size(); index++) {
+ SyncTransaction(block.data->vtx[index], TxStateConfirmed{block.hash, block.height, static_cast<int>(index)});
+ transactionRemovedFromMempool(block.data->vtx[index], MemPoolRemovalReason::BLOCK, 0 /* mempool_sequence */);
}
}
-void CWallet::blockDisconnected(const CBlock& block, int height)
+void CWallet::blockDisconnected(const interfaces::BlockInfo& block)
{
+ assert(block.data);
LOCK(cs_wallet);
// At block disconnection, this will change an abandoned transaction to
// be unconfirmed, whether or not the transaction is added back to the mempool.
// User may have to call abandontransaction again. It may be addressed in the
// future with a stickier abandoned state or even removing abandontransaction call.
- m_last_block_processed_height = height - 1;
- m_last_block_processed = block.hashPrevBlock;
- for (const CTransactionRef& ptx : block.vtx) {
+ m_last_block_processed_height = block.height - 1;
+ m_last_block_processed = *Assert(block.prev_hash);
+ for (const CTransactionRef& ptx : Assert(block.data)->vtx) {
SyncTransaction(ptx, TxStateInactive{});
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index e2c3d76438..15f5917040 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -508,8 +508,8 @@ public:
CWalletTx* AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block = false);
bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override;
- void blockConnected(const CBlock& block, int height) override;
- void blockDisconnected(const CBlock& block, int height) override;
+ void blockConnected(const interfaces::BlockInfo& block) override;
+ void blockDisconnected(const interfaces::BlockInfo& block) override;
void updatedBlockTip() override;
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
diff --git a/test/functional/feature_addrman.py b/test/functional/feature_addrman.py
index 5e49d0214a..63abf0d9f8 100755
--- a/test/functional/feature_addrman.py
+++ b/test/functional/feature_addrman.py
@@ -95,7 +95,7 @@ class AddrmanTest(BitcoinTestFramework):
with open(peers_dat, "wb") as f:
f.write(serialize_addrman()[:-1])
self.nodes[0].assert_start_raises_init_error(
- expected_msg=init_error("CAutoFile::read: end of file.*"),
+ expected_msg=init_error("AutoFile::read: end of file.*"),
match=ErrorMatch.FULL_REGEX,
)
diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py
index 0e44038196..777f873f70 100755
--- a/test/functional/feature_taproot.py
+++ b/test/functional/feature_taproot.py
@@ -91,7 +91,11 @@ from test_framework.script_util import (
script_to_p2wsh_script,
)
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_raises_rpc_error, assert_equal
+from test_framework.util import (
+ assert_raises_rpc_error,
+ assert_equal,
+ random_bytes,
+)
from test_framework.key import generate_privkey, compute_xonly_pubkey, sign_schnorr, tweak_add_privkey, ECKey
from test_framework.address import (
hash160,
@@ -566,10 +570,6 @@ def random_checksig_style(pubkey):
ret = CScript([pubkey, opcode])
return bytes(ret)
-def random_bytes(n):
- """Return a random bytes object of length n."""
- return bytes(random.getrandbits(8) for i in range(n))
-
def bitflipper(expr):
"""Return a callable that evaluates expr and returns it with a random bitflip."""
def fn(ctx):
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 93b8d81959..23a581469e 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -11,10 +11,23 @@ from itertools import product
from test_framework.descriptors import descsum_create
from test_framework.key import ECKey, H_POINT
from test_framework.messages import (
+ COutPoint,
+ CTransaction,
+ CTxIn,
+ CTxOut,
MAX_BIP125_RBF_SEQUENCE,
WITNESS_SCALE_FACTOR,
ser_compact_size,
)
+from test_framework.psbt import (
+ PSBT,
+ PSBTMap,
+ PSBT_GLOBAL_UNSIGNED_TX,
+ PSBT_IN_RIPEMD160,
+ PSBT_IN_SHA256,
+ PSBT_IN_HASH160,
+ PSBT_IN_HASH256,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_approx,
@@ -23,6 +36,7 @@ from test_framework.util import (
assert_raises_rpc_error,
find_output,
find_vout_for_address,
+ random_bytes,
)
from test_framework.wallet_util import bytes_to_wif
@@ -775,5 +789,47 @@ class PSBTTest(BitcoinTestFramework):
self.nodes[0].sendrawtransaction(rawtx)
self.generate(self.nodes[0], 1)
+ self.log.info("Test decoding PSBT with per-input preimage types")
+ # note that the decodepsbt RPC doesn't check whether preimages and hashes match
+ hash_ripemd160, preimage_ripemd160 = random_bytes(20), random_bytes(50)
+ hash_sha256, preimage_sha256 = random_bytes(32), random_bytes(50)
+ hash_hash160, preimage_hash160 = random_bytes(20), random_bytes(50)
+ hash_hash256, preimage_hash256 = random_bytes(32), random_bytes(50)
+
+ tx = CTransaction()
+ tx.vin = [CTxIn(outpoint=COutPoint(hash=int('aa' * 32, 16), n=0), scriptSig=b""),
+ CTxIn(outpoint=COutPoint(hash=int('bb' * 32, 16), n=0), scriptSig=b""),
+ CTxIn(outpoint=COutPoint(hash=int('cc' * 32, 16), n=0), scriptSig=b""),
+ CTxIn(outpoint=COutPoint(hash=int('dd' * 32, 16), n=0), scriptSig=b"")]
+ tx.vout = [CTxOut(nValue=0, scriptPubKey=b"")]
+ psbt = PSBT()
+ psbt.g = PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()})
+ psbt.i = [PSBTMap({bytes([PSBT_IN_RIPEMD160]) + hash_ripemd160: preimage_ripemd160}),
+ PSBTMap({bytes([PSBT_IN_SHA256]) + hash_sha256: preimage_sha256}),
+ PSBTMap({bytes([PSBT_IN_HASH160]) + hash_hash160: preimage_hash160}),
+ PSBTMap({bytes([PSBT_IN_HASH256]) + hash_hash256: preimage_hash256})]
+ psbt.o = [PSBTMap()]
+ res_inputs = self.nodes[0].decodepsbt(psbt.to_base64())["inputs"]
+ assert_equal(len(res_inputs), 4)
+ preimage_keys = ["ripemd160_preimages", "sha256_preimages", "hash160_preimages", "hash256_preimages"]
+ expected_hashes = [hash_ripemd160, hash_sha256, hash_hash160, hash_hash256]
+ expected_preimages = [preimage_ripemd160, preimage_sha256, preimage_hash160, preimage_hash256]
+ for res_input, preimage_key, hash, preimage in zip(res_inputs, preimage_keys, expected_hashes, expected_preimages):
+ assert preimage_key in res_input
+ assert_equal(len(res_input[preimage_key]), 1)
+ assert hash.hex() in res_input[preimage_key]
+ assert_equal(res_input[preimage_key][hash.hex()], preimage.hex())
+
+ self.log.info("Test that combining PSBTs with different transactions fails")
+ tx = CTransaction()
+ tx.vin = [CTxIn(outpoint=COutPoint(hash=int('aa' * 32, 16), n=0), scriptSig=b"")]
+ tx.vout = [CTxOut(nValue=0, scriptPubKey=b"")]
+ psbt1 = PSBT(g=PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()}), i=[PSBTMap()], o=[PSBTMap()]).to_base64()
+ tx.vout[0].nValue += 1 # slightly modify tx
+ psbt2 = PSBT(g=PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()}), i=[PSBTMap()], o=[PSBTMap()]).to_base64()
+ assert_raises_rpc_error(-8, "PSBTs not compatible (different transactions)", self.nodes[0].combinepsbt, [psbt1, psbt2])
+ assert_equal(self.nodes[0].combinepsbt([psbt1, psbt1]), psbt1)
+
+
if __name__ == '__main__':
PSBTTest().main()
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index e6d9f9ae3a..4a68312379 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -208,6 +208,20 @@ def tx_from_hex(hex_string):
return from_hex(CTransaction(), hex_string)
+# like from_hex, but without the hex part
+def from_binary(cls, stream):
+ """deserialize a binary stream (or bytes object) into an object"""
+ # handle bytes object by turning it into a stream
+ was_bytes = isinstance(stream, bytes)
+ if was_bytes:
+ stream = BytesIO(stream)
+ obj = cls()
+ obj.deserialize(stream)
+ if was_bytes:
+ assert len(stream.read()) == 0
+ return obj
+
+
# Objects that map to bitcoind objects, which can be serialized/deserialized
diff --git a/test/functional/test_framework/psbt.py b/test/functional/test_framework/psbt.py
new file mode 100644
index 0000000000..68945e7e84
--- /dev/null
+++ b/test/functional/test_framework/psbt.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import base64
+
+from .messages import (
+ CTransaction,
+ deser_string,
+ from_binary,
+ ser_compact_size,
+)
+
+
+# global types
+PSBT_GLOBAL_UNSIGNED_TX = 0x00
+PSBT_GLOBAL_XPUB = 0x01
+PSBT_GLOBAL_TX_VERSION = 0x02
+PSBT_GLOBAL_FALLBACK_LOCKTIME = 0x03
+PSBT_GLOBAL_INPUT_COUNT = 0x04
+PSBT_GLOBAL_OUTPUT_COUNT = 0x05
+PSBT_GLOBAL_TX_MODIFIABLE = 0x06
+PSBT_GLOBAL_VERSION = 0xfb
+PSBT_GLOBAL_PROPRIETARY = 0xfc
+
+# per-input types
+PSBT_IN_NON_WITNESS_UTXO = 0x00
+PSBT_IN_WITNESS_UTXO = 0x01
+PSBT_IN_PARTIAL_SIG = 0x02
+PSBT_IN_SIGHASH_TYPE = 0x03
+PSBT_IN_REDEEM_SCRIPT = 0x04
+PSBT_IN_WITNESS_SCRIPT = 0x05
+PSBT_IN_BIP32_DERIVATION = 0x06
+PSBT_IN_FINAL_SCRIPTSIG = 0x07
+PSBT_IN_FINAL_SCRIPTWITNESS = 0x08
+PSBT_IN_POR_COMMITMENT = 0x09
+PSBT_IN_RIPEMD160 = 0x0a
+PSBT_IN_SHA256 = 0x0b
+PSBT_IN_HASH160 = 0x0c
+PSBT_IN_HASH256 = 0x0d
+PSBT_IN_PREVIOUS_TXID = 0x0e
+PSBT_IN_OUTPUT_INDEX = 0x0f
+PSBT_IN_SEQUENCE = 0x10
+PSBT_IN_REQUIRED_TIME_LOCKTIME = 0x11
+PSBT_IN_REQUIRED_HEIGHT_LOCKTIME = 0x12
+PSBT_IN_TAP_KEY_SIG = 0x13
+PSBT_IN_TAP_SCRIPT_SIG = 0x14
+PSBT_IN_TAP_LEAF_SCRIPT = 0x15
+PSBT_IN_TAP_BIP32_DERIVATION = 0x16
+PSBT_IN_TAP_INTERNAL_KEY = 0x17
+PSBT_IN_TAP_MERKLE_ROOT = 0x18
+PSBT_IN_PROPRIETARY = 0xfc
+
+# per-output types
+PSBT_OUT_REDEEM_SCRIPT = 0x00
+PSBT_OUT_WITNESS_SCRIPT = 0x01
+PSBT_OUT_BIP32_DERIVATION = 0x02
+PSBT_OUT_AMOUNT = 0x03
+PSBT_OUT_SCRIPT = 0x04
+PSBT_OUT_TAP_INTERNAL_KEY = 0x05
+PSBT_OUT_TAP_TREE = 0x06
+PSBT_OUT_TAP_BIP32_DERIVATION = 0x07
+PSBT_OUT_PROPRIETARY = 0xfc
+
+
+class PSBTMap:
+ """Class for serializing and deserializing PSBT maps"""
+
+ def __init__(self, map=None):
+ self.map = map if map is not None else {}
+
+ def deserialize(self, f):
+ m = {}
+ while True:
+ k = deser_string(f)
+ if len(k) == 0:
+ break
+ v = deser_string(f)
+ if len(k) == 1:
+ k = k[0]
+ assert k not in m
+ m[k] = v
+ self.map = m
+
+ def serialize(self):
+ m = b""
+ for k,v in self.map.items():
+ if isinstance(k, int) and 0 <= k and k <= 255:
+ k = bytes([k])
+ m += ser_compact_size(len(k)) + k
+ m += ser_compact_size(len(v)) + v
+ m += b"\x00"
+ return m
+
+class PSBT:
+ """Class for serializing and deserializing PSBTs"""
+
+ def __init__(self, *, g=None, i=None, o=None):
+ self.g = g if g is not None else PSBTMap()
+ self.i = i if i is not None else []
+ self.o = o if o is not None else []
+ self.tx = None
+
+ def deserialize(self, f):
+ assert f.read(5) == b"psbt\xff"
+ self.g = from_binary(PSBTMap, f)
+ assert 0 in self.g.map
+ self.tx = from_binary(CTransaction, self.g.map[0])
+ self.i = [from_binary(PSBTMap, f) for _ in self.tx.vin]
+ self.o = [from_binary(PSBTMap, f) for _ in self.tx.vout]
+ return self
+
+ def serialize(self):
+ assert isinstance(self.g, PSBTMap)
+ assert isinstance(self.i, list) and all(isinstance(x, PSBTMap) for x in self.i)
+ assert isinstance(self.o, list) and all(isinstance(x, PSBTMap) for x in self.o)
+ assert 0 in self.g.map
+ tx = from_binary(CTransaction, self.g.map[0])
+ assert len(tx.vin) == len(self.i)
+ assert len(tx.vout) == len(self.o)
+
+ psbt = [x.serialize() for x in [self.g] + self.i + self.o]
+ return b"psbt\xff" + b"".join(psbt)
+
+ def to_base64(self):
+ return base64.b64encode(self.serialize()).decode("utf8")
+
+ @classmethod
+ def from_base64(cls, b64psbt):
+ return from_binary(cls, base64.b64decode(b64psbt))
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 58528b7858..fe61ff95f8 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -12,6 +12,7 @@ import inspect
import json
import logging
import os
+import random
import re
import time
import unittest
@@ -286,6 +287,13 @@ def sha256sum_file(filename):
d = f.read(4096)
return h.digest()
+
+# TODO: Remove and use random.randbytes(n) instead, available in Python 3.9
+def random_bytes(n):
+ """Return a random bytes object of length n."""
+ return bytes(random.getrandbits(8) for i in range(n))
+
+
# RPC/P2P connection constants and functions
############################################
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index f7c80f805c..5b836f693f 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -345,31 +345,19 @@ class AddressTypeTest(BitcoinTestFramework):
self.log.info("Nodes with addresstype=legacy never use a P2WPKH change output (unless changetype is set otherwise):")
self.test_change_output_type(0, [to_address_bech32_1], 'legacy')
- if self.options.descriptors:
- self.log.info("Nodes with addresstype=p2sh-segwit match the change output")
- self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
- self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
- else:
- self.log.info("Nodes with addresstype=p2sh-segwit match the change output")
- self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
- self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
- self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
+ self.log.info("Nodes with addresstype=p2sh-segwit match the change output")
+ self.test_change_output_type(1, [to_address_p2sh], 'p2sh-segwit')
+ self.test_change_output_type(1, [to_address_bech32_1], 'bech32')
+ self.test_change_output_type(1, [to_address_p2sh, to_address_bech32_1], 'bech32')
+ self.test_change_output_type(1, [to_address_bech32_1, to_address_bech32_2], 'bech32')
self.log.info("Nodes with change_type=bech32 always use a P2WPKH change output:")
self.test_change_output_type(2, [to_address_bech32_1], 'bech32')
self.test_change_output_type(2, [to_address_p2sh], 'bech32')
- if self.options.descriptors:
- self.log.info("Nodes with addresstype=bech32 match the change output (unless changetype is set otherwise):")
- self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(3, [to_address_p2sh], 'p2sh-segwit')
- else:
- self.log.info("Nodes with addresstype=bech32 match the change output (unless changetype is set otherwise):")
- self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
- self.test_change_output_type(3, [to_address_p2sh], 'p2sh-segwit')
+ self.log.info("Nodes with addresstype=bech32 match the change output (unless changetype is set otherwise):")
+ self.test_change_output_type(3, [to_address_bech32_1], 'bech32')
+ self.test_change_output_type(3, [to_address_p2sh], 'p2sh-segwit')
self.log.info('getrawchangeaddress defaults to addresstype if -changetype is not set and argument is absent')
self.test_address(3, self.nodes[3].getrawchangeaddress(), multisig=False, typ='bech32')
diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py
index f44ed8f7c7..a0f17ac119 100755
--- a/test/lint/lint-circular-dependencies.py
+++ b/test/lint/lint-circular-dependencies.py
@@ -23,6 +23,9 @@ EXPECTED_CIRCULAR_DEPENDENCIES = (
"wallet/wallet -> wallet/walletdb -> wallet/wallet",
"kernel/coinstats -> validation -> kernel/coinstats",
"kernel/mempool_persist -> validation -> kernel/mempool_persist",
+
+ # Temporary, removed in followup https://github.com/bitcoin/bitcoin/pull/24230
+ "index/base -> node/context -> net_processing -> index/blockfilterindex -> index/base",
)
CODE_DIR = "src"