Skip to content

Commit 82e5634

Browse files
committed
fix: restore BLS scheme after failed block validation
1 parent 317917a commit 82e5634

4 files changed

Lines changed: 89 additions & 14 deletions

File tree

src/test/evo_deterministicmns_tests.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,43 @@ BOOST_AUTO_TEST_CASE(v19_activation_legacy)
990990
FuncV19Activation(setup);
991991
}
992992

993+
BOOST_AUTO_TEST_CASE(v19_boundary_validation_failure_restores_bls_scheme)
994+
{
995+
TestChainV19Setup setup;
996+
auto& chainman = *Assert(setup.m_node.chainman.get());
997+
const CScript coinbase_pk = GetScriptForRawPubKey(setup.coinbaseKey.GetPubKey());
998+
999+
BOOST_REQUIRE(!DeploymentActiveAt(*chainman.ActiveChain().Tip(), chainman.GetConsensus(), Consensus::DEPLOYMENT_V19));
1000+
BOOST_REQUIRE(DeploymentActiveAfter(chainman.ActiveChain().Tip(), chainman.GetConsensus(), Consensus::DEPLOYMENT_V19));
1001+
const bool previous_bls_scheme{bls::bls_legacy_scheme.load()};
1002+
1003+
CMutableTransaction bad_tx;
1004+
bad_tx.nVersion = 1;
1005+
bad_tx.vin.emplace_back(COutPoint(uint256::ONE, 0));
1006+
bad_tx.vout.emplace_back(1 * COIN, CScript{} << OP_TRUE);
1007+
1008+
bls::bls_legacy_scheme.store(true);
1009+
1010+
CBlock proposal_block = setup.CreateBlock({bad_tx}, coinbase_pk, chainman.ActiveChainstate());
1011+
{
1012+
LOCK(cs_main);
1013+
BlockValidationState state;
1014+
BOOST_CHECK(!TestBlockValidity(state, *Assert(setup.m_node.chainlocks), *Assert(setup.m_node.evodb), Params(),
1015+
chainman.ActiveChainstate(), proposal_block, chainman.ActiveChain().Tip(),
1016+
/*fCheckPOW=*/true, /*fCheckMerkleRoot=*/true));
1017+
BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-inputs-missingorspent");
1018+
}
1019+
BOOST_CHECK(bls::bls_legacy_scheme.load());
1020+
1021+
CBlock connect_block = setup.CreateBlock({bad_tx}, coinbase_pk, chainman.ActiveChainstate());
1022+
const int height_before_invalid_block{chainman.ActiveChain().Height()};
1023+
(void)chainman.ProcessNewBlock(std::make_shared<const CBlock>(connect_block), /*force_processing=*/true, /*new_block=*/nullptr);
1024+
BOOST_CHECK_EQUAL(chainman.ActiveChain().Height(), height_before_invalid_block);
1025+
BOOST_CHECK(bls::bls_legacy_scheme.load());
1026+
1027+
bls::bls_legacy_scheme.store(previous_bls_scheme);
1028+
}
1029+
9931030
BOOST_AUTO_TEST_CASE(dip3_protx_legacy)
9941031
{
9951032
TestChainDIP3Setup setup;

src/test/validation_block_tests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,4 +362,5 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
362362
rpc_thread.join();
363363
}
364364
}
365+
365366
BOOST_AUTO_TEST_SUITE_END()

src/validation.cpp

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <validation.h>
88

99
#include <arith_uint256.h>
10+
#include <bls/bls.h>
1011
#include <chain.h>
1112
#include <chainparams.h>
1213
#include <checkqueue.h>
@@ -140,6 +141,40 @@ CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMe
140141
} // namespace node
141142
using node::GetTransaction;
142143

144+
namespace {
145+
146+
void SetBLSLegacyScheme(bool legacy_scheme, const char* logging_context) noexcept
147+
{
148+
if (legacy_scheme != bls::bls_legacy_scheme.load()) {
149+
bls::bls_legacy_scheme.store(legacy_scheme);
150+
LogPrintf("%s: bls_legacy_scheme=%d\n", logging_context, bls::bls_legacy_scheme.load());
151+
}
152+
}
153+
154+
class ScopedBLSLegacyScheme
155+
{
156+
public:
157+
explicit ScopedBLSLegacyScheme(const char* logging_context) noexcept :
158+
m_logging_context(logging_context),
159+
m_saved_scheme(bls::bls_legacy_scheme.load())
160+
{
161+
}
162+
163+
ScopedBLSLegacyScheme(const ScopedBLSLegacyScheme&) = delete;
164+
ScopedBLSLegacyScheme& operator=(const ScopedBLSLegacyScheme&) = delete;
165+
166+
~ScopedBLSLegacyScheme() noexcept
167+
{
168+
SetBLSLegacyScheme(m_saved_scheme, m_logging_context);
169+
}
170+
171+
private:
172+
const char* const m_logging_context;
173+
const bool m_saved_scheme;
174+
};
175+
176+
} // namespace
177+
143178
const CBlockIndex* CChainState::FindForkInGlobalIndex(const CBlockLocator& locator) const
144179
{
145180
AssertLockHeld(cs_main);
@@ -2181,7 +2216,7 @@ static int64_t nBlocksTotal = 0;
21812216
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
21822217
* can fail if those validity checks fail (among other reasons). */
21832218
bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex,
2184-
CCoinsViewCache& view, bool fJustCheck)
2219+
CCoinsViewCache& view, bool fJustCheck, bool* effective_bls_legacy_scheme)
21852220
{
21862221
int64_t nTimeStart = GetTimeMicros();
21872222

@@ -2193,6 +2228,8 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
21932228

21942229
assert(m_chain_helper);
21952230

2231+
ScopedBLSLegacyScheme bls_scheme_guard{__func__};
2232+
21962233
// Check it again in case a previous version let a bad block in
21972234
// NOTE: We don't currently (re-)invoke ContextualCheckBlock() or
21982235
// ContextualCheckBlockHeader() here. This means that if we add a new
@@ -2551,6 +2588,9 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
25512588
nTime8 - nTimeStart // in microseconds (µs)
25522589
);
25532590

