From b52248f3632fb2bcdf4529dbb204de64dc66efa6 Mon Sep 17 00:00:00 2001 From: Studio KVC Date: Mon, 14 Sep 2026 19:17:01 +0200 Subject: [PATCH 1/6] fix(t8n): preserve unsigned block timestamps --- test/state/block.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/state/block.hpp b/test/state/block.hpp index 295f98956e..161b397eae 100644 --- a/test/state/block.hpp +++ b/test/state/block.hpp @@ -34,10 +34,10 @@ struct Withdrawal struct BlockInfo { int64_t number = 0; - int64_t timestamp = 0; + uint64_t timestamp = 0; hash256 hash; hash256 parent_hash; - int64_t parent_timestamp = 0; + uint64_t parent_timestamp = 0; int64_t gas_limit = 0; int64_t gas_used = 0; address coinbase; From 5b7bee4961f57686b1670d49a3147e7eb1606f13 Mon Sep 17 00:00:00 2001 From: Studio KVC Date: Mon, 14 Sep 2026 19:17:30 +0200 Subject: [PATCH 2/6] fix(t8n): use unsigned timestamps in difficulty API --- test/state/ethash_difficulty.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/state/ethash_difficulty.hpp b/test/state/ethash_difficulty.hpp index a271cc2a22..408fbab73f 100644 --- a/test/state/ethash_difficulty.hpp +++ b/test/state/ethash_difficulty.hpp @@ -8,6 +8,6 @@ namespace evmone::state { int64_t calculate_difficulty(int64_t parent_difficulty, bool parent_has_ommers, - int64_t parent_timestamp, int64_t current_timestamp, int64_t block_number, + uint64_t parent_timestamp, uint64_t current_timestamp, int64_t block_number, evmc_revision rev) noexcept; } // namespace evmone::state From ce6552ad16460acb6f26c3fbcec3b75f1cc579c5 Mon Sep 17 00:00:00 2001 From: Studio KVC Date: Mon, 14 Sep 2026 19:19:50 +0200 Subject: [PATCH 3/6] Update statetest_loader.cpp --- test/utils/statetest_loader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/utils/statetest_loader.cpp b/test/utils/statetest_loader.cpp index 2d282e54d7..36b6389228 100644 --- a/test/utils/statetest_loader.cpp +++ b/test/utils/statetest_loader.cpp @@ -277,8 +277,8 @@ state::BlockInfo from_json_with_rev( return state::BlockInfo{ .number = from_json(j.at("currentNumber")), - .timestamp = from_json(j.at("currentTimestamp")), - .parent_timestamp = load_or(j, "parentTimestamp", 0), + .timestamp = from_json(j.at("currentTimestamp")), + .parent_timestamp = load_or(j, "parentTimestamp", 0), .gas_limit = from_json(j.at("currentGasLimit")), .coinbase = from_json(j.at("currentCoinbase")), .difficulty = load_or(j, "currentDifficulty", 0), @@ -328,7 +328,7 @@ TestState from_json(const json::json& j) acc.storage[from_json(j_key)] = value; } } - } + // Block timestamps are loaded as uint64_t to preserve the full EVM range. return o; } From 0e9860f0e47e6c95a24e2b91fe7c5a875fa67433 Mon Sep 17 00:00:00 2001 From: Studio KVC Date: Mon, 14 Sep 2026 19:20:17 +0200 Subject: [PATCH 4/6] fix(t8n): avoid signed overflow in difficulty calculation --- test/state/ethash_difficulty.cpp | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/test/state/ethash_difficulty.cpp b/test/state/ethash_difficulty.cpp index 31254f2fb8..e888d6f86a 100644 --- a/test/state/ethash_difficulty.cpp +++ b/test/state/ethash_difficulty.cpp @@ -2,10 +2,12 @@ // Copyright 2023 The evmone Authors. // SPDX-License-Identifier: Apache-2.0 + #include "ethash_difficulty.hpp" #include #include + namespace evmone::state { namespace @@ -28,30 +30,40 @@ int64_t get_bomb_delay(evmc_revision rev) noexcept } } -int64_t calculate_difficulty_pre_byzantium(int64_t parent_difficulty, int64_t parent_timestamp, - int64_t current_timestamp, int64_t block_number, evmc_revision rev) + +int64_t calculate_difficulty_pre_byzantium(int64_t parent_difficulty, uint64_t parent_timestamp, + uint64_t current_timestamp, int64_t block_number, evmc_revision rev) { // According to https://eips.ethereum.org/EIPS/eip-2 const auto period_count = block_number / 100'000; const auto offset = parent_difficulty / 2048; + auto diff = parent_difficulty; + if (rev < EVMC_HOMESTEAD) diff += offset * (current_timestamp - parent_timestamp < 13 ? 1 : -1); else - diff += offset * std::max(1 - (current_timestamp - parent_timestamp) / 10, int64_t{-99}); + { + const auto timestamp_delta = (current_timestamp - parent_timestamp) / 10; + diff += offset * (timestamp_delta > 100 ? int64_t{-99} : + std::max(1 - static_cast(timestamp_delta), int64_t{-99})); + } + if (period_count > 2) diff += 2 << (block_number / 100'000 - 3); else if (period_count == 2) diff += 1; + return diff; } + int64_t calculate_difficulty_since_byzantium(int64_t parent_difficulty, bool parent_has_ommers, - int64_t parent_timestamp, int64_t current_timestamp, int64_t block_number, + uint64_t parent_timestamp, uint64_t current_timestamp, int64_t block_number, evmc_revision rev) noexcept { const auto delay = get_bomb_delay(rev); @@ -61,24 +73,29 @@ int64_t calculate_difficulty_since_byzantium(int64_t parent_difficulty, bool par const auto epsilon = p < 0 ? 0 : int64_t{1} << p; const auto y = parent_has_ommers ? 2 : 1; + const auto timestamp_diff = current_timestamp - parent_timestamp; assert(timestamp_diff > 0); - const auto sigma_2 = std::max(y - timestamp_diff / 9, int64_t{-99}); + const auto sigma_2 = timestamp_diff / 9 >= 100 ? int64_t{-99} : + std::max(y - static_cast(timestamp_diff / 9), int64_t{-99}); const auto x = parent_difficulty / 2048; return parent_difficulty + x * sigma_2 + epsilon; } } // namespace + int64_t calculate_difficulty(int64_t parent_difficulty, bool parent_has_ommers, - int64_t parent_timestamp, int64_t current_timestamp, int64_t block_number, + uint64_t parent_timestamp, uint64_t current_timestamp, int64_t block_number, evmc_revision rev) noexcept { // The calculation follows Ethereum Yellow Paper section 4.3.4. "Block Header Validity". static constexpr int64_t MIN_DIFFICULTY = 0x20000; + if (rev >= EVMC_PARIS) return 0; // No difficulty after the Merge. + const auto difficulty = (rev < EVMC_BYZANTIUM) ? calculate_difficulty_pre_byzantium( @@ -86,6 +103,7 @@ int64_t calculate_difficulty(int64_t parent_difficulty, bool parent_has_ommers, calculate_difficulty_since_byzantium(parent_difficulty, parent_has_ommers, parent_timestamp, current_timestamp, block_number, rev); + return std::max(MIN_DIFFICULTY, difficulty); } } // namespace evmone::state From 196deec6164682d697447e6e9eacd97fc54cd034 Mon Sep 17 00:00:00 2001 From: Studio KVC Date: Mon, 14 Sep 2026 19:21:00 +0200 Subject: [PATCH 5/6] style: normalize BlockInfo timestamp indentation --- test/state/block.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/state/block.hpp b/test/state/block.hpp index 161b397eae..1027935d8f 100644 --- a/test/state/block.hpp +++ b/test/state/block.hpp @@ -34,10 +34,10 @@ struct Withdrawal struct BlockInfo { int64_t number = 0; - uint64_t timestamp = 0; + uint64_t timestamp = 0; hash256 hash; hash256 parent_hash; - uint64_t parent_timestamp = 0; + uint64_t parent_timestamp = 0; int64_t gas_limit = 0; int64_t gas_used = 0; address coinbase; From 82831d6c0dfb21275373dd2e400747c3f8113fe5 Mon Sep 17 00:00:00 2001 From: Studio KVC Date: Mon, 14 Sep 2026 19:21:24 +0200 Subject: [PATCH 6/6] style: normalize timestamp loader indentation --- test/utils/statetest_loader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils/statetest_loader.cpp b/test/utils/statetest_loader.cpp index 36b6389228..cfb42b6f71 100644 --- a/test/utils/statetest_loader.cpp +++ b/test/utils/statetest_loader.cpp @@ -277,9 +277,9 @@ state::BlockInfo from_json_with_rev( return state::BlockInfo{ .number = from_json(j.at("currentNumber")), - .timestamp = from_json(j.at("currentTimestamp")), + .timestamp = from_json(j.at("currentTimestamp")), .parent_timestamp = load_or(j, "parentTimestamp", 0), - .gas_limit = from_json(j.at("currentGasLimit")), + .parent_timestamp = load_or(j, "parentTimestamp", 0), .coinbase = from_json(j.at("currentCoinbase")), .difficulty = load_or(j, "currentDifficulty", 0), .parent_difficulty = load_or(j, "parentDifficulty", 0),