Skip to content

Commit 6a803ac

Browse files
fix: canonicalize serialization of block-derived EvoDB payloads
1 parent 35c47c4 commit 6a803ac

8 files changed

Lines changed: 39 additions & 8 deletions

File tree

src/evo/chainhelper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ bool CChainstateHelper::RemoveConflictingISLockByTx(const CTransaction& tx)
8585
return true;
8686
}
8787

88-
std::unordered_map<uint8_t, int> CChainstateHelper::GetSignalsStage(const CBlockIndex* const pindexPrev)
88+
std::map<uint8_t, int> CChainstateHelper::GetSignalsStage(const CBlockIndex* const pindexPrev)
8989
{
9090
return ehf_manager->GetSignalsStage(pindexPrev);
9191
}

src/evo/chainhelper.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
#define BITCOIN_EVO_CHAINHELPER_H
77

88
#include <cstdint>
9+
#include <map>
910
#include <memory>
1011
#include <optional>
11-
#include <unordered_map>
1212

1313
class CBlockIndex;
1414
class CCreditPoolManager;
@@ -77,7 +77,7 @@ class CChainstateHelper
7777
bool IsInstantSendWaitingForTx(const uint256& hash) const;
7878
bool RemoveConflictingISLockByTx(const CTransaction& tx);
7979

80-
std::unordered_map<uint8_t, int> GetSignalsStage(const CBlockIndex* const pindexPrev);
80+
std::map<uint8_t, int> GetSignalsStage(const CBlockIndex* const pindexPrev);
8181
};
8282

8383
#endif // BITCOIN_EVO_CHAINHELPER_H

src/evo/deterministicmns.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121
#include <gsl/pointers.h>
2222
#include <immer/map.hpp>
2323

24+
#include <algorithm>
2425
#include <atomic>
2526
#include <limits>
2627
#include <numeric>
2728
#include <unordered_map>
2829
#include <utility>
30+
#include <vector>
2931

3032
class CBlock;
3133
class CBlockIndex;
@@ -593,9 +595,15 @@ class CDeterministicMNListDiff
593595
s << addedMNs;
594596

595597
WriteCompactSize(s, updatedMNs.size());
596-
for (const auto& [internalId, pdmnState] : updatedMNs) {
598+
std::vector<uint64_t> updatedMNsInternalIds;
599+
updatedMNsInternalIds.reserve(updatedMNs.size());
600+
for (const auto& entry : updatedMNs) {
601+
updatedMNsInternalIds.emplace_back(entry.first);
602+
}
603+
std::sort(updatedMNsInternalIds.begin(), updatedMNsInternalIds.end());
604+
for (const auto& internalId : updatedMNsInternalIds) {
597605
WriteVarInt<Stream, VarIntMode::DEFAULT, uint64_t>(s, internalId);
598-
s << pdmnState;
606+
s << updatedMNs.at(internalId);
599607
}
600608

601609
WriteCompactSize(s, removedMns.size());

src/evo/evodb.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ class CEvoDB
113113

114114
/**
115115
* Write immutable block-derived data, accepting an identical existing value.
116+
* V must have canonical serialization: its bytes must be a pure function of
117+
* its logical content. Audited call-site types are CDeterministicMNListDiff,
118+
* CDeterministicMNList, AbstractEHFManager::Signals, the mined-commitment
119+
* pair, and CCreditPool.
116120
* TODO(assumeutxo): WriteDerived spot-checks are not the holistic base-state
117121
* comparison required at snapshot completion.
118122
*/

src/node/miner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ void BlockAssembler::addPackageTxs(const CTxMemPool& mempool, int& nPackagesSele
473473
}
474474

475475
// This map with signals is used only to find duplicates
476-
std::unordered_map<uint8_t, int> signals = m_chain_helper.ehf_manager->GetSignalsStage(pindexPrev);
476+
auto signals = m_chain_helper.ehf_manager->GetSignalsStage(pindexPrev);
477477

478478
// mapModifiedTx will store sorted packages after they are modified
479479
// because some of their txs are already in the block

src/rpc/blockchain.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1457,7 +1457,7 @@ static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue&
14571457
softforks.pushKV(DeploymentName(dep), rv);
14581458
}
14591459

1460-
static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, const std::unordered_map<uint8_t, int>& signals, UniValue& softforks, const ChainstateManager& chainman, Consensus::DeploymentPos id)
1460+
static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, const AbstractEHFManager::Signals& signals, UniValue& softforks, const ChainstateManager& chainman, Consensus::DeploymentPos id)
14611461
{
14621462
// For BIP9 deployments.
14631463

src/test/evo_deterministicmns_tests.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,25 @@ static void SmlCache(TestChainSetup& setup)
15061506

15071507
BOOST_AUTO_TEST_SUITE(evo_dip3_activation_tests)
15081508

1509+
BOOST_AUTO_TEST_CASE(deterministic_mn_list_diff_serialization_is_canonical)
1510+
{
1511+
CDeterministicMNListDiff forward;
1512+
forward.updatedMNs.emplace(1, CDeterministicMNStateDiff{});
1513+
forward.updatedMNs.emplace(2, CDeterministicMNStateDiff{});
1514+
1515+
CDeterministicMNListDiff reverse;
1516+
reverse.updatedMNs.emplace(2, CDeterministicMNStateDiff{});
1517+
reverse.updatedMNs.emplace(1, CDeterministicMNStateDiff{});
1518+
1519+
CDataStream forward_stream{SER_DISK, CLIENT_VERSION};
1520+
CDataStream reverse_stream{SER_DISK, CLIENT_VERSION};
1521+
forward_stream << forward;
1522+
reverse_stream << reverse;
1523+
1524+
BOOST_CHECK_EQUAL_COLLECTIONS(forward_stream.begin(), forward_stream.end(),
1525+
reverse_stream.begin(), reverse_stream.end());
1526+
}
1527+
15091528
struct TestChainDIP3BeforeActivationSetup : public TestChainSetup {
15101529
TestChainDIP3BeforeActivationSetup() :
15111530
TestChainSetup(430)

src/versionbits.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ class VersionBitsCache
105105
class AbstractEHFManager
106106
{
107107
public:
108-
using Signals = std::unordered_map<uint8_t, int>;
108+
using Signals = std::map<uint8_t, int>;
109109

110110
public:
111111
AbstractEHFManager() = default;

0 commit comments

Comments
 (0)