2591+
if (effective_bls_legacy_scheme) {
2592+
*effective_bls_legacy_scheme = bls::bls_legacy_scheme.load();
2593+
}
25542594
return true;
25552595
}
25562596

@@ -3011,11 +3051,12 @@ bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew
30113051
// When adding aggregate statistics in the future, keep in mind that
30123052
// nBlocksTotal may be zero until the ConnectBlock() call below.
30133053
LogPrint(BCLog::BENCHMARK, " - Load block from disk: %.2fms\n", (nTime2 - nTime1) * MILLI);
3054+
bool effective_bls_legacy_scheme{bls::bls_legacy_scheme.load()};
30143055
{
30153056
auto dbTx = m_evoDb.BeginTransaction();
30163057

30173058
CCoinsViewCache view(&CoinsTip());
3018-
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view);
3059+
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, /*fJustCheck=*/false, &effective_bls_legacy_scheme);
30193060
GetMainSignals().BlockChecked(blockConnecting, state);
30203061
if (!rv) {
30213062
if (state.IsInvalid())
@@ -3045,6 +3086,7 @@ bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew
30453086
}
30463087
// Update m_chain & related variables.
30473088
m_chain.SetTip(*pindexNew);
3089+
SetBLSLegacyScheme(effective_bls_legacy_scheme, __func__);
30483090
UpdateTip(pindexNew);
30493091

30503092
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
@@ -4338,10 +4380,7 @@ bool TestBlockValidity(BlockValidationState& state,
43384380
AssertLockHeld(cs_main);
43394381
assert(pindexPrev && pindexPrev == chainstate.m_chain.Tip());
43404382

4341-
// TODO: instead restoring bls_legacy_scheme better to keep it unchanged
4342-
// Moreover, current implementation is working incorrect if current function
4343-
// will return value too early due to error: old value won't be restored
4344-
auto bls_legacy_scheme = bls::bls_legacy_scheme.load();
4383+
ScopedBLSLegacyScheme bls_scheme_guard{__func__};
43454384

43464385
uint256 hash = block.GetHash();
43474386
if (chainlocks.HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) {
@@ -4371,12 +4410,6 @@ bool TestBlockValidity(BlockValidationState& state,
43714410

43724411
assert(state.IsValid());
43734412

4374-
// we could switch to another scheme while testing, switch back to the original one
4375-
if (bls_legacy_scheme != bls::bls_legacy_scheme.load()) {
4376-
bls::bls_legacy_scheme.store(bls_legacy_scheme);
4377-
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
4378-
}
4379-
43804413
return true;
43814414
}
43824415

@@ -4449,6 +4482,8 @@ bool CVerifyDB::VerifyDB(
44494482
return true;
44504483
}
44514484

4485+
ScopedBLSLegacyScheme bls_scheme_guard{__func__};
4486+
44524487
// begin tx and let it rollback
44534488
auto dbTx = evoDb.BeginTransaction();
44544489

@@ -4538,6 +4573,7 @@ bool CVerifyDB::VerifyDB(
45384573

45394574
// check level 4: try reconnecting blocks
45404575
if (nCheckLevel >= 4 && !skipped_l3_checks) {
4576+
bool effective_bls_legacy_scheme{bls::bls_legacy_scheme.load()};
45414577
while (pindex != chainstate.m_chain.Tip()) {
45424578
const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)));
45434579
if (reportDone < percentageDone / 10) {
@@ -4550,8 +4586,9 @@ bool CVerifyDB::VerifyDB(
45504586
CBlock block;
45514587
if (!ReadBlockFromDisk(block, pindex, consensus_params))
45524588
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
4553-
if (!chainstate.ConnectBlock(block, state, pindex, coins))
4589+
if (!chainstate.ConnectBlock(block, state, pindex, coins, /*fJustCheck=*/false, &effective_bls_legacy_scheme))
45544590
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
4591+
SetBLSLegacyScheme(effective_bls_legacy_scheme, __func__);
45554592
if (ShutdownRequested()) return true;
45564593
}
45574594
}

src/validation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ class CChainState
709709

710710
// Block (dis)connection on a given view:
711711
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
712-
bool ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
712+
bool ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck = false, bool* effective_bls_legacy_scheme = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
713713

714714
// Apply the effects of a block disconnection on the UTXO set.
715715
bool DisconnectTip(BlockValidationState& state, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);

0 commit comments

Comments
 (0)