aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.bear-tidy-config15
-rw-r--r--src/.clang-tidy4
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/addrdb.cpp11
-rw-r--r--src/addrdb.h3
-rw-r--r--src/addrman.cpp67
-rw-r--r--src/addrman.h5
-rw-r--r--src/addrman_impl.h29
-rw-r--r--src/arith_uint256.h7
-rw-r--r--src/bench/addrman.cpp11
-rw-r--r--src/bitcoin-tx.cpp17
-rw-r--r--src/chainparams.cpp7
-rw-r--r--src/dbwrapper.cpp2
-rw-r--r--src/index/base.cpp33
-rw-r--r--src/index/base.h6
-rw-r--r--src/index/blockfilterindex.h2
-rw-r--r--src/index/coinstatsindex.h2
-rw-r--r--src/index/txindex.h2
-rw-r--r--src/init.cpp37
-rw-r--r--src/key.cpp6
-rw-r--r--src/mapport.cpp4
-rw-r--r--src/net.cpp56
-rw-r--r--src/net.h52
-rw-r--r--src/net_processing.cpp2
-rw-r--r--src/netaddress.cpp102
-rw-r--r--src/netaddress.h6
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/netgroup.cpp111
-rw-r--r--src/netgroup.h66
-rw-r--r--src/node/blockstorage.cpp17
-rw-r--r--src/node/blockstorage.h34
-rw-r--r--src/node/context.cpp1
-rw-r--r--src/node/context.h2
-rw-r--r--src/qt/guiutil.h12
-rw-r--r--src/qt/initexecutor.cpp6
-rw-r--r--src/qt/intro.cpp2
-rw-r--r--src/qt/walletcontroller.cpp3
-rw-r--r--src/random.cpp7
-rw-r--r--src/random.h5
-rw-r--r--src/randomenv.cpp4
-rw-r--r--src/rest.cpp13
-rw-r--r--src/rpc/blockchain.cpp103
-rw-r--r--src/rpc/external_signer.cpp12
-rw-r--r--src/rpc/mempool.cpp2
-rw-r--r--src/rpc/mining.cpp41
-rw-r--r--src/rpc/misc.cpp45
-rw-r--r--src/rpc/net.cpp43
-rw-r--r--src/rpc/rawtransaction.cpp41
-rw-r--r--src/rpc/request.cpp2
-rw-r--r--src/rpc/server.cpp20
-rw-r--r--src/rpc/txoutproof.cpp2
-rw-r--r--src/rpc/util.cpp24
-rw-r--r--src/script/interpreter.h2
-rw-r--r--src/serialize.h8
-rw-r--r--src/span.h8
-rw-r--r--src/support/allocators/secure.h2
-rw-r--r--src/test/addrman_tests.cpp119
-rw-r--r--src/test/denialofservice_tests.cpp129
-rw-r--r--src/test/fuzz/addrman.cpp33
-rw-r--r--src/test/fuzz/asmap.cpp4
-rw-r--r--src/test/fuzz/connman.cpp13
-rw-r--r--src/test/fuzz/crypto_diff_fuzz_chacha20.cpp2
-rw-r--r--src/test/fuzz/deserialize.cpp4
-rw-r--r--src/test/fuzz/script_assets_test_minimizer.cpp5
-rw-r--r--src/test/fuzz/string.cpp1
-rw-r--r--src/test/key_tests.cpp2
-rw-r--r--src/test/netbase_tests.cpp27
-rw-r--r--src/test/orphanage_tests.cpp137
-rw-r--r--src/test/pmt_tests.cpp15
-rw-r--r--src/test/transaction_tests.cpp5
-rw-r--r--src/test/util/setup_common.cpp6
-rw-r--r--src/test/util_tests.cpp49
-rw-r--r--src/torcontrol.cpp16
-rw-r--r--src/util/bytevectorhash.cpp4
-rw-r--r--src/util/check.h41
-rw-r--r--src/util/spanparsing.cpp16
-rw-r--r--src/util/spanparsing.h17
-rw-r--r--src/util/string.h6
-rw-r--r--src/validation.cpp41
-rw-r--r--src/validation.h1
-rw-r--r--src/wallet/bdb.cpp6
-rw-r--r--src/wallet/coinselection.cpp19
-rw-r--r--src/wallet/coinselection.h21
-rw-r--r--src/wallet/rpc/backup.cpp15
-rw-r--r--src/wallet/rpc/wallet.cpp138
-rw-r--r--src/wallet/spend.cpp13
-rw-r--r--src/wallet/sqlite.cpp6
-rw-r--r--src/wallet/test/coinselector_tests.cpp2
-rw-r--r--src/wallet/test/wallet_crypto_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp6
-rw-r--r--src/zmq/zmqrpc.cpp6
92 files changed, 1143 insertions, 915 deletions
diff --git a/src/.bear-tidy-config b/src/.bear-tidy-config
new file mode 100644
index 0000000000..111ef6ee44
--- /dev/null
+++ b/src/.bear-tidy-config
@@ -0,0 +1,15 @@
+{
+ "output": {
+ "content": {
+ "include_only_existing_source": true,
+ "paths_to_include": [],
+ "paths_to_exclude": [
+ "src/leveldb"
+ ]
+ },
+ "format": {
+ "command_as_array": true,
+ "drop_output_field": false
+ }
+ }
+}
diff --git a/src/.clang-tidy b/src/.clang-tidy
index 27616ad072..fda95967f5 100644
--- a/src/.clang-tidy
+++ b/src/.clang-tidy
@@ -1,2 +1,2 @@
-Checks: '-*,bugprone-argument-comment'
-WarningsAsErrors: bugprone-argument-comment
+Checks: '-*,bugprone-argument-comment,modernize-use-nullptr'
+WarningsAsErrors: 'bugprone-argument-comment,modernize-use-nullptr'
diff --git a/src/Makefile.am b/src/Makefile.am
index c089bed0c9..476ff0a6c5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -180,6 +180,7 @@ BITCOIN_CORE_H = \
net_types.h \
netaddress.h \
netbase.h \
+ netgroup.h \
netmessagemaker.h \
node/blockstorage.h \
node/caches.h \
@@ -352,6 +353,7 @@ libbitcoin_node_a_SOURCES = \
init.cpp \
mapport.cpp \
net.cpp \
+ netgroup.cpp \
net_processing.cpp \
node/blockstorage.cpp \
node/caches.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 96a9a74802..4a35f40112 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -110,6 +110,7 @@ BITCOIN_TESTS =\
test/net_peer_eviction_tests.cpp \
test/net_tests.cpp \
test/netbase_tests.cpp \
+ test/orphanage_tests.cpp \
test/pmt_tests.cpp \
test/policy_fee_tests.cpp \
test/policyestimator_tests.cpp \
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 1fa2644647..0a76f83150 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -13,6 +13,7 @@
#include <hash.h>
#include <logging/timer.h>
#include <netbase.h>
+#include <netgroup.h>
#include <random.h>
#include <streams.h>
#include <tinyformat.h>
@@ -49,7 +50,7 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
{
// Generate random temporary filename
uint16_t randv = 0;
- GetRandBytes((unsigned char*)&randv, sizeof(randv));
+ GetRandBytes({(unsigned char*)&randv, sizeof(randv)});
std::string tmpfn = strprintf("%s.%04x", prefix, randv);
// open temp output file, and associate with CAutoFile
@@ -182,10 +183,10 @@ void ReadFromStream(AddrMan& addr, CDataStream& ssPeers)
DeserializeDB(ssPeers, addr, false);
}
-std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman)
+std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman)
{
auto check_addrman = std::clamp<int32_t>(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
- addrman = std::make_unique<AddrMan>(asmap, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
+ addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
int64_t nStart = GetTimeMillis();
const auto path_addr{args.GetDataDirNet() / "peers.dat"};
@@ -194,7 +195,7 @@ std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const A
LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->size(), GetTimeMillis() - nStart);
} catch (const DbNotFoundError&) {
// Addrman can be in an inconsistent state after failure, reset it
- addrman = std::make_unique<AddrMan>(asmap, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
+ addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
LogPrintf("Creating peers.dat because the file was not found (%s)\n", fs::quoted(fs::PathToString(path_addr)));
DumpPeerAddresses(args, *addrman);
} catch (const InvalidAddrManVersionError&) {
@@ -203,7 +204,7 @@ std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const A
return strprintf(_("Failed to rename invalid peers.dat file. Please move or delete it and try again."));
}
// Addrman can be in an inconsistent state after failure, reset it
- addrman = std::make_unique<AddrMan>(asmap, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
+ addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
LogPrintf("Creating new peers.dat because the file version was not compatible (%s). Original backed up to peers.dat.bak\n", fs::quoted(fs::PathToString(path_addr)));
DumpPeerAddresses(args, *addrman);
} catch (const std::exception& e) {
diff --git a/src/addrdb.h b/src/addrdb.h
index 4bdafb64e4..627ef3ac3c 100644
--- a/src/addrdb.h
+++ b/src/addrdb.h
@@ -17,6 +17,7 @@ class ArgsManager;
class AddrMan;
class CAddress;
class CDataStream;
+class NetGroupManager;
struct bilingual_str;
bool DumpPeerAddresses(const ArgsManager& args, const AddrMan& addr);
@@ -48,7 +49,7 @@ public:
};
/** Returns an error string on failure */
-std::optional<bilingual_str> LoadAddrman(const std::vector<bool>& asmap, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman);
+std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, const ArgsManager& args, std::unique_ptr<AddrMan>& addrman);
/**
* Dump the anchor IP address database (anchors.dat)
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 2a08d99eef..f74729d47b 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -43,17 +43,17 @@ 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
-int AddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool>& asmap) const
+int AddrInfo::GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const
{
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();
- uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
+ uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << netgroupman.GetGroup(*this) << (hash1 % ADDRMAN_TRIED_BUCKETS_PER_GROUP)).GetCheapHash();
return hash2 % ADDRMAN_TRIED_BUCKET_COUNT;
}
-int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const std::vector<bool>& asmap) const
+int AddrInfo::GetNewBucket(const uint256& nKey, const CNetAddr& src, const NetGroupManager& netgroupman) const
{
- std::vector<unsigned char> vchSourceGroupKey = src.GetGroup(asmap);
- uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetGroup(asmap) << vchSourceGroupKey).GetCheapHash();
+ std::vector<unsigned char> vchSourceGroupKey = netgroupman.GetGroup(src);
+ uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << netgroupman.GetGroup(*this) << vchSourceGroupKey).GetCheapHash();
uint64_t hash2 = (CHashWriter(SER_GETHASH, 0) << nKey << vchSourceGroupKey << (hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP)).GetCheapHash();
return hash2 % ADDRMAN_NEW_BUCKET_COUNT;
}
@@ -99,11 +99,11 @@ double AddrInfo::GetChance(int64_t nNow) const
return fChance;
}
-AddrManImpl::AddrManImpl(std::vector<bool>&& asmap, bool deterministic, int32_t consistency_check_ratio)
+AddrManImpl::AddrManImpl(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio)
: insecure_rand{deterministic}
, nKey{deterministic ? uint256{1} : insecure_rand.rand256()}
, m_consistency_check_ratio{consistency_check_ratio}
- , m_asmap{std::move(asmap)}
+ , m_netgroupman{netgroupman}
{
for (auto& bucket : vvNew) {
for (auto& entry : bucket) {
@@ -218,11 +218,7 @@ void AddrManImpl::Serialize(Stream& s_) const
}
// Store asmap checksum after bucket entries so that it
// can be ignored by older clients for backward compatibility.
- uint256 asmap_checksum;
- if (m_asmap.size() != 0) {
- asmap_checksum = SerializeHash(m_asmap);
- }
- s << asmap_checksum;
+ s << m_netgroupman.GetAsmapChecksum();
}
template <typename Stream>
@@ -298,7 +294,7 @@ void AddrManImpl::Unserialize(Stream& s_)
for (int n = 0; n < nTried; n++) {
AddrInfo info;
s >> info;
- int nKBucket = info.GetTriedBucket(nKey, m_asmap);
+ int nKBucket = info.GetTriedBucket(nKey, m_netgroupman);
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
if (info.IsValid()
&& vvTried[nKBucket][nKBucketPos] == -1) {
@@ -335,10 +331,7 @@ void AddrManImpl::Unserialize(Stream& s_)
// If the bucket count and asmap checksum haven't changed, then attempt
// to restore the entries to the buckets/positions they were in before
// serialization.
- uint256 supplied_asmap_checksum;
- if (m_asmap.size() != 0) {
- supplied_asmap_checksum = SerializeHash(m_asmap);
- }
+ uint256 supplied_asmap_checksum{m_netgroupman.GetAsmapChecksum()};
uint256 serialized_asmap_checksum;
if (format >= Format::V2_ASMAP) {
s >> serialized_asmap_checksum;
@@ -371,7 +364,7 @@ void AddrManImpl::Unserialize(Stream& s_)
} else {
// In case the new table data cannot be used (bucket count wrong or new asmap),
// try to give them a reference based on their primary source address.
- bucket = info.GetNewBucket(nKey, m_asmap);
+ bucket = info.GetNewBucket(nKey, m_netgroupman);
bucket_position = info.GetBucketPosition(nKey, true, bucket);
if (vvNew[bucket][bucket_position] == -1) {
vvNew[bucket][bucket_position] = entry_index;
@@ -495,7 +488,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
AssertLockHeld(cs);
// remove the entry from all new buckets
- const int start_bucket{info.GetNewBucket(nKey, m_asmap)};
+ const int start_bucket{info.GetNewBucket(nKey, m_netgroupman)};
for (int n = 0; n < ADDRMAN_NEW_BUCKET_COUNT; ++n) {
const int bucket{(start_bucket + n) % ADDRMAN_NEW_BUCKET_COUNT};
const int pos{info.GetBucketPosition(nKey, true, bucket)};
@@ -510,7 +503,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
assert(info.nRefCount == 0);
// which tried bucket to move the entry to
- int nKBucket = info.GetTriedBucket(nKey, m_asmap);
+ int nKBucket = info.GetTriedBucket(nKey, m_netgroupman);
int nKBucketPos = info.GetBucketPosition(nKey, false, nKBucket);
// first make space to add it (the existing tried entry there is moved to new, deleting whatever is there).
@@ -526,7 +519,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
nTried--;
// find which new bucket it belongs to
- int nUBucket = infoOld.GetNewBucket(nKey, m_asmap);
+ int nUBucket = infoOld.GetNewBucket(nKey, m_netgroupman);
int nUBucketPos = infoOld.GetBucketPosition(nKey, true, nUBucket);
ClearNew(nUBucket, nUBucketPos);
assert(vvNew[nUBucket][nUBucketPos] == -1);
@@ -594,7 +587,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
nNew++;
}
- int nUBucket = pinfo->GetNewBucket(nKey, source, m_asmap);
+ int nUBucket = pinfo->GetNewBucket(nKey, source, m_netgroupman);
int nUBucketPos = pinfo->GetBucketPosition(nKey, true, nUBucket);
bool fInsert = vvNew[nUBucket][nUBucketPos] == -1;
if (vvNew[nUBucket][nUBucketPos] != nId) {
@@ -610,7 +603,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
pinfo->nRefCount++;
vvNew[nUBucket][nUBucketPos] = nId;
LogPrint(BCLog::ADDRMAN, "Added %s mapped to AS%i to new[%i][%i]\n",
- addr.ToString(), addr.GetMappedAS(m_asmap), nUBucket, nUBucketPos);
+ addr.ToString(), m_netgroupman.GetMappedAS(addr), nUBucket, nUBucketPos);
} else {
if (pinfo->nRefCount == 0) {
Delete(nId);
@@ -650,7 +643,7 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
// which tried bucket to move the entry to
- int tried_bucket = info.GetTriedBucket(nKey, m_asmap);
+ int tried_bucket = info.GetTriedBucket(nKey, m_netgroupman);
int tried_bucket_pos = info.GetBucketPosition(nKey, false, tried_bucket);
// Will moving this address into tried evict another entry?
@@ -669,7 +662,7 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
// move nId to the tried tables
MakeTried(info, nId);
LogPrint(BCLog::ADDRMAN, "Moved %s mapped to AS%i to tried[%i][%i]\n",
- addr.ToString(), addr.GetMappedAS(m_asmap), tried_bucket, tried_bucket_pos);
+ addr.ToString(), m_netgroupman.GetMappedAS(addr), tried_bucket, tried_bucket_pos);
return true;
}
}
@@ -863,7 +856,7 @@ void AddrManImpl::ResolveCollisions_()
AddrInfo& info_new = mapInfo[id_new];
// Which tried bucket to move the entry to.
- int tried_bucket = info_new.GetTriedBucket(nKey, m_asmap);
+ int tried_bucket = info_new.GetTriedBucket(nKey, m_netgroupman);
int tried_bucket_pos = info_new.GetBucketPosition(nKey, false, tried_bucket);
if (!info_new.IsValid()) { // id_new may no longer map to a valid address
erase_collision = true;
@@ -929,7 +922,7 @@ std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
const AddrInfo& newInfo = mapInfo[id_new];
// which tried bucket to move the entry to
- int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
+ int tried_bucket = newInfo.GetTriedBucket(nKey, m_netgroupman);
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
@@ -945,13 +938,13 @@ std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& ad
if (!addr_info) return std::nullopt;
if(addr_info->fInTried) {
- int bucket{addr_info->GetTriedBucket(nKey, m_asmap)};
+ int bucket{addr_info->GetTriedBucket(nKey, m_netgroupman)};
return AddressPosition(/*tried_in=*/true,
/*multiplicity_in=*/1,
/*bucket_in=*/bucket,
/*position_in=*/addr_info->GetBucketPosition(nKey, false, bucket));
} else {
- int bucket{addr_info->GetNewBucket(nKey, m_asmap)};
+ int bucket{addr_info->GetNewBucket(nKey, m_netgroupman)};
return AddressPosition(/*tried_in=*/false,
/*multiplicity_in=*/addr_info->nRefCount,
/*bucket_in=*/bucket,
@@ -1026,7 +1019,7 @@ int AddrManImpl::CheckAddrman() const
if (!setTried.count(vvTried[n][i]))
return -11;
const auto it{mapInfo.find(vvTried[n][i])};
- if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_asmap) != n) {
+ if (it == mapInfo.end() || it->second.GetTriedBucket(nKey, m_netgroupman) != n) {
return -17;
}
if (it->second.GetBucketPosition(nKey, false, n) != i) {
@@ -1154,13 +1147,8 @@ std::optional<AddressPosition> AddrManImpl::FindAddressEntry(const CAddress& add
return entry;
}
-const std::vector<bool>& AddrManImpl::GetAsmap() const
-{
- return m_asmap;
-}
-
-AddrMan::AddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio)
- : m_impl(std::make_unique<AddrManImpl>(std::move(asmap), deterministic, consistency_check_ratio)) {}
+AddrMan::AddrMan(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio)
+ : m_impl(std::make_unique<AddrManImpl>(netgroupman, deterministic, consistency_check_ratio)) {}
AddrMan::~AddrMan() = default;
@@ -1235,11 +1223,6 @@ void AddrMan::SetServices(const CService& addr, ServiceFlags nServices)
m_impl->SetServices(addr, nServices);
}
-const std::vector<bool>& AddrMan::GetAsmap() const
-{
- return m_impl->GetAsmap();
-}
-
std::optional<AddressPosition> AddrMan::FindAddressEntry(const CAddress& addr)
{
return m_impl->FindAddressEntry(addr);
diff --git a/src/addrman.h b/src/addrman.h
index 472282833b..a0063e8a9c 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -7,6 +7,7 @@
#define BITCOIN_ADDRMAN_H
#include <netaddress.h>
+#include <netgroup.h>
#include <protocol.h>
#include <streams.h>
#include <timedata.h>
@@ -88,7 +89,7 @@ protected:
const std::unique_ptr<AddrManImpl> m_impl;
public:
- explicit AddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio);
+ explicit AddrMan(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio);
~AddrMan();
@@ -172,8 +173,6 @@ public:
//! Update an entry's service bits.
void SetServices(const CService& addr, ServiceFlags nServices);
- const std::vector<bool>& GetAsmap() const;
-
/** Test-only function
* Find the address record in AddrMan and return information about its
* position.
diff --git a/src/addrman_impl.h b/src/addrman_impl.h
index 5e76f72342..9d98cdde54 100644
--- a/src/addrman_impl.h
+++ b/src/addrman_impl.h
@@ -76,15 +76,15 @@ public:
}
//! Calculate in which "tried" bucket this entry belongs
- int GetTriedBucket(const uint256 &nKey, const std::vector<bool> &asmap) const;
+ int GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const;
//! Calculate in which "new" bucket this entry belongs, given a certain source
- int GetNewBucket(const uint256 &nKey, const CNetAddr& src, const std::vector<bool> &asmap) const;
+ int GetNewBucket(const uint256& nKey, const CNetAddr& src, const NetGroupManager& netgroupman) const;
//! Calculate in which "new" bucket this entry belongs, using its default source
- int GetNewBucket(const uint256 &nKey, const std::vector<bool> &asmap) const
+ int GetNewBucket(const uint256& nKey, const NetGroupManager& netgroupman) const
{
- return GetNewBucket(nKey, source, asmap);
+ return GetNewBucket(nKey, source, netgroupman);
}
//! Calculate in which position of a bucket to store this entry.
@@ -100,7 +100,7 @@ public:
class AddrManImpl
{
public:
- AddrManImpl(std::vector<bool>&& asmap, bool deterministic, int32_t consistency_check_ratio);
+ AddrManImpl(const NetGroupManager& netgroupman, bool deterministic, int32_t consistency_check_ratio);
~AddrManImpl();
@@ -140,8 +140,6 @@ public:
std::optional<AddressPosition> FindAddressEntry(const CAddress& addr)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
- const std::vector<bool>& GetAsmap() const;
-
friend class AddrManDeterministic;
private:
@@ -212,21 +210,8 @@ private:
/** Perform consistency checks every m_consistency_check_ratio operations (if non-zero). */
const int32_t m_consistency_check_ratio;
- // Compressed IP->ASN mapping, loaded from a file when a node starts.
- // Should be always empty if no file was provided.
- // This mapping is then used for bucketing nodes in Addrman.
- //
- // If asmap is provided, nodes will be bucketed by
- // AS they belong to, in order to make impossible for a node
- // to connect to several nodes hosted in a single AS.
- // This is done in response to Erebus attack, but also to generally
- // diversify the connections every node creates,
- // especially useful when a large fraction of nodes
- // operate under a couple of cloud providers.
- //
- // If a new asmap was provided, the existing records
- // would be re-bucketed accordingly.
- const std::vector<bool> m_asmap;
+ /** Reference to the netgroup manager. netgroupman must be constructed before addrman and destructed after. */
+ const NetGroupManager& m_netgroupman;
//! Find an entry.
AddrInfo* Find(const CService& addr, int* pnId = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs);
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index 19193972a4..b7b3b3a285 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -24,22 +24,19 @@ template<unsigned int BITS>
class base_uint
{
protected:
+ static_assert(BITS / 32 > 0 && BITS % 32 == 0, "Template parameter BITS must be a positive multiple of 32.");
static constexpr int WIDTH = BITS / 32;
uint32_t pn[WIDTH];
public:
base_uint()
{
- static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
-
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
}
base_uint(const base_uint& b)
{
- static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
-
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
}
@@ -53,8 +50,6 @@ public:
base_uint(uint64_t b)
{
- static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
-
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp
index 34bc4380dd..76300f4db8 100644
--- a/src/bench/addrman.cpp
+++ b/src/bench/addrman.cpp
@@ -4,6 +4,7 @@
#include <addrman.h>
#include <bench/bench.h>
+#include <netgroup.h>
#include <random.h>
#include <util/check.h>
#include <util/time.h>
@@ -16,7 +17,7 @@
static constexpr size_t NUM_SOURCES = 64;
static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
-static const std::vector<bool> EMPTY_ASMAP;
+static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()};
static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0};
static std::vector<CAddress> g_sources;
@@ -77,14 +78,14 @@ static void AddrManAdd(benchmark::Bench& bench)
CreateAddresses();
bench.run([&] {
- AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
+ AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
AddAddressesToAddrMan(addrman);
});
}
static void AddrManSelect(benchmark::Bench& bench)
{
- AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
+ AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
FillAddrMan(addrman);
@@ -96,7 +97,7 @@ static void AddrManSelect(benchmark::Bench& bench)
static void AddrManGetAddr(benchmark::Bench& bench)
{
- AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
+ AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
FillAddrMan(addrman);
@@ -125,7 +126,7 @@ static void AddrManAddThenGood(benchmark::Bench& bench)
//
// This has some overhead (exactly the result of AddrManAdd benchmark), but that overhead is constant so improvements in
// AddrMan::Good() will still be noticeable.
- AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
+ AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
AddAddressesToAddrMan(addrman);
markSomeAsGood(addrman);
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 0b40626595..05f910e9cb 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -31,8 +31,6 @@
#include <memory>
#include <stdio.h>
-#include <boost/algorithm/string.hpp>
-
static bool fCreateBlank;
static std::map<std::string,UniValue> registers;
static const int CONTINUE_EXECUTION=-1;
@@ -251,8 +249,7 @@ static T TrimAndParse(const std::string& int_str, const std::string& err)
static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
{
- std::vector<std::string> vStrInputParts;
- boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
+ std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
// separate TXID:VOUT in string
if (vStrInputParts.size()<2)
@@ -287,8 +284,7 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput)
{
// Separate into VALUE:ADDRESS
- std::vector<std::string> vStrInputParts;
- boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
+ std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
if (vStrInputParts.size() != 2)
throw std::runtime_error("TX output missing or too many separators");
@@ -312,8 +308,7 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput)
{
// Separate into VALUE:PUBKEY[:FLAGS]
- std::vector<std::string> vStrInputParts;
- boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
+ std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3)
throw std::runtime_error("TX output missing or too many separators");
@@ -356,8 +351,7 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput)
{
// Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
- std::vector<std::string> vStrInputParts;
- boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
+ std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
// Check that there are enough parameters
if (vStrInputParts.size()<3)
@@ -460,8 +454,7 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn
static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput)
{
// separate VALUE:SCRIPT[:FLAGS]
- std::vector<std::string> vStrInputParts;
- boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
+ std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
if (vStrInputParts.size() < 2)
throw std::runtime_error("TX output missing separator");
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index c65a816a5f..7a7c72ea25 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -10,13 +10,11 @@
#include <deploymentinfo.h>
#include <hash.h> // for signet block challenge hash
#include <script/interpreter.h>
+#include <util/string.h>
#include <util/system.h>
#include <assert.h>
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/split.hpp>
-
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
CMutableTransaction txNew;
@@ -528,8 +526,7 @@ void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args)
if (!args.IsArgSet("-vbparams")) return;
for (const std::string& strDeployment : args.GetArgs("-vbparams")) {
- std::vector<std::string> vDeploymentParams;
- boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":"));
+ std::vector<std::string> vDeploymentParams = SplitString(strDeployment, ':');
if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) {
throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]");
}
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index b0ea80ea1a..50a601c684 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -227,7 +227,7 @@ const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8;
std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
{
std::vector<uint8_t> ret(OBFUSCATE_KEY_NUM_BYTES);
- GetRandBytes(ret.data(), OBFUSCATE_KEY_NUM_BYTES);
+ GetRandBytes(ret);
return ret;
}
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 8fe30f8960..488a214ccf 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -65,9 +65,9 @@ bool BaseIndex::Init()
LOCK(cs_main);
CChain& active_chain = m_chainstate->m_chain;
if (locator.IsNull()) {
- m_best_block_index = nullptr;
+ SetBestBlockIndex(nullptr);
} else {
- m_best_block_index = m_chainstate->FindForkInGlobalIndex(locator);
+ SetBestBlockIndex(m_chainstate->FindForkInGlobalIndex(locator));
}
m_synced = m_best_block_index.load() == active_chain.Tip();
if (!m_synced) {
@@ -75,11 +75,7 @@ bool BaseIndex::Init()
if (!m_best_block_index) {
// index is not built yet
// make sure we have all block data back to the genesis
- const CBlockIndex* block = active_chain.Tip();
- while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
- block = block->pprev;
- }
- prune_violation = block != active_chain.Genesis();
+ prune_violation = node::GetFirstStoredBlock(active_chain.Tip()) != active_chain.Genesis();
}
// in case the index has a best block set and is not fully synced
// check if we have the required blocks to continue building the index
@@ -138,7 +134,7 @@ void BaseIndex::ThreadSync()
int64_t last_locator_write_time = 0;
while (true) {
if (m_interrupt) {
- m_best_block_index = pindex;
+ SetBestBlockIndex(pindex);
// No need to handle errors in Commit. If it fails, the error will be already be
// logged. The best way to recover is to continue, as index cannot be corrupted by
// a missed commit to disk for an advanced index state.
@@ -150,7 +146,7 @@ void BaseIndex::ThreadSync()
LOCK(cs_main);
const CBlockIndex* pindex_next = NextSyncBlock(pindex, m_chainstate->m_chain);
if (!pindex_next) {
- m_best_block_index = pindex;
+ SetBestBlockIndex(pindex);
m_synced = true;
// No need to handle errors in Commit. See rationale above.
Commit();
@@ -172,7 +168,7 @@ void BaseIndex::ThreadSync()
}
if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) {
- m_best_block_index = pindex;
+ SetBestBlockIndex(pindex);
last_locator_write_time = current_time;
// No need to handle errors in Commit. See rationale above.
Commit();
@@ -230,10 +226,10 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
// out of sync may be possible but a users fault.
// In case we reorg beyond the pruned depth, ReadBlockFromDisk would
// throw and lead to a graceful shutdown
- m_best_block_index = new_tip;
+ SetBestBlockIndex(new_tip);
if (!Commit()) {
// If commit fails, revert the best block index to avoid corruption.
- m_best_block_index = current_tip;
+ SetBestBlockIndex(current_tip);
return false;
}
@@ -274,7 +270,7 @@ void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const
}
if (WriteBlock(*block, pindex)) {
- m_best_block_index = pindex;
+ SetBestBlockIndex(pindex);
} else {
FatalError("%s: Failed to write block %s to index",
__func__, pindex->GetBlockHash().ToString());
@@ -381,3 +377,14 @@ IndexSummary BaseIndex::GetSummary() const
summary.best_block_height = m_best_block_index ? m_best_block_index.load()->nHeight : 0;
return summary;
}
+
+void BaseIndex::SetBestBlockIndex(const CBlockIndex* block) {
+ assert(!node::fPruneMode || AllowPrune());
+
+ m_best_block_index = block;
+ if (AllowPrune() && block) {
+ node::PruneLockInfo prune_lock;
+ prune_lock.height_first = block->nHeight;
+ WITH_LOCK(::cs_main, m_chainstate->m_blockman.UpdatePruneLock(GetName(), prune_lock));
+ }
+}
diff --git a/src/index/base.h b/src/index/base.h
index c4a8215bc4..a8f6a18c8d 100644
--- a/src/index/base.h
+++ b/src/index/base.h
@@ -75,6 +75,9 @@ private:
/// to a chain reorganization), the index must halt until Commit succeeds or else it could end up
/// getting corrupted.
bool Commit();
+
+ virtual bool AllowPrune() const = 0;
+
protected:
CChainState* m_chainstate{nullptr};
@@ -103,6 +106,9 @@ protected:
/// Get the name of the index for display in logs.
virtual const char* GetName() const = 0;
+ /// Update the internal best block index as well as the prune lock.
+ void SetBestBlockIndex(const CBlockIndex* block);
+
public:
/// Destructor interrupts sync thread if running and blocks until it exits.
virtual ~BaseIndex();
diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h
index a049019c02..b1836fe12f 100644
--- a/src/index/blockfilterindex.h
+++ b/src/index/blockfilterindex.h
@@ -38,6 +38,8 @@ private:
/** cache of block hash to filter header, to avoid disk access when responding to getcfcheckpt. */
std::unordered_map<uint256, uint256, FilterHeaderHasher> m_headers_cache GUARDED_BY(m_cs_headers_cache);
+ bool AllowPrune() const override { return true; }
+
protected:
bool Init() override;
diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h
index 24190ac137..6f53bb74fb 100644
--- a/src/index/coinstatsindex.h
+++ b/src/index/coinstatsindex.h
@@ -36,6 +36,8 @@ private:
bool ReverseBlock(const CBlock& block, const CBlockIndex* pindex);
+ bool AllowPrune() const override { return true; }
+
protected:
bool Init() override;
diff --git a/src/index/txindex.h b/src/index/txindex.h
index 2bbc602631..ec339abaa1 100644
--- a/src/index/txindex.h
+++ b/src/index/txindex.h
@@ -20,6 +20,8 @@ protected:
private:
const std::unique_ptr<DB> m_db;
+ bool AllowPrune() const override { return false; }
+
protected:
bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
diff --git a/src/init.cpp b/src/init.cpp
index c0af2b136f..cccb088eec 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -33,6 +33,7 @@
#include <net_permissions.h>
#include <net_processing.h>
#include <netbase.h>
+#include <netgroup.h>
#include <node/blockstorage.h>
#include <node/caches.h>
#include <node/chainstate.h>
@@ -239,6 +240,7 @@ void Shutdown(NodeContext& node)
node.connman.reset();
node.banman.reset();
node.addrman.reset();
+ node.netgroupman.reset();
if (node.mempool && node.mempool->IsLoaded() && node.args->GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
DumpMempool(*node.mempool);
@@ -419,11 +421,11 @@ void SetupServerArgs(ArgsManager& argsman)
-GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-pid=<file>", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -coinstatsindex. "
+ argsman.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex. "
"Warning: Reverting this setting requires re-downloading the entire blockchain. "
"(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-reindex", "Rebuild chain state and block index from the blk*.dat files on disk", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-reindex", "Rebuild chain state and block index from the blk*.dat files on disk. This will also rebuild active optional indexes.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead. Deactivate all optional indexes before running this.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
#if HAVE_SYSTEM
argsman.AddArg("-startupnotify=<cmd>", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -856,8 +858,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
if (args.GetIntArg("-prune", 0)) {
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX))
return InitError(_("Prune mode is incompatible with -txindex."));
- if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX))
- return InitError(_("Prune mode is incompatible with -coinstatsindex."));
if (args.GetBoolArg("-reindex-chainstate", false)) {
return InitError(_("Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead."));
}
@@ -1031,6 +1031,19 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
return InitError(_("No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>."));
}
+ if (args.GetBoolArg("-reindex-chainstate", false)) {
+ // indexes that must be deactivated to prevent index corruption, see #24630
+ if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
+ return InitError(_("-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes."));
+ }
+ if (g_enabled_filter_types.count(BlockFilterType::BASIC)) {
+ return InitError(_("-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes."));
+ }
+ if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
+ return InitError(_("-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes."));
+ }
+ }
+
#if defined(USE_SYSCALL_SANDBOX)
if (args.IsArgSet("-sandbox") && !args.IsArgNegated("-sandbox")) {
const std::string sandbox_arg{args.GetArg("-sandbox", "")};
@@ -1228,8 +1241,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
const bool ignores_incoming_txs{args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)};
{
- // Initialize addrman
- assert(!node.addrman);
// Read asmap file if configured
std::vector<bool> asmap;
@@ -1253,8 +1264,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
LogPrintf("Using /16 prefix for IP bucketing\n");
}
+ // Initialize netgroup manager
+ assert(!node.netgroupman);
+ node.netgroupman = std::make_unique<NetGroupManager>(std::move(asmap));
+
+ // Initialize addrman
+ assert(!node.addrman);
uiInterface.InitMessage(_("Loading P2P addresses…").translated);
- if (const auto error{LoadAddrman(asmap, args, node.addrman)}) {
+ if (const auto error{LoadAddrman(*node.netgroupman, args, node.addrman)}) {
return InitError(*error);
}
}
@@ -1262,7 +1279,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
assert(!node.banman);
node.banman = std::make_unique<BanMan>(gArgs.GetDataDirNet() / "banlist", &uiInterface, args.GetIntArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!node.connman);
- node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), *node.addrman, args.GetBoolArg("-networkactive", true));
+ node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()),
+ GetRand(std::numeric_limits<uint64_t>::max()),
+ *node.addrman, *node.netgroupman, args.GetBoolArg("-networkactive", true));
assert(!node.fee_estimator);
// Don't initialize fee estimation with old data if we don't relay transactions,
diff --git a/src/key.cpp b/src/key.cpp
index a54569b39e..d1d521f97d 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -159,7 +159,7 @@ bool CKey::Check(const unsigned char *vch) {
void CKey::MakeNewKey(bool fCompressedIn) {
do {
- GetStrongRandBytes(keydata.data(), keydata.size());
+ GetStrongRandBytes(keydata);
} while (!Check(keydata.data()));
fValid = true;
fCompressed = fCompressedIn;
@@ -244,7 +244,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
}
unsigned char rnd[8];
std::string str = "Bitcoin key verification\n";
- GetRandBytes(rnd, sizeof(rnd));
+ GetRandBytes(rnd);
uint256 hash;
CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
std::vector<unsigned char> vchSig;
@@ -397,7 +397,7 @@ void ECC_Start() {
{
// Pass in a random blinding seed to the secp256k1 context.
std::vector<unsigned char, secure_allocator<unsigned char>> vseed(32);
- GetRandBytes(vseed.data(), 32);
+ GetRandBytes(vseed);
bool ret = secp256k1_context_randomize(ctx, vseed.data());
assert(ret);
}
diff --git a/src/mapport.cpp b/src/mapport.cpp
index 42ca366089..235e6f904c 100644
--- a/src/mapport.cpp
+++ b/src/mapport.cpp
@@ -193,7 +193,7 @@ static bool ProcessUpnp()
std::string strDesc = PACKAGE_NAME " " + FormatFullVersion();
do {
- r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
+ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", nullptr, "0");
if (r != UPNPCOMMAND_SUCCESS) {
ret = false;
@@ -206,7 +206,7 @@ static bool ProcessUpnp()
} while (g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD));
g_mapport_interrupt.reset();
- r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
+ r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", nullptr);
LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
freeUPNPDevlist(devlist); devlist = nullptr;
FreeUPNPUrls(&urls);
diff --git a/src/net.cpp b/src/net.cpp
index 5a0c057c3e..aa70bed226 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1567,6 +1567,8 @@ void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
void CConnman::SocketHandler()
{
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+
std::set<SOCKET> recv_set;
std::set<SOCKET> send_set;
std::set<SOCKET> error_set;
@@ -1593,6 +1595,8 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
const std::set<SOCKET>& send_set,
const std::set<SOCKET>& error_set)
{
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+
for (CNode* pnode : nodes) {
if (interruptNet)
return;
@@ -1694,6 +1698,8 @@ void CConnman::SocketHandlerListening(const std::set<SOCKET>& recv_set)
void CConnman::ThreadSocketHandler()
{
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET);
while (!interruptNet)
{
@@ -2001,7 +2007,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
case ConnectionType::BLOCK_RELAY:
case ConnectionType::ADDR_FETCH:
case ConnectionType::FEELER:
- setConnected.insert(pnode->addr.GetGroup(addrman.GetAsmap()));
+ setConnected.insert(m_netgroupman.GetGroup(pnode->addr));
} // no default case, so the compiler can warn about missing cases
}
}
@@ -2075,7 +2081,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
m_anchors.pop_back();
if (!addr.IsValid() || IsLocal(addr) || !IsReachable(addr) ||
!HasAllDesirableServiceFlags(addr.nServices) ||
- setConnected.count(addr.GetGroup(addrman.GetAsmap()))) continue;
+ setConnected.count(m_netgroupman.GetGroup(addr))) continue;
addrConnect = addr;
LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToString());
break;
@@ -2116,7 +2122,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
}
// Require outbound connections, other than feelers, to be to distinct network groups
- if (!fFeeler && setConnected.count(addr.GetGroup(addrman.GetAsmap()))) {
+ if (!fFeeler && setConnected.count(m_netgroupman.GetGroup(addr))) {
break;
}
@@ -2512,8 +2518,12 @@ void CConnman::SetNetworkActive(bool active)
}
}
-CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in, bool network_active)
- : addrman(addrman_in), nSeed0(nSeed0In), nSeed1(nSeed1In)
+CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in,
+ const NetGroupManager& netgroupman, bool network_active)
+ : addrman(addrman_in)
+ , m_netgroupman{netgroupman}
+ , nSeed0(nSeed0In)
+ , nSeed1(nSeed1In)
{
SetTryNewOutboundPeer(false);
@@ -2574,6 +2584,7 @@ bool CConnman::InitBinds(const Options& options)
bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
{
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
Init(connOptions);
if (fListen && !InitBinds(connOptions)) {
@@ -2872,7 +2883,7 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
for (CNode* pnode : m_nodes) {
vstats.emplace_back();
pnode->CopyStats(vstats.back());
- vstats.back().m_mapped_as = pnode->addr.GetMappedAS(addrman.GetAsmap());
+ vstats.back().m_mapped_as = m_netgroupman.GetMappedAS(pnode->addr);
}
}
@@ -2926,7 +2937,9 @@ void CConnman::RecordBytesRecv(uint64_t bytes)
void CConnman::RecordBytesSent(uint64_t bytes)
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
+
nTotalBytesSent += bytes;
const auto now = GetTime<std::chrono::seconds>();
@@ -2942,7 +2955,8 @@ void CConnman::RecordBytesSent(uint64_t bytes)
uint64_t CConnman::GetMaxOutboundTarget() const
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
return nMaxOutboundLimit;
}
@@ -2953,7 +2967,15 @@ std::chrono::seconds CConnman::GetMaxOutboundTimeframe() const
std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() const
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
+ return GetMaxOutboundTimeLeftInCycle_();
+}
+
+std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle_() const
+{
+ AssertLockHeld(m_total_bytes_sent_mutex);
+
if (nMaxOutboundLimit == 0)
return 0s;
@@ -2967,14 +2989,15 @@ std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() const
bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) const
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
if (nMaxOutboundLimit == 0)
return false;
if (historicalBlockServingLimit)
{
// keep a large enough buffer to at least relay each block once
- const std::chrono::seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle();
+ const std::chrono::seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle_();
const uint64_t buffer = timeLeftInCycle / std::chrono::minutes{10} * MAX_BLOCK_SERIALIZED_SIZE;
if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer)
return true;
@@ -2987,7 +3010,8 @@ bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) const
uint64_t CConnman::GetOutboundTargetBytesLeft() const
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
if (nMaxOutboundLimit == 0)
return 0;
@@ -3001,7 +3025,8 @@ uint64_t CConnman::GetTotalBytesRecv() const
uint64_t CConnman::GetTotalBytesSent() const
{
- LOCK(cs_totalBytesSent);
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+ LOCK(m_total_bytes_sent_mutex);
return nTotalBytesSent;
}
@@ -3048,6 +3073,7 @@ bool CConnman::NodeFullyConnected(const CNode* pnode)
void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
{
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
size_t nMessageSize = msg.data.size();
LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", msg.m_type, nMessageSize, pnode->GetId());
if (gArgs.GetBoolArg("-capturemessages", false)) {
@@ -3105,9 +3131,9 @@ CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const
return CSipHasher(nSeed0, nSeed1).Write(id);
}
-uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad) const
+uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& address) const
{
- std::vector<unsigned char> vchNetGroup(ad.GetGroup(addrman.GetAsmap()));
+ std::vector<unsigned char> vchNetGroup(m_netgroupman.GetGroup(address));
return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(vchNetGroup.data(), vchNetGroup.size()).Finalize();
}
diff --git a/src/net.h b/src/net.h
index 1bc011c748..3271930a35 100644
--- a/src/net.h
+++ b/src/net.h
@@ -17,6 +17,7 @@
#include <net_permissions.h>
#include <netaddress.h>
#include <netbase.h>
+#include <netgroup.h>
#include <policy/feerate.h>
#include <protocol.h>
#include <random.h>
@@ -760,7 +761,10 @@ public:
bool m_i2p_accept_incoming;
};
- void Init(const Options& connOptions) {
+ void Init(const Options& connOptions) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex)
+ {
+ AssertLockNotHeld(m_total_bytes_sent_mutex);
+
nLocalServices = connOptions.nLocalServices;
nMaxConnections = connOptions.nMaxConnections;
m_max_outbound_full_relay = std::min(connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections);
@@ -776,7 +780,7 @@ public:
nReceiveFloodSize = connOptions.nReceiveFloodSize;
m_peer_connect_timeout = std::chrono::seconds{connOptions.m_peer_connect_timeout};
{
- LOCK(cs_totalBytesSent);
+ LOCK(m_total_bytes_sent_mutex);
nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
}
vWhitelistedRange = connOptions.vWhitelistedRange;
@@ -787,9 +791,11 @@ public:
m_onion_binds = connOptions.onion_binds;
}
- CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, bool network_active = true);
+ CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, const NetGroupManager& netgroupman,
+ bool network_active = true);
+
~CConnman();
- bool Start(CScheduler& scheduler, const Options& options);
+ bool Start(CScheduler& scheduler, const Options& options) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
void StopThreads();
void StopNodes();
@@ -808,7 +814,7 @@ public:
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
- void PushMessage(CNode* pnode, CSerializedNetMsg&& msg);
+ void PushMessage(CNode* pnode, CSerializedNetMsg&& msg) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
using NodeFn = std::function<void(CNode*)>;
void ForEachNode(const NodeFn& func)
@@ -899,24 +905,22 @@ public:
//! that peer during `net_processing.cpp:PushNodeVersion()`.
ServiceFlags GetLocalServices() const;
- uint64_t GetMaxOutboundTarget() const;
+ uint64_t GetMaxOutboundTarget() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
std::chrono::seconds GetMaxOutboundTimeframe() const;
//! check if the outbound target is reached
//! if param historicalBlockServingLimit is set true, the function will
//! response true if the limit for serving historical blocks has been reached
- bool OutboundTargetReached(bool historicalBlockServingLimit) const;
+ bool OutboundTargetReached(bool historicalBlockServingLimit) const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
//! response the bytes left in the current max outbound cycle
//! in case of no limit, it will always response 0
- uint64_t GetOutboundTargetBytesLeft() const;
+ uint64_t GetOutboundTargetBytesLeft() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
- //! returns the time left in the current max outbound cycle
- //! in case of no limit, it will always return 0
- std::chrono::seconds GetMaxOutboundTimeLeftInCycle() const;
+ std::chrono::seconds GetMaxOutboundTimeLeftInCycle() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
uint64_t GetTotalBytesRecv() const;
- uint64_t GetTotalBytesSent() const;
+ uint64_t GetTotalBytesSent() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
/** Get a unique deterministic randomizer. */
CSipHasher GetDeterministicRandomizer(uint64_t id) const;
@@ -942,6 +946,10 @@ private:
NetPermissionFlags m_permissions;
};
+ //! returns the time left in the current max outbound cycle
+ //! in case of no limit, it will always return 0
+ std::chrono::seconds GetMaxOutboundTimeLeftInCycle_() const EXCLUSIVE_LOCKS_REQUIRED(m_total_bytes_sent_mutex);
+
bool BindListenPort(const CService& bindAddr, bilingual_str& strError, NetPermissionFlags permissions);
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
bool InitBinds(const Options& options);
@@ -1001,7 +1009,7 @@ private:
/**
* Check connected and listening sockets for IO readiness and process them accordingly.
*/
- void SocketHandler();
+ void SocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
/**
* Do the read/write for connected sockets that are ready for IO.
@@ -1014,7 +1022,8 @@ private:
void SocketHandlerConnected(const std::vector<CNode*>& nodes,
const std::set<SOCKET>& recv_set,
const std::set<SOCKET>& send_set,
- const std::set<SOCKET>& error_set);
+ const std::set<SOCKET>& error_set)
+ EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
/**
* Accept incoming connections, one from each read-ready listening socket.
@@ -1022,7 +1031,7 @@ private:
*/
void SocketHandlerListening(const std::set<SOCKET>& recv_set);
- void ThreadSocketHandler();
+ void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
void ThreadDNSAddressSeed();
uint64_t CalculateKeyedNetGroup(const CAddress& ad) const;
@@ -1051,7 +1060,7 @@ private:
// Network stats
void RecordBytesRecv(uint64_t bytes);
- void RecordBytesSent(uint64_t bytes);
+ void RecordBytesSent(uint64_t bytes) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
/**
* Return vector of current BLOCK_RELAY peers.
@@ -1062,14 +1071,14 @@ private:
static bool NodeFullyConnected(const CNode* pnode);
// Network usage totals
- mutable RecursiveMutex cs_totalBytesSent;
+ mutable Mutex m_total_bytes_sent_mutex;
std::atomic<uint64_t> nTotalBytesRecv{0};
- uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0};
+ uint64_t nTotalBytesSent GUARDED_BY(m_total_bytes_sent_mutex) {0};
// outbound limit & stats
- uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(cs_totalBytesSent) {0};
- std::chrono::seconds nMaxOutboundCycleStartTime GUARDED_BY(cs_totalBytesSent) {0};
- uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent);
+ uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(m_total_bytes_sent_mutex) {0};
+ std::chrono::seconds nMaxOutboundCycleStartTime GUARDED_BY(m_total_bytes_sent_mutex) {0};
+ uint64_t nMaxOutboundLimit GUARDED_BY(m_total_bytes_sent_mutex);
// P2P timeout in seconds
std::chrono::seconds m_peer_connect_timeout;
@@ -1085,6 +1094,7 @@ private:
std::atomic<bool> fNetworkActive{true};
bool fAddressesInitialized{false};
AddrMan& addrman;
+ const NetGroupManager& m_netgroupman;
std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
Mutex m_addr_fetches_mutex;
std::vector<std::string> m_added_nodes GUARDED_BY(m_added_nodes_mutex);
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 02eb3762b1..46b4d2e3df 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -4472,7 +4472,7 @@ void PeerManagerImpl::MaybeSendPing(CNode& node_to, Peer& peer, std::chrono::mic
if (pingSend) {
uint64_t nonce = 0;
while (nonce == 0) {
- GetRandBytes((unsigned char*)&nonce, sizeof(nonce));
+ GetRandBytes({(unsigned char*)&nonce, sizeof(nonce)});
}
peer.m_ping_queued = false;
peer.m_ping_start = now;
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index f7640329f8..bc1915aad9 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -10,7 +10,6 @@
#include <hash.h>
#include <prevector.h>
#include <tinyformat.h>
-#include <util/asmap.h>
#include <util/strencodings.h>
#include <util/string.h>
@@ -722,107 +721,6 @@ Network CNetAddr::GetNetClass() const
return m_net;
}
-uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
- uint32_t net_class = GetNetClass();
- if (asmap.size() == 0 || (net_class != NET_IPV4 && net_class != NET_IPV6)) {
- return 0; // Indicates not found, safe because AS0 is reserved per RFC7607.
- }
- std::vector<bool> ip_bits(128);
- if (HasLinkedIPv4()) {
- // For lookup, treat as if it was just an IPv4 address (IPV4_IN_IPV6_PREFIX + IPv4 bits)
- for (int8_t byte_i = 0; byte_i < 12; ++byte_i) {
- for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
- ip_bits[byte_i * 8 + bit_i] = (IPV4_IN_IPV6_PREFIX[byte_i] >> (7 - bit_i)) & 1;
- }
- }
- uint32_t ipv4 = GetLinkedIPv4();
- for (int i = 0; i < 32; ++i) {
- ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1;
- }
- } else {
- // Use all 128 bits of the IPv6 address otherwise
- assert(IsIPv6());
- for (int8_t byte_i = 0; byte_i < 16; ++byte_i) {
- uint8_t cur_byte = m_addr[byte_i];
- for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
- ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1;
- }
- }
- }
- uint32_t mapped_as = Interpret(asmap, ip_bits);
- return mapped_as;
-}
-
-/**
- * Get the canonical identifier of our network group
- *
- * The groups are assigned in a way where it should be costly for an attacker to
- * obtain addresses with many different group identifiers, even if it is cheap
- * to obtain addresses with the same identifier.
- *
- * @note No two connections will be attempted to addresses with the same network
- * group.
- */
-std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) const
-{
- std::vector<unsigned char> vchRet;
- uint32_t net_class = GetNetClass();
- // If non-empty asmap is supplied and the address is IPv4/IPv6,
- // return ASN to be used for bucketing.
- uint32_t asn = GetMappedAS(asmap);
- if (asn != 0) { // Either asmap was empty, or address has non-asmappable net class (e.g. TOR).
- vchRet.push_back(NET_IPV6); // IPv4 and IPv6 with same ASN should be in the same bucket
- for (int i = 0; i < 4; i++) {
- vchRet.push_back((asn >> (8 * i)) & 0xFF);
- }
- return vchRet;
- }
-
- vchRet.push_back(net_class);
- int nBits{0};
-
- if (IsLocal()) {
- // all local addresses belong to the same group
- } else if (IsInternal()) {
- // all internal-usage addresses get their own group
- nBits = ADDR_INTERNAL_SIZE * 8;
- } else if (!IsRoutable()) {
- // all other unroutable addresses belong to the same group
- } else if (HasLinkedIPv4()) {
- // IPv4 addresses (and mapped IPv4 addresses) use /16 groups
- uint32_t ipv4 = GetLinkedIPv4();
- vchRet.push_back((ipv4 >> 24) & 0xFF);
- vchRet.push_back((ipv4 >> 16) & 0xFF);
- return vchRet;
- } else if (IsTor() || IsI2P()) {
- nBits = 4;
- } else if (IsCJDNS()) {
- // Treat in the same way as Tor and I2P because the address in all of
- // them is "random" bytes (derived from a public key). However in CJDNS
- // the first byte is a constant 0xfc, so the random bytes come after it.
- // Thus skip the constant 8 bits at the start.
- nBits = 12;
- } else if (IsHeNet()) {
- // for he.net, use /36 groups
- nBits = 36;
- } else {
- // for the rest of the IPv6 network, use /32 groups
- nBits = 32;
- }
-
- // Push our address onto vchRet.
- const size_t num_bytes = nBits / 8;
- vchRet.insert(vchRet.end(), m_addr.begin(), m_addr.begin() + num_bytes);
- nBits %= 8;
- // ...for the last byte, push nBits and for the rest of the byte push 1's
- if (nBits > 0) {
- assert(num_bytes < m_addr.size());
- vchRet.push_back(m_addr[num_bytes] | ((1 << (8 - nBits)) - 1));
- }
-
- return vchRet;
-}
-
std::vector<unsigned char> CNetAddr::GetAddrBytes() const
{
if (IsAddrV1Compatible()) {
diff --git a/src/netaddress.h b/src/netaddress.h
index 6d21dcd5cd..b9a8dc589a 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -202,12 +202,6 @@ public:
//! Whether this address has a linked IPv4 address (see GetLinkedIPv4()).
bool HasLinkedIPv4() const;
- // The AS on the BGP path to the node we use to diversify
- // peers in AddrMan bucketing based on the AS infrastructure.
- // The ip->AS mapping depends on how asmap is constructed.
- uint32_t GetMappedAS(const std::vector<bool>& asmap) const;
-
- std::vector<unsigned char> GetGroup(const std::vector<bool>& asmap) const;
std::vector<unsigned char> GetAddrBytes() const;
int GetReachabilityFrom(const CNetAddr* paddrPartner = nullptr) const;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 9557297df1..ce23f7e4ad 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -675,7 +675,7 @@ bool ConnectThroughProxy(const Proxy& proxy, const std::string& strDest, uint16_
return false;
}
} else {
- if (!Socks5(strDest, port, 0, sock)) {
+ if (!Socks5(strDest, port, nullptr, sock)) {
return false;
}
}
diff --git a/src/netgroup.cpp b/src/netgroup.cpp
new file mode 100644
index 0000000000..5f42d6c719
--- /dev/null
+++ b/src/netgroup.cpp
@@ -0,0 +1,111 @@
+// 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 <netgroup.h>
+
+#include <hash.h>
+#include <util/asmap.h>
+
+uint256 NetGroupManager::GetAsmapChecksum() const
+{
+ if (!m_asmap.size()) return {};
+
+ return SerializeHash(m_asmap);
+}
+
+std::vector<unsigned char> NetGroupManager::GetGroup(const CNetAddr& address) const
+{
+ std::vector<unsigned char> vchRet;
+ // If non-empty asmap is supplied and the address is IPv4/IPv6,
+ // return ASN to be used for bucketing.
+ uint32_t asn = GetMappedAS(address);
+ if (asn != 0) { // Either asmap was empty, or address has non-asmappable net class (e.g. TOR).
+ vchRet.push_back(NET_IPV6); // IPv4 and IPv6 with same ASN should be in the same bucket
+ for (int i = 0; i < 4; i++) {
+ vchRet.push_back((asn >> (8 * i)) & 0xFF);
+ }
+ return vchRet;
+ }
+
+ vchRet.push_back(address.GetNetClass());
+ int nStartByte{0};
+ int nBits{0};
+
+ if (address.IsLocal()) {
+ // all local addresses belong to the same group
+ } else if (address.IsInternal()) {
+ // All internal-usage addresses get their own group.
+ // Skip over the INTERNAL_IN_IPV6_PREFIX returned by CAddress::GetAddrBytes().
+ nStartByte = INTERNAL_IN_IPV6_PREFIX.size();
+ nBits = ADDR_INTERNAL_SIZE * 8;
+ } else if (!address.IsRoutable()) {
+ // all other unroutable addresses belong to the same group
+ } else if (address.HasLinkedIPv4()) {
+ // IPv4 addresses (and mapped IPv4 addresses) use /16 groups
+ uint32_t ipv4 = address.GetLinkedIPv4();
+ vchRet.push_back((ipv4 >> 24) & 0xFF);
+ vchRet.push_back((ipv4 >> 16) & 0xFF);
+ return vchRet;
+ } else if (address.IsTor() || address.IsI2P()) {
+ nBits = 4;
+ } else if (address.IsCJDNS()) {
+ // Treat in the same way as Tor and I2P because the address in all of
+ // them is "random" bytes (derived from a public key). However in CJDNS
+ // the first byte is a constant 0xfc, so the random bytes come after it.
+ // Thus skip the constant 8 bits at the start.
+ nBits = 12;
+ } else if (address.IsHeNet()) {
+ // for he.net, use /36 groups
+ nBits = 36;
+ } else {
+ // for the rest of the IPv6 network, use /32 groups
+ nBits = 32;
+ }
+
+ // Push our address onto vchRet.
+ auto addr_bytes = address.GetAddrBytes();
+ const size_t num_bytes = nBits / 8;
+ vchRet.insert(vchRet.end(), addr_bytes.begin() + nStartByte, addr_bytes.begin() + nStartByte + num_bytes);
+ nBits %= 8;
+ // ...for the last byte, push nBits and for the rest of the byte push 1's
+ if (nBits > 0) {
+ assert(num_bytes < addr_bytes.size());
+ vchRet.push_back(addr_bytes[num_bytes] | ((1 << (8 - nBits)) - 1));
+ }
+
+ return vchRet;
+}
+
+uint32_t NetGroupManager::GetMappedAS(const CNetAddr& address) const
+{
+ uint32_t net_class = address.GetNetClass();
+ if (m_asmap.size() == 0 || (net_class != NET_IPV4 && net_class != NET_IPV6)) {
+ return 0; // Indicates not found, safe because AS0 is reserved per RFC7607.
+ }
+ std::vector<bool> ip_bits(128);
+ if (address.HasLinkedIPv4()) {
+ // For lookup, treat as if it was just an IPv4 address (IPV4_IN_IPV6_PREFIX + IPv4 bits)
+ for (int8_t byte_i = 0; byte_i < 12; ++byte_i) {
+ for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
+ ip_bits[byte_i * 8 + bit_i] = (IPV4_IN_IPV6_PREFIX[byte_i] >> (7 - bit_i)) & 1;
+ }
+ }
+ uint32_t ipv4 = address.GetLinkedIPv4();
+ for (int i = 0; i < 32; ++i) {
+ ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1;
+ }
+ } else {
+ // Use all 128 bits of the IPv6 address otherwise
+ assert(address.IsIPv6());
+ auto addr_bytes = address.GetAddrBytes();
+ for (int8_t byte_i = 0; byte_i < 16; ++byte_i) {
+ uint8_t cur_byte = addr_bytes[byte_i];
+ for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
+ ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1;
+ }
+ }
+ }
+ uint32_t mapped_as = Interpret(m_asmap, ip_bits);
+ return mapped_as;
+}
diff --git a/src/netgroup.h b/src/netgroup.h
new file mode 100644
index 0000000000..2dd63ec66b
--- /dev/null
+++ b/src/netgroup.h
@@ -0,0 +1,66 @@
+// 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.
+
+#ifndef BITCOIN_NETGROUP_H
+#define BITCOIN_NETGROUP_H
+
+#include <netaddress.h>
+#include <uint256.h>
+
+#include <vector>
+
+/**
+ * Netgroup manager
+ */
+class NetGroupManager {
+public:
+ explicit NetGroupManager(std::vector<bool> asmap)
+ : m_asmap{std::move(asmap)}
+ {}
+
+ /** Get a checksum identifying the asmap being used. */
+ uint256 GetAsmapChecksum() const;
+
+ /**
+ * Get the canonical identifier of the network group for address.
+ *
+ * The groups are assigned in a way where it should be costly for an attacker to
+ * obtain addresses with many different group identifiers, even if it is cheap
+ * to obtain addresses with the same identifier.
+ *
+ * @note No two connections will be attempted to addresses with the same network
+ * group.
+ */
+ std::vector<unsigned char> GetGroup(const CNetAddr& address) const;
+
+ /**
+ * Get the autonomous system on the BGP path to address.
+ *
+ * The ip->AS mapping depends on how asmap is constructed.
+ */
+ uint32_t GetMappedAS(const CNetAddr& address) const;
+
+private:
+ /** Compressed IP->ASN mapping, loaded from a file when a node starts.
+ *
+ * This mapping is then used for bucketing nodes in Addrman and for
+ * ensuring we connect to a diverse set of peers in Connman. The map is
+ * empty if no file was provided.
+ *
+ * If asmap is provided, nodes will be bucketed by AS they belong to, in
+ * order to make impossible for a node to connect to several nodes hosted
+ * in a single AS. This is done in response to Erebus attack, but also to
+ * generally diversify the connections every node creates, especially
+ * useful when a large fraction of nodes operate under a couple of cloud
+ * providers.
+ *
+ * If a new asmap is provided, the existing addrman records are
+ * re-bucketed.
+ *
+ * This is initialized in the constructor, const, and therefore is
+ * thread-safe. */
+ const std::vector<bool> m_asmap;
+};
+
+#endif // BITCOIN_NETGROUP_H
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 21cb0250d8..8ed22bbbce 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -21,6 +21,8 @@
#include <util/system.h>
#include <validation.h>
+#include <unordered_map>
+
namespace node {
std::atomic_bool fImporting(false);
std::atomic_bool fReindex(false);
@@ -230,6 +232,11 @@ void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPr
nLastBlockWeCanPrune, count);
}
+void BlockManager::UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) {
+ AssertLockHeld(::cs_main);
+ m_prune_locks[name] = lock_info;
+}
+
CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
{
AssertLockHeld(cs_main);
@@ -397,6 +404,16 @@ bool BlockManager::IsBlockPruned(const CBlockIndex* pblockindex)
return (m_have_pruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
}
+const CBlockIndex* GetFirstStoredBlock(const CBlockIndex* start_block) {
+ AssertLockHeld(::cs_main);
+ assert(start_block);
+ const CBlockIndex* last_block = start_block;
+ while (last_block->pprev && (last_block->pprev->nStatus & BLOCK_HAVE_DATA)) {
+ last_block = last_block->pprev;
+ }
+ return last_block;
+}
+
// If we're using -prune with -reindex, then delete block files that will be ignored by the
// reindex. Since reindexing works by starting at block file 0 and looping until a blockfile
// is missing, do the same here to delete any later block files after a gap. Also delete all
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index 11445aa22e..e4b9657372 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -13,6 +13,7 @@
#include <atomic>
#include <cstdint>
+#include <unordered_map>
#include <vector>
extern RecursiveMutex cs_main;
@@ -65,6 +66,10 @@ struct CBlockIndexHeightOnlyComparator {
bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const;
};
+struct PruneLockInfo {
+ int height_first{std::numeric_limits<int>::max()}; //! Height of earliest block that should be kept and not pruned
+};
+
/**
* Maintains a tree of blocks (stored in `m_block_index`) which is consulted
* to determine where the most-work tip is.
@@ -78,6 +83,13 @@ class BlockManager
friend ChainstateManager;
private:
+ /**
+ * Load the blocktree off disk and into memory. Populate certain metadata
+ * per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral
+ * collections like m_dirty_blockindex.
+ */
+ bool LoadBlockIndex(const Consensus::Params& consensus_params)
+ EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false);
void FlushUndoFile(int block_file, bool finalize = false);
bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown);
@@ -118,6 +130,14 @@ private:
/** Dirty block file entries. */
std::set<int> m_dirty_fileinfo;
+ /**
+ * Map from external index name to oldest block that must not be pruned.
+ *
+ * @note Internally, only blocks at height (height_first - PRUNE_LOCK_BUFFER - 1) and
+ * below will be pruned, but callers should avoid assuming any particular buffer size.
+ */
+ std::unordered_map<std::string, PruneLockInfo> m_prune_locks GUARDED_BY(::cs_main);
+
public:
BlockMap m_block_index GUARDED_BY(cs_main);
@@ -134,14 +154,6 @@ public:
bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
bool LoadBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
- /**
- * Load the blocktree off disk and into memory. Populate certain metadata
- * per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral
- * collections like m_dirty_blockindex.
- */
- bool LoadBlockIndex(const Consensus::Params& consensus_params)
- EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
/** Clear all data members. */
void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -175,12 +187,18 @@ public:
//! Check whether the block associated with this index entry is pruned or not.
bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ //! Create or update a prune lock identified by its name
+ void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
~BlockManager()
{
Unload();
}
};
+//! Find the first block that is not pruned
+const CBlockIndex* GetFirstStoredBlock(const CBlockIndex* start_block) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
void CleanupBlockRevFiles();
/** Open a block file (blk?????.dat) */
diff --git a/src/node/context.cpp b/src/node/context.cpp
index 893c32f1bc..0b31c10f44 100644
--- a/src/node/context.cpp
+++ b/src/node/context.cpp
@@ -9,6 +9,7 @@
#include <interfaces/chain.h>
#include <net.h>
#include <net_processing.h>
+#include <netgroup.h>
#include <policy/fees.h>
#include <scheduler.h>
#include <txmempool.h>
diff --git a/src/node/context.h b/src/node/context.h
index 644c997531..91ba456219 100644
--- a/src/node/context.h
+++ b/src/node/context.h
@@ -18,6 +18,7 @@ class CConnman;
class CScheduler;
class CTxMemPool;
class ChainstateManager;
+class NetGroupManager;
class PeerManager;
namespace interfaces {
class Chain;
@@ -43,6 +44,7 @@ struct NodeContext {
std::unique_ptr<AddrMan> addrman;
std::unique_ptr<CConnman> connman;
std::unique_ptr<CTxMemPool> mempool;
+ std::unique_ptr<const NetGroupManager> netgroupman;
std::unique_ptr<CBlockPolicyEstimator> fee_estimator;
std::unique_ptr<PeerManager> peerman;
std::unique_ptr<ChainstateManager> chainman;
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 76e5207d81..e38ac6026a 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -361,18 +361,6 @@ namespace GUIUtil
#endif
}
- /**
- * Queue a function to run in an object's event loop. This can be
- * replaced by a call to the QMetaObject::invokeMethod functor overload after Qt 5.10, but
- * for now use a QObject::connect for compatibility with older Qt versions, based on
- * https://stackoverflow.com/questions/21646467/how-to-execute-a-functor-or-a-lambda-in-a-given-thread-in-qt-gcd-style
- */
- template <typename Fn>
- void ObjectInvoke(QObject* object, Fn&& function, Qt::ConnectionType connection = Qt::QueuedConnection)
- {
- QObject source;
- QObject::connect(&source, &QObject::destroyed, object, std::forward<Fn>(function), connection);
- }
/**
* Replaces a plain text link with an HTML tagged one.
diff --git a/src/qt/initexecutor.cpp b/src/qt/initexecutor.cpp
index 24ae7ba73d..d269dfec71 100644
--- a/src/qt/initexecutor.cpp
+++ b/src/qt/initexecutor.cpp
@@ -5,13 +5,13 @@
#include <qt/initexecutor.h>
#include <interfaces/node.h>
-#include <qt/guiutil.h>
#include <util/system.h>
#include <util/threadnames.h>
#include <exception>
#include <QDebug>
+#include <QMetaObject>
#include <QObject>
#include <QString>
#include <QThread>
@@ -39,7 +39,7 @@ void InitExecutor::handleRunawayException(const std::exception* e)
void InitExecutor::initialize()
{
- GUIUtil::ObjectInvoke(&m_context, [this] {
+ QMetaObject::invokeMethod(&m_context, [this] {
try {
util::ThreadRename("qt-init");
qDebug() << "Running initialization in thread";
@@ -56,7 +56,7 @@ void InitExecutor::initialize()
void InitExecutor::shutdown()
{
- GUIUtil::ObjectInvoke(&m_context, [this] {
+ QMetaObject::invokeMethod(&m_context, [this] {
try {
qDebug() << "Running Shutdown in thread";
m_node.appShutdown();
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 63b4055092..f4928951fe 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -226,7 +226,7 @@ bool Intro::showIfNeeded(bool& did_show_intro, int64_t& prune_MiB)
}
/* If current default data directory does not exist, let the user choose one */
- Intro intro(0, Params().AssumedBlockchainSize(), Params().AssumedChainStateSize());
+ Intro intro(nullptr, Params().AssumedBlockchainSize(), Params().AssumedChainStateSize());
intro.setDataDirectory(dataDir);
intro.setWindowIcon(QIcon(":icons/bitcoin"));
did_show_intro = true;
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index b025bb367c..d27ddf1aba 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -24,6 +24,7 @@
#include <QApplication>
#include <QMessageBox>
+#include <QMetaObject>
#include <QMutexLocker>
#include <QThread>
#include <QTimer>
@@ -135,7 +136,7 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
// handled on the GUI event loop.
wallet_model->moveToThread(thread());
// setParent(parent) must be called in the thread which created the parent object. More details in #18948.
- GUIUtil::ObjectInvoke(this, [wallet_model, this] {
+ QMetaObject::invokeMethod(this, [wallet_model, this] {
wallet_model->setParent(this);
}, GUIUtil::blockingGUIThreadConnection());
diff --git a/src/random.cpp b/src/random.cpp
index 77d2ae4d43..6ae08103b1 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -16,6 +16,7 @@
#include <logging.h>
#include <randomenv.h>
#include <support/allocators/secure.h>
+#include <span.h>
#include <sync.h> // for Mutex
#include <util/time.h> // for GetTimeMicros()
@@ -578,8 +579,8 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level) noexcept
}
}
-void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::FAST); }
-void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); }
+void GetRandBytes(Span<unsigned char> bytes) noexcept { ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST); }
+void GetStrongRandBytes(Span<unsigned char> bytes) noexcept { ProcRand(bytes.data(), bytes.size(), RNGLevel::SLOW); }
void RandAddPeriodic() noexcept { ProcRand(nullptr, 0, RNGLevel::PERIODIC); }
void RandAddEvent(const uint32_t event_info) noexcept { GetRNGState().AddEvent(event_info); }
@@ -598,7 +599,7 @@ int GetRandInt(int nMax) noexcept
uint256 GetRandHash() noexcept
{
uint256 hash;
- GetRandBytes((unsigned char*)&hash, sizeof(hash));
+ GetRandBytes(hash);
return hash;
}
diff --git a/src/random.h b/src/random.h
index 97302d61ab..285158b1c3 100644
--- a/src/random.h
+++ b/src/random.h
@@ -8,6 +8,7 @@
#include <crypto/chacha20.h>
#include <crypto/common.h>
+#include <span.h>
#include <uint256.h>
#include <chrono>
@@ -66,7 +67,7 @@
*
* Thread-safe.
*/
-void GetRandBytes(unsigned char* buf, int num) noexcept;
+void GetRandBytes(Span<unsigned char> bytes) noexcept;
/** Generate a uniform random integer in the range [0..range). Precondition: range > 0 */
uint64_t GetRand(uint64_t nMax) noexcept;
/** Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */
@@ -105,7 +106,7 @@ uint256 GetRandHash() noexcept;
*
* Thread-safe.
*/
-void GetStrongRandBytes(unsigned char* buf, int num) noexcept;
+void GetStrongRandBytes(Span<unsigned char> bytes) noexcept;
/**
* Gather entropy from various expensive sources, and feed them to the PRNG state.
diff --git a/src/randomenv.cpp b/src/randomenv.cpp
index 388841289a..53ebeb31cd 100644
--- a/src/randomenv.cpp
+++ b/src/randomenv.cpp
@@ -363,10 +363,10 @@ void RandAddStaticEnv(CSHA512& hasher)
#if HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS
// Network interfaces
- struct ifaddrs *ifad = NULL;
+ struct ifaddrs *ifad = nullptr;
getifaddrs(&ifad);
struct ifaddrs *ifit = ifad;
- while (ifit != NULL) {
+ while (ifit != nullptr) {
hasher.Write((const unsigned char*)&ifit, sizeof(ifit));
hasher.Write((const unsigned char*)ifit->ifa_name, strlen(ifit->ifa_name) + 1);
hasher.Write((const unsigned char*)&ifit->ifa_flags, sizeof(ifit->ifa_flags));
diff --git a/src/rest.cpp b/src/rest.cpp
index 2aeb9c68c3..22b5d2e074 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -32,8 +32,6 @@
#include <any>
#include <string>
-#include <boost/algorithm/string.hpp>
-
#include <univalue.h>
using node::GetTransaction;
@@ -191,8 +189,7 @@ static bool rest_headers(const std::any& context,
return false;
std::string param;
const RESTResponseFormat rf = ParseDataFormat(param, strURIPart);
- std::vector<std::string> path;
- boost::split(path, param, boost::is_any_of("/"));
+ std::vector<std::string> path = SplitString(param, '/');
std::string raw_count;
std::string hashStr;
@@ -362,8 +359,7 @@ static bool rest_filter_header(const std::any& context, HTTPRequest* req, const
std::string param;
const RESTResponseFormat rf = ParseDataFormat(param, strURIPart);
- std::vector<std::string> uri_parts;
- boost::split(uri_parts, param, boost::is_any_of("/"));
+ std::vector<std::string> uri_parts = SplitString(param, '/');
std::string raw_count;
std::string raw_blockhash;
if (uri_parts.size() == 3) {
@@ -483,8 +479,7 @@ static bool rest_block_filter(const std::any& context, HTTPRequest* req, const s
const RESTResponseFormat rf = ParseDataFormat(param, strURIPart);
// request is sent over URI scheme /rest/blockfilter/filtertype/blockhash
- std::vector<std::string> uri_parts;
- boost::split(uri_parts, param, boost::is_any_of("/"));
+ std::vector<std::string> uri_parts = SplitString(param, '/');
if (uri_parts.size() != 2) {
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>");
}
@@ -712,7 +707,7 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std::
if (param.length() > 1)
{
std::string strUriParams = param.substr(1);
- boost::split(uriParts, strUriParams, boost::is_any_of("/"));
+ uriParts = SplitString(strUriParams, '/');
}
// throw exception in case of an empty request
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index f46e5e9fef..398b948388 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -37,6 +37,7 @@
#include <txmempool.h>
#include <undo.h>
#include <univalue.h>
+#include <util/check.h>
#include <util/strencodings.h>
#include <util/translation.h>
#include <validation.h>
@@ -785,12 +786,10 @@ static RPCHelpMan pruneblockchain()
}
PruneBlockFilesManual(active_chainstate, height);
- const CBlockIndex* block = active_chain.Tip();
- CHECK_NONFATAL(block);
- while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
- block = block->pprev;
- }
- return uint64_t(block->nHeight);
+ const CBlockIndex* block = CHECK_NONFATAL(active_chain.Tip());
+ const CBlockIndex* last_block = node::GetFirstStoredBlock(block);
+
+ return static_cast<uint64_t>(last_block->nHeight);
},
};
}
@@ -1200,8 +1199,7 @@ RPCHelpMan getblockchaininfo()
LOCK(cs_main);
CChainState& active_chainstate = chainman.ActiveChainstate();
- const CBlockIndex* tip = active_chainstate.m_chain.Tip();
- CHECK_NONFATAL(tip);
+ const CBlockIndex* tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
const int height = tip->nHeight;
UniValue obj(UniValue::VOBJ);
obj.pushKV("chain", Params().NetworkIDString());
@@ -1217,13 +1215,8 @@ RPCHelpMan getblockchaininfo()
obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
obj.pushKV("pruned", node::fPruneMode);
if (node::fPruneMode) {
- const CBlockIndex* block = tip;
- CHECK_NONFATAL(block);
- while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
- block = block->pprev;
- }
-
- obj.pushKV("pruneheight", block->nHeight);
+ const CBlockIndex* block = CHECK_NONFATAL(tip);
+ obj.pushKV("pruneheight", node::GetFirstStoredBlock(block)->nHeight);
// if 0, execution bypasses the whole if block.
bool automatic_pruning{args.GetIntArg("-prune", 0) != 1};
@@ -1309,8 +1302,7 @@ static RPCHelpMan getdeploymentinfo()
const CBlockIndex* blockindex;
if (request.params[0].isNull()) {
- blockindex = active_chainstate.m_chain.Tip();
- CHECK_NONFATAL(blockindex);
+ blockindex = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
} else {
const uint256 hash(ParseHashV(request.params[0], "blockhash"));
blockindex = chainman.m_blockman.LookupBlockIndex(hash);
@@ -2131,10 +2123,8 @@ static RPCHelpMan scantxoutset()
LOCK(cs_main);
CChainState& active_chainstate = chainman.ActiveChainstate();
active_chainstate.ForceFlushStateToDisk();
- pcursor = active_chainstate.CoinsDB().Cursor();
- CHECK_NONFATAL(pcursor);
- tip = active_chainstate.m_chain.Tip();
- CHECK_NONFATAL(tip);
+ pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
+ tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
}
bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
result.pushKV("success", res);
@@ -2336,8 +2326,7 @@ UniValue CreateUTXOSnapshot(
}
pcursor = chainstate.CoinsDB().Cursor();
- tip = chainstate.m_blockman.LookupBlockIndex(stats.hashBlock);
- CHECK_NONFATAL(tip);
+ tip = CHECK_NONFATAL(chainstate.m_blockman.LookupBlockIndex(stats.hashBlock));
}
LOG_TIME_SECONDS(strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
@@ -2377,44 +2366,36 @@ UniValue CreateUTXOSnapshot(
return result;
}
-
-void RegisterBlockchainRPCCommands(CRPCTable &t)
-{
-// clang-format off
-static const CRPCCommand commands[] =
-{ // category actor (function)
- // --------------------- ------------------------
- { "blockchain", &getblockchaininfo, },
- { "blockchain", &getchaintxstats, },
- { "blockchain", &getblockstats, },
- { "blockchain", &getbestblockhash, },
- { "blockchain", &getblockcount, },
- { "blockchain", &getblock, },
- { "blockchain", &getblockfrompeer, },
- { "blockchain", &getblockhash, },
- { "blockchain", &getblockheader, },
- { "blockchain", &getchaintips, },
- { "blockchain", &getdifficulty, },
- { "blockchain", &getdeploymentinfo, },
- { "blockchain", &gettxout, },
- { "blockchain", &gettxoutsetinfo, },
- { "blockchain", &pruneblockchain, },
- { "blockchain", &verifychain, },
-
- { "blockchain", &preciousblock, },
- { "blockchain", &scantxoutset, },
- { "blockchain", &getblockfilter, },
-
- /* Not shown in help */
- { "hidden", &invalidateblock, },
- { "hidden", &reconsiderblock, },
- { "hidden", &waitfornewblock, },
- { "hidden", &waitforblock, },
- { "hidden", &waitforblockheight, },
- { "hidden", &syncwithvalidationinterfacequeue, },
- { "hidden", &dumptxoutset, },
-};
-// clang-format on
+void RegisterBlockchainRPCCommands(CRPCTable& t)
+{
+ static const CRPCCommand commands[]{
+ {"blockchain", &getblockchaininfo},
+ {"blockchain", &getchaintxstats},
+ {"blockchain", &getblockstats},
+ {"blockchain", &getbestblockhash},
+ {"blockchain", &getblockcount},
+ {"blockchain", &getblock},
+ {"blockchain", &getblockfrompeer},
+ {"blockchain", &getblockhash},
+ {"blockchain", &getblockheader},
+ {"blockchain", &getchaintips},
+ {"blockchain", &getdifficulty},
+ {"blockchain", &getdeploymentinfo},
+ {"blockchain", &gettxout},
+ {"blockchain", &gettxoutsetinfo},
+ {"blockchain", &pruneblockchain},
+ {"blockchain", &verifychain},
+ {"blockchain", &preciousblock},
+ {"blockchain", &scantxoutset},
+ {"blockchain", &getblockfilter},
+ {"hidden", &invalidateblock},
+ {"hidden", &reconsiderblock},
+ {"hidden", &waitfornewblock},
+ {"hidden", &waitforblock},
+ {"hidden", &waitforblockheight},
+ {"hidden", &syncwithvalidationinterfacequeue},
+ {"hidden", &dumptxoutset},
+ };
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
}
diff --git a/src/rpc/external_signer.cpp b/src/rpc/external_signer.cpp
index 82aa6f9516..4de7fc4205 100644
--- a/src/rpc/external_signer.cpp
+++ b/src/rpc/external_signer.cpp
@@ -62,15 +62,11 @@ static RPCHelpMan enumeratesigners()
};
}
-void RegisterSignerRPCCommands(CRPCTable &t)
+void RegisterSignerRPCCommands(CRPCTable& t)
{
-// clang-format off
-static const CRPCCommand commands[] =
-{ // category actor (function)
- // --------------------- ------------------------
- { "signer", &enumeratesigners, },
-};
-// clang-format on
+ static const CRPCCommand commands[]{
+ {"signer", &enumeratesigners},
+ };
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
}
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index 1caf4ad96c..27080d3881 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -672,8 +672,6 @@ static RPCHelpMan savemempool()
void RegisterMempoolRPCCommands(CRPCTable& t)
{
static const CRPCCommand commands[]{
- // category actor (function)
- // -------- ----------------
{"rawtransactions", &sendrawtransaction},
{"rawtransactions", &testmempoolaccept},
{"blockchain", &getmempoolancestors},
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 211026c8d9..e4b38efe07 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -1249,30 +1249,25 @@ static RPCHelpMan estimaterawfee()
};
}
-void RegisterMiningRPCCommands(CRPCTable &t)
+void RegisterMiningRPCCommands(CRPCTable& t)
{
-// clang-format off
-static const CRPCCommand commands[] =
-{ // category actor (function)
- // --------------------- -----------------------
- { "mining", &getnetworkhashps, },
- { "mining", &getmininginfo, },
- { "mining", &prioritisetransaction, },
- { "mining", &getblocktemplate, },
- { "mining", &submitblock, },
- { "mining", &submitheader, },
-
-
- { "hidden", &generatetoaddress, },
- { "hidden", &generatetodescriptor, },
- { "hidden", &generateblock, },
-
- { "util", &estimatesmartfee, },
-
- { "hidden", &estimaterawfee, },
- { "hidden", &generate, },
-};
-// clang-format on
+ static const CRPCCommand commands[]{
+ {"mining", &getnetworkhashps},
+ {"mining", &getmininginfo},
+ {"mining", &prioritisetransaction},
+ {"mining", &getblocktemplate},
+ {"mining", &submitblock},
+ {"mining", &submitheader},
+
+ {"hidden", &generatetoaddress},
+ {"hidden", &generatetodescriptor},
+ {"hidden", &generateblock},
+
+ {"util", &estimatesmartfee},
+
+ {"hidden", &estimaterawfee},
+ {"hidden", &generate},
+ };
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 99671ee6ac..98d751e69d 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -484,9 +484,8 @@ static RPCHelpMan mockscheduler()
throw std::runtime_error("delta_time must be between 1 and 3600 seconds (1 hr)");
}
- auto node_context = util::AnyPtr<NodeContext>(request.context);
+ auto node_context = CHECK_NONFATAL(util::AnyPtr<NodeContext>(request.context));
// protect against null pointer dereference
- CHECK_NONFATAL(node_context);
CHECK_NONFATAL(node_context->scheduler);
node_context->scheduler->MockForward(std::chrono::seconds(delta_seconds));
@@ -791,33 +790,27 @@ static RPCHelpMan getindexinfo()
};
}
-void RegisterMiscRPCCommands(CRPCTable &t)
+void RegisterMiscRPCCommands(CRPCTable& t)
{
-// clang-format off
-static const CRPCCommand commands[] =
-{ // category actor (function)
- // --------------------- ------------------------
- { "control", &getmemoryinfo, },
- { "control", &logging, },
- { "util", &validateaddress, },
- { "util", &createmultisig, },
- { "util", &deriveaddresses, },
- { "util", &getdescriptorinfo, },
- { "util", &verifymessage, },
- { "util", &signmessagewithprivkey, },
- { "util", &getindexinfo, },
-
- /* Not shown in help */
- { "hidden", &setmocktime, },
- { "hidden", &mockscheduler, },
- { "hidden", &echo, },
- { "hidden", &echojson, },
- { "hidden", &echoipc, },
+ static const CRPCCommand commands[]{
+ {"control", &getmemoryinfo},
+ {"control", &logging},
+ {"util", &validateaddress},
+ {"util", &createmultisig},
+ {"util", &deriveaddresses},
+ {"util", &getdescriptorinfo},
+ {"util", &verifymessage},
+ {"util", &signmessagewithprivkey},
+ {"util", &getindexinfo},
+ {"hidden", &setmocktime},
+ {"hidden", &mockscheduler},
+ {"hidden", &echo},
+ {"hidden", &echojson},
+ {"hidden", &echoipc},
#if defined(USE_SYSCALL_SANDBOX)
- { "hidden", &invokedisallowedsyscall, },
+ {"hidden", &invokedisallowedsyscall},
#endif // USE_SYSCALL_SANDBOX
-};
-// clang-format on
+ };
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 225feabf14..a9f9cb0153 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -959,30 +959,25 @@ static RPCHelpMan addpeeraddress()
};
}
-void RegisterNetRPCCommands(CRPCTable &t)
-{
-// clang-format off
-static const CRPCCommand commands[] =
-{ // category actor
- // --------------------- -----------------------
- { "network", &getconnectioncount, },
- { "network", &ping, },
- { "network", &getpeerinfo, },
- { "network", &addnode, },
- { "network", &disconnectnode, },
- { "network", &getaddednodeinfo, },
- { "network", &getnettotals, },
- { "network", &getnetworkinfo, },
- { "network", &setban, },
- { "network", &listbanned, },
- { "network", &clearbanned, },
- { "network", &setnetworkactive, },
- { "network", &getnodeaddresses, },
-
- { "hidden", &addconnection, },
- { "hidden", &addpeeraddress, },
-};
-// clang-format on
+void RegisterNetRPCCommands(CRPCTable& t)
+{
+ static const CRPCCommand commands[]{
+ {"network", &getconnectioncount},
+ {"network", &ping},
+ {"network", &getpeerinfo},
+ {"network", &addnode},
+ {"network", &disconnectnode},
+ {"network", &getaddednodeinfo},
+ {"network", &getnettotals},
+ {"network", &getnetworkinfo},
+ {"network", &setban},
+ {"network", &listbanned},
+ {"network", &clearbanned},
+ {"network", &setnetworkactive},
+ {"network", &getnodeaddresses},
+ {"hidden", &addconnection},
+ {"hidden", &addpeeraddress},
+ };
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 8e4b396da9..ce8f16540f 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -33,6 +33,7 @@
#include <script/standard.h>
#include <uint256.h>
#include <util/bip32.h>
+#include <util/check.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/vector.h>
@@ -466,7 +467,7 @@ static RPCHelpMan decodescript()
// Should not be wrapped
return false;
} // no default case, so the compiler can warn about missing cases
- CHECK_NONFATAL(false);
+ NONFATAL_UNREACHABLE();
}()};
if (can_wrap_P2WSH) {
UniValue sr(UniValue::VOBJ);
@@ -1679,28 +1680,24 @@ static RPCHelpMan analyzepsbt()
};
}
-void RegisterRawTransactionRPCCommands(CRPCTable &t)
+void RegisterRawTransactionRPCCommands(CRPCTable& t)
{
-// clang-format off
-static const CRPCCommand commands[] =
-{ // category actor (function)
- // --------------------- -----------------------
- { "rawtransactions", &getrawtransaction, },
- { "rawtransactions", &createrawtransaction, },
- { "rawtransactions", &decoderawtransaction, },
- { "rawtransactions", &decodescript, },
- { "rawtransactions", &combinerawtransaction, },
- { "rawtransactions", &signrawtransactionwithkey, },
- { "rawtransactions", &decodepsbt, },
- { "rawtransactions", &combinepsbt, },
- { "rawtransactions", &finalizepsbt, },
- { "rawtransactions", &createpsbt, },
- { "rawtransactions", &converttopsbt, },
- { "rawtransactions", &utxoupdatepsbt, },
- { "rawtransactions", &joinpsbts, },
- { "rawtransactions", &analyzepsbt, },
-};
-// clang-format on
+ static const CRPCCommand commands[]{
+ {"rawtransactions", &getrawtransaction},
+ {"rawtransactions", &createrawtransaction},
+ {"rawtransactions", &decoderawtransaction},
+ {"rawtransactions", &decodescript},
+ {"rawtransactions", &combinerawtransaction},
+ {"rawtransactions", &signrawtransactionwithkey},
+ {"rawtransactions", &decodepsbt},
+ {"rawtransactions", &combinepsbt},
+ {"rawtransactions", &finalizepsbt},
+ {"rawtransactions", &createpsbt},
+ {"rawtransactions", &converttopsbt},
+ {"rawtransactions", &utxoupdatepsbt},
+ {"rawtransactions", &joinpsbts},
+ {"rawtransactions", &analyzepsbt},
+ };
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
}
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index 95a7c25b93..d0e068de19 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -82,7 +82,7 @@ bool GenerateAuthCookie(std::string *cookie_out)
{
const size_t COOKIE_SIZE = 32;
unsigned char rand_pwd[COOKIE_SIZE];
- GetRandBytes(rand_pwd, COOKIE_SIZE);
+ GetRandBytes(rand_pwd);
std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd);
/** the umask determines what permissions are used to create this file -
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 333ed6f5da..3817a4a45c 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -9,10 +9,9 @@
#include <shutdown.h>
#include <sync.h>
#include <util/strencodings.h>
+#include <util/string.h>
#include <util/system.h>
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/split.hpp>
#include <boost/signals2/signal.hpp>
#include <cassert>
@@ -248,17 +247,13 @@ static RPCHelpMan getrpcinfo()
};
}
-// clang-format off
-static const CRPCCommand vRPCCommands[] =
-{ // category actor (function)
- // --------------------- -----------------------
+static const CRPCCommand vRPCCommands[]{
/* Overall control/query calls */
- { "control", &getrpcinfo, },
- { "control", &help, },
- { "control", &stop, },
- { "control", &uptime, },
+ {"control", &getrpcinfo},
+ {"control", &help},
+ {"control", &stop},
+ {"control", &uptime},
};
-// clang-format on
CRPCTable::CRPCTable()
{
@@ -407,8 +402,7 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
// Process expected parameters.
int hole = 0;
for (const std::string &argNamePattern: argNames) {
- std::vector<std::string> vargNames;
- boost::algorithm::split(vargNames, argNamePattern, boost::algorithm::is_any_of("|"));
+ std::vector<std::string> vargNames = SplitString(argNamePattern, '|');
auto fr = argsIn.end();
for (const std::string & argName : vargNames) {
fr = argsIn.find(argName);
diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp
index a5443b0329..d16820baeb 100644
--- a/src/rpc/txoutproof.cpp
+++ b/src/rpc/txoutproof.cpp
@@ -172,8 +172,6 @@ static RPCHelpMan verifytxoutproof()
void RegisterTxoutProofRPCCommands(CRPCTable& t)
{
static const CRPCCommand commands[]{
- // category actor (function)
- // -------- ----------------
{"blockchain", &gettxoutproof},
{"blockchain", &verifytxoutproof},
};
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 01fae140cc..ef3e58494e 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -9,15 +9,13 @@
#include <script/descriptor.h>
#include <script/signingprovider.h>
#include <tinyformat.h>
+#include <util/check.h>
#include <util/strencodings.h>
#include <util/string.h>
#include <util/translation.h>
#include <tuple>
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/split.hpp>
-
const std::string UNIX_EPOCH_TIME = "UNIX epoch time";
const std::string EXAMPLE_ADDRESS[2] = {"bc1q09vm5lfy0j5reeulh4x5752q25uqqvz34hufdl", "bc1q02ad21edsxd23d32dfgqqsz4vv4nmtfzuklhy3"};
@@ -513,8 +511,7 @@ RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RP
{
std::set<std::string> named_args;
for (const auto& arg : m_args) {
- std::vector<std::string> names;
- boost::split(names, arg.m_names, boost::is_any_of("|"));
+ std::vector<std::string> names = SplitString(arg.m_names, '|');
// Should have unique named arguments
for (const std::string& name : names) {
CHECK_NONFATAL(named_args.insert(name).second);
@@ -542,7 +539,7 @@ RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RP
// Null values are accepted in all arguments
break;
default:
- CHECK_NONFATAL(false);
+ NONFATAL_UNREACHABLE();
break;
}
}
@@ -665,8 +662,7 @@ UniValue RPCHelpMan::GetArgMap() const
UniValue arr{UniValue::VARR};
for (int i{0}; i < int(m_args.size()); ++i) {
const auto& arg = m_args.at(i);
- std::vector<std::string> arg_names;
- boost::split(arg_names, arg.m_names, boost::is_any_of("|"));
+ std::vector<std::string> arg_names = SplitString(arg.m_names, '|');
for (const auto& arg_name : arg_names) {
UniValue map{UniValue::VARR};
map.push_back(m_name);
@@ -793,7 +789,7 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const
return;
}
case Type::ANY: {
- CHECK_NONFATAL(false); // Only for testing
+ NONFATAL_UNREACHABLE(); // Only for testing
}
case Type::NONE: {
sections.PushSection({indent + "null" + maybe_separator, Description("json null")});
@@ -860,7 +856,7 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const
return;
}
} // no default case, so the compiler can warn about missing cases
- CHECK_NONFATAL(false);
+ NONFATAL_UNREACHABLE();
}
bool RPCResult::MatchesType(const UniValue& result) const
@@ -938,7 +934,7 @@ bool RPCResult::MatchesType(const UniValue& result) const
return true;
}
} // no default case, so the compiler can warn about missing cases
- CHECK_NONFATAL(false);
+ NONFATAL_UNREACHABLE();
}
void RPCResult::CheckInnerDoc() const
@@ -984,9 +980,9 @@ std::string RPCArg::ToStringObj(const bool oneline) const
case Type::OBJ:
case Type::OBJ_USER_KEYS:
// Currently unused, so avoid writing dead code
- CHECK_NONFATAL(false);
+ NONFATAL_UNREACHABLE();
} // no default case, so the compiler can warn about missing cases
- CHECK_NONFATAL(false);
+ NONFATAL_UNREACHABLE();
}
std::string RPCArg::ToString(const bool oneline) const
@@ -1021,7 +1017,7 @@ std::string RPCArg::ToString(const bool oneline) const
return "[" + res + "...]";
}
} // no default case, so the compiler can warn about missing cases
- CHECK_NONFATAL(false);
+ NONFATAL_UNREACHABLE();
}
static std::pair<int64_t, int64_t> ParseRange(const UniValue& value)
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index fbd904fb7b..adf454aa15 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -151,7 +151,7 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
struct PrecomputedTransactionData
{
// BIP341 precomputed data.
- // These are single-SHA256, see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-15.
+ // These are single-SHA256, see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-16.
uint256 m_prevouts_single_hash;
uint256 m_sequences_single_hash;
uint256 m_outputs_single_hash;
diff --git a/src/serialize.h b/src/serialize.h
index 44bb471f25..a1cce78451 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -472,10 +472,10 @@ struct CustomUintFormatter
if (v < 0 || v > MAX) throw std::ios_base::failure("CustomUintFormatter value out of range");
if (BigEndian) {
uint64_t raw = htobe64(v);
- s.write({BytePtr(&raw) + 8 - Bytes, Bytes});
+ s.write({AsBytePtr(&raw) + 8 - Bytes, Bytes});
} else {
uint64_t raw = htole64(v);
- s.write({BytePtr(&raw), Bytes});
+ s.write({AsBytePtr(&raw), Bytes});
}
}
@@ -485,10 +485,10 @@ struct CustomUintFormatter
static_assert(std::numeric_limits<U>::max() >= MAX && std::numeric_limits<U>::min() <= 0, "Assigned type too small");
uint64_t raw = 0;
if (BigEndian) {
- s.read({BytePtr(&raw) + 8 - Bytes, Bytes});
+ s.read({AsBytePtr(&raw) + 8 - Bytes, Bytes});
v = static_cast<I>(be64toh(raw));
} else {
- s.read({BytePtr(&raw), Bytes});
+ s.read({AsBytePtr(&raw), Bytes});
v = static_cast<I>(le64toh(raw));
}
}
diff --git a/src/span.h b/src/span.h
index b627b993c2..444d63001f 100644
--- a/src/span.h
+++ b/src/span.h
@@ -245,19 +245,19 @@ T& SpanPopBack(Span<T>& span)
//! Convert a data pointer to a std::byte data pointer.
//! Where possible, please use the safer AsBytes helpers.
-inline const std::byte* BytePtr(const void* data) { return reinterpret_cast<const std::byte*>(data); }
-inline std::byte* BytePtr(void* data) { return reinterpret_cast<std::byte*>(data); }
+inline const std::byte* AsBytePtr(const void* data) { return reinterpret_cast<const std::byte*>(data); }
+inline std::byte* AsBytePtr(void* data) { return reinterpret_cast<std::byte*>(data); }
// From C++20 as_bytes and as_writeable_bytes
template <typename T>
Span<const std::byte> AsBytes(Span<T> s) noexcept
{
- return {BytePtr(s.data()), s.size_bytes()};
+ return {AsBytePtr(s.data()), s.size_bytes()};
}
template <typename T>
Span<std::byte> AsWritableBytes(Span<T> s) noexcept
{
- return {BytePtr(s.data()), s.size_bytes()};
+ return {AsBytePtr(s.data()), s.size_bytes()};
}
template <typename V>
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index a9aa928082..c6bd685189 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -37,7 +37,7 @@ struct secure_allocator : public std::allocator<T> {
typedef secure_allocator<_Other> other;
};
- T* allocate(std::size_t n, const void* hint = 0)
+ T* allocate(std::size_t n, const void* hint = nullptr)
{
T* allocation = static_cast<T*>(LockedPoolManager::Instance().alloc(sizeof(T) * n));
if (!allocation) {
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index efc30b6822..12cf1176a6 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -23,7 +23,7 @@
using namespace std::literals;
using node::NodeContext;
-static const std::vector<bool> EMPTY_ASMAP;
+static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()};
static const bool DETERMINISTIC{true};
static int32_t GetCheckRatio(const NodeContext& node_ctx)
@@ -62,7 +62,7 @@ BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(addrman_simple)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
@@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
BOOST_CHECK(addrman->size() >= 1);
// Test: reset addrman and test AddrMan::Add multiple addresses works as expected
- addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
std::vector<CAddress> vAddr;
vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE));
vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE));
@@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple)
BOOST_AUTO_TEST_CASE(addrman_ports)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
@@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(addrman_ports)
BOOST_AUTO_TEST_CASE(addrman_select)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
@@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE(addrman_select)
BOOST_AUTO_TEST_CASE(addrman_new_collisions)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
@@ -223,7 +223,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_collisions)
BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ 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()};
addr.nTime = start_time;
@@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
@@ -286,7 +286,7 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
BOOST_AUTO_TEST_CASE(addrman_getaddr)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
// Test: Sanity check, GetAddr should never return anything if addrman
// is empty.
@@ -357,27 +357,25 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
- std::vector<bool> asmap; // use /16
-
- BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 40);
+ BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN), 40);
// Test: Make sure key actually randomizes bucket placement. A fail on
// this test could be a security issue.
- BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info1.GetTriedBucket(nKey2, asmap));
+ BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info1.GetTriedBucket(nKey2, EMPTY_NETGROUPMAN));
// Test: Two addresses with same IP but different ports can map to
// different buckets because they have different keys.
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
- BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
+ BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info2.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN));
std::set<int> buckets;
for (int i = 0; i < 255; i++) {
AddrInfo infoi = AddrInfo(
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
ResolveIP("250.1.1." + ToString(i)));
- int bucket = infoi.GetTriedBucket(nKey1, asmap);
+ int bucket = infoi.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
// Test: IP addresses in the same /16 prefix should
@@ -389,7 +387,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
ResolveIP("250." + ToString(j) + ".1.1"));
- int bucket = infoj.GetTriedBucket(nKey1, asmap);
+ int bucket = infoj.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
// Test: IP addresses in the different /16 prefix should map to more than
@@ -409,27 +407,25 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
- std::vector<bool> asmap; // use /16
-
// Test: Make sure the buckets are what we expect
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 786);
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 786);
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), 786);
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, EMPTY_NETGROUPMAN), 786);
// Test: Make sure key actually randomizes bucket placement. A fail on
// this test could be a security issue.
- BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
+ BOOST_CHECK(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN) != info1.GetNewBucket(nKey2, EMPTY_NETGROUPMAN));
// Test: Ports should not affect bucket placement in the addr
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), info2.GetNewBucket(nKey1, EMPTY_NETGROUPMAN));
std::set<int> buckets;
for (int i = 0; i < 255; i++) {
AddrInfo infoi = AddrInfo(
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
ResolveIP("250.1.1." + ToString(i)));
- int bucket = infoi.GetNewBucket(nKey1, asmap);
+ int bucket = infoi.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
// Test: IP addresses in the same group (\16 prefix for IPv4) should
@@ -442,7 +438,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
ResolveService(
ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
ResolveIP("251.4.1.1"));
- int bucket = infoj.GetNewBucket(nKey1, asmap);
+ int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
// Test: IP addresses in the same source groups should map to NO MORE
@@ -454,7 +450,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
ResolveIP("250." + ToString(p) + ".1.1"));
- int bucket = infoj.GetNewBucket(nKey1, asmap);
+ int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
// Test: IP addresses in the different source groups should map to MORE
@@ -475,6 +471,9 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
// 101.8.0.0/16 AS8
BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
{
+ std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
+ NetGroupManager ngm_asmap{asmap};
+
CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
@@ -486,27 +485,25 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
- std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
-
- BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 236);
+ BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, ngm_asmap), 236);
// Test: Make sure key actually randomizes bucket placement. A fail on
// this test could be a security issue.
- BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info1.GetTriedBucket(nKey2, asmap));
+ BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info1.GetTriedBucket(nKey2, ngm_asmap));
// Test: Two addresses with same IP but different ports can map to
// different buckets because they have different keys.
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
- BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != info2.GetTriedBucket(nKey1, asmap));
+ BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info2.GetTriedBucket(nKey1, ngm_asmap));
std::set<int> buckets;
for (int j = 0; j < 255; j++) {
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("101." + ToString(j) + ".1.1"), NODE_NONE),
ResolveIP("101." + ToString(j) + ".1.1"));
- int bucket = infoj.GetTriedBucket(nKey1, asmap);
+ int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the different /16 prefix MAY map to more than
@@ -518,7 +515,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
ResolveIP("250." + ToString(j) + ".1.1"));
- int bucket = infoj.GetTriedBucket(nKey1, asmap);
+ int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the different /16 prefix MAY NOT map to more than
@@ -528,6 +525,9 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
{
+ std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
+ NetGroupManager ngm_asmap{asmap};
+
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
@@ -538,27 +538,25 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash();
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash();
- std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
-
// Test: Make sure the buckets are what we expect
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 795);
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 795);
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), 795);
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, ngm_asmap), 795);
// Test: Make sure key actually randomizes bucket placement. A fail on
// this test could be a security issue.
- BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != info1.GetNewBucket(nKey2, asmap));
+ BOOST_CHECK(info1.GetNewBucket(nKey1, ngm_asmap) != info1.GetNewBucket(nKey2, ngm_asmap));
// Test: Ports should not affect bucket placement in the addr
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
- BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), info2.GetNewBucket(nKey1, asmap));
+ BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), info2.GetNewBucket(nKey1, ngm_asmap));
std::set<int> buckets;
for (int i = 0; i < 255; i++) {
AddrInfo infoi = AddrInfo(
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
ResolveIP("250.1.1." + ToString(i)));
- int bucket = infoi.GetNewBucket(nKey1, asmap);
+ int bucket = infoi.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the same /16 prefix
@@ -571,7 +569,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
ResolveService(
ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
ResolveIP("251.4.1.1"));
- int bucket = infoj.GetNewBucket(nKey1, asmap);
+ int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the same source /16 prefix should not map to more
@@ -583,7 +581,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
ResolveIP("101." + ToString(p) + ".1.1"));
- int bucket = infoj.GetNewBucket(nKey1, asmap);
+ int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the different source /16 prefixes usually map to MORE
@@ -595,7 +593,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
ResolveIP("250." + ToString(p) + ".1.1"));
- int bucket = infoj.GetNewBucket(nKey1, asmap);
+ int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
// Test: IP addresses in the different source /16 prefixes sometimes map to NO MORE
@@ -606,11 +604,12 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
BOOST_AUTO_TEST_CASE(addrman_serialization)
{
std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8);
+ NetGroupManager netgroupman{asmap1};
const auto ratio = GetCheckRatio(m_node);
- auto addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
- auto addrman_asmap1_dup = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
- auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
+ auto addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
+ auto addrman_asmap1_dup = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
+ auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
@@ -639,8 +638,8 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
BOOST_CHECK(addr_pos1.position != addr_pos3.position);
// deserializing non-asmaped peers.dat to asmaped addrman
- addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
- addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
+ addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
+ addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
addrman_noasmap->Add({addr}, default_source);
stream << *addrman_noasmap;
stream >> *addrman_asmap1;
@@ -651,8 +650,8 @@ BOOST_AUTO_TEST_CASE(addrman_serialization)
BOOST_CHECK(addr_pos4 == addr_pos2);
// used to map to different buckets, now maps to the same bucket.
- addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio);
- addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio);
+ addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
+ addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE);
addrman_noasmap->Add({addr, addr2}, default_source);
@@ -671,7 +670,7 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
{
// Confirm that invalid addresses are ignored in unserialization.
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
@@ -703,14 +702,14 @@ BOOST_AUTO_TEST_CASE(remove_invalid)
BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size());
memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement));
- addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
stream >> *addrman;
BOOST_CHECK_EQUAL(addrman->size(), 2);
}
BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK(addrman->size() == 0);
@@ -743,7 +742,7 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
BOOST_AUTO_TEST_CASE(addrman_noevict)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
// Add 35 addresses.
CNetAddr source = ResolveIP("252.2.2.2");
@@ -795,7 +794,7 @@ BOOST_AUTO_TEST_CASE(addrman_noevict)
BOOST_AUTO_TEST_CASE(addrman_evictionworks)
{
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK(addrman->size() == 0);
@@ -865,7 +864,7 @@ static CDataStream AddrmanToStream(const AddrMan& addrman)
BOOST_AUTO_TEST_CASE(load_addrman)
{
- AddrMan addrman{EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)};
+ AddrMan addrman{EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node)};
CService addr1, addr2, addr3;
BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false));
@@ -884,7 +883,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
// Test that the de-serialization does not throw an exception.
CDataStream ssPeers1 = AddrmanToStream(addrman);
bool exceptionThrown = false;
- AddrMan addrman1{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
+ AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman1.size() == 0);
try {
@@ -901,7 +900,7 @@ BOOST_AUTO_TEST_CASE(load_addrman)
// Test that ReadFromStream creates an addrman with the correct number of addrs.
CDataStream ssPeers2 = AddrmanToStream(addrman);
- AddrMan addrman2{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
+ AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman2.size() == 0);
ReadFromStream(addrman2, ssPeers2);
BOOST_CHECK(addrman2.size() == 3);
@@ -939,7 +938,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
// Test that the de-serialization of corrupted peers.dat throws an exception.
CDataStream ssPeers1 = MakeCorruptPeersDat();
bool exceptionThrown = false;
- AddrMan addrman1{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
+ AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman1.size() == 0);
try {
unsigned char pchMsgTmp[4];
@@ -955,7 +954,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
// Test that ReadFromStream fails if peers.dat is corrupt
CDataStream ssPeers2 = MakeCorruptPeersDat();
- AddrMan addrman2{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)};
+ AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman2.size() == 0);
BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
}
@@ -963,7 +962,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
BOOST_AUTO_TEST_CASE(addrman_update_address)
{
// Tests updating nTime via Connected() and nServices via SetServices()
- auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node));
+ auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source{ResolveIP("252.2.2.2")};
CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index f03ff5ba3a..7a917649a8 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -4,7 +4,6 @@
// Unit tests for denial-of-service detection/prevention code
-#include <arith_uint256.h>
#include <banman.h>
#include <chainparams.h>
#include <net.h>
@@ -16,7 +15,6 @@
#include <serialize.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>
-#include <txorphanage.h>
#include <util/string.h>
#include <util/system.h>
#include <util/time.h>
@@ -49,7 +47,7 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
const CChainParams& chainparams = Params();
- auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
+ auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
// Disable inactivity checks for this test to avoid interference
static_cast<ConnmanTestMsg*>(connman.get())->SetPeerConnectTimeout(99999s);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
@@ -139,7 +137,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
{
NodeId id{0};
const CChainParams& chainparams = Params();
- auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman);
+ auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
*m_node.chainman, *m_node.mempool, false);
@@ -217,7 +215,7 @@ BOOST_AUTO_TEST_CASE(block_relay_only_eviction)
{
NodeId id{0};
const CChainParams& chainparams = Params();
- auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman);
+ auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, nullptr,
*m_node.chainman, *m_node.mempool, false);
@@ -280,7 +278,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
{
const CChainParams& chainparams = Params();
auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman);
+ auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
*m_node.chainman, *m_node.mempool, false);
@@ -396,7 +394,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
{
const CChainParams& chainparams = Params();
auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
+ auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
auto peerLogic = PeerManager::make(chainparams, *connman, *m_node.addrman, banman.get(),
*m_node.chainman, *m_node.mempool, false);
@@ -430,121 +428,4 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
peerLogic->FinalizeNode(dummyNode);
}
-class TxOrphanageTest : public TxOrphanage
-{
-public:
- inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
- {
- return m_orphans.size();
- }
-
- CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
- {
- std::map<uint256, OrphanTx>::iterator it;
- it = m_orphans.lower_bound(InsecureRand256());
- if (it == m_orphans.end())
- it = m_orphans.begin();
- return it->second.tx;
- }
-};
-
-static void MakeNewKeyWithFastRandomContext(CKey& key)
-{
- std::vector<unsigned char> keydata;
- keydata = g_insecure_rand_ctx.randbytes(32);
- key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn=*/true);
- assert(key.IsValid());
-}
-
-BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
-{
- // This test had non-deterministic coverage due to
- // randomly selected seeds.
- // This seed is chosen so that all branches of the function
- // ecdsa_signature_parse_der_lax are executed during this test.
- // Specifically branches that run only when an ECDSA
- // signature's R and S values have leading zeros.
- g_insecure_rand_ctx = FastRandomContext(ArithToUint256(arith_uint256(33)));
-
- TxOrphanageTest orphanage;
- CKey key;
- MakeNewKeyWithFastRandomContext(key);
- FillableSigningProvider keystore;
- BOOST_CHECK(keystore.AddKey(key));
-
- LOCK(g_cs_orphans);
-
- // 50 orphan transactions:
- for (int i = 0; i < 50; i++)
- {
- CMutableTransaction tx;
- tx.vin.resize(1);
- tx.vin[0].prevout.n = 0;
- tx.vin[0].prevout.hash = InsecureRand256();
- tx.vin[0].scriptSig << OP_1;
- tx.vout.resize(1);
- tx.vout[0].nValue = 1*CENT;
- tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
-
- orphanage.AddTx(MakeTransactionRef(tx), i);
- }
-
- // ... and 50 that depend on other orphans:
- for (int i = 0; i < 50; i++)
- {
- CTransactionRef txPrev = orphanage.RandomOrphan();
-
- CMutableTransaction tx;
- tx.vin.resize(1);
- tx.vin[0].prevout.n = 0;
- tx.vin[0].prevout.hash = txPrev->GetHash();
- tx.vout.resize(1);
- tx.vout[0].nValue = 1*CENT;
- tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
- BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL));
-
- orphanage.AddTx(MakeTransactionRef(tx), i);
- }
-
- // This really-big orphan should be ignored:
- for (int i = 0; i < 10; i++)
- {
- CTransactionRef txPrev = orphanage.RandomOrphan();
-
- CMutableTransaction tx;
- tx.vout.resize(1);
- tx.vout[0].nValue = 1*CENT;
- tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
- tx.vin.resize(2777);
- for (unsigned int j = 0; j < tx.vin.size(); j++)
- {
- tx.vin[j].prevout.n = j;
- tx.vin[j].prevout.hash = txPrev->GetHash();
- }
- BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL));
- // Re-use same signature for other inputs
- // (they don't have to be valid for this test)
- for (unsigned int j = 1; j < tx.vin.size(); j++)
- tx.vin[j].scriptSig = tx.vin[0].scriptSig;
-
- BOOST_CHECK(!orphanage.AddTx(MakeTransactionRef(tx), i));
- }
-
- // Test EraseOrphansFor:
- for (NodeId i = 0; i < 3; i++)
- {
- size_t sizeBefore = orphanage.CountOrphans();
- orphanage.EraseForPeer(i);
- BOOST_CHECK(orphanage.CountOrphans() < sizeBefore);
- }
-
- // Test LimitOrphanTxSize() function:
- orphanage.LimitOrphans(40);
- BOOST_CHECK(orphanage.CountOrphans() <= 40);
- orphanage.LimitOrphans(10);
- BOOST_CHECK(orphanage.CountOrphans() <= 10);
- orphanage.LimitOrphans(0);
- BOOST_CHECK(orphanage.CountOrphans() == 0);
-}
-
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index ba917dec2a..af7a282781 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -37,11 +37,19 @@ void initialize_addrman()
g_setup = testing_setup.get();
}
+[[nodiscard]] inline NetGroupManager ConsumeNetGroupManager(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
+ if (!SanityCheckASMap(asmap, 128)) asmap.clear();
+ return NetGroupManager(asmap);
+}
+
FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
- AddrMan addr_man{/*asmap=*/std::vector<bool>(), /*deterministic=*/false, GetCheckRatio()};
+ NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
+ AddrMan addr_man(netgroupman, /*deterministic=*/false, GetCheckRatio());
try {
ReadFromStream(addr_man, data_stream);
} catch (const std::exception&) {
@@ -124,8 +132,8 @@ void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
class AddrManDeterministic : public AddrMan
{
public:
- explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider)
- : AddrMan{std::move(asmap), /*deterministic=*/true, GetCheckRatio()}
+ explicit AddrManDeterministic(const NetGroupManager& netgroupman, FuzzedDataProvider& fuzzed_data_provider)
+ : AddrMan(netgroupman, /*deterministic=*/true, GetCheckRatio())
{
WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)});
}
@@ -223,19 +231,12 @@ public:
}
};
-[[nodiscard]] inline std::vector<bool> ConsumeAsmap(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
- if (!SanityCheckASMap(asmap, 128)) asmap.clear();
- return asmap;
-}
-
FUZZ_TARGET_INIT(addrman, initialize_addrman)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
SetMockTime(ConsumeTime(fuzzed_data_provider));
- std::vector<bool> asmap = ConsumeAsmap(fuzzed_data_provider);
- auto addr_man_ptr = std::make_unique<AddrManDeterministic>(asmap, fuzzed_data_provider);
+ NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
+ auto addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider);
if (fuzzed_data_provider.ConsumeBool()) {
const std::vector<uint8_t> serialized_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
CDataStream ds(serialized_data, SER_DISK, INIT_PROTO_VERSION);
@@ -244,7 +245,7 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
try {
ds >> *addr_man_ptr;
} catch (const std::ios_base::failure&) {
- addr_man_ptr = std::make_unique<AddrManDeterministic>(asmap, fuzzed_data_provider);
+ addr_man_ptr = std::make_unique<AddrManDeterministic>(netgroupman, fuzzed_data_provider);
}
}
AddrManDeterministic& addr_man = *addr_man_ptr;
@@ -313,9 +314,9 @@ FUZZ_TARGET_INIT(addrman_serdeser, initialize_addrman)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
SetMockTime(ConsumeTime(fuzzed_data_provider));
- std::vector<bool> asmap = ConsumeAsmap(fuzzed_data_provider);
- AddrManDeterministic addr_man1{asmap, fuzzed_data_provider};
- AddrManDeterministic addr_man2{asmap, fuzzed_data_provider};
+ NetGroupManager netgroupman{ConsumeNetGroupManager(fuzzed_data_provider)};
+ AddrManDeterministic addr_man1{netgroupman, fuzzed_data_provider};
+ AddrManDeterministic addr_man2{netgroupman, fuzzed_data_provider};
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);
diff --git a/src/test/fuzz/asmap.cpp b/src/test/fuzz/asmap.cpp
index 95be963dc8..1720f8e0ab 100644
--- a/src/test/fuzz/asmap.cpp
+++ b/src/test/fuzz/asmap.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <netaddress.h>
+#include <netgroup.h>
#include <test/fuzz/fuzz.h>
#include <util/asmap.h>
@@ -56,5 +57,6 @@ FUZZ_TARGET(asmap)
memcpy(&ipv4, addr_data, addr_size);
net_addr.SetIP(CNetAddr{ipv4});
}
- (void)net_addr.GetMappedAS(asmap);
+ NetGroupManager netgroupman{asmap};
+ (void)netgroupman.GetMappedAS(net_addr);
}
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index a14d28f4ef..4406779015 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -19,12 +19,12 @@
#include <vector>
namespace {
-const BasicTestingSetup* g_setup;
+const TestingSetup* g_setup;
} // namespace
void initialize_connman()
{
- static const auto testing_setup = MakeNoLogFileContext<>();
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
}
@@ -32,10 +32,11 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider));
- AddrMan addrman(/*asmap=*/std::vector<bool>(),
- /*deterministic=*/false,
- g_setup->m_node.args->GetIntArg("-checkaddrman", 0));
- CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()};
+ CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
+ fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
+ *g_setup->m_node.addrman,
+ *g_setup->m_node.netgroupman,
+ fuzzed_data_provider.ConsumeBool()};
CNetAddr random_netaddr;
CNode random_node = ConsumeNode(fuzzed_data_provider);
CSubNet random_subnet;
diff --git a/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp b/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp
index fcc96c6418..1b89d55773 100644
--- a/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp
+++ b/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp
@@ -128,7 +128,7 @@ void ECRYPT_encrypt_bytes(ECRYPT_ctx* x, const u8* m, u8* c, u32 bytes)
{
u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
- u8* ctarget = NULL;
+ u8* ctarget = nullptr;
u8 tmp[64];
uint32_t i;
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index ed6f172a2a..0a7d0c55bd 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -15,6 +15,7 @@
#include <merkleblock.h>
#include <net.h>
#include <netbase.h>
+#include <netgroup.h>
#include <node/utxo_snapshot.h>
#include <primitives/block.h>
#include <protocol.h>
@@ -200,7 +201,8 @@ FUZZ_TARGET_DESERIALIZE(blockmerkleroot, {
BlockMerkleRoot(block, &mutated);
})
FUZZ_TARGET_DESERIALIZE(addrman_deserialize, {
- AddrMan am(/*asmap=*/std::vector<bool>(),
+ NetGroupManager netgroupman{std::vector<bool>()};
+ AddrMan am(netgroupman,
/*deterministic=*/false,
g_setup->m_node.args->GetIntArg("-checkaddrman", 0));
DeserializeFromFuzzingInput(buffer, am);
diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp
index 00a3bed12f..a18a0de47e 100644
--- a/src/test/fuzz/script_assets_test_minimizer.cpp
+++ b/src/test/fuzz/script_assets_test_minimizer.cpp
@@ -11,8 +11,8 @@
#include <streams.h>
#include <univalue.h>
#include <util/strencodings.h>
+#include <util/string.h>
-#include <boost/algorithm/string.hpp>
#include <cstdint>
#include <string>
#include <vector>
@@ -130,8 +130,7 @@ unsigned int ParseScriptFlags(const std::string& str)
if (str.empty()) return 0;
unsigned int flags = 0;
- std::vector<std::string> words;
- boost::algorithm::split(words, str, boost::algorithm::is_any_of(","));
+ std::vector<std::string> words = SplitString(str, ',');
for (const std::string& word : words) {
auto it = FLAG_NAMES.find(word);
diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp
index ca57af25c4..b4876d427f 100644
--- a/src/test/fuzz/string.cpp
+++ b/src/test/fuzz/string.cpp
@@ -224,6 +224,7 @@ FUZZ_TARGET(string)
int64_t amount_out;
(void)ParseFixedPoint(random_string_1, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 1024), &amount_out);
}
+ (void)SplitString(random_string_1, fuzzed_data_provider.ConsumeIntegral<char>());
{
(void)Untranslated(random_string_1);
const bilingual_str bs1{random_string_1, random_string_2};
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 61d334ab18..8cb0515a8a 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -204,7 +204,7 @@ BOOST_AUTO_TEST_CASE(key_key_negation)
// create a dummy hash for signature comparison
unsigned char rnd[8];
std::string str = "Bitcoin key verification\n";
- GetRandBytes(rnd, sizeof(rnd));
+ GetRandBytes(rnd);
uint256 hash;
CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 8e6e911ec2..224dc88d0f 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -5,6 +5,7 @@
#include <net_permissions.h>
#include <netaddress.h>
#include <netbase.h>
+#include <netgroup.h>
#include <protocol.h>
#include <serialize.h>
#include <streams.h>
@@ -315,22 +316,22 @@ BOOST_AUTO_TEST_CASE(subnet_test)
BOOST_AUTO_TEST_CASE(netbase_getgroup)
{
- std::vector<bool> asmap; // use /16
- BOOST_CHECK(ResolveIP("127.0.0.1").GetGroup(asmap) == std::vector<unsigned char>({0})); // Local -> !Routable()
- BOOST_CHECK(ResolveIP("257.0.0.1").GetGroup(asmap) == std::vector<unsigned char>({0})); // !Valid -> !Routable()
- BOOST_CHECK(ResolveIP("10.0.0.1").GetGroup(asmap) == std::vector<unsigned char>({0})); // RFC1918 -> !Routable()
- BOOST_CHECK(ResolveIP("169.254.1.1").GetGroup(asmap) == std::vector<unsigned char>({0})); // RFC3927 -> !Routable()
- BOOST_CHECK(ResolveIP("1.2.3.4").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // IPv4
- BOOST_CHECK(ResolveIP("::FFFF:0:102:304").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6145
- BOOST_CHECK(ResolveIP("64:FF9B::102:304").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6052
- BOOST_CHECK(ResolveIP("2002:102:304:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC3964
- BOOST_CHECK(ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC4380
- BOOST_CHECK(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net
- BOOST_CHECK(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup(asmap) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6
+ NetGroupManager netgroupman{std::vector<bool>()}; // use /16
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("127.0.0.1")) == std::vector<unsigned char>({0})); // Local -> !Routable()
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("257.0.0.1")) == std::vector<unsigned char>({0})); // !Valid -> !Routable()
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("10.0.0.1")) == std::vector<unsigned char>({0})); // RFC1918 -> !Routable()
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("169.254.1.1")) == std::vector<unsigned char>({0})); // RFC3927 -> !Routable()
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("1.2.3.4")) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // IPv4
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("::FFFF:0:102:304")) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6145
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("64:FF9B::102:304")) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC6052
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("2002:102:304:9999:9999:9999:9999:9999")) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC3964
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB")) == std::vector<unsigned char>({(unsigned char)NET_IPV4, 1, 2})); // RFC4380
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999")) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net
+ BOOST_CHECK(netgroupman.GetGroup(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999")) == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6
// baz.net sha256 hash: 12929400eb4607c4ac075f087167e75286b179c693eb059a01774b864e8fe505
std::vector<unsigned char> internal_group = {NET_INTERNAL, 0x12, 0x92, 0x94, 0x00, 0xeb, 0x46, 0x07, 0xc4, 0xac, 0x07};
- BOOST_CHECK(CreateInternal("baz.net").GetGroup(asmap) == internal_group);
+ BOOST_CHECK(netgroupman.GetGroup(CreateInternal("baz.net")) == internal_group);
}
BOOST_AUTO_TEST_CASE(netbase_parsenetwork)
diff --git a/src/test/orphanage_tests.cpp b/src/test/orphanage_tests.cpp
new file mode 100644
index 0000000000..842daa8bd4
--- /dev/null
+++ b/src/test/orphanage_tests.cpp
@@ -0,0 +1,137 @@
+// Copyright (c) 2011-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 <arith_uint256.h>
+#include <pubkey.h>
+#include <script/sign.h>
+#include <script/signingprovider.h>
+#include <script/standard.h>
+#include <test/util/setup_common.h>
+#include <txorphanage.h>
+
+#include <array>
+#include <cstdint>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup)
+
+class TxOrphanageTest : public TxOrphanage
+{
+public:
+ inline size_t CountOrphans() const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
+ {
+ return m_orphans.size();
+ }
+
+ CTransactionRef RandomOrphan() EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
+ {
+ std::map<uint256, OrphanTx>::iterator it;
+ it = m_orphans.lower_bound(InsecureRand256());
+ if (it == m_orphans.end())
+ it = m_orphans.begin();
+ return it->second.tx;
+ }
+};
+
+static void MakeNewKeyWithFastRandomContext(CKey& key)
+{
+ std::vector<unsigned char> keydata;
+ keydata = g_insecure_rand_ctx.randbytes(32);
+ key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn=*/true);
+ assert(key.IsValid());
+}
+
+BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
+{
+ // This test had non-deterministic coverage due to
+ // randomly selected seeds.
+ // This seed is chosen so that all branches of the function
+ // ecdsa_signature_parse_der_lax are executed during this test.
+ // Specifically branches that run only when an ECDSA
+ // signature's R and S values have leading zeros.
+ g_insecure_rand_ctx = FastRandomContext{uint256{33}};
+
+ TxOrphanageTest orphanage;
+ CKey key;
+ MakeNewKeyWithFastRandomContext(key);
+ FillableSigningProvider keystore;
+ BOOST_CHECK(keystore.AddKey(key));
+
+ LOCK(g_cs_orphans);
+
+ // 50 orphan transactions:
+ for (int i = 0; i < 50; i++)
+ {
+ CMutableTransaction tx;
+ tx.vin.resize(1);
+ tx.vin[0].prevout.n = 0;
+ tx.vin[0].prevout.hash = InsecureRand256();
+ tx.vin[0].scriptSig << OP_1;
+ tx.vout.resize(1);
+ tx.vout[0].nValue = 1*CENT;
+ tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
+
+ orphanage.AddTx(MakeTransactionRef(tx), i);
+ }
+
+ // ... and 50 that depend on other orphans:
+ for (int i = 0; i < 50; i++)
+ {
+ CTransactionRef txPrev = orphanage.RandomOrphan();
+
+ CMutableTransaction tx;
+ tx.vin.resize(1);
+ tx.vin[0].prevout.n = 0;
+ tx.vin[0].prevout.hash = txPrev->GetHash();
+ tx.vout.resize(1);
+ tx.vout[0].nValue = 1*CENT;
+ tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
+ BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL));
+
+ orphanage.AddTx(MakeTransactionRef(tx), i);
+ }
+
+ // This really-big orphan should be ignored:
+ for (int i = 0; i < 10; i++)
+ {
+ CTransactionRef txPrev = orphanage.RandomOrphan();
+
+ CMutableTransaction tx;
+ tx.vout.resize(1);
+ tx.vout[0].nValue = 1*CENT;
+ tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
+ tx.vin.resize(2777);
+ for (unsigned int j = 0; j < tx.vin.size(); j++)
+ {
+ tx.vin[j].prevout.n = j;
+ tx.vin[j].prevout.hash = txPrev->GetHash();
+ }
+ BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL));
+ // Re-use same signature for other inputs
+ // (they don't have to be valid for this test)
+ for (unsigned int j = 1; j < tx.vin.size(); j++)
+ tx.vin[j].scriptSig = tx.vin[0].scriptSig;
+
+ BOOST_CHECK(!orphanage.AddTx(MakeTransactionRef(tx), i));
+ }
+
+ // Test EraseOrphansFor:
+ for (NodeId i = 0; i < 3; i++)
+ {
+ size_t sizeBefore = orphanage.CountOrphans();
+ orphanage.EraseForPeer(i);
+ BOOST_CHECK(orphanage.CountOrphans() < sizeBefore);
+ }
+
+ // Test LimitOrphanTxSize() function:
+ orphanage.LimitOrphans(40);
+ BOOST_CHECK(orphanage.CountOrphans() <= 40);
+ orphanage.LimitOrphans(10);
+ BOOST_CHECK(orphanage.CountOrphans() <= 10);
+ orphanage.LimitOrphans(0);
+ BOOST_CHECK(orphanage.CountOrphans() == 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index a9d661438c..3cbbec92d6 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <arith_uint256.h>
#include <consensus/merkle.h>
#include <merkleblock.h>
#include <serialize.h>
@@ -107,13 +106,13 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
BOOST_AUTO_TEST_CASE(pmt_malleability)
{
- std::vector<uint256> vTxid = {
- ArithToUint256(1), ArithToUint256(2),
- ArithToUint256(3), ArithToUint256(4),
- ArithToUint256(5), ArithToUint256(6),
- ArithToUint256(7), ArithToUint256(8),
- ArithToUint256(9), ArithToUint256(10),
- ArithToUint256(9), ArithToUint256(10),
+ std::vector<uint256> vTxid{
+ uint256{1}, uint256{2},
+ uint256{3}, uint256{4},
+ uint256{5}, uint256{6},
+ uint256{7}, uint256{8},
+ uint256{9}, uint256{10},
+ uint256{9}, uint256{10},
};
std::vector<bool> vMatch = {false, false, false, false, false, false, false, false, false, true, true, false};
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 4fb7f9c405..df67841b66 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -31,8 +31,6 @@
#include <map>
#include <string>
-#include <boost/algorithm/string/classification.hpp>
-#include <boost/algorithm/string/split.hpp>
#include <boost/test/unit_test.hpp>
#include <univalue.h>
@@ -70,8 +68,7 @@ unsigned int ParseScriptFlags(std::string strFlags)
{
if (strFlags.empty() || strFlags == "NONE") return 0;
unsigned int flags = 0;
- std::vector<std::string> words;
- boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(","));
+ std::vector<std::string> words = SplitString(strFlags, ',');
for (const std::string& word : words)
{
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 13f17ca277..1830ec05af 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -180,6 +180,7 @@ ChainTestingSetup::~ChainTestingSetup()
m_node.connman.reset();
m_node.banman.reset();
m_node.addrman.reset();
+ m_node.netgroupman.reset();
m_node.args = nullptr;
WITH_LOCK(::cs_main, UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman));
m_node.mempool.reset();
@@ -223,11 +224,12 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));
}
- m_node.addrman = std::make_unique<AddrMan>(/*asmap=*/std::vector<bool>(),
+ m_node.netgroupman = std::make_unique<NetGroupManager>(/*asmap=*/std::vector<bool>());
+ m_node.addrman = std::make_unique<AddrMan>(*m_node.netgroupman,
/*deterministic=*/false,
m_node.args->GetIntArg("-checkaddrman", 0));
m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- m_node.connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
+ m_node.connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman); // Deterministic randomness for tests.
m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman,
m_node.banman.get(), *m_node.chainman,
*m_node.mempool, false);
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index b5d8411e1d..779ed20032 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -2349,6 +2349,55 @@ BOOST_AUTO_TEST_CASE(test_spanparsing)
BOOST_CHECK_EQUAL(SpanToStr(results[3]), "");
}
+BOOST_AUTO_TEST_CASE(test_SplitString)
+{
+ // Empty string.
+ {
+ std::vector<std::string> result = SplitString("", '-');
+ BOOST_CHECK_EQUAL(result.size(), 1);
+ BOOST_CHECK_EQUAL(result[0], "");
+ }
+
+ // Empty items.
+ {
+ std::vector<std::string> result = SplitString("-", '-');
+ BOOST_CHECK_EQUAL(result.size(), 2);
+ BOOST_CHECK_EQUAL(result[0], "");
+ BOOST_CHECK_EQUAL(result[1], "");
+ }
+
+ // More empty items.
+ {
+ std::vector<std::string> result = SplitString("--", '-');
+ BOOST_CHECK_EQUAL(result.size(), 3);
+ BOOST_CHECK_EQUAL(result[0], "");
+ BOOST_CHECK_EQUAL(result[1], "");
+ BOOST_CHECK_EQUAL(result[2], "");
+ }
+
+ // Separator is not present.
+ {
+ std::vector<std::string> result = SplitString("abc", '-');
+ BOOST_CHECK_EQUAL(result.size(), 1);
+ BOOST_CHECK_EQUAL(result[0], "abc");
+ }
+
+ // Basic behavior.
+ {
+ std::vector<std::string> result = SplitString("a-b", '-');
+ BOOST_CHECK_EQUAL(result.size(), 2);
+ BOOST_CHECK_EQUAL(result[0], "a");
+ BOOST_CHECK_EQUAL(result[1], "b");
+ }
+
+ // Case-sensitivity of the separator.
+ {
+ std::vector<std::string> result = SplitString("AAA", 'a');
+ BOOST_CHECK_EQUAL(result.size(), 1);
+ BOOST_CHECK_EQUAL(result[0], "AAA");
+ }
+}
+
BOOST_AUTO_TEST_CASE(test_LogEscapeMessage)
{
// ASCII and UTF-8 must pass through unaltered.
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index a15094e5c8..e2a7cb4066 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -24,9 +24,7 @@
#include <set>
#include <vector>
-#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
-#include <boost/algorithm/string/split.hpp>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
@@ -308,7 +306,7 @@ std::map<std::string,std::string> ParseTorReplyMapping(const std::string &s)
TorController::TorController(struct event_base* _base, const std::string& tor_control_center, const CService& target):
base(_base),
- m_tor_control_center(tor_control_center), conn(base), reconnect(true), reconnect_ev(0),
+ m_tor_control_center(tor_control_center), conn(base), reconnect(true), reconnect_ev(nullptr),
reconnect_timeout(RECONNECT_TIMEOUT_START),
m_target(target)
{
@@ -347,8 +345,8 @@ void TorController::get_socks_cb(TorControlConnection& _conn, const TorControlRe
for (const auto& line : reply.lines) {
if (0 == line.compare(0, 20, "net/listeners/socks=")) {
const std::string port_list_str = line.substr(20);
- std::vector<std::string> port_list;
- boost::split(port_list, port_list_str, boost::is_any_of(" "));
+ std::vector<std::string> port_list = SplitString(port_list_str, ' ');
+
for (auto& portstr : port_list) {
if (portstr.empty()) continue;
if ((portstr[0] == '"' || portstr[0] == '\'') && portstr.size() >= 2 && (*portstr.rbegin() == portstr[0])) {
@@ -542,8 +540,10 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
if (l.first == "AUTH") {
std::map<std::string,std::string> m = ParseTorReplyMapping(l.second);
std::map<std::string,std::string>::iterator i;
- if ((i = m.find("METHODS")) != m.end())
- boost::split(methods, i->second, boost::is_any_of(","));
+ if ((i = m.find("METHODS")) != m.end()) {
+ std::vector<std::string> m_vec = SplitString(i->second, ',');
+ methods = std::set<std::string>(m_vec.begin(), m_vec.end());
+ }
if ((i = m.find("COOKIEFILE")) != m.end())
cookiefile = i->second;
} else if (l.first == "VERSION") {
@@ -582,7 +582,7 @@ void TorController::protocolinfo_cb(TorControlConnection& _conn, const TorContro
// _conn.Command("AUTHENTICATE " + HexStr(status_cookie.second), std::bind(&TorController::auth_cb, this, std::placeholders::_1, std::placeholders::_2));
cookie = std::vector<uint8_t>(status_cookie.second.begin(), status_cookie.second.end());
clientNonce = std::vector<uint8_t>(TOR_NONCE_SIZE, 0);
- GetRandBytes(clientNonce.data(), TOR_NONCE_SIZE);
+ GetRandBytes(clientNonce);
_conn.Command("AUTHCHALLENGE SAFECOOKIE " + HexStr(clientNonce), std::bind(&TorController::authchallenge_cb, this, std::placeholders::_1, std::placeholders::_2));
} else {
if (status_cookie.first) {
diff --git a/src/util/bytevectorhash.cpp b/src/util/bytevectorhash.cpp
index f87d0e04b3..bc060a44c9 100644
--- a/src/util/bytevectorhash.cpp
+++ b/src/util/bytevectorhash.cpp
@@ -8,8 +8,8 @@
ByteVectorHash::ByteVectorHash()
{
- GetRandBytes(reinterpret_cast<unsigned char*>(&m_k0), sizeof(m_k0));
- GetRandBytes(reinterpret_cast<unsigned char*>(&m_k1), sizeof(m_k1));
+ GetRandBytes({reinterpret_cast<unsigned char*>(&m_k0), sizeof(m_k0)});
+ GetRandBytes({reinterpret_cast<unsigned char*>(&m_k1), sizeof(m_k1)});
}
size_t ByteVectorHash::operator()(const std::vector<unsigned char>& input) const
diff --git a/src/util/check.h b/src/util/check.h
index 4ee65c8d34..91d62e262d 100644
--- a/src/util/check.h
+++ b/src/util/check.h
@@ -18,8 +18,24 @@ class NonFatalCheckError : public std::runtime_error
using std::runtime_error::runtime_error;
};
+#define format_internal_error(msg, file, line, func, report) \
+ strprintf("Internal bug detected: \"%s\"\n%s:%d (%s)\nPlease report this issue here: %s\n", \
+ msg, file, line, func, report)
+
+/** Helper for CHECK_NONFATAL() */
+template <typename T>
+T&& inline_check_non_fatal(T&& val, const char* file, int line, const char* func, const char* assertion)
+{
+ if (!(val)) {
+ throw NonFatalCheckError(
+ format_internal_error(assertion, file, line, func, PACKAGE_BUGREPORT));
+ }
+
+ return std::forward<T>(val);
+}
+
/**
- * Throw a NonFatalCheckError when the condition evaluates to false
+ * Identity function. Throw a NonFatalCheckError when the condition evaluates to false
*
* This should only be used
* - where the condition is assumed to be true, not for error handling or validating user input
@@ -29,18 +45,8 @@ class NonFatalCheckError : public std::runtime_error
* asserts or recoverable logic errors. A NonFatalCheckError in RPC code is caught and passed as a string to the RPC
* caller, which can then report the issue to the developers.
*/
-#define CHECK_NONFATAL(condition) \
- do { \
- if (!(condition)) { \
- throw NonFatalCheckError( \
- strprintf("Internal bug detected: '%s'\n" \
- "%s:%d (%s)\n" \
- "You may report this issue here: %s\n", \
- (#condition), \
- __FILE__, __LINE__, __func__, \
- PACKAGE_BUGREPORT)); \
- } \
- } while (false)
+#define CHECK_NONFATAL(condition) \
+ inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition)
#if defined(NDEBUG)
#error "Cannot compile without assertions!"
@@ -80,4 +86,13 @@ T&& inline_assertion_check(T&& val, [[maybe_unused]] const char* file, [[maybe_u
*/
#define Assume(val) inline_assertion_check<false>(val, __FILE__, __LINE__, __func__, #val)
+/**
+ * NONFATAL_UNREACHABLE() is a macro that is used to mark unreachable code. It throws a NonFatalCheckError.
+ * This is used to mark code that is not yet implemented or is not yet reachable.
+ */
+#define NONFATAL_UNREACHABLE() \
+ throw NonFatalCheckError( \
+ format_internal_error("Unreachable code reached (non-fatal)", \
+ __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT))
+
#endif // BITCOIN_UTIL_CHECK_H
diff --git a/src/util/spanparsing.cpp b/src/util/spanparsing.cpp
index 50f6aee419..8614bd1176 100644
--- a/src/util/spanparsing.cpp
+++ b/src/util/spanparsing.cpp
@@ -48,20 +48,4 @@ Span<const char> Expr(Span<const char>& sp)
return ret;
}
-std::vector<Span<const char>> Split(const Span<const char>& sp, char sep)
-{
- std::vector<Span<const char>> ret;
- auto it = sp.begin();
- auto start = it;
- while (it != sp.end()) {
- if (*it == sep) {
- ret.emplace_back(start, it);
- start = it + 1;
- }
- ++it;
- }
- ret.emplace_back(start, it);
- return ret;
-}
-
} // namespace spanparsing
diff --git a/src/util/spanparsing.h b/src/util/spanparsing.h
index fa2e698e6d..ebec8714a7 100644
--- a/src/util/spanparsing.h
+++ b/src/util/spanparsing.h
@@ -43,7 +43,22 @@ Span<const char> Expr(Span<const char>& sp);
* Note that this function does not care about braces, so splitting
* "foo(bar(1),2),3) on ',' will return {"foo(bar(1)", "2)", "3)"}.
*/
-std::vector<Span<const char>> Split(const Span<const char>& sp, char sep);
+template <typename T = Span<const char>>
+std::vector<T> Split(const Span<const char>& sp, char sep)
+{
+ std::vector<T> ret;
+ auto it = sp.begin();
+ auto start = it;
+ while (it != sp.end()) {
+ if (*it == sep) {
+ ret.emplace_back(start, it);
+ start = it + 1;
+ }
+ ++it;
+ }
+ ret.emplace_back(start, it);
+ return ret;
+}
} // namespace spanparsing
diff --git a/src/util/string.h b/src/util/string.h
index a3b8df8d78..bcd6905fd5 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -6,6 +6,7 @@
#define BITCOIN_UTIL_STRING_H
#include <attributes.h>
+#include <util/spanparsing.h>
#include <algorithm>
#include <array>
@@ -15,6 +16,11 @@
#include <string>
#include <vector>
+[[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep)
+{
+ return spanparsing::Split<std::string>(str, sep);
+}
+
[[nodiscard]] inline std::string TrimString(const std::string& str, const std::string& pattern = " \f\n\r\t\v")
{
std::string::size_type front = str.find_first_not_of(pattern);
diff --git a/src/validation.cpp b/src/validation.cpp
index 58686632f9..3676316f76 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -19,7 +19,6 @@
#include <deploymentstatus.h>
#include <flatfile.h>
#include <hash.h>
-#include <index/blockfilterindex.h>
#include <logging.h>
#include <logging/timer.h>
#include <node/blockstorage.h>
@@ -106,6 +105,12 @@ const std::vector<std::string> CHECKLEVEL_DOC {
"level 4 tries to reconnect the blocks",
"each level includes the checks of the previous levels",
};
+/** The number of blocks to keep below the deepest prune lock.
+ * There is nothing special about this number. It is higher than what we
+ * expect to see in regular mainnet reorgs, but not so high that it would
+ * noticeably interfere with the pruning mechanism.
+ * */
+static constexpr int PRUNE_LOCK_BUFFER{10};
/**
* Mutex to guard access to validation specific variables, such as reading
@@ -2338,12 +2343,24 @@ bool CChainState::FlushStateToDisk(
CoinsCacheSizeState cache_state = GetCoinsCacheSizeState();
LOCK(m_blockman.cs_LastBlockFile);
if (fPruneMode && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && !fReindex) {
- // make sure we don't prune above the blockfilterindexes bestblocks
+ // make sure we don't prune above any of the prune locks bestblocks
// pruning is height-based
- int last_prune = m_chain.Height(); // last height we can prune
- ForEachBlockFilterIndex([&](BlockFilterIndex& index) {
- last_prune = std::max(1, std::min(last_prune, index.GetSummary().best_block_height));
- });
+ int last_prune{m_chain.Height()}; // last height we can prune
+ std::optional<std::string> limiting_lock; // prune lock that actually was the limiting factor, only used for logging
+
+ for (const auto& prune_lock : m_blockman.m_prune_locks) {
+ if (prune_lock.second.height_first == std::numeric_limits<int>::max()) continue;
+ // Remove the buffer and one additional block here to get actual height that is outside of the buffer
+ const int lock_height{prune_lock.second.height_first - PRUNE_LOCK_BUFFER - 1};
+ last_prune = std::max(1, std::min(last_prune, lock_height));
+ if (last_prune == lock_height) {
+ limiting_lock = prune_lock.first;
+ }
+ }
+
+ if (limiting_lock) {
+ LogPrint(BCLog::PRUNE, "%s limited pruning to height %d\n", limiting_lock.value(), last_prune);
+ }
if (nManualPruneHeight > 0) {
LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune (manual)", BCLog::BENCH);
@@ -2581,6 +2598,18 @@ bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTr
assert(flushed);
}
LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI);
+
+ {
+ // Prune locks that began at or after the tip should be moved backward so they get a chance to reorg
+ const int max_height_first{pindexDelete->nHeight - 1};
+ for (auto& prune_lock : m_blockman.m_prune_locks) {
+ if (prune_lock.second.height_first <= max_height_first) continue;
+
+ prune_lock.second.height_first = max_height_first;
+ LogPrint(BCLog::PRUNE, "%s prune lock moved back to %d\n", prune_lock.first, max_height_first);
+ }
+ }
+
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(state, FlushStateMode::IF_NEEDED)) {
return false;
diff --git a/src/validation.h b/src/validation.h
index 2e7ab42f88..38d3d98465 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -834,7 +834,6 @@ private:
bool m_snapshot_validated{false};
CBlockIndex* m_best_invalid;
- friend bool node::BlockManager::LoadBlockIndex(const Consensus::Params&);
//! Internal helper for ActivateSnapshot().
[[nodiscard]] bool PopulateAndValidateSnapshot(
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 0d0456af4b..7f709ffa3e 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -683,10 +683,10 @@ bool BerkeleyBatch::ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool&
// Convert to streams
ssKey.SetType(SER_DISK);
ssKey.clear();
- ssKey.write({BytePtr(datKey.get_data()), datKey.get_size()});
+ ssKey.write({AsBytePtr(datKey.get_data()), datKey.get_size()});
ssValue.SetType(SER_DISK);
ssValue.clear();
- ssValue.write({BytePtr(datValue.get_data()), datValue.get_size()});
+ ssValue.write({AsBytePtr(datValue.get_data()), datValue.get_size()});
return true;
}
@@ -758,7 +758,7 @@ bool BerkeleyBatch::ReadKey(CDataStream&& key, CDataStream& value)
SafeDbt datValue;
int ret = pdb->get(activeTxn, datKey, datValue, 0);
if (ret == 0 && datValue.get_data() != nullptr) {
- value.write({BytePtr(datValue.get_data()), datValue.get_size()});
+ value.write({AsBytePtr(datValue.get_data()), datValue.get_size()});
return true;
}
return false;
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index 433759e086..0b236e2e48 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -64,7 +64,7 @@ static const size_t TOTAL_TRIES = 100000;
std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change)
{
- SelectionResult result(selection_target);
+ SelectionResult result(selection_target, SelectionAlgorithm::BNB);
CAmount curr_value = 0;
std::vector<size_t> curr_selection; // selected utxo indexes
@@ -167,7 +167,7 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
std::optional<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utxo_pool, CAmount target_value, FastRandomContext& rng)
{
- SelectionResult result(target_value);
+ SelectionResult result(target_value, SelectionAlgorithm::SRD);
std::vector<size_t> indexes;
indexes.resize(utxo_pool.size());
@@ -249,7 +249,7 @@ static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::v
std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue,
CAmount change_target, FastRandomContext& rng)
{
- SelectionResult result(nTargetValue);
+ SelectionResult result(nTargetValue, SelectionAlgorithm::KNAPSACK);
// List of values less than target
std::optional<OutputGroup> lowest_larger;
@@ -460,4 +460,17 @@ std::string COutput::ToString() const
{
return strprintf("COutput(%s, %d, %d) [%s]", outpoint.hash.ToString(), outpoint.n, depth, FormatMoney(txout.nValue));
}
+
+std::string GetAlgorithmName(const SelectionAlgorithm algo)
+{
+ switch (algo)
+ {
+ case SelectionAlgorithm::BNB: return "bnb";
+ case SelectionAlgorithm::KNAPSACK: return "knapsack";
+ case SelectionAlgorithm::SRD: return "srd";
+ case SelectionAlgorithm::MANUAL: return "manual";
+ // No default case to allow for compiler to warn
+ }
+ assert(false);
+}
} // namespace wallet
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index c1484c0a57..25c672eda0 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -239,21 +239,34 @@ struct OutputGroup
*/
[[nodiscard]] CAmount GenerateChangeTarget(CAmount payment_value, FastRandomContext& rng);
+enum class SelectionAlgorithm : uint8_t
+{
+ BNB = 0,
+ KNAPSACK = 1,
+ SRD = 2,
+ MANUAL = 3,
+};
+
+std::string GetAlgorithmName(const SelectionAlgorithm algo);
+
struct SelectionResult
{
private:
/** Set of inputs selected by the algorithm to use in the transaction */
std::set<COutput> m_selected_inputs;
- /** The target the algorithm selected for. Note that this may not be equal to the recipient amount as it can include non-input fees */
- const CAmount m_target;
/** Whether the input values for calculations should be the effective value (true) or normal value (false) */
bool m_use_effective{false};
/** The computed waste */
std::optional<CAmount> m_waste;
public:
- explicit SelectionResult(const CAmount target)
- : m_target(target) {}
+ /** The target the algorithm selected for. Note that this may not be equal to the recipient amount as it can include non-input fees */
+ const CAmount m_target;
+ /** The algorithm used to produce this result */
+ const SelectionAlgorithm m_algo;
+
+ explicit SelectionResult(const CAmount target, SelectionAlgorithm algo)
+ : m_target(target), m_algo(algo) {}
SelectionResult() = delete;
diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp
index b048ddfc6e..b4f01b00de 100644
--- a/src/wallet/rpc/backup.cpp
+++ b/src/wallet/rpc/backup.cpp
@@ -26,8 +26,6 @@
#include <tuple>
#include <string>
-#include <boost/algorithm/string.hpp>
-
#include <univalue.h>
@@ -546,8 +544,7 @@ RPCHelpMan importwallet()
if (line.empty() || line[0] == '#')
continue;
- std::vector<std::string> vstr;
- boost::split(vstr, line, boost::is_any_of(" "));
+ std::vector<std::string> vstr = SplitString(line, ' ');
if (vstr.size() < 2)
continue;
CKey key = DecodeSecret(vstr[0]);
@@ -915,7 +912,7 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
case TxoutType::WITNESS_V1_TAPROOT:
return "unrecognized script";
} // no default case, so the compiler can warn about missing cases
- CHECK_NONFATAL(false);
+ NONFATAL_UNREACHABLE();
}
static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<CKeyID>& ordered_pubkeys)
@@ -1748,13 +1745,13 @@ RPCHelpMan listdescriptors()
{RPCResult::Type::OBJ, "", "", {
{RPCResult::Type::STR, "desc", "Descriptor string representation"},
{RPCResult::Type::NUM, "timestamp", "The creation time of the descriptor"},
- {RPCResult::Type::BOOL, "active", "Activeness flag"},
- {RPCResult::Type::BOOL, "internal", true, "Whether this is an internal or external descriptor; defined only for active descriptors"},
- {RPCResult::Type::ARR_FIXED, "range", true, "Defined only for ranged descriptors", {
+ {RPCResult::Type::BOOL, "active", "Whether this descriptor is currently used to generate new addresses"},
+ {RPCResult::Type::BOOL, "internal", /*optional=*/true, "True if this descriptor is used to generate change addresses. False if this descriptor is used to generate receiving addresses; defined only for active descriptors"},
+ {RPCResult::Type::ARR_FIXED, "range", /*optional=*/true, "Defined only for ranged descriptors", {
{RPCResult::Type::NUM, "", "Range start inclusive"},
{RPCResult::Type::NUM, "", "Range end inclusive"},
}},
- {RPCResult::Type::NUM, "next", true, "The next index to generate addresses from; defined only for ranged descriptors"},
+ {RPCResult::Type::NUM, "next", /*optional=*/true, "The next index to generate addresses from; defined only for ranged descriptors"},
}},
}}
}},
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 1291663847..efb4d8fc7e 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -664,79 +664,75 @@ RPCHelpMan abortrescan();
Span<const CRPCCommand> GetWalletRPCCommands()
{
-// clang-format off
-static const CRPCCommand commands[] =
-{ // category actor (function)
- // ------------------ ------------------------
- { "rawtransactions", &fundrawtransaction, },
- { "wallet", &abandontransaction, },
- { "wallet", &abortrescan, },
- { "wallet", &addmultisigaddress, },
- { "wallet", &backupwallet, },
- { "wallet", &bumpfee, },
- { "wallet", &psbtbumpfee, },
- { "wallet", &createwallet, },
- { "wallet", &restorewallet, },
- { "wallet", &dumpprivkey, },
- { "wallet", &dumpwallet, },
- { "wallet", &encryptwallet, },
- { "wallet", &getaddressesbylabel, },
- { "wallet", &getaddressinfo, },
- { "wallet", &getbalance, },
- { "wallet", &getnewaddress, },
- { "wallet", &getrawchangeaddress, },
- { "wallet", &getreceivedbyaddress, },
- { "wallet", &getreceivedbylabel, },
- { "wallet", &gettransaction, },
- { "wallet", &getunconfirmedbalance, },
- { "wallet", &getbalances, },
- { "wallet", &getwalletinfo, },
- { "wallet", &importaddress, },
- { "wallet", &importdescriptors, },
- { "wallet", &importmulti, },
- { "wallet", &importprivkey, },
- { "wallet", &importprunedfunds, },
- { "wallet", &importpubkey, },
- { "wallet", &importwallet, },
- { "wallet", &keypoolrefill, },
- { "wallet", &listaddressgroupings, },
- { "wallet", &listdescriptors, },
- { "wallet", &listlabels, },
- { "wallet", &listlockunspent, },
- { "wallet", &listreceivedbyaddress, },
- { "wallet", &listreceivedbylabel, },
- { "wallet", &listsinceblock, },
- { "wallet", &listtransactions, },
- { "wallet", &listunspent, },
- { "wallet", &listwalletdir, },
- { "wallet", &listwallets, },
- { "wallet", &loadwallet, },
- { "wallet", &lockunspent, },
- { "wallet", &newkeypool, },
- { "wallet", &removeprunedfunds, },
- { "wallet", &rescanblockchain, },
- { "wallet", &send, },
- { "wallet", &sendmany, },
- { "wallet", &sendtoaddress, },
- { "wallet", &sethdseed, },
- { "wallet", &setlabel, },
- { "wallet", &settxfee, },
- { "wallet", &setwalletflag, },
- { "wallet", &signmessage, },
- { "wallet", &signrawtransactionwithwallet, },
- { "wallet", &sendall, },
- { "wallet", &unloadwallet, },
- { "wallet", &upgradewallet, },
- { "wallet", &walletcreatefundedpsbt, },
+ static const CRPCCommand commands[]{
+ {"rawtransactions", &fundrawtransaction},
+ {"wallet", &abandontransaction},
+ {"wallet", &abortrescan},
+ {"wallet", &addmultisigaddress},
+ {"wallet", &backupwallet},
+ {"wallet", &bumpfee},
+ {"wallet", &psbtbumpfee},
+ {"wallet", &createwallet},
+ {"wallet", &restorewallet},
+ {"wallet", &dumpprivkey},
+ {"wallet", &dumpwallet},
+ {"wallet", &encryptwallet},
+ {"wallet", &getaddressesbylabel},
+ {"wallet", &getaddressinfo},
+ {"wallet", &getbalance},
+ {"wallet", &getnewaddress},
+ {"wallet", &getrawchangeaddress},
+ {"wallet", &getreceivedbyaddress},
+ {"wallet", &getreceivedbylabel},
+ {"wallet", &gettransaction},
+ {"wallet", &getunconfirmedbalance},
+ {"wallet", &getbalances},
+ {"wallet", &getwalletinfo},
+ {"wallet", &importaddress},
+ {"wallet", &importdescriptors},
+ {"wallet", &importmulti},
+ {"wallet", &importprivkey},
+ {"wallet", &importprunedfunds},
+ {"wallet", &importpubkey},
+ {"wallet", &importwallet},
+ {"wallet", &keypoolrefill},
+ {"wallet", &listaddressgroupings},
+ {"wallet", &listdescriptors},
+ {"wallet", &listlabels},
+ {"wallet", &listlockunspent},
+ {"wallet", &listreceivedbyaddress},
+ {"wallet", &listreceivedbylabel},
+ {"wallet", &listsinceblock},
+ {"wallet", &listtransactions},
+ {"wallet", &listunspent},
+ {"wallet", &listwalletdir},
+ {"wallet", &listwallets},
+ {"wallet", &loadwallet},
+ {"wallet", &lockunspent},
+ {"wallet", &newkeypool},
+ {"wallet", &removeprunedfunds},
+ {"wallet", &rescanblockchain},
+ {"wallet", &send},
+ {"wallet", &sendmany},
+ {"wallet", &sendtoaddress},
+ {"wallet", &sethdseed},
+ {"wallet", &setlabel},
+ {"wallet", &settxfee},
+ {"wallet", &setwalletflag},
+ {"wallet", &signmessage},
+ {"wallet", &signrawtransactionwithwallet},
+ {"wallet", &sendall},
+ {"wallet", &unloadwallet},
+ {"wallet", &upgradewallet},
+ {"wallet", &walletcreatefundedpsbt},
#ifdef ENABLE_EXTERNAL_SIGNER
- { "wallet", &walletdisplayaddress, },
+ {"wallet", &walletdisplayaddress},
#endif // ENABLE_EXTERNAL_SIGNER
- { "wallet", &walletlock, },
- { "wallet", &walletpassphrase, },
- { "wallet", &walletpassphrasechange, },
- { "wallet", &walletprocesspsbt, },
-};
-// clang-format on
+ {"wallet", &walletlock},
+ {"wallet", &walletpassphrase},
+ {"wallet", &walletpassphrasechange},
+ {"wallet", &walletprocesspsbt},
+ };
return commands;
}
} // namespace wallet
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 9e508f3a32..55c0a2cb7f 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -11,6 +11,7 @@
#include <util/fees.h>
#include <util/moneystr.h>
#include <util/rbf.h>
+#include <util/trace.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/fees.h>
@@ -435,9 +436,10 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
*/
preset_inputs.Insert(out, /*ancestors=*/ 0, /*descendants=*/ 0, /*positive_only=*/ false);
}
- SelectionResult result(nTargetValue);
+ SelectionResult result(nTargetValue, SelectionAlgorithm::MANUAL);
result.AddInput(preset_inputs);
if (result.GetSelectedValue() < nTargetValue) return std::nullopt;
+ result.ComputeAndSetWaste(coin_selection_params.m_cost_of_change);
return result;
}
@@ -519,7 +521,7 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
// permissive CoinEligibilityFilter.
std::optional<SelectionResult> res = [&] {
// Pre-selected inputs already cover the target amount.
- if (value_to_select <= 0) return std::make_optional(SelectionResult(nTargetValue));
+ if (value_to_select <= 0) return std::make_optional(SelectionResult(nTargetValue, SelectionAlgorithm::MANUAL));
// If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
// confirmations on outputs received from other wallets and only spend confirmed change.
@@ -573,6 +575,9 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
// Add preset inputs to result
res->AddInput(preset_inputs);
+ if (res->m_algo == SelectionAlgorithm::MANUAL) {
+ res->ComputeAndSetWaste(coin_selection_params.m_cost_of_change);
+ }
return res;
}
@@ -788,6 +793,7 @@ static bool CreateTransactionInternal(
error = _("Insufficient funds");
return false;
}
+ TRACE5(coin_selection, selected_coins, wallet.GetName().c_str(), GetAlgorithmName(result->m_algo).c_str(), result->m_target, result->GetWaste(), result->GetSelectedValue());
// Always make a change output
// We will reduce the fee from this change output later, and remove the output if it is too small.
@@ -978,8 +984,10 @@ bool CreateTransaction(
int nChangePosIn = nChangePosInOut;
Assert(!tx); // tx is an out-param. TODO change the return type from bool to tx (or nullptr)
bool res = CreateTransactionInternal(wallet, vecSend, tx, nFeeRet, nChangePosInOut, error, coin_control, fee_calc_out, sign);
+ TRACE4(coin_selection, normal_create_tx_internal, wallet.GetName().c_str(), res, nFeeRet, nChangePosInOut);
// try with avoidpartialspends unless it's enabled already
if (res && nFeeRet > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends) {
+ TRACE1(coin_selection, attempting_aps_create_tx, wallet.GetName().c_str());
CCoinControl tmp_cc = coin_control;
tmp_cc.m_avoid_partial_spends = true;
CAmount nFeeRet2;
@@ -990,6 +998,7 @@ bool CreateTransaction(
// if fee of this alternative one is within the range of the max fee, we use this one
const bool use_aps = nFeeRet2 <= nFeeRet + wallet.m_max_aps_fee;
wallet.WalletLogPrintf("Fee non-grouped = %lld, grouped = %lld, using %s\n", nFeeRet, nFeeRet2, use_aps ? "grouped" : "non-grouped");
+ TRACE5(coin_selection, aps_create_tx_internal, wallet.GetName().c_str(), use_aps, res, nFeeRet2, nChangePosInOut2);
if (use_aps) {
tx = tx2;
nFeeRet = nFeeRet2;
diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp
index 3f860289f9..2515df3177 100644
--- a/src/wallet/sqlite.cpp
+++ b/src/wallet/sqlite.cpp
@@ -405,7 +405,7 @@ bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value)
return false;
}
// Leftmost column in result is index 0
- const std::byte* data{BytePtr(sqlite3_column_blob(m_read_stmt, 0))};
+ const std::byte* data{AsBytePtr(sqlite3_column_blob(m_read_stmt, 0))};
size_t data_size(sqlite3_column_bytes(m_read_stmt, 0));
value.write({data, data_size});
@@ -497,10 +497,10 @@ bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& compl
}
// Leftmost column in result is index 0
- const std::byte* key_data{BytePtr(sqlite3_column_blob(m_cursor_stmt, 0))};
+ const std::byte* key_data{AsBytePtr(sqlite3_column_blob(m_cursor_stmt, 0))};
size_t key_data_size(sqlite3_column_bytes(m_cursor_stmt, 0));
key.write({key_data, key_data_size});
- const std::byte* value_data{BytePtr(sqlite3_column_blob(m_cursor_stmt, 1))};
+ const std::byte* value_data{AsBytePtr(sqlite3_column_blob(m_cursor_stmt, 1))};
size_t value_data_size(sqlite3_column_bytes(m_cursor_stmt, 1));
value.write({value_data, value_data_size});
return true;
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 2a08c8ab57..72e749477b 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
FastRandomContext rand{};
// Setup
std::vector<COutput> utxo_pool;
- SelectionResult expected_result(CAmount(0));
+ SelectionResult expected_result(CAmount(0), SelectionAlgorithm::BNB);
/////////////////////////
// Known Outcome tests //
diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp
index 166e27bab9..327c28412a 100644
--- a/src/wallet/test/wallet_crypto_tests.cpp
+++ b/src/wallet/test/wallet_crypto_tests.cpp
@@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(passphrase) {
std::string hash(GetRandHash().ToString());
std::vector<unsigned char> vchSalt(8);
- GetRandBytes(vchSalt.data(), vchSalt.size());
+ GetRandBytes(vchSalt);
uint32_t rounds = InsecureRand32();
if (rounds > 30000)
rounds = 30000;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index c3ae098aee..489599e2a0 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -682,12 +682,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
CKeyingMaterial _vMasterKey;
_vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
- GetStrongRandBytes(_vMasterKey.data(), WALLET_CRYPTO_KEY_SIZE);
+ GetStrongRandBytes(_vMasterKey);
CMasterKey kMasterKey;
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
- GetStrongRandBytes(kMasterKey.vchSalt.data(), WALLET_CRYPTO_SALT_SIZE);
+ GetStrongRandBytes(kMasterKey.vchSalt);
CCrypter crypter;
int64_t nStartTime = GetTimeMillis();
@@ -2768,7 +2768,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
// Make it impossible to disable private keys after creation
error = strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile);
- return NULL;
+ return nullptr;
} else if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (spk_man->HavePrivateKeys()) {
diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp
index f9f8b5a9dc..ec6d1cbba3 100644
--- a/src/zmq/zmqrpc.cpp
+++ b/src/zmq/zmqrpc.cpp
@@ -51,10 +51,8 @@ static RPCHelpMan getzmqnotifications()
};
}
-const CRPCCommand commands[] =
-{ // category actor (function)
- // ----------------- -----------------------
- { "zmq", &getzmqnotifications, },
+const CRPCCommand commands[]{
+ {"zmq", &getzmqnotifications},
};
} // anonymous namespace