Add function to validate difficulty changes

The rule against difficulty adjustments changing by more than a factor of 4 can
be helpful for anti-DoS measures in contexts where we lack a full headers
chain, so expose this functionality separately and in the narrow case where we
only know the height, new value, and old value.

Includes fuzz test by Martin Zumsande.
This commit is contained in:
Suhas Daftuar
2022-05-25 10:16:56 -04:00
parent 2bd9aa5a44
commit 1d4cfa4272
4 changed files with 125 additions and 4 deletions

View File

@@ -83,3 +83,40 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
}
}
}
FUZZ_TARGET_INIT(pow_transition, initialize_pow)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const Consensus::Params& consensus_params{Params().GetConsensus()};
std::vector<std::unique_ptr<CBlockIndex>> blocks;
const uint32_t old_time{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
const uint32_t new_time{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
const int32_t version{fuzzed_data_provider.ConsumeIntegral<int32_t>()};
uint32_t nbits{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
const arith_uint256 pow_limit = UintToArith256(consensus_params.powLimit);
arith_uint256 old_target;
old_target.SetCompact(nbits);
if (old_target > pow_limit) {
nbits = pow_limit.GetCompact();
}
// Create one difficulty adjustment period worth of headers
for (int height = 0; height < consensus_params.DifficultyAdjustmentInterval(); ++height) {
CBlockHeader header;
header.nVersion = version;
header.nTime = old_time;
header.nBits = nbits;
if (height == consensus_params.DifficultyAdjustmentInterval() - 1) {
header.nTime = new_time;
}
auto current_block{std::make_unique<CBlockIndex>(header)};
current_block->pprev = blocks.empty() ? nullptr : blocks.back().get();
current_block->nHeight = height;
blocks.emplace_back(std::move(current_block)).get();
}
auto last_block{blocks.back().get()};
unsigned int new_nbits{GetNextWorkRequired(last_block, nullptr, consensus_params)};
Assert(PermittedDifficultyTransition(consensus_params, last_block->nHeight + 1, last_block->nBits, new_nbits));
}