Skip to content

Commit 496ed89

Browse files
UdjinM6claude
andcommitted
refactor: add BuildNewListFromBlock overload accepting explicit prevList
Add overload that takes an explicit starting CDeterministicMNList instead of loading from GetListForBlock. This allows rebuilding masternode lists from trusted snapshots without depending on potentially corrupted diffs in the database. Key changes: - Add new overload taking prevList parameter (specialtxman.h) - Refactor original method to delegate to new overload (specialtxman.cpp) - Add assert to verify prevList is either empty or matches previous block - Skip collateral validation when using dummy coins view (historical blocks) Co-authored-by: Claude (Anthropic AI) <[email protected]>
1 parent 38baa5f commit 496ed89

File tree

2 files changed

+34
-8
lines changed

2 files changed

+34
-8
lines changed

src/evo/specialtxman.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,24 @@ bool CSpecialTxProcessor::BuildNewListFromBlock(const CBlock& block, gsl::not_nu
176176
BlockValidationState& state, CDeterministicMNList& mnListRet)
177177
{
178178
AssertLockHeld(cs_main);
179+
CDeterministicMNList oldList = m_dmnman.GetListForBlock(pindexPrev);
180+
return BuildNewListFromBlock(block, pindexPrev, oldList, view, debugLogs, state, mnListRet);
181+
}
182+
183+
bool CSpecialTxProcessor::BuildNewListFromBlock(const CBlock& block, gsl::not_null<const CBlockIndex*> pindexPrev,
184+
const CDeterministicMNList& prevList, const CCoinsViewCache& view,
185+
bool debugLogs, BlockValidationState& state,
186+
CDeterministicMNList& mnListRet)
187+
{
188+
AssertLockHeld(cs_main);
189+
190+
// Verify that prevList either represents an empty/initial state (default-constructed),
191+
// or it matches the previous block's hash.
192+
assert(prevList == CDeterministicMNList() || prevList.GetBlockHash() == pindexPrev->GetBlockHash());
179193

180194
int nHeight = pindexPrev->nHeight + 1;
181195

182-
CDeterministicMNList oldList = m_dmnman.GetListForBlock(pindexPrev);
196+
CDeterministicMNList oldList = prevList;
183197
CDeterministicMNList newList = oldList;
184198
newList.SetBlockHash(uint256()); // we can't know the final block hash, so better not return a (invalid) block hash
185199
newList.SetHeight(nHeight);
@@ -235,13 +249,18 @@ bool CSpecialTxProcessor::BuildNewListFromBlock(const CBlock& block, gsl::not_nu
235249
dmn->collateralOutpoint = proTx.collateralOutpoint;
236250
}
237251

238-
Coin coin;
239-
CAmount expectedCollateral = GetMnType(proTx.nType).collat_amount;
240-
if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) ||
241-
coin.IsSpent() || coin.out.nValue != expectedCollateral)) {
242-
// should actually never get to this point as CheckProRegTx should have handled this case.
243-
// We do this additional check nevertheless to be 100% sure
244-
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-collateral");
252+
// Complain about spent collaterals only when we process the tip.
253+
// This is safe because blocks below the tip were verified
254+
// when they were connected initially.
255+
if (!view.GetBestBlock().IsNull()) {
256+
Coin coin;
257+
CAmount expectedCollateral = GetMnType(proTx.nType).collat_amount;
258+
if (!proTx.collateralOutpoint.hash.IsNull() && (!view.GetCoin(dmn->collateralOutpoint, coin) ||
259+
coin.IsSpent() || coin.out.nValue != expectedCollateral)) {
260+
// should actually never get to this point as CheckProRegTx should have handled this case.
261+
// We do this additional check nevertheless to be 100% sure
262+
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-collateral");
263+
}
245264
}
246265

247266
auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint);

src/evo/specialtxman.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ class CSpecialTxProcessor
7979
const CCoinsViewCache& view, bool debugLogs, BlockValidationState& state,
8080
CDeterministicMNList& mnListRet) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
8181

82+
// Variant that takes an explicit starting list instead of loading from GetListForBlock
83+
// Used for rebuilding diffs from trusted snapshots
84+
bool BuildNewListFromBlock(const CBlock& block, gsl::not_null<const CBlockIndex*> pindexPrev,
85+
const CDeterministicMNList& prevList, const CCoinsViewCache& view, bool debugLogs,
86+
BlockValidationState& state, CDeterministicMNList& mnListRet)
87+
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
88+
8289
private:
8390
bool CheckCreditPoolDiffForBlock(const CBlock& block, const CBlockIndex* pindex, const CCbTx& cbTx,
8491
BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);

0 commit comments

Comments
 (0)