mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
Merge #6097: backport: merge bitcoin#24024, #23880, #24909, #24178, #24171, #25404, #25514, #25720, partial bitcoin#23832, #24169, #25454 (headers backports)
c92b0f57da
merge bitcoin#25720: Reduce bandwidth during initial headers sync when a block is found (Kittywhiskers Van Gogh)0f9ece0ed9
merge bitcoin#25514: Move CNode::nServices and CNode::nLocalServices to Peer (Kittywhiskers Van Gogh)c9923ca36b
partial bitcoin#25454: Avoid multiple getheaders messages in flight to the same peer (Kittywhiskers Van Gogh)26d477b6ae
revert: Fix duplicate initial headers sync (Kittywhiskers Van Gogh)abccb2dd03
test: drop genesis block from `blockheader_testnet3` (Kittywhiskers Van Gogh)0574a7d19e
merge bitcoin#25404: Use MAX_BLOCKS_TO_ANNOUNCE consistently (Kittywhiskers Van Gogh)ed871d2a07
merge bitcoin#24171: Sync chain more readily from inbound peers during IBD (Kittywhiskers Van Gogh)a04290fc5c
merge bitcoin#24178: Respond to getheaders if we have sufficient chainwork (Kittywhiskers Van Gogh)bcafa282a3
merge bitcoin#24909: Move and rename pindexBestHeader, fHavePruned (Kittywhiskers Van Gogh)70485cb2f5
partial bitcoin#24169: Add --enable-c++20 option (Kittywhiskers Van Gogh)27e885de5f
merge bitcoin#23880: Serialize cmpctblock at most once in NewPoWValidBlock (Kittywhiskers Van Gogh)9f7ac69a7e
merge bitcoin#24024: Remove cs_main lock annotation from ChainstateManager.m_blockman (Kittywhiskers Van Gogh)9399f90a13
partial bitcoin#23832: Changes time variables from int to chrono (Kittywhiskers Van Gogh) Pull request description: ## Additional Information * Dependent on https://github.com/dashpay/dash/pull/6085 * Dependency for https://github.com/dashpay/dash/pull/6098 * ~~[bitcoin#25514](https://github.com/bitcoin/bitcoin/pull/25514) removes `peers.spvNodeConnections` and `peers.fullNodeConnections` reporting from `CalculateNumConnectionsChangedStats` as the services flags used to distingush between the two have been moved to the `Peer` struct, accessable only through `PeerManager`.~~ ~~As `PeerManager` isn't accessable to `CConnman`, even if a new public function was exposed through `PeerManger` (as we have for `IsInvInFilter` and others or we try to access the value through `GetNodeStateStats`), `CConnman` would be unable to leverage it.~~ Resolved with patch by UdjinM6, thanks! * [bitcoin#23880](https://github.com/bitcoin/bitcoin/pull/23880) introduces code that is not valid C++20 (but valid C++17) and therefore, required a partial backport of [bitcoin#24169](https://github.com/bitcoin/bitcoin/pull/24169) (fae679065e4ef0c6383bbdd1876aaed6c1e40104) to make the code C++20 legal. * [bitcoin#25454](https://github.com/bitcoin/bitcoin/pull/25454) introduces a 10-point penalty for remitting more than `MAX_BLOCKS_TO_ANNOUNCE` unconnected block headers. `blockheader_testnet3.hex` (introduced in [bitcoin#16551](https://github.com/bitcoin/bitcoin/pull/16551), part of [dash#5963](https://github.com/dashpay/dash/pull/5963)), unlike in Bitcoin, includes the genesis block. By definition of a genesis block, there is no block before it that connects to, which causes the 10-point penalty to trip and `p2p_dos_header_tree.py` to fail (see below). This has been remedied by removing the genesis block from the test data to match upstream and also because no node has a good reason to ever broadcast the genesis block as-is over P2P. <details> <summary>Test Failure</summary> ``` dash@6a2649cc721f:/src/dash$ ./test/functional/p2p_dos_header_tree.py 2024-06-17T17:59:35.874000Z TestFramework (INFO): Initializing test directory /tmp/dash_func_test_h5hfluy1 2024-06-17T17:59:36.892000Z TestFramework (INFO): Read headers data 2024-06-17T17:59:36.895000Z TestFramework (INFO): Feed all non-fork headers, including and up to the first checkpoint 2024-06-17T17:59:38.411000Z TestFramework (ERROR): Assertion failed Traceback (most recent call last): File "/src/dash/test/functional/test_framework/test_framework.py", line 158, in main self.run_test() File "./test/functional/p2p_dos_header_tree.py", line 53, in run_test assert { AssertionError 2024-06-17T17:59:38.913000Z TestFramework (INFO): Stopping nodes 2024-06-17T17:59:39.917000Z TestFramework (WARNING): Not cleaning up dir /tmp/dash_func_test_h5hfluy1 2024-06-17T17:59:39.917000Z TestFramework (ERROR): Test failed. Test logging available at /tmp/dash_func_test_h5hfluy1/test_framework.log 2024-06-17T17:59:39.917000Z TestFramework (ERROR): 2024-06-17T17:59:39.917000Z TestFramework (ERROR): Hint: Call /src/dash/test/functional/combine_logs.py '/tmp/dash_func_test_h5hfluy1' to consolidate all logs 2024-06-17T17:59:39.917000Z TestFramework (ERROR): 2024-06-17T17:59:39.917000Z TestFramework (ERROR): If this failure happened unexpectedly or intermittently, please file a bug and provide a link or upload of the combined log. 2024-06-17T17:59:39.917000Z TestFramework (ERROR): https://github.com/dashpay/dash/issues 2024-06-17T17:59:39.917000Z TestFramework (ERROR): ``` </details> * [bitcoin#25454](https://github.com/bitcoin/bitcoin/pull/25454) has a goal similar to [dash#2032](https://github.com/dashpay/dash/pull/2032) (and its predecessor, [dash#1589](https://github.com/dashpay/dash/pull/1589)), namely, avoiding `getheaders`(`2`) duplication to the same peer. Unfortunately, Dash's mitigation seems to conflict with Bitcoin's mitigation and this results in `feature_minchainwork.py` failing (see below). This has been remedied by partially reverting [dash#2032](https://github.com/dashpay/dash/pull/2032). <details> <summary>Test Failure</summary> ``` dash@1bebec413839:/src/dash$ ./test/functional/feature_minchainwork.py 2024-08-01T17:29:41.116000Z TestFramework (INFO): Initializing test directory /tmp/dash_func_test_co8xkx43 2024-08-01T17:29:42.145000Z TestFramework (INFO): Testing relay across node 1 (minChainWork = 101) 2024-08-01T17:29:42.145000Z TestFramework (INFO): Generating 49 blocks on node0 [...] 2024-08-01T17:29:51.707000Z TestFramework (INFO): Generating one more block 2024-08-01T17:29:51.709000Z TestFramework (INFO): Verifying nodes are all synced 2024-08-01T17:30:51.989000Z TestFramework (ERROR): Assertion failed Traceback (most recent call last): File "/src/dash/test/functional/test_framework/test_framework.py", line 159, in main self.run_test() File "./test/functional/feature_minchainwork.py", line 101, in run_test self.sync_all() File "/src/dash/test/functional/test_framework/test_framework.py", line 811, in sync_all self.sync_blocks(nodes) File "/src/dash/test/functional/test_framework/test_framework.py", line 777, in sync_blocks raise AssertionError("Block sync timed out after {}s:{}".format( AssertionError: Block sync timed out after 60s: '00ab061e30aebd2f97153d26cd72f921af896f05c6469ad73c7de4fc283d9590' '00ab061e30aebd2f97153d26cd72f921af896f05c6469ad73c7de4fc283d9590' '000008ca1832a4baf228eb1553c03d3a2c8e02399550dd6ea8d65cec3ef23d2e' 2024-08-01T17:30:52.490000Z TestFramework (INFO): Stopping nodes 2024-08-01T17:30:53.495000Z TestFramework (WARNING): Not cleaning up dir /tmp/dash_func_test_co8xkx43 2024-08-01T17:30:53.495000Z TestFramework (ERROR): Test failed. Test logging available at /tmp/dash_func_test_co8xkx43/test_framework.log 2024-08-01T17:30:53.495000Z TestFramework (ERROR): 2024-08-01T17:30:53.495000Z TestFramework (ERROR): Hint: Call /src/dash/test/functional/combine_logs.py '/tmp/dash_func_test_co8xkx43' to consolidate all logs 2024-08-01T17:30:53.495000Z TestFramework (ERROR): 2024-08-01T17:30:53.495000Z TestFramework (ERROR): If this failure happened unexpectedly or intermittently, please file a bug and provide a link or upload of the combined log. 2024-08-01T17:30:53.495000Z TestFramework (ERROR): https://github.com/dashpay/dash/issues 2024-08-01T17:30:53.495000Z TestFramework (ERROR): ``` </details> * [bitcoin#25720](https://github.com/bitcoin/bitcoin/pull/25720) introduces a new test, `p2p_initial_headers_sync.py`, to validate that when a client has a stale tip, it will only engage in headers sync with one peer (emit a `getheaders2`\* message). Unmodified, this test fails (see below) as while the backport deals with one source of `getheaders2` messages, the test setup unwittingly triggers another ([source](2379462294/src/net_processing.cpp (L5446-L5448)
)), specifically, allowing the `pindexBestHeader->GetBlockTime() > GetAdjustedTime() - nMaxTipAge` condition to evaluate `true`. This is because, unlike in Bitcoin test suite's `setup_chain()` ([source](22d96d76ab/test/functional/test_framework/test_framework.py (L379-L385)
)), Dash sets the mocktime to match the mock chain ([source](2379462294/test/functional/test_framework/test_framework.py (L408-L416)
)) during setup, while the test assumes that the mock chain is stale enough to not trigger this source of `getheaders2` messages. As the tip is barely stale, it emits the `getheaders2` message, which is detected, causing the test to fail. This has been remedied by overriding `setup_chain()` to behave more like Bitcoin's test suite. _\* - `getheaders2` is a Dash-specific message that is courtesy of compressed headers, Bitcoin would be checking for `getheaders`_ <details> <summary>Test Failure</summary> ``` dash@6a2649cc721f:/src/dash$ ./test/functional/p2p_initial_headers_sync.py 2024-06-17T21:24:09.921000Z TestFramework (INFO): Initializing test directory /tmp/dash_func_test_3gypo3ab 2024-06-17T21:24:10.681000Z TestFramework (INFO): Adding a peer to node0 2024-06-17T21:24:11.684000Z TestFramework (INFO): Connecting two more peers to node0 2024-06-17T21:24:13.689000Z TestFramework (INFO): Verify that peer2 and peer3 don't receive a getheaders after connecting 2024-06-17T21:24:15.193000Z TestFramework (ERROR): Assertion failed Traceback (most recent call last): File "/src/dash/test/functional/test_framework/test_framework.py", line 158, in main self.run_test() File "./test/functional/p2p_initial_headers_sync.py", line 60, in run_test assert "getheaders2" not in peer2.last_message AssertionError 2024-06-17T21:24:15.695000Z TestFramework (INFO): Stopping nodes 2024-06-17T21:24:16.698000Z TestFramework (WARNING): Not cleaning up dir /tmp/dash_func_test_3gypo3ab 2024-06-17T21:24:16.698000Z TestFramework (ERROR): Test failed. Test logging available at /tmp/dash_func_test_3gypo3ab/test_framework.log 2024-06-17T21:24:16.699000Z TestFramework (ERROR): 2024-06-17T21:24:16.699000Z TestFramework (ERROR): Hint: Call /src/dash/test/functional/combine_logs.py '/tmp/dash_func_test_3gypo3ab' to consolidate all logs 2024-06-17T21:24:16.699000Z TestFramework (ERROR): 2024-06-17T21:24:16.699000Z TestFramework (ERROR): If this failure happened unexpectedly or intermittently, please file a bug and provide a link or upload of the combined log. 2024-06-17T21:24:16.699000Z TestFramework (ERROR): https://github.com/dashpay/dash/issues 2024-06-17T21:24:16.699000Z TestFramework (ERROR): ``` </details> ## Checklist: - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have added or updated relevant unit/integration/functional/e2e tests - [x] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ Top commit has no ACKs. Tree-SHA512: 16b7c42195e197e8b6800c3425b4ff15a124b0e3e0da5c98ca6e22486b52c4ea82f2f05b83e28e838860b1ce76daa1e435c5eae4fb7591a161f26a5fff6189cc
This commit is contained in:
commit
117dda9d6f
@ -45,7 +45,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench)
|
||||
TestBlockAndIndex data;
|
||||
const LLMQContext& llmq_ctx = *data.testing_setup->m_node.llmq_ctx;
|
||||
bench.run([&] {
|
||||
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, /*verbose*/ true);
|
||||
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, /*verbose*/ true);
|
||||
ankerl::nanobench::doNotOptimizeAway(univalue);
|
||||
});
|
||||
}
|
||||
@ -56,7 +56,7 @@ static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
|
||||
{
|
||||
TestBlockAndIndex data;
|
||||
const LLMQContext& llmq_ctx = *data.testing_setup->m_node.llmq_ctx;
|
||||
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, /*verbose*/ true);
|
||||
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, /*verbose*/ true);
|
||||
bench.run([&] {
|
||||
auto str = univalue.write();
|
||||
ankerl::nanobench::doNotOptimizeAway(str);
|
||||
|
@ -79,7 +79,7 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con
|
||||
if (pindexNew == pindexFork) // blocks were disconnected without any new ones
|
||||
return;
|
||||
|
||||
m_mn_sync.UpdatedBlockTip(pindexNew, fInitialDownload);
|
||||
m_mn_sync.UpdatedBlockTip(m_chainman.m_best_header, pindexNew, fInitialDownload);
|
||||
|
||||
// Update global DIP0001 activation status
|
||||
fDIP0001ActiveAtTip = pindexNew->nHeight >= Params().GetConsensus().DIP0001Height;
|
||||
|
@ -60,7 +60,7 @@ void CMNAuth::PushMNAUTH(CNode& peer, CConnman& connman, const CActiveMasternode
|
||||
connman.PushMessage(&peer, CNetMsgMaker(peer.GetCommonVersion()).Make(NetMsgType::MNAUTH, mnauth));
|
||||
}
|
||||
|
||||
PeerMsgRet CMNAuth::ProcessMessage(CNode& peer, CConnman& connman, CMasternodeMetaMan& mn_metaman, const CActiveMasternodeManager* const mn_activeman,
|
||||
PeerMsgRet CMNAuth::ProcessMessage(CNode& peer, ServiceFlags node_services, CConnman& connman, CMasternodeMetaMan& mn_metaman, const CActiveMasternodeManager* const mn_activeman,
|
||||
const CChain& active_chain, const CMasternodeSync& mn_sync, const CDeterministicMNList& tip_mn_list,
|
||||
std::string_view msg_type, CDataStream& vRecv)
|
||||
{
|
||||
@ -79,7 +79,7 @@ PeerMsgRet CMNAuth::ProcessMessage(CNode& peer, CConnman& connman, CMasternodeMe
|
||||
return tl::unexpected{MisbehavingError{100, "duplicate mnauth"}};
|
||||
}
|
||||
|
||||
if ((~peer.nServices) & (NODE_NETWORK | NODE_BLOOM)) {
|
||||
if ((~node_services) & (NODE_NETWORK | NODE_BLOOM)) {
|
||||
// either NODE_NETWORK or NODE_BLOOM bit is missing in node's services
|
||||
return tl::unexpected{MisbehavingError{100, "mnauth from a node with invalid services"}};
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ class CNode;
|
||||
|
||||
class UniValue;
|
||||
|
||||
enum ServiceFlags : uint64_t;
|
||||
|
||||
/**
|
||||
* This class handles the p2p message MNAUTH. MNAUTH is sent directly after VERACK and authenticates the sender as a
|
||||
* masternode. It is only sent when the sender is actually a masternode.
|
||||
@ -59,7 +61,7 @@ public:
|
||||
* @pre CMasternodeMetaMan's database must be successfully loaded before
|
||||
* attempting to call this function regardless of sync state
|
||||
*/
|
||||
static PeerMsgRet ProcessMessage(CNode& peer, CConnman& connman, CMasternodeMetaMan& mn_metaman, const CActiveMasternodeManager* const mn_activeman,
|
||||
static PeerMsgRet ProcessMessage(CNode& peer, ServiceFlags node_services, CConnman& connman, CMasternodeMetaMan& mn_metaman, const CActiveMasternodeManager* const mn_activeman,
|
||||
const CChain& active_chain, const CMasternodeSync& mn_sync, const CDeterministicMNList& tip_mn_list,
|
||||
std::string_view msg_type, CDataStream& vRecv);
|
||||
static void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman);
|
||||
|
12
src/init.cpp
12
src/init.cpp
@ -1890,7 +1890,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||
|
||||
if (ShutdownRequested()) break;
|
||||
|
||||
// LoadBlockIndex will load fHavePruned if we've ever removed a
|
||||
// LoadBlockIndex will load m_have_pruned if we've ever removed a
|
||||
// block file from disk.
|
||||
// Note that it also sets fReindex based on the disk flag!
|
||||
// From here on out fReindex and fReset mean something different!
|
||||
@ -1936,7 +1936,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||
|
||||
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
|
||||
// in the past, but is now trying to run unpruned.
|
||||
if (fHavePruned && !fPruneMode) {
|
||||
if (chainman.m_blockman.m_have_pruned && !fPruneMode) {
|
||||
strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
|
||||
break;
|
||||
}
|
||||
@ -2022,7 +2022,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||
for (CChainState* chainstate : chainman.GetAll()) {
|
||||
if (!is_coinsview_empty(chainstate)) {
|
||||
uiInterface.InitMessage(_("Verifying blocks…").translated);
|
||||
if (fHavePruned && args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
|
||||
if (chainman.m_blockman.m_have_pruned && args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
|
||||
LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n",
|
||||
MIN_BLOCKS_TO_KEEP);
|
||||
}
|
||||
@ -2328,9 +2328,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||
tip_info->block_hash = chainman.ActiveChain().Tip() ? chainman.ActiveChain().Tip()->GetBlockHash() : Params().GenesisBlock().GetHash();
|
||||
tip_info->verification_progress = GuessVerificationProgress(Params().TxData(), chainman.ActiveChain().Tip());
|
||||
}
|
||||
if (tip_info && ::pindexBestHeader) {
|
||||
tip_info->header_height = ::pindexBestHeader->nHeight;
|
||||
tip_info->header_time = ::pindexBestHeader->GetBlockTime();
|
||||
if (tip_info && chainman.m_best_header) {
|
||||
tip_info->header_height = chainman.m_best_header->nHeight;
|
||||
tip_info->header_time = chainman.m_best_header->GetBlockTime();
|
||||
}
|
||||
}
|
||||
LogPrintf("nBestHeight = %d\n", chain_active_height);
|
||||
|
@ -329,7 +329,7 @@ void CMasternodeSync::NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitia
|
||||
}
|
||||
}
|
||||
|
||||
void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload)
|
||||
void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindexTip, const CBlockIndex *pindexNew, bool fInitialDownload)
|
||||
{
|
||||
LogPrint(BCLog::MNSYNC, "CMasternodeSync::UpdatedBlockTip -- pindexNew->nHeight: %d fInitialDownload=%d\n", pindexNew->nHeight, fInitialDownload);
|
||||
nTimeLastUpdateBlockTip = GetTime<std::chrono::seconds>().count();
|
||||
@ -353,7 +353,6 @@ void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitia
|
||||
}
|
||||
|
||||
// Note: since we sync headers first, it should be ok to use this
|
||||
CBlockIndex* pindexTip = WITH_LOCK(cs_main, return pindexBestHeader);
|
||||
if (pindexTip == nullptr) return;
|
||||
bool fReachedBestHeaderNew = pindexNew->GetBlockHash() == pindexTip->GetBlockHash();
|
||||
|
||||
|
@ -75,7 +75,7 @@ public:
|
||||
|
||||
void AcceptedBlockHeader(const CBlockIndex *pindexNew);
|
||||
void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload);
|
||||
void UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload);
|
||||
void UpdatedBlockTip(const CBlockIndex *pindexTip, const CBlockIndex *pindexNew, bool fInitialDownload);
|
||||
|
||||
void DoMaintenance();
|
||||
};
|
||||
|
42
src/net.cpp
42
src/net.cpp
@ -230,15 +230,13 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
|
||||
// Otherwise, return the unroutable 0.0.0.0 but filled in with
|
||||
// the normal parameters, since the IP may be changed to a useful
|
||||
// one by discovery.
|
||||
CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
|
||||
CService GetLocalAddress(const CNetAddr& addrPeer)
|
||||
{
|
||||
CAddress ret(CService(CNetAddr(),GetListenPort()), nLocalServices);
|
||||
CService ret{CNetAddr(), GetListenPort()};
|
||||
CService addr;
|
||||
if (GetLocal(addr, paddrPeer))
|
||||
{
|
||||
ret = CAddress(addr, nLocalServices);
|
||||
if (GetLocal(addr, &addrPeer)) {
|
||||
ret = CService{addr};
|
||||
}
|
||||
ret.nTime = GetAdjustedTime();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -257,35 +255,35 @@ bool IsPeerAddrLocalGood(CNode *pnode)
|
||||
IsReachable(addrLocal.GetNetwork());
|
||||
}
|
||||
|
||||
std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
|
||||
std::optional<CService> GetLocalAddrForPeer(CNode& node)
|
||||
{
|
||||
CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices());
|
||||
CService addrLocal{GetLocalAddress(node.addr)};
|
||||
if (gArgs.GetBoolArg("-addrmantest", false)) {
|
||||
// use IPv4 loopback during addrmantest
|
||||
addrLocal = CAddress(CService(LookupNumeric("127.0.0.1", GetListenPort())), pnode->GetLocalServices());
|
||||
addrLocal = CService(LookupNumeric("127.0.0.1", GetListenPort()));
|
||||
}
|
||||
// If discovery is enabled, sometimes give our peer the address it
|
||||
// tells us that it sees us as in case it has a better idea of our
|
||||
// address than we do.
|
||||
FastRandomContext rng;
|
||||
if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
|
||||
if (IsPeerAddrLocalGood(&node) && (!addrLocal.IsRoutable() ||
|
||||
rng.randbits((GetnScore(addrLocal) > LOCAL_MANUAL) ? 3 : 1) == 0))
|
||||
{
|
||||
if (pnode->IsInboundConn()) {
|
||||
if (node.IsInboundConn()) {
|
||||
// For inbound connections, assume both the address and the port
|
||||
// as seen from the peer.
|
||||
addrLocal = CAddress{pnode->GetAddrLocal(), addrLocal.nServices, addrLocal.nTime};
|
||||
addrLocal = CService{node.GetAddrLocal()};
|
||||
} else {
|
||||
// For outbound connections, assume just the address as seen from
|
||||
// the peer and leave the port in `addrLocal` as returned by
|
||||
// `GetLocalAddress()` above. The peer has no way to observe our
|
||||
// listening port when we have initiated the connection.
|
||||
addrLocal.SetIP(pnode->GetAddrLocal());
|
||||
addrLocal.SetIP(node.GetAddrLocal());
|
||||
}
|
||||
}
|
||||
if (addrLocal.IsRoutable() || gArgs.GetBoolArg("-addrmantest", false))
|
||||
{
|
||||
LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToString(), pnode->GetId());
|
||||
LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToString(), node.GetId());
|
||||
return addrLocal;
|
||||
}
|
||||
// Address is unroutable. Don't advertise.
|
||||
@ -610,7 +608,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
|
||||
addr_bind = GetBindAddress(*sock);
|
||||
}
|
||||
CNode* pnode = new CNode(id,
|
||||
nLocalServices,
|
||||
std::move(sock),
|
||||
addrConnect,
|
||||
CalculateKeyedNetGroup(addrConnect),
|
||||
@ -733,7 +730,6 @@ Network CNode::ConnectedThroughNetwork() const
|
||||
void CNode::CopyStats(CNodeStats& stats)
|
||||
{
|
||||
stats.nodeid = this->GetId();
|
||||
X(nServices);
|
||||
X(addr);
|
||||
X(addrBind);
|
||||
stats.m_network = ConnectedThroughNetwork();
|
||||
@ -1247,7 +1243,7 @@ bool CConnman::AttemptToEvictConnection()
|
||||
|
||||
NodeEvictionCandidate candidate = {node->GetId(), node->m_connected, node->m_min_ping_time,
|
||||
node->m_last_block_time, node->m_last_tx_time,
|
||||
HasAllDesirableServiceFlags(node->nServices),
|
||||
node->m_has_all_wanted_services,
|
||||
node->m_relays_txs.load(), node->m_bloom_filter_loaded.load(),
|
||||
node->nKeyedNetGroup, node->m_prefer_evict, node->addr.IsLocal(),
|
||||
node->ConnectedThroughNetwork()};
|
||||
@ -1404,7 +1400,6 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
||||
|
||||
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
|
||||
CNode* pnode = new CNode(id,
|
||||
nodeServices,
|
||||
std::move(sock),
|
||||
addr,
|
||||
CalculateKeyedNetGroup(addr),
|
||||
@ -1418,7 +1413,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
|
||||
// If this flag is present, the user probably expect that RPC and QT report it as whitelisted (backward compatibility)
|
||||
pnode->m_legacyWhitelisted = legacyWhitelisted;
|
||||
pnode->m_prefer_evict = discouraged;
|
||||
m_msgproc->InitializeNode(pnode);
|
||||
m_msgproc->InitializeNode(*pnode, nodeServices);
|
||||
|
||||
{
|
||||
LOCK(pnode->m_sock_mutex);
|
||||
@ -1645,10 +1640,11 @@ void CConnman::CalculateNumConnectionsChangedStats()
|
||||
for (const mapMsgTypeSize::value_type &i : pnode->mapSendBytesPerMsgType)
|
||||
mapSentBytesMsgStats[i.first] += i.second;
|
||||
}
|
||||
if(pnode->fClient)
|
||||
if (pnode->m_bloom_filter_loaded.load()) {
|
||||
spvNodes++;
|
||||
else
|
||||
} else {
|
||||
fullNodes++;
|
||||
}
|
||||
if(pnode->IsInboundConn())
|
||||
inboundNodes++;
|
||||
else
|
||||
@ -3139,7 +3135,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
|
||||
mapSocketToNode.emplace(pnode->m_sock->Get(), pnode);
|
||||
}
|
||||
|
||||
m_msgproc->InitializeNode(pnode);
|
||||
m_msgproc->InitializeNode(*pnode, nLocalServices);
|
||||
{
|
||||
LOCK(m_nodes_mutex);
|
||||
m_nodes.push_back(pnode);
|
||||
@ -4133,7 +4129,6 @@ ServiceFlags CConnman::GetLocalServices() const
|
||||
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
|
||||
|
||||
CNode::CNode(NodeId idIn,
|
||||
ServiceFlags nLocalServicesIn,
|
||||
std::shared_ptr<Sock> sock,
|
||||
const CAddress& addrIn,
|
||||
uint64_t nKeyedNetGroupIn,
|
||||
@ -4155,7 +4150,6 @@ CNode::CNode(NodeId idIn,
|
||||
id{idIn},
|
||||
nLocalHostNonce{nLocalHostNonceIn},
|
||||
m_conn_type{conn_type_in},
|
||||
nLocalServices{nLocalServicesIn},
|
||||
m_i2p_sam_session{std::move(i2p_sam_session)}
|
||||
{
|
||||
if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
|
||||
|
61
src/net.h
61
src/net.h
@ -133,15 +133,22 @@ struct AddedNodeInfo
|
||||
class CNodeStats;
|
||||
class CClientUIInterface;
|
||||
|
||||
struct CSerializedNetMsg
|
||||
{
|
||||
struct CSerializedNetMsg {
|
||||
CSerializedNetMsg() = default;
|
||||
CSerializedNetMsg(CSerializedNetMsg&&) = default;
|
||||
CSerializedNetMsg& operator=(CSerializedNetMsg&&) = default;
|
||||
// No copying, only moves.
|
||||
// No implicit copying, only moves.
|
||||
CSerializedNetMsg(const CSerializedNetMsg& msg) = delete;
|
||||
CSerializedNetMsg& operator=(const CSerializedNetMsg&) = delete;
|
||||
|
||||
CSerializedNetMsg Copy() const
|
||||
{
|
||||
CSerializedNetMsg copy;
|
||||
copy.data = data;
|
||||
copy.m_type = m_type;
|
||||
return copy;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> data;
|
||||
std::string m_type;
|
||||
};
|
||||
@ -240,8 +247,8 @@ enum
|
||||
};
|
||||
|
||||
bool IsPeerAddrLocalGood(CNode *pnode);
|
||||
/** Returns a local address that we should advertise to this peer */
|
||||
std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode);
|
||||
/** Returns a local address that we should advertise to this peer. */
|
||||
std::optional<CService> GetLocalAddrForPeer(CNode& node);
|
||||
|
||||
/**
|
||||
* Mark a network as reachable or unreachable (no automatic connects to it)
|
||||
@ -259,7 +266,7 @@ void RemoveLocal(const CService& addr);
|
||||
bool SeenLocal(const CService& addr);
|
||||
bool IsLocal(const CService& addr);
|
||||
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = nullptr);
|
||||
CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices);
|
||||
CService GetLocalAddress(const CNetAddr& addrPeer);
|
||||
|
||||
|
||||
extern bool fDiscover;
|
||||
@ -283,7 +290,6 @@ class CNodeStats
|
||||
{
|
||||
public:
|
||||
NodeId nodeid;
|
||||
ServiceFlags nServices;
|
||||
std::chrono::seconds m_last_send;
|
||||
std::chrono::seconds m_last_recv;
|
||||
std::chrono::seconds m_last_tx_time;
|
||||
@ -449,7 +455,6 @@ public:
|
||||
const std::unique_ptr<const TransportSerializer> m_serializer;
|
||||
|
||||
NetPermissionFlags m_permissionFlags{NetPermissionFlags::None}; // treated as const outside of fuzz tester
|
||||
std::atomic<ServiceFlags> nServices{NODE_NONE};
|
||||
|
||||
/**
|
||||
* Socket used for communication with the node.
|
||||
@ -509,8 +514,6 @@ public:
|
||||
}
|
||||
// This boolean is unusued in actual processing, only present for backward compatibility at RPC/QT level
|
||||
bool m_legacyWhitelisted{false};
|
||||
bool fClient{false}; // set by version message
|
||||
bool m_limited_node{false}; //after BIP159, set by version message
|
||||
/** fSuccessfullyConnected is set to true on receiving VERACK from the peer. */
|
||||
std::atomic_bool fSuccessfullyConnected{false};
|
||||
// Setting fDisconnect to true will cause the node to be disconnected the
|
||||
@ -610,6 +613,9 @@ public:
|
||||
// Peer selected us as (compact blocks) high-bandwidth peer (BIP152)
|
||||
std::atomic<bool> m_bip152_highbandwidth_from{false};
|
||||
|
||||
/** Whether this peer provides all services that we want. Used for eviction decisions */
|
||||
std::atomic_bool m_has_all_wanted_services{false};
|
||||
|
||||
/** Whether we should relay transactions to this peer (their version
|
||||
* message did not include fRelay=false and this is not a block-relay-only
|
||||
* connection). This only changes from false to true. It will never change
|
||||
@ -651,7 +657,6 @@ public:
|
||||
bool IsBlockRelayOnly() const;
|
||||
|
||||
CNode(NodeId id,
|
||||
ServiceFlags nLocalServicesIn,
|
||||
std::shared_ptr<Sock> sock,
|
||||
const CAddress &addrIn,
|
||||
uint64_t nKeyedNetGroupIn,
|
||||
@ -718,11 +723,6 @@ public:
|
||||
|
||||
void CopyStats(CNodeStats& stats) EXCLUSIVE_LOCKS_REQUIRED(!m_subver_mutex, !m_addr_local_mutex, !cs_vSend, !cs_vRecv);
|
||||
|
||||
ServiceFlags GetLocalServices() const
|
||||
{
|
||||
return nLocalServices;
|
||||
}
|
||||
|
||||
std::string ConnectionTypeAsString() const { return ::ConnectionTypeAsString(m_conn_type); }
|
||||
|
||||
/** A ping-pong round trip has completed successfully. Update latest and minimum ping times. */
|
||||
@ -781,23 +781,6 @@ private:
|
||||
const ConnectionType m_conn_type;
|
||||
std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION};
|
||||
|
||||
//! Services offered to this peer.
|
||||
//!
|
||||
//! This is supplied by the parent CConnman during peer connection
|
||||
//! (CConnman::ConnectNode()) from its attribute of the same name.
|
||||
//!
|
||||
//! This is const because there is no protocol defined for renegotiating
|
||||
//! services initially offered to a peer. The set of local services we
|
||||
//! offer should not change after initialization.
|
||||
//!
|
||||
//! An interesting example of this is NODE_NETWORK and initial block
|
||||
//! download: a node which starts up from scratch doesn't have any blocks
|
||||
//! to serve, but still advertises NODE_NETWORK because it will eventually
|
||||
//! fulfill this role after IBD completes. P2P code is written in such a
|
||||
//! way that it can gracefully handle peers who don't make good on their
|
||||
//! service advertisements.
|
||||
const ServiceFlags nLocalServices;
|
||||
|
||||
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
|
||||
|
||||
// Our address, as reported by the peer
|
||||
@ -834,7 +817,7 @@ class NetEventsInterface
|
||||
{
|
||||
public:
|
||||
/** Initialize a peer (setup state, queue any initial messages) */
|
||||
virtual void InitializeNode(CNode* pnode) = 0;
|
||||
virtual void InitializeNode(CNode& node, ServiceFlags our_services) = 0;
|
||||
|
||||
/** Handle removal of a peer (clear state) */
|
||||
virtual void FinalizeNode(const CNode& node) = 0;
|
||||
@ -1496,16 +1479,14 @@ private:
|
||||
std::map<uint64_t, CachedAddrResponse> m_addr_response_caches;
|
||||
|
||||
/**
|
||||
* Services this instance offers.
|
||||
* Services this node offers.
|
||||
*
|
||||
* This data is replicated in each CNode instance we create during peer
|
||||
* connection (in ConnectNode()) under a member also called
|
||||
* nLocalServices.
|
||||
* This data is replicated in each Peer instance we create.
|
||||
*
|
||||
* This data is not marked const, but after being set it should not
|
||||
* change. See the note in CNode::nLocalServices documentation.
|
||||
* change.
|
||||
*
|
||||
* \sa CNode::nLocalServices
|
||||
* \sa Peer::our_services
|
||||
*/
|
||||
ServiceFlags nLocalServices;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -51,6 +51,7 @@ struct CNodeStateStats {
|
||||
uint64_t m_addr_processed = 0;
|
||||
uint64_t m_addr_rate_limited = 0;
|
||||
bool m_addr_relay_enabled{false};
|
||||
ServiceFlags their_services;
|
||||
};
|
||||
|
||||
class PeerManager : public CValidationInterface, public NetEventsInterface
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
std::atomic_bool fImporting(false);
|
||||
std::atomic_bool fReindex(false);
|
||||
bool fHavePruned = false;
|
||||
bool fPruneMode = false;
|
||||
uint64_t nPruneTarget = 0;
|
||||
|
||||
@ -86,7 +85,8 @@ const CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const
|
||||
return it == m_block_index.end() ? nullptr : &it->second;
|
||||
}
|
||||
|
||||
CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, const uint256& hash, enum BlockStatus nStatus)
|
||||
CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, const uint256& hash, CBlockIndex*& best_header,
|
||||
enum BlockStatus nStatus)
|
||||
{
|
||||
assert(!(nStatus & BLOCK_FAILED_MASK)); // no failed blocks allowed
|
||||
AssertLockHeld(cs_main);
|
||||
@ -113,8 +113,8 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, const uint
|
||||
pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
|
||||
if (nStatus & BLOCK_VALID_MASK) {
|
||||
pindexNew->RaiseValidity(nStatus);
|
||||
if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork) {
|
||||
pindexBestHeader = pindexNew;
|
||||
if (best_header == nullptr || best_header->nChainWork < pindexNew->nChainWork) {
|
||||
best_header = pindexNew;
|
||||
}
|
||||
} else {
|
||||
pindexNew->RaiseValidity(BLOCK_VALID_TREE); // required validity level
|
||||
@ -309,8 +309,6 @@ bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
|
||||
if (pindex->pprev) {
|
||||
pindex->BuildSkip();
|
||||
}
|
||||
if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == nullptr || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
|
||||
pindexBestHeader = pindex;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -327,6 +325,8 @@ void BlockManager::Unload()
|
||||
m_last_blockfile = 0;
|
||||
m_dirty_blockindex.clear();
|
||||
m_dirty_fileinfo.clear();
|
||||
|
||||
m_have_pruned = false;
|
||||
}
|
||||
|
||||
bool BlockManager::WriteBlockIndexDB()
|
||||
@ -389,8 +389,8 @@ bool BlockManager::LoadBlockIndexDB()
|
||||
}
|
||||
|
||||
// Check whether we have ever pruned block & undo files
|
||||
m_block_tree_db->ReadFlag("prunedblockfiles", fHavePruned);
|
||||
if (fHavePruned) {
|
||||
m_block_tree_db->ReadFlag("prunedblockfiles", m_have_pruned);
|
||||
if (m_have_pruned) {
|
||||
LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n");
|
||||
}
|
||||
|
||||
@ -428,10 +428,10 @@ const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IsBlockPruned(const CBlockIndex* pblockindex)
|
||||
bool BlockManager::IsBlockPruned(const CBlockIndex* pblockindex)
|
||||
{
|
||||
AssertLockHeld(::cs_main);
|
||||
return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
|
||||
return (m_have_pruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
|
||||
}
|
||||
|
||||
// If we're using -prune with -reindex, then delete block files that will be ignored by the
|
||||
|
@ -49,8 +49,6 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
|
||||
extern std::atomic_bool fImporting;
|
||||
extern std::atomic_bool fReindex;
|
||||
/** Pruning-related variables and constants */
|
||||
/** True if any block files have ever been pruned. */
|
||||
extern bool fHavePruned;
|
||||
/** True if we're running in -prune mode. */
|
||||
extern bool fPruneMode;
|
||||
/** Number of bytes of block files that we're trying to stay below. */
|
||||
@ -160,7 +158,9 @@ public:
|
||||
/** Clear all data members. */
|
||||
void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
CBlockIndex* AddToBlockIndex(const CBlockHeader& block, const uint256& hash, enum BlockStatus nStatus = BLOCK_VALID_TREE) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
CBlockIndex* AddToBlockIndex(const CBlockHeader& block, const uint256& hash, CBlockIndex*& best_header,
|
||||
enum BlockStatus nStatus = BLOCK_VALID_TREE)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
/** Create a new block index entry for a given block hash */
|
||||
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
@ -184,6 +184,12 @@ public:
|
||||
//! Returns last CBlockIndex* that is a checkpoint
|
||||
const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
/** True if any block files have ever been pruned. */
|
||||
bool m_have_pruned = false;
|
||||
|
||||
//! Check whether the block associated with this index entry is pruned or not.
|
||||
bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||
|
||||
/**
|
||||
* Return the spend height, which is one more than the inputs.GetBestBlock().
|
||||
* While checking, GetBestBlock() refers to the parent block. (protected by cs_main)
|
||||
@ -197,9 +203,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
//! Check whether the block associated with this index entry is pruned or not.
|
||||
bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||
|
||||
void CleanupBlockRevFiles();
|
||||
|
||||
/** Open a block file (blk?????.dat) */
|
||||
|
@ -419,9 +419,10 @@ public:
|
||||
bool getHeaderTip(int& height, int64_t& block_time) override
|
||||
{
|
||||
LOCK(::cs_main);
|
||||
if (::pindexBestHeader) {
|
||||
height = ::pindexBestHeader->nHeight;
|
||||
block_time = ::pindexBestHeader->GetBlockTime();
|
||||
auto best_header = chainman().m_best_header;
|
||||
if (best_header) {
|
||||
height = best_header->nHeight;
|
||||
block_time = best_header->GetBlockTime();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -934,7 +935,7 @@ public:
|
||||
bool havePruned() override
|
||||
{
|
||||
LOCK(cs_main);
|
||||
return ::fHavePruned;
|
||||
return m_node.chainman->m_blockman.m_have_pruned;
|
||||
}
|
||||
bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); }
|
||||
bool isInitialBlockDownload() override {
|
||||
|
@ -1295,7 +1295,6 @@ void RPCConsole::updateDetailWidget()
|
||||
if (!stats->nodeStats.addrLocal.empty())
|
||||
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
|
||||
ui->peerHeading->setText(peerAddrDetails);
|
||||
ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices));
|
||||
const auto time_now{GetTime<std::chrono::seconds>()};
|
||||
ui->peerConnTime->setText(GUIUtil::formatDurationStr(time_now - stats->nodeStats.m_connected));
|
||||
ui->peerLastBlock->setText(TimeDurationField(time_now, stats->nodeStats.m_last_block_time));
|
||||
@ -1342,6 +1341,7 @@ void RPCConsole::updateDetailWidget()
|
||||
// This check fails for example if the lock was busy and
|
||||
// nodeStateStats couldn't be fetched.
|
||||
if (stats->fNodeStateStatsAvailable) {
|
||||
ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStateStats.their_services));
|
||||
// Sync height is init to -1
|
||||
if (stats->nodeStateStats.nSyncHeight > -1) {
|
||||
ui->peerSyncHeight->setText(QString("%1").arg(stats->nodeStateStats.nSyncHeight));
|
||||
|
10
src/rest.cpp
10
src/rest.cpp
@ -273,10 +273,10 @@ static bool rest_block(const CoreContext& context,
|
||||
CBlock block;
|
||||
const CBlockIndex* pblockindex = nullptr;
|
||||
const CBlockIndex* tip = nullptr;
|
||||
ChainstateManager* maybe_chainman = GetChainman(context, req);
|
||||
if (!maybe_chainman) return false;
|
||||
ChainstateManager& chainman = *maybe_chainman;
|
||||
{
|
||||
ChainstateManager* maybe_chainman = GetChainman(context, req);
|
||||
if (!maybe_chainman) return false;
|
||||
ChainstateManager& chainman = *maybe_chainman;
|
||||
LOCK(cs_main);
|
||||
tip = chainman.ActiveChain().Tip();
|
||||
pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
|
||||
@ -284,7 +284,7 @@ static bool rest_block(const CoreContext& context,
|
||||
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
|
||||
}
|
||||
|
||||
if (IsBlockPruned(pblockindex))
|
||||
if (chainman.m_blockman.IsBlockPruned(pblockindex))
|
||||
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
|
||||
|
||||
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
|
||||
@ -311,7 +311,7 @@ static bool rest_block(const CoreContext& context,
|
||||
}
|
||||
|
||||
case RetFormat::JSON: {
|
||||
UniValue objBlock = blockToJSON(block, tip, pblockindex, *llmq::chainLocksHandler, *llmq::quorumInstantSendManager, showTxDetails);
|
||||
UniValue objBlock = blockToJSON(chainman.m_blockman, block, tip, pblockindex, *llmq::chainLocksHandler, *llmq::quorumInstantSendManager, showTxDetails);
|
||||
std::string strJSON = objBlock.write() + "\n";
|
||||
req->WriteHeader("Content-Type", "application/json");
|
||||
req->WriteReply(HTTP_OK, strJSON);
|
||||
|
@ -156,7 +156,7 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, llmq::CChainLocksHandler& clhandler, llmq::CInstantSendManager& isman, bool txDetails)
|
||||
UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, llmq::CChainLocksHandler& clhandler, llmq::CInstantSendManager& isman, bool txDetails)
|
||||
{
|
||||
UniValue result = blockheaderToJSON(tip, blockindex, clhandler, isman);
|
||||
|
||||
@ -164,7 +164,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
|
||||
UniValue txs(UniValue::VARR);
|
||||
if (txDetails) {
|
||||
CBlockUndo blockUndo;
|
||||
const bool have_undo{WITH_LOCK(::cs_main, return !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))};
|
||||
const bool have_undo{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))};
|
||||
for (size_t i = 0; i < block.vtx.size(); ++i) {
|
||||
const CTransactionRef& tx = block.vtx.at(i);
|
||||
// coinbase transaction (i == 0) doesn't have undo data
|
||||
@ -1060,11 +1060,11 @@ static RPCHelpMan getblockheaders()
|
||||
};
|
||||
}
|
||||
|
||||
static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
||||
static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
||||
{
|
||||
AssertLockHeld(::cs_main);
|
||||
CBlock block;
|
||||
if (IsBlockPruned(pblockindex)) {
|
||||
if (blockman.IsBlockPruned(pblockindex)) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
|
||||
}
|
||||
|
||||
@ -1078,11 +1078,11 @@ static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_RE
|
||||
return block;
|
||||
}
|
||||
|
||||
static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
{
|
||||
AssertLockHeld(::cs_main);
|
||||
CBlockUndo blockUndo;
|
||||
if (IsBlockPruned(pblockindex)) {
|
||||
if (blockman.IsBlockPruned(pblockindex)) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
|
||||
}
|
||||
|
||||
@ -1137,7 +1137,7 @@ static RPCHelpMan getmerkleblocks()
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Count is out of range");
|
||||
}
|
||||
|
||||
CBlock block = GetBlockChecked(pblockindex);
|
||||
CBlock block = GetBlockChecked(chainman.m_blockman, pblockindex);
|
||||
|
||||
UniValue arrMerkleBlocks(UniValue::VARR);
|
||||
|
||||
@ -1247,8 +1247,8 @@ static RPCHelpMan getblock()
|
||||
CBlock block;
|
||||
const CBlockIndex* pblockindex;
|
||||
const CBlockIndex* tip;
|
||||
ChainstateManager& chainman = EnsureChainman(node);
|
||||
{
|
||||
ChainstateManager& chainman = EnsureChainman(node);
|
||||
LOCK(cs_main);
|
||||
pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
|
||||
tip = chainman.ActiveChain().Tip();
|
||||
@ -1257,7 +1257,7 @@ static RPCHelpMan getblock()
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
|
||||
}
|
||||
|
||||
block = GetBlockChecked(pblockindex);
|
||||
block = GetBlockChecked(chainman.m_blockman, pblockindex);
|
||||
}
|
||||
|
||||
if (verbosity <= 0)
|
||||
@ -1269,7 +1269,7 @@ static RPCHelpMan getblock()
|
||||
}
|
||||
|
||||
LLMQContext& llmq_ctx = EnsureLLMQContext(node);
|
||||
return blockToJSON(block, tip, pblockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, verbosity >= 2);
|
||||
return blockToJSON(chainman.m_blockman, block, tip, pblockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, verbosity >= 2);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -1760,18 +1760,18 @@ RPCHelpMan getblockchaininfo()
|
||||
const auto ehfSignals = node.mnhf_manager->GetSignalsStage(tip);
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.pushKV("chain", strChainName);
|
||||
obj.pushKV("blocks", height);
|
||||
obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1);
|
||||
obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
|
||||
obj.pushKV("difficulty", (double)GetDifficulty(tip));
|
||||
obj.pushKV("time", (int64_t)tip->nTime);
|
||||
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
|
||||
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
|
||||
obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload());
|
||||
obj.pushKV("chainwork", tip->nChainWork.GetHex());
|
||||
obj.pushKV("chain", strChainName);
|
||||
obj.pushKV("blocks", height);
|
||||
obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
|
||||
obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
|
||||
obj.pushKV("difficulty", (double)GetDifficulty(tip));
|
||||
obj.pushKV("time", (int64_t)tip->nTime);
|
||||
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
|
||||
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
|
||||
obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload());
|
||||
obj.pushKV("chainwork", tip->nChainWork.GetHex());
|
||||
obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
|
||||
obj.pushKV("pruned", fPruneMode);
|
||||
obj.pushKV("pruned", fPruneMode);
|
||||
if (fPruneMode) {
|
||||
const CBlockIndex* block = tip;
|
||||
CHECK_NONFATAL(block);
|
||||
@ -2358,8 +2358,8 @@ static RPCHelpMan getblockstats()
|
||||
}
|
||||
}
|
||||
|
||||
const CBlock block = GetBlockChecked(pindex);
|
||||
const CBlockUndo blockUndo = GetUndoChecked(pindex);
|
||||
const CBlock block = GetBlockChecked(chainman.m_blockman, pindex);
|
||||
const CBlockUndo blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
|
||||
|
||||
const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
|
||||
const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
|
||||
@ -2571,7 +2571,7 @@ static RPCHelpMan getspecialtxes()
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
|
||||
}
|
||||
|
||||
const CBlock block = GetBlockChecked(pblockindex);
|
||||
const CBlock block = GetBlockChecked(chainman.m_blockman, pblockindex);
|
||||
|
||||
int nTxNum = 0;
|
||||
UniValue result(UniValue::VARR);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <core_io.h>
|
||||
#include <streams.h>
|
||||
#include <sync.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
@ -40,7 +41,7 @@ double GetDifficulty(const CBlockIndex* blockindex);
|
||||
void RPCNotifyBlockChange(const CBlockIndex*);
|
||||
|
||||
/** Block description to JSON */
|
||||
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, llmq::CChainLocksHandler& clhandler, llmq::CInstantSendManager& isman, bool txDetails = false) LOCKS_EXCLUDED(cs_main);
|
||||
UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, llmq::CChainLocksHandler& clhandler, llmq::CInstantSendManager& isman, bool txDetails = false) LOCKS_EXCLUDED(cs_main);
|
||||
|
||||
/** Mempool information to JSON */
|
||||
UniValue MempoolInfoToJSON(const CTxMemPool& pool, llmq::CInstantSendManager& isman);
|
||||
|
@ -103,16 +103,16 @@ static RPCHelpMan getpeerinfo()
|
||||
{RPCResult::Type::STR, "network", "Network (" + Join(GetNetworkNames(/* append_unroutable */ true), ", ") + ")"},
|
||||
{RPCResult::Type::STR, "mapped_as", "The AS in the BGP route to the peer used for diversifying peer selection"},
|
||||
{RPCResult::Type::STR_HEX, "services", "The services offered"},
|
||||
{RPCResult::Type::ARR, "servicesnames", "the services offered, in human-readable form",
|
||||
{
|
||||
{RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"}
|
||||
}},
|
||||
{RPCResult::Type::STR_HEX, "verified_proregtx_hash", true /*optional*/, "Only present when the peer is a masternode and successfully "
|
||||
"authenticated via MNAUTH. In this case, this field contains the "
|
||||
"protx hash of the masternode"},
|
||||
{RPCResult::Type::STR_HEX, "verified_pubkey_hash", true /*optional*/, "Only present when the peer is a masternode and successfully "
|
||||
"authenticated via MNAUTH. In this case, this field contains the "
|
||||
"hash of the masternode's operator public key"},
|
||||
{RPCResult::Type::ARR, "servicesnames", "the services offered, in human-readable form",
|
||||
{
|
||||
{RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"}
|
||||
}},
|
||||
{RPCResult::Type::BOOL, "relaytxes", "Whether peer has asked us to relay transactions to it"},
|
||||
{RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"},
|
||||
{RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"},
|
||||
@ -198,14 +198,15 @@ static RPCHelpMan getpeerinfo()
|
||||
if (stats.m_mapped_as != 0) {
|
||||
obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as));
|
||||
}
|
||||
obj.pushKV("services", strprintf("%016x", stats.nServices));
|
||||
ServiceFlags services{fStateStats ? statestats.their_services : ServiceFlags::NODE_NONE};
|
||||
obj.pushKV("services", strprintf("%016x", services));
|
||||
obj.pushKV("servicesnames", GetServicesNames(services));
|
||||
if (!stats.verifiedProRegTxHash.IsNull()) {
|
||||
obj.pushKV("verified_proregtx_hash", stats.verifiedProRegTxHash.ToString());
|
||||
}
|
||||
if (!stats.verifiedPubKeyHash.IsNull()) {
|
||||
obj.pushKV("verified_pubkey_hash", stats.verifiedPubKeyHash.ToString());
|
||||
}
|
||||
obj.pushKV("servicesnames", GetServicesNames(stats.nServices));
|
||||
obj.pushKV("lastsend", count_seconds(stats.m_last_send));
|
||||
obj.pushKV("lastrecv", count_seconds(stats.m_last_recv));
|
||||
obj.pushKV("last_transaction", count_seconds(stats.m_last_tx_time));
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <script/standard.h>
|
||||
#include <test/util/net.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <timedata.h>
|
||||
#include <util/string.h>
|
||||
#include <util/system.h>
|
||||
#include <util/time.h>
|
||||
@ -58,20 +59,15 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
|
||||
// work.
|
||||
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
||||
{
|
||||
const CChainParams& chainparams = Params();
|
||||
auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
|
||||
ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
|
||||
// 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,
|
||||
*m_node.chainman, *m_node.mempool, *m_node.mn_metaman, *m_node.mn_sync,
|
||||
*m_node.govman, *m_node.sporkman, /* mn_activeman = */ nullptr, m_node.dmnman,
|
||||
m_node.cj_ctx, m_node.llmq_ctx, /* ignore_incoming_txs = */ false);
|
||||
connman.SetPeerConnectTimeout(99999s);
|
||||
PeerManager& peerman = *m_node.peerman;
|
||||
|
||||
// Mock an outbound peer
|
||||
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
|
||||
NodeId id{0};
|
||||
CNode dummyNode1{id++,
|
||||
ServiceFlags(NODE_NETWORK),
|
||||
/*sock=*/nullptr,
|
||||
addr1,
|
||||
/*nKeyedNetGroupIn=*/0,
|
||||
@ -80,10 +76,16 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
||||
/*addrNameIn=*/"",
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false};
|
||||
dummyNode1.SetCommonVersion(PROTOCOL_VERSION);
|
||||
|
||||
peerLogic->InitializeNode(&dummyNode1);
|
||||
dummyNode1.fSuccessfullyConnected = true;
|
||||
connman.Handshake(
|
||||
/*node=*/dummyNode1,
|
||||
/*successfully_connected=*/true,
|
||||
/*remote_services=*/ServiceFlags(NODE_NETWORK),
|
||||
/*local_services=*/ServiceFlags(NODE_NETWORK),
|
||||
/*permission_flags=*/NetPermissionFlags::None,
|
||||
/*version=*/PROTOCOL_VERSION,
|
||||
/*relay_txs=*/true);
|
||||
TestOnlyResetTimeData();
|
||||
|
||||
// This test requires that we have a chain with non-zero work.
|
||||
{
|
||||
@ -95,7 +97,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
||||
// Test starts here
|
||||
{
|
||||
LOCK(dummyNode1.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in getheaders
|
||||
BOOST_CHECK(peerman.SendMessages(&dummyNode1)); // should result in getheaders
|
||||
}
|
||||
{
|
||||
LOCK(dummyNode1.cs_vSend);
|
||||
@ -109,7 +111,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
||||
SetMockTime(nStartTime+21*60);
|
||||
{
|
||||
LOCK(dummyNode1.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in getheaders
|
||||
BOOST_CHECK(peerman.SendMessages(&dummyNode1)); // should result in getheaders
|
||||
}
|
||||
{
|
||||
LOCK(dummyNode1.cs_vSend);
|
||||
@ -119,18 +121,17 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
|
||||
SetMockTime(nStartTime+24*60);
|
||||
{
|
||||
LOCK(dummyNode1.cs_sendProcessing);
|
||||
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in disconnect
|
||||
BOOST_CHECK(peerman.SendMessages(&dummyNode1)); // should result in disconnect
|
||||
}
|
||||
BOOST_CHECK(dummyNode1.fDisconnect == true);
|
||||
|
||||
peerLogic->FinalizeNode(dummyNode1);
|
||||
peerman.FinalizeNode(dummyNode1);
|
||||
}
|
||||
|
||||
static void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType)
|
||||
{
|
||||
CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE);
|
||||
vNodes.emplace_back(new CNode{id++,
|
||||
ServiceFlags(NODE_NETWORK),
|
||||
/*sock=*/nullptr,
|
||||
addr,
|
||||
/*nKeyedNetGroupIn=*/0,
|
||||
@ -142,7 +143,7 @@ static void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerM
|
||||
CNode &node = *vNodes.back();
|
||||
node.SetCommonVersion(PROTOCOL_VERSION);
|
||||
|
||||
peerLogic.InitializeNode(&node);
|
||||
peerLogic.InitializeNode(node, ServiceFlags(NODE_NETWORK));
|
||||
node.fSuccessfullyConnected = true;
|
||||
|
||||
connman.AddTestNode(node);
|
||||
@ -319,7 +320,6 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
banman->ClearBanned();
|
||||
NodeId id{0};
|
||||
nodes[0] = new CNode{id++,
|
||||
NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
addr[0],
|
||||
/*nKeyedNetGroupIn=*/0,
|
||||
@ -329,7 +329,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(nodes[0]);
|
||||
peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
|
||||
nodes[0]->fSuccessfullyConnected = true;
|
||||
connman->AddTestNode(*nodes[0]);
|
||||
peerLogic->Misbehaving(nodes[0]->GetId(), DISCOURAGEMENT_THRESHOLD); // Should be discouraged
|
||||
@ -342,7 +342,6 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
BOOST_CHECK(!banman->IsDiscouraged(other_addr)); // Different address, not discouraged
|
||||
|
||||
nodes[1] = new CNode{id++,
|
||||
NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
addr[1],
|
||||
/*nKeyedNetGroupIn=*/1,
|
||||
@ -352,7 +351,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(nodes[1]);
|
||||
peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
|
||||
nodes[1]->fSuccessfullyConnected = true;
|
||||
connman->AddTestNode(*nodes[1]);
|
||||
peerLogic->Misbehaving(nodes[1]->GetId(), DISCOURAGEMENT_THRESHOLD - 1);
|
||||
@ -380,7 +379,6 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
// Make sure non-IP peers are discouraged and disconnected properly.
|
||||
|
||||
nodes[2] = new CNode{id++,
|
||||
NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
addr[2],
|
||||
/*nKeyedNetGroupIn=*/1,
|
||||
@ -390,7 +388,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
|
||||
ConnectionType::OUTBOUND_FULL_RELAY,
|
||||
/*inbound_onion=*/false};
|
||||
nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(nodes[2]);
|
||||
peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
|
||||
nodes[2]->fSuccessfullyConnected = true;
|
||||
connman->AddTestNode(*nodes[2]);
|
||||
peerLogic->Misbehaving(nodes[2]->GetId(), DISCOURAGEMENT_THRESHOLD, /* message */ "");
|
||||
@ -428,7 +426,6 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||
CAddress addr(ip(0xa0b0c001), NODE_NONE);
|
||||
NodeId id{0};
|
||||
CNode dummyNode{id++,
|
||||
NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
addr,
|
||||
/*nKeyedNetGroupIn=*/4,
|
||||
@ -438,7 +435,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
||||
ConnectionType::INBOUND,
|
||||
/*inbound_onion=*/false};
|
||||
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
|
||||
peerLogic->InitializeNode(&dummyNode);
|
||||
peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
|
||||
dummyNode.fSuccessfullyConnected = true;
|
||||
|
||||
peerLogic->Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD);
|
||||
|
@ -270,7 +270,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
|
||||
CCoinsStats stats{CoinStatsHashType::HASH_SERIALIZED};
|
||||
bool expected_code_path = false;
|
||||
try {
|
||||
(void)GetUTXOStats(&coins_view_cache, WITH_LOCK(::cs_main, return std::ref(g_setup->m_node.chainman->m_blockman)), stats);
|
||||
(void)GetUTXOStats(&coins_view_cache, g_setup->m_node.chainman->m_blockman, stats);
|
||||
} catch (const std::logic_error&) {
|
||||
expected_code_path = true;
|
||||
}
|
||||
|
@ -71,7 +71,6 @@ FUZZ_TARGET_INIT(net, initialize_net)
|
||||
(void)node.GetAddrLocal();
|
||||
(void)node.GetId();
|
||||
(void)node.GetLocalNonce();
|
||||
(void)node.GetLocalServices();
|
||||
const int ref_count = node.GetRefCount();
|
||||
assert(ref_count >= 0);
|
||||
(void)node.GetCommonVersion();
|
||||
|
@ -287,6 +287,7 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman,
|
||||
connman.Handshake(node,
|
||||
/*successfully_connected=*/fuzzed_data_provider.ConsumeBool(),
|
||||
/*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
|
||||
/*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
|
||||
/*permission_flags=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS),
|
||||
/*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()),
|
||||
/*relay_txs=*/fuzzed_data_provider.ConsumeBool());
|
||||
|
@ -360,7 +360,6 @@ template <bool ReturnUniquePtr = false>
|
||||
auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
|
||||
{
|
||||
const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max()));
|
||||
const ServiceFlags local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
|
||||
const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
|
||||
const CAddress address = ConsumeAddress(fuzzed_data_provider);
|
||||
const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
|
||||
@ -372,7 +371,6 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
|
||||
const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
|
||||
if constexpr (ReturnUniquePtr) {
|
||||
return std::make_unique<CNode>(node_id,
|
||||
local_services,
|
||||
sock,
|
||||
address,
|
||||
keyed_net_group,
|
||||
@ -383,7 +381,6 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
|
||||
inbound_onion);
|
||||
} else {
|
||||
return CNode{node_id,
|
||||
local_services,
|
||||
sock,
|
||||
address,
|
||||
keyed_net_group,
|
||||
|
@ -59,7 +59,6 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
std::string pszDest;
|
||||
|
||||
std::unique_ptr<CNode> pnode1 = std::make_unique<CNode>(id++,
|
||||
NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
addr,
|
||||
/*nKeyedNetGroupIn=*/0,
|
||||
@ -78,7 +77,6 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4);
|
||||
|
||||
std::unique_ptr<CNode> pnode2 = std::make_unique<CNode>(id++,
|
||||
NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
addr,
|
||||
/*nKeyedNetGroupIn=*/1,
|
||||
@ -97,7 +95,6 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4);
|
||||
|
||||
std::unique_ptr<CNode> pnode3 = std::make_unique<CNode>(id++,
|
||||
NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
addr,
|
||||
/*nKeyedNetGroupIn=*/0,
|
||||
@ -116,7 +113,6 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
|
||||
BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4);
|
||||
|
||||
std::unique_ptr<CNode> pnode4 = std::make_unique<CNode>(id++,
|
||||
NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
addr,
|
||||
/*nKeyedNetGroupIn=*/1,
|
||||
@ -630,7 +626,6 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
|
||||
ipv4AddrPeer.s_addr = 0xa0b0c001;
|
||||
CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
|
||||
std::unique_ptr<CNode> pnode = std::make_unique<CNode>(/*id=*/0,
|
||||
NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
addr,
|
||||
/*nKeyedNetGroupIn=*/0,
|
||||
@ -649,7 +644,7 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
|
||||
pnode->SetAddrLocal(addrLocal);
|
||||
|
||||
// before patch, this causes undefined behavior detectable with clang's -fsanitize=memory
|
||||
GetLocalAddrForPeer(&*pnode);
|
||||
GetLocalAddrForPeer(*pnode);
|
||||
|
||||
// suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer
|
||||
BOOST_CHECK(1);
|
||||
@ -682,13 +677,12 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
|
||||
// Our address:port as seen from the peer, completely different from the above.
|
||||
in_addr peer_us_addr;
|
||||
peer_us_addr.s_addr = htonl(0x02030405);
|
||||
const CAddress peer_us{CService{peer_us_addr, 20002}, NODE_NETWORK, current_time};
|
||||
const CService peer_us{peer_us_addr, 20002};
|
||||
|
||||
// Create a peer with a routable IPv4 address (outbound).
|
||||
in_addr peer_out_in_addr;
|
||||
peer_out_in_addr.s_addr = htonl(0x01020304);
|
||||
CNode peer_out{/*id=*/0,
|
||||
/*nLocalServicesIn=*/NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
/*addrIn=*/CAddress{CService{peer_out_in_addr, 8333}, NODE_NETWORK},
|
||||
/*nKeyedNetGroupIn=*/0,
|
||||
@ -701,7 +695,7 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
|
||||
peer_out.SetAddrLocal(peer_us);
|
||||
|
||||
// Without the fix peer_us:8333 is chosen instead of the proper peer_us:bind_port.
|
||||
auto chosen_local_addr = GetLocalAddrForPeer(&peer_out);
|
||||
auto chosen_local_addr = GetLocalAddrForPeer(peer_out);
|
||||
BOOST_REQUIRE(chosen_local_addr);
|
||||
const CAddress expected{CService{peer_us_addr, bind_port}, NODE_NETWORK, current_time};
|
||||
BOOST_CHECK(*chosen_local_addr == expected);
|
||||
@ -710,7 +704,6 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
|
||||
in_addr peer_in_in_addr;
|
||||
peer_in_in_addr.s_addr = htonl(0x05060708);
|
||||
CNode peer_in{/*id=*/0,
|
||||
/*nLocalServicesIn=*/NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
/*addrIn=*/CAddress{CService{peer_in_in_addr, 8333}, NODE_NETWORK},
|
||||
/*nKeyedNetGroupIn=*/0,
|
||||
@ -723,7 +716,7 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
|
||||
peer_in.SetAddrLocal(peer_us);
|
||||
|
||||
// Without the fix peer_us:8333 is chosen instead of the proper peer_us:peer_us.GetPort().
|
||||
chosen_local_addr = GetLocalAddrForPeer(&peer_in);
|
||||
chosen_local_addr = GetLocalAddrForPeer(peer_in);
|
||||
BOOST_REQUIRE(chosen_local_addr);
|
||||
BOOST_CHECK(*chosen_local_addr == peer_us);
|
||||
|
||||
@ -838,7 +831,6 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
|
||||
in_addr peer_in_addr;
|
||||
peer_in_addr.s_addr = htonl(0x01020304);
|
||||
CNode peer{/*id=*/0,
|
||||
/*nLocalServicesIn=*/NODE_NETWORK,
|
||||
/*sock=*/nullptr,
|
||||
/*addrIn=*/CAddress{CService{peer_in_addr, 8333}, NODE_NETWORK},
|
||||
/*nKeyedNetGroupIn=*/0,
|
||||
@ -858,7 +850,7 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
|
||||
*static_cast<TestChainState*>(&m_node.chainman->ActiveChainstate());
|
||||
chainstate.JumpOutOfIbd();
|
||||
|
||||
m_node.peerman->InitializeNode(&peer);
|
||||
m_node.peerman->InitializeNode(peer, NODE_NETWORK);
|
||||
|
||||
std::atomic<bool> interrupt_dummy{false};
|
||||
std::chrono::microseconds time_received_dummy{0};
|
||||
|
@ -15,6 +15,7 @@
|
||||
void ConnmanTestMsg::Handshake(CNode& node,
|
||||
bool successfully_connected,
|
||||
ServiceFlags remote_services,
|
||||
ServiceFlags local_services,
|
||||
NetPermissionFlags permission_flags,
|
||||
int32_t version,
|
||||
bool relay_txs)
|
||||
@ -23,7 +24,7 @@ void ConnmanTestMsg::Handshake(CNode& node,
|
||||
auto& connman{*this};
|
||||
const CNetMsgMaker mm{0};
|
||||
|
||||
peerman.InitializeNode(&node);
|
||||
peerman.InitializeNode(node, local_services);
|
||||
|
||||
CSerializedNetMsg msg_version{
|
||||
mm.Make(NetMsgType::VERSION,
|
||||
@ -50,10 +51,10 @@ void ConnmanTestMsg::Handshake(CNode& node,
|
||||
if (node.fDisconnect) return;
|
||||
assert(node.nVersion == version);
|
||||
assert(node.GetCommonVersion() == std::min(version, PROTOCOL_VERSION));
|
||||
assert(node.nServices == remote_services);
|
||||
CNodeStateStats statestats;
|
||||
assert(peerman.GetNodeStateStats(node.GetId(), statestats));
|
||||
assert(statestats.m_relay_txs == (relay_txs && !node.IsBlockOnlyConn()));
|
||||
assert(statestats.their_services == remote_services);
|
||||
node.m_permissionFlags = permission_flags;
|
||||
if (successfully_connected) {
|
||||
CSerializedNetMsg msg_verack{mm.Make(NetMsgType::VERACK)};
|
||||
|
@ -41,6 +41,7 @@ struct ConnmanTestMsg : public CConnman {
|
||||
void Handshake(CNode& node,
|
||||
bool successfully_connected,
|
||||
ServiceFlags remote_services,
|
||||
ServiceFlags local_services,
|
||||
NetPermissionFlags permission_flags,
|
||||
int32_t version,
|
||||
bool relay_txs);
|
||||
|
@ -105,7 +105,6 @@ const std::vector<std::string> CHECKLEVEL_DOC {
|
||||
*/
|
||||
RecursiveMutex cs_main;
|
||||
|
||||
CBlockIndex* pindexBestHeader = nullptr;
|
||||
Mutex g_best_block_mutex;
|
||||
std::condition_variable g_best_block_cv;
|
||||
uint256 g_best_block;
|
||||
@ -348,8 +347,9 @@ static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_
|
||||
return false;
|
||||
if (active_chainstate.m_chain.Tip()->GetBlockTime() < count_seconds(GetTime<std::chrono::seconds>() - MAX_FEE_ESTIMATION_TIP_AGE))
|
||||
return false;
|
||||
if (active_chainstate.m_chain.Height() < pindexBestHeader->nHeight - 1)
|
||||
if (active_chainstate.m_chain.Height() < active_chainstate.m_chainman.m_best_header->nHeight - 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1296,8 +1296,8 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
|
||||
if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) {
|
||||
m_chainman.m_best_invalid = pindexNew;
|
||||
}
|
||||
if (pindexBestHeader != nullptr && pindexBestHeader->GetAncestor(pindexNew->nHeight) == pindexNew) {
|
||||
pindexBestHeader = m_chain.Tip();
|
||||
if (m_chainman.m_best_header != nullptr && m_chainman.m_best_header->GetAncestor(pindexNew->nHeight) == pindexNew) {
|
||||
m_chainman.m_best_header = m_chain.Tip();
|
||||
}
|
||||
|
||||
LogPrintf("%s: invalid block=%s height=%d log2_work=%f date=%s\n", __func__,
|
||||
@ -1888,8 +1888,8 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
|
||||
BlockMap::const_iterator it = m_blockman.m_block_index.find(hashAssumeValid);
|
||||
if (it != m_blockman.m_block_index.end()) {
|
||||
if (it->second.GetAncestor(pindex->nHeight) == pindex &&
|
||||
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
|
||||
pindexBestHeader->nChainWork >= nMinimumChainWork) {
|
||||
m_chainman.m_best_header->GetAncestor(pindex->nHeight) == pindex &&
|
||||
m_chainman.m_best_header->nChainWork >= nMinimumChainWork) {
|
||||
// This block is a member of the assumed verified chain and an ancestor of the best header.
|
||||
// Script verification is skipped when connecting blocks under the
|
||||
// assumevalid block. Assuming the assumevalid block is valid this
|
||||
@ -1904,7 +1904,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
|
||||
// artificially set the default assumed verified block further back.
|
||||
// The test against nMinimumChainWork prevents the skipping when denied access to any chain at
|
||||
// least as good as the expected chain.
|
||||
fScriptChecks = (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);
|
||||
fScriptChecks = (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2348,9 +2348,9 @@ bool CChainState::FlushStateToDisk(
|
||||
}
|
||||
if (!setFilesToPrune.empty()) {
|
||||
fFlushForPrune = true;
|
||||
if (!fHavePruned) {
|
||||
if (!m_blockman.m_have_pruned) {
|
||||
m_blockman.m_block_tree_db->WriteFlag("prunedblockfiles", true);
|
||||
fHavePruned = true;
|
||||
m_blockman.m_have_pruned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2911,7 +2911,7 @@ static bool NotifyHeaderTip(CChainState& chainstate) LOCKS_EXCLUDED(cs_main) {
|
||||
CBlockIndex* pindexHeader = nullptr;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
pindexHeader = pindexBestHeader;
|
||||
pindexHeader = chainstate.m_chainman.m_best_header;
|
||||
|
||||
if (pindexHeader != pindexHeaderOld) {
|
||||
fNotify = true;
|
||||
@ -3129,9 +3129,9 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
|
||||
CBlockIndex *invalid_walk_tip = m_chain.Tip();
|
||||
const CBlockIndex* pindexOldTip = m_chain.Tip();
|
||||
|
||||
if (pindex == pindexBestHeader) {
|
||||
m_chainman.m_best_invalid = pindexBestHeader;
|
||||
pindexBestHeader = pindexBestHeader->pprev;
|
||||
if (pindex == m_chainman.m_best_header) {
|
||||
m_chainman.m_best_invalid = m_chainman.m_best_header;
|
||||
m_chainman.m_best_header = m_chainman.m_best_header->pprev;
|
||||
}
|
||||
|
||||
// ActivateBestChain considers blocks already in m_chain
|
||||
@ -3147,9 +3147,9 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
|
||||
if (!ret) return false;
|
||||
assert(invalid_walk_tip->pprev == m_chain.Tip());
|
||||
|
||||
if (pindexOldTip == pindexBestHeader) {
|
||||
m_chainman.m_best_invalid = pindexBestHeader;
|
||||
pindexBestHeader = pindexBestHeader->pprev;
|
||||
if (pindexOldTip == m_chainman.m_best_header) {
|
||||
m_chainman.m_best_invalid = m_chainman.m_best_header;
|
||||
m_chainman.m_best_header = m_chainman.m_best_header->pprev;
|
||||
}
|
||||
|
||||
// We immediately mark the disconnected blocks as invalid.
|
||||
@ -3264,8 +3264,8 @@ bool CChainState::MarkConflictingBlock(BlockValidationState& state, CBlockIndex
|
||||
bool pindex_was_in_chain = false;
|
||||
CBlockIndex *conflicting_walk_tip = m_chain.Tip();
|
||||
|
||||
if (pindex == pindexBestHeader) {
|
||||
pindexBestHeader = pindexBestHeader->pprev;
|
||||
if (pindex == m_chainman.m_best_header) {
|
||||
m_chainman.m_best_header = m_chainman.m_best_header->pprev;
|
||||
}
|
||||
|
||||
{
|
||||
@ -3282,8 +3282,8 @@ bool CChainState::MarkConflictingBlock(BlockValidationState& state, CBlockIndex
|
||||
MaybeUpdateMempoolForReorg(disconnectpool, false);
|
||||
return false;
|
||||
}
|
||||
if (pindexOldTip == pindexBestHeader) {
|
||||
pindexBestHeader = pindexBestHeader->pprev;
|
||||
if (pindexOldTip == m_chainman.m_best_header) {
|
||||
m_chainman.m_best_header = m_chainman.m_best_header->pprev;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3749,13 +3749,13 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
|
||||
|
||||
if (llmq::chainLocksHandler->HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) {
|
||||
if (miSelf == m_blockman.m_block_index.end()) {
|
||||
m_blockman.AddToBlockIndex(block, hash, BLOCK_CONFLICT_CHAINLOCK);
|
||||
m_blockman.AddToBlockIndex(block, hash, m_best_header, BLOCK_CONFLICT_CHAINLOCK);
|
||||
}
|
||||
LogPrintf("ERROR: %s: header %s conflicts with chainlock\n", __func__, hash.ToString());
|
||||
return state.Invalid(BlockValidationResult::BLOCK_CHAINLOCK, "bad-chainlock");
|
||||
}
|
||||
}
|
||||
CBlockIndex* pindex{m_blockman.AddToBlockIndex(block, hash)};
|
||||
CBlockIndex* pindex{m_blockman.AddToBlockIndex(block, hash, m_best_header)};
|
||||
|
||||
if (ppindex)
|
||||
*ppindex = pindex;
|
||||
@ -4342,13 +4342,11 @@ void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
chainman.Unload();
|
||||
pindexBestHeader = nullptr;
|
||||
if (mempool) mempool->clear();
|
||||
g_versionbitscache.Clear();
|
||||
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
|
||||
warningcache[b].clear();
|
||||
}
|
||||
fHavePruned = false;
|
||||
}
|
||||
|
||||
bool ChainstateManager::LoadBlockIndex()
|
||||
@ -4423,6 +4421,8 @@ bool ChainstateManager::LoadBlockIndex()
|
||||
if (pindex->nStatus & BLOCK_FAILED_MASK && (!m_best_invalid || pindex->nChainWork > m_best_invalid->nChainWork)) {
|
||||
m_best_invalid = pindex;
|
||||
}
|
||||
if (pindex->IsValid(BLOCK_VALID_TREE) && (m_best_header == nullptr || CBlockIndexWorkComparator()(m_best_header, pindex)))
|
||||
m_best_header = pindex;
|
||||
}
|
||||
|
||||
needs_init = m_blockman.m_block_index.empty();
|
||||
@ -4458,7 +4458,7 @@ bool CChainState::AddGenesisBlock(const CBlock& block, BlockValidationState& sta
|
||||
if (blockPos.IsNull()) {
|
||||
return error("%s: writing genesis block to disk failed (%s)", __func__, state.ToString());
|
||||
}
|
||||
CBlockIndex* pindex = m_blockman.AddToBlockIndex(block, block.GetHash());
|
||||
CBlockIndex* pindex = m_blockman.AddToBlockIndex(block, block.GetHash(), m_chainman.m_best_header);
|
||||
ReceivedBlockTransactions(block, pindex, blockPos);
|
||||
return true;
|
||||
}
|
||||
@ -4700,7 +4700,7 @@ void CChainState::CheckBlockIndex()
|
||||
// HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
|
||||
// Unless these indexes are assumed valid and pending block download on a
|
||||
// background chainstate.
|
||||
if (!fHavePruned && !pindex->IsAssumedValid()) {
|
||||
if (!m_blockman.m_have_pruned && !pindex->IsAssumedValid()) {
|
||||
// If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0
|
||||
assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0));
|
||||
assert(pindexFirstMissing == pindexFirstNeverProcessed);
|
||||
@ -4778,7 +4778,7 @@ void CChainState::CheckBlockIndex()
|
||||
if (pindexFirstMissing == nullptr) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in m_blocks_unlinked.
|
||||
if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == nullptr && pindexFirstMissing != nullptr) {
|
||||
// We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent.
|
||||
assert(fHavePruned); // We must have pruned.
|
||||
assert(m_blockman.m_have_pruned); // We must have pruned.
|
||||
// This block may have entered m_blocks_unlinked if:
|
||||
// - it has a descendant that at some point had more work than the
|
||||
// tip, and
|
||||
@ -5341,7 +5341,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
|
||||
// about the snapshot_chainstate.
|
||||
CCoinsViewDB* snapshot_coinsdb = WITH_LOCK(::cs_main, return &snapshot_chainstate.CoinsDB());
|
||||
|
||||
if (!GetUTXOStats(snapshot_coinsdb, WITH_LOCK(::cs_main, return std::ref(m_blockman)), stats, breakpoint_fnc)) {
|
||||
if (!GetUTXOStats(snapshot_coinsdb, m_blockman, stats, breakpoint_fnc)) {
|
||||
LogPrintf("[snapshot] failed to generate coins stats\n");
|
||||
return false;
|
||||
}
|
||||
@ -5424,6 +5424,7 @@ void ChainstateManager::Unload()
|
||||
|
||||
m_failed_blocks.clear();
|
||||
m_blockman.Unload();
|
||||
m_best_header = nullptr;
|
||||
m_best_invalid = nullptr;
|
||||
}
|
||||
|
||||
|
@ -150,9 +150,6 @@ extern uint256 hashAssumeValid;
|
||||
/** Minimum work we will assume exists on some valid chain. */
|
||||
extern arith_uint256 nMinimumChainWork;
|
||||
|
||||
/** Best header we've seen so far (used for getheaders queries' starting points). */
|
||||
extern CBlockIndex *pindexBestHeader;
|
||||
|
||||
/** Documentation for argument 'checklevel'. */
|
||||
extern const std::vector<std::string> CHECKLEVEL_DOC;
|
||||
|
||||
@ -858,7 +855,7 @@ public:
|
||||
std::thread m_load_block;
|
||||
//! A single BlockManager instance is shared across each constructed
|
||||
//! chainstate to avoid duplicating block metadata.
|
||||
BlockManager m_blockman GUARDED_BY(::cs_main);
|
||||
BlockManager m_blockman;
|
||||
|
||||
/**
|
||||
* In order to efficiently track invalidity of headers, we keep the set of
|
||||
@ -881,6 +878,9 @@ public:
|
||||
*/
|
||||
std::set<CBlockIndex*> m_failed_blocks;
|
||||
|
||||
/** Best header we've seen so far (used for getheaders queries' starting points). */
|
||||
CBlockIndex* m_best_header = nullptr;
|
||||
|
||||
//! The total number of bytes available for us to use across all in-memory
|
||||
//! coins caches. This will be split somehow across chainstates.
|
||||
int64_t m_total_coinstip_cache{0};
|
||||
|
@ -1,6 +1,5 @@
|
||||
fork:000000202cbcf83b62913d56f605c0e581a48872839428c92e5eb76cd7ad94bcaf0b0000c41f893a0d296b3b17730b42beb432aedc62473d0e6839910209d7f21af31a9bb9968054ffff0f1efd6b0e00
|
||||
fork:000000201ed4bb12db90cfb7c68051d82f922b86b24c6a247de6168678c9a489ef020000e5968c16ea68f5f8d6ce1f1a987a7484986710c7cae2ac81ca1b5552f059aeceba968054f0ff0f1ef38f0c00
|
||||
010000000000000000000000000000000000000000000000000000000000000000000000c762a6567f3cc092f0684bb62b7e00a84890b990f07cc71a6bb58d64b98e02e0dee1e352f0ff0f1ec3c927e6
|
||||
020000002cbcf83b62913d56f605c0e581a48872839428c92e5eb76cd7ad94bcaf0b00007f11dcce14075520e8f74cc4ddf092b4e26ebd23b8d8665a1ae5bfc41b58fdb4c3a95e53ffff0f1ef37a0000
|
||||
02000000c108f2910109954fcdec2f962f1a9094be266cb6aeaae37b345e63247d0400004d29e4f9b2e05a9ac97dd5ae4128b3c0104bdc95aabaa566cc8eeb682e336d0dc4a95e53f0ff0f1e7b190000
|
||||
02000000c2cc6fa3fe4d9fb73476bc3cf02248aa762af4960399232dbab4fa64620c000058968247522cc488db01996de610d6f3b8c348e748198dc528a305941211c71cc6a95e53f0ff0f1ecacf0000
|
||||
|
@ -91,11 +91,10 @@ class BIP68_112_113Test(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
self.setup_clean_chain = True
|
||||
# Must also set '-maxtipage=600100' to allow syncing from very old blocks
|
||||
# and '-dip3params=2000:2000' to create pre-dip3 blocks only
|
||||
# Must set '-dip3params=2000:2000' to create pre-dip3 blocks only
|
||||
self.extra_args = [[
|
||||
'-whitelist=noban@127.0.0.1',
|
||||
'-maxtipage=600100', '-dip3params=2000:2000',
|
||||
'-dip3params=2000:2000',
|
||||
'-par=1', # Use only one script thread to get the exact reject reason for testing
|
||||
]]
|
||||
self.supports_cli = False
|
||||
|
@ -38,7 +38,6 @@ class MaxUploadTest(BitcoinTestFramework):
|
||||
self.extra_args = [[
|
||||
"-maxuploadtarget=200",
|
||||
"-blockmaxsize=999000",
|
||||
"-maxtipage="+str(2*60*60*24*7),
|
||||
"-acceptnonstdtxn=1"
|
||||
]]
|
||||
self.supports_cli = False
|
||||
@ -149,7 +148,7 @@ class MaxUploadTest(BitcoinTestFramework):
|
||||
self.nodes[0].disconnect_p2ps()
|
||||
|
||||
self.log.info("Restarting node 0 with download permission and 1MB maxuploadtarget")
|
||||
self.restart_node(0, ["-whitelist=download@127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000", "-maxtipage="+str(2*60*60*24*7), "-mocktime="+str(current_mocktime)])
|
||||
self.restart_node(0, ["-whitelist=download@127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000", "-mocktime="+str(current_mocktime)])
|
||||
|
||||
# Reconnect to self.nodes[0]
|
||||
peer = self.nodes[0].add_p2p_connection(TestP2PConn())
|
||||
|
@ -17,6 +17,7 @@ only succeeds past a given node once its nMinimumChainWork has been exceeded.
|
||||
|
||||
import time
|
||||
|
||||
from test_framework.p2p import P2PInterface, msg_getheaders
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal
|
||||
|
||||
@ -43,6 +44,9 @@ class MinimumChainWorkTest(BitcoinTestFramework):
|
||||
for i in range(self.num_nodes-1):
|
||||
self.connect_nodes(i+1, i)
|
||||
|
||||
# Set clock of node2 2 days ahead, to keep it in IBD during this test.
|
||||
self.nodes[2].setmocktime(int(time.time()) + 48*60*60)
|
||||
|
||||
def run_test(self):
|
||||
# Start building a chain on node0. node2 shouldn't be able to sync until node1's
|
||||
# minchainwork is exceeded
|
||||
@ -74,6 +78,15 @@ class MinimumChainWorkTest(BitcoinTestFramework):
|
||||
assert self.nodes[1].getbestblockhash() != self.nodes[0].getbestblockhash()
|
||||
assert_equal(self.nodes[2].getblockcount(), starting_blockcount)
|
||||
|
||||
self.log.info("Check that getheaders requests to node2 are ignored")
|
||||
peer = self.nodes[2].add_p2p_connection(P2PInterface())
|
||||
msg = msg_getheaders()
|
||||
msg.locator.vHave = [int(self.nodes[2].getbestblockhash(), 16)]
|
||||
msg.hashstop = 0
|
||||
peer.send_and_ping(msg)
|
||||
time.sleep(5)
|
||||
assert ("headers" not in peer.last_message or len(peer.last_message["headers"].headers) == 0)
|
||||
|
||||
self.log.info("Generating one more block")
|
||||
self.nodes[0].generatetoaddress(1, self.nodes[0].get_deterministic_priv_key().address)
|
||||
|
||||
@ -88,6 +101,14 @@ class MinimumChainWorkTest(BitcoinTestFramework):
|
||||
self.sync_all()
|
||||
self.log.info("Blockcounts: %s", [n.getblockcount() for n in self.nodes])
|
||||
|
||||
self.log.info("Test that getheaders requests to node2 are not ignored")
|
||||
peer.send_and_ping(msg)
|
||||
assert "headers" in peer.last_message
|
||||
|
||||
# Verify that node2 is in fact still in IBD (otherwise this test may
|
||||
# not be exercising the logic we want!)
|
||||
assert_equal(self.nodes[2].getblockchaininfo()['initialblockdownload'], True)
|
||||
|
||||
self.log.info("Test -minimumchainwork with a non-hex value")
|
||||
self.stop_node(0)
|
||||
self.nodes[0].assert_start_raises_init_error(
|
||||
|
37
test/functional/p2p_block_sync.py
Executable file
37
test/functional/p2p_block_sync.py
Executable file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2022 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test block download
|
||||
|
||||
Ensure that even in IBD, we'll eventually sync chain from inbound peers
|
||||
(whether we have only inbound peers or both inbound and outbound peers).
|
||||
"""
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
|
||||
class BlockSyncTest(BitcoinTestFramework):
|
||||
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 3
|
||||
|
||||
def setup_network(self):
|
||||
self.setup_nodes()
|
||||
# Construct a network:
|
||||
# node0 -> node1 -> node2
|
||||
# So node1 has both an inbound and outbound peer.
|
||||
# In our test, we will mine a block on node0, and ensure that it makes
|
||||
# to to both node1 and node2.
|
||||
self.connect_nodes(0, 1)
|
||||
self.connect_nodes(1, 2)
|
||||
|
||||
def run_test(self):
|
||||
self.log.info("Setup network: node0->node1->node2")
|
||||
self.log.info("Mining one block on node0 and verify all nodes sync")
|
||||
self.nodes[0].generate(1)
|
||||
self.log.info("Success!")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
BlockSyncTest().main()
|
119
test/functional/p2p_initial_headers_sync.py
Executable file
119
test/functional/p2p_initial_headers_sync.py
Executable file
@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2022 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test initial headers download
|
||||
|
||||
Test that we only try to initially sync headers from one peer (until our chain
|
||||
is close to caught up), and that each block announcement results in only one
|
||||
additional peer receiving a getheaders message.
|
||||
"""
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.messages import (
|
||||
CInv,
|
||||
MSG_BLOCK,
|
||||
msg_headers2,
|
||||
msg_inv,
|
||||
)
|
||||
from test_framework.p2p import (
|
||||
p2p_lock,
|
||||
P2PInterface,
|
||||
)
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
)
|
||||
import random
|
||||
|
||||
class HeadersSyncTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
|
||||
def setup_chain(self):
|
||||
# This test operates under the assumption that the adjusted time is well ahead of block
|
||||
# time.
|
||||
#
|
||||
# By default when we setup a new chain, we also adjust the mocktime (this is not done in
|
||||
# Bitcoin's test suite), which violates this test's assumption and causes it to fail. We
|
||||
# remedy this by ensuring the test's assumptions are met (i.e. we don't adjust mocktime)
|
||||
#
|
||||
self.log.info("Initializing test directory " + self.options.tmpdir)
|
||||
if self.setup_clean_chain:
|
||||
self._initialize_chain_clean()
|
||||
else:
|
||||
self._initialize_chain()
|
||||
|
||||
def announce_random_block(self, peers):
|
||||
new_block_announcement = msg_inv(inv=[CInv(MSG_BLOCK, random.randrange(1<<256))])
|
||||
for p in peers:
|
||||
p.send_and_ping(new_block_announcement)
|
||||
|
||||
def run_test(self):
|
||||
self.log.info("Adding a peer to node0")
|
||||
peer1 = self.nodes[0].add_p2p_connection(P2PInterface())
|
||||
|
||||
# Wait for peer1 to receive a getheaders
|
||||
peer1.wait_for_getheaders()
|
||||
# An empty reply will clear the outstanding getheaders request,
|
||||
# allowing additional getheaders requests to be sent to this peer in
|
||||
# the future.
|
||||
peer1.send_message(msg_headers2())
|
||||
|
||||
self.log.info("Connecting two more peers to node0")
|
||||
# Connect 2 more peers; they should not receive a getheaders yet
|
||||
peer2 = self.nodes[0].add_p2p_connection(P2PInterface())
|
||||
peer3 = self.nodes[0].add_p2p_connection(P2PInterface())
|
||||
|
||||
all_peers = [peer1, peer2, peer3]
|
||||
|
||||
self.log.info("Verify that peer2 and peer3 don't receive a getheaders after connecting")
|
||||
for p in all_peers:
|
||||
p.sync_with_ping()
|
||||
with p2p_lock:
|
||||
assert "getheaders2" not in peer2.last_message
|
||||
assert "getheaders2" not in peer3.last_message
|
||||
|
||||
with p2p_lock:
|
||||
peer1.last_message.pop("getheaders2", None)
|
||||
|
||||
self.log.info("Have all peers announce a new block")
|
||||
self.announce_random_block(all_peers)
|
||||
|
||||
self.log.info("Check that peer1 receives a getheaders in response")
|
||||
peer1.wait_for_getheaders()
|
||||
peer1.send_message(msg_headers2()) # Send empty response, see above
|
||||
with p2p_lock:
|
||||
peer1.last_message.pop("getheaders2", None)
|
||||
|
||||
self.log.info("Check that exactly 1 of {peer2, peer3} received a getheaders in response")
|
||||
count = 0
|
||||
peer_receiving_getheaders = None
|
||||
for p in [peer2, peer3]:
|
||||
with p2p_lock:
|
||||
if "getheaders2" in p.last_message:
|
||||
count += 1
|
||||
peer_receiving_getheaders = p
|
||||
p.last_message.pop("getheaders2", None)
|
||||
p.send_message(msg_headers2()) # Send empty response, see above
|
||||
|
||||
assert_equal(count, 1)
|
||||
|
||||
self.log.info("Announce another new block, from all peers")
|
||||
self.announce_random_block(all_peers)
|
||||
|
||||
self.log.info("Check that peer1 receives a getheaders in response")
|
||||
peer1.wait_for_getheaders()
|
||||
|
||||
self.log.info("Check that the remaining peer received a getheaders as well")
|
||||
expected_peer = peer2
|
||||
if peer2 == peer_receiving_getheaders:
|
||||
expected_peer = peer3
|
||||
|
||||
expected_peer.wait_for_getheaders()
|
||||
|
||||
self.log.info("Success!")
|
||||
|
||||
if __name__ == '__main__':
|
||||
HeadersSyncTest().main()
|
||||
|
@ -172,6 +172,7 @@ BASE_SCRIPTS = [
|
||||
'wallet_avoidreuse.py --descriptors',
|
||||
'mempool_reorg.py',
|
||||
'mempool_persist.py',
|
||||
'p2p_block_sync.py',
|
||||
'wallet_multiwallet.py --legacy-wallet',
|
||||
'wallet_multiwallet.py --descriptors',
|
||||
'wallet_multiwallet.py --usecli',
|
||||
@ -254,6 +255,7 @@ BASE_SCRIPTS = [
|
||||
'rpc_generate.py',
|
||||
'wallet_balance.py --legacy-wallet',
|
||||
'wallet_balance.py --descriptors',
|
||||
'p2p_initial_headers_sync.py',
|
||||
'feature_nulldummy.py --legacy-wallet',
|
||||
'feature_nulldummy.py --descriptors',
|
||||
'mempool_accept.py',
|
||||
|
Loading…
Reference in New Issue
Block a user