mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-13 06:04:42 +02:00
kernel: add btck_set_mock_time for testing time-dependent paths
Some kernel paths read the current time (e.g. header validation's future-time check, and the `btck_SynchronizationState` carried by `btck_NotifyBlockTip` / `btck_NotifyHeaderTip` callbacks), which makes them awkward to exercise deterministically in tests. This commit exposes `btck_set_mock_time` as a wrapper over the existing `SetMockTime`, mirroring what the node has via the `setmocktime` RPC.
This commit is contained in:
@@ -1386,3 +1386,51 @@ BOOST_AUTO_TEST_CASE(btck_transaction_check_tests)
|
||||
"ffffffff00ffffffff000100000000000000000000000000000000000000000000000000000000"
|
||||
"00000000000000ffffffff010000000000000000015100000000");
|
||||
}
|
||||
|
||||
class KernelMockTime
|
||||
{
|
||||
public:
|
||||
explicit KernelMockTime(std::chrono::seconds timestamp) { set(timestamp); }
|
||||
~KernelMockTime()
|
||||
{
|
||||
set_mock_time(std::chrono::seconds{0});
|
||||
}
|
||||
|
||||
KernelMockTime(const KernelMockTime&) = delete;
|
||||
KernelMockTime& operator=(const KernelMockTime&) = delete;
|
||||
|
||||
void set(std::chrono::seconds timestamp) { set_mock_time(timestamp); }
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(btck_set_mock_time_tests)
|
||||
{
|
||||
// Out-of-range timestamps throw
|
||||
BOOST_CHECK_EXCEPTION(set_mock_time(std::chrono::seconds{-1}), std::runtime_error, HasReason("timestamp out of range"));
|
||||
constexpr std::chrono::seconds max_time{std::numeric_limits<uint32_t>::max()};
|
||||
BOOST_CHECK_EXCEPTION(set_mock_time(max_time + std::chrono::seconds{1}), std::runtime_error, HasReason("timestamp out of range"));
|
||||
|
||||
// Confirm the mock time actually takes effect by exercising the header future-time check
|
||||
auto test_directory{TestDirectory{"set_mock_time_test_bitcoin_kernel"}};
|
||||
auto notifications{std::make_shared<TestKernelNotifications>()};
|
||||
auto context{create_context(notifications, ChainType::REGTEST)};
|
||||
auto chainman{create_chainman(
|
||||
test_directory, /*reindex=*/false, /*wipe_chainstate=*/false,
|
||||
/*block_tree_db_in_memory=*/true, /*chainstate_db_in_memory=*/true, context)};
|
||||
|
||||
Block block{hex_string_to_byte_vec(REGTEST_BLOCK_DATA[0])};
|
||||
BlockHeader header{block.GetHeader()};
|
||||
const std::chrono::seconds block_time{header.Timestamp()};
|
||||
|
||||
// With the time set 3h before the header, the kernel must see the header as >2h in the future and reject it
|
||||
KernelMockTime mock_time{block_time - std::chrono::hours{3}};
|
||||
BlockValidationState future_state{chainman->ProcessBlockHeader(header)};
|
||||
BOOST_CHECK(future_state.GetValidationMode() == ValidationMode::INVALID);
|
||||
BOOST_CHECK(future_state.GetBlockValidationResult() == BlockValidationResult::TIME_FUTURE);
|
||||
|
||||
// At the upper bound the header is far in the past and must be accepted; this also
|
||||
// confirms the future-time check's "now + 2h" computation doesn't overflow when now is at its max.
|
||||
mock_time.set(max_time);
|
||||
BlockValidationState ok_state{chainman->ProcessBlockHeader(header)};
|
||||
BOOST_CHECK(ok_state.GetValidationMode() == ValidationMode::VALID);
|
||||
BOOST_CHECK(ok_state.GetBlockValidationResult() == BlockValidationResult::UNSET);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user