From 855ac740d4f26f8e563196338391e77a864b6faa Mon Sep 17 00:00:00 2001 From: rodiazet Date: Wed, 16 Aug 2023 19:14:35 +0200 Subject: [PATCH] Introduce difficulty calculation in t8n --- test/state/mpt_hash.hpp | 3 + test/state/state.hpp | 4 + test/statetest/statetest_loader.cpp | 33 +++++-- test/t8n/t8n.cpp | 87 ++++++++++++++++++- .../statetest_loader_block_info_test.cpp | 3 +- 5 files changed, 120 insertions(+), 10 deletions(-) diff --git a/test/state/mpt_hash.hpp b/test/state/mpt_hash.hpp index e0a25a9df6..64d2cf0122 100644 --- a/test/state/mpt_hash.hpp +++ b/test/state/mpt_hash.hpp @@ -9,6 +9,9 @@ namespace evmone::state { +static constexpr auto EmptyListHash = + 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347_bytes32; + struct Account; struct Transaction; struct TransactionReceipt; diff --git a/test/state/state.hpp b/test/state/state.hpp index 9c725d6c90..120be3efd9 100644 --- a/test/state/state.hpp +++ b/test/state/state.hpp @@ -82,8 +82,12 @@ struct BlockInfo { int64_t number = 0; int64_t timestamp = 0; + int64_t parent_timestamp = 0; int64_t gas_limit = 0; address coinbase; + int64_t current_difficulty = 0; + int64_t parent_difficulty = 0; + hash256 parent_uncle_hash; bytes32 prev_randao; uint64_t base_fee = 0; std::vector withdrawals; diff --git a/test/statetest/statetest_loader.cpp b/test/statetest/statetest_loader.cpp index 344d3ba2c7..2bc555ce8f 100644 --- a/test/statetest/statetest_loader.cpp +++ b/test/statetest/statetest_loader.cpp @@ -150,16 +150,30 @@ inline uint64_t calculate_current_base_fee_eip1559( template <> state::BlockInfo from_json(const json::json& j) { - evmc::bytes32 difficulty; + evmc::bytes32 prev_randao; + int64_t current_difficulty = 0; + int64_t parent_difficulty = 0; const auto prev_randao_it = j.find("currentRandom"); const auto current_difficulty_it = j.find("currentDifficulty"); const auto parent_difficulty_it = j.find("parentDifficulty"); + + if (current_difficulty_it != j.end()) + current_difficulty = from_json(*current_difficulty_it); + if (parent_difficulty_it != j.end()) + parent_difficulty = from_json(*parent_difficulty_it); + + // When it's not defined init it with difficulty value. if (prev_randao_it != j.end()) - difficulty = from_json(*prev_randao_it); + prev_randao = from_json(*prev_randao_it); else if (current_difficulty_it != j.end()) - difficulty = from_json(*current_difficulty_it); + prev_randao = from_json(*current_difficulty_it); else if (parent_difficulty_it != j.end()) - difficulty = from_json(*parent_difficulty_it); + prev_randao = from_json(*parent_difficulty_it); + + hash256 parent_uncle_hash; + const auto parent_uncle_hash_it = j.find("parentUncleHash"); + if (parent_uncle_hash_it != j.end()) + parent_uncle_hash = from_json(*parent_uncle_hash_it); uint64_t base_fee = 0; if (j.contains("currentBaseFee")) @@ -181,10 +195,15 @@ state::BlockInfo from_json(const json::json& j) } } + int64_t parent_timestamp = 0; + auto parent_timestamp_it = j.find("parentTimestamp"); + if (parent_timestamp_it != j.end()) + parent_timestamp = from_json(*parent_timestamp_it); + return {from_json(j.at("currentNumber")), from_json(j.at("currentTimestamp")), - from_json(j.at("currentGasLimit")), - from_json(j.at("currentCoinbase")), difficulty, base_fee, - std::move(withdrawals)}; + parent_timestamp, from_json(j.at("currentGasLimit")), + from_json(j.at("currentCoinbase")), current_difficulty, parent_difficulty, + parent_uncle_hash, prev_randao, base_fee, std::move(withdrawals)}; } template <> diff --git a/test/t8n/t8n.cpp b/test/t8n/t8n.cpp index 4f267efc57..86af40b057 100644 --- a/test/t8n/t8n.cpp +++ b/test/t8n/t8n.cpp @@ -19,6 +19,61 @@ using namespace evmone; using namespace evmone::test; using namespace std::literals; +namespace +{ +using namespace intx; + +int64_t get_bomb_delay(evmc_revision rev) +{ + switch (rev) + { + case EVMC_BYZANTIUM: + return 3000000; + case EVMC_CONSTANTINOPLE: + case EVMC_PETERSBURG: + case EVMC_ISTANBUL: + return 5000000; + case EVMC_BERLIN: + return 9000000; + case EVMC_LONDON: + return 9700000; + default: + throw std::runtime_error("get_bomb_delay: Wrong rev"); + } +} + +int64_t calc_difficulty(const int64_t& parent_difficulty, const hash256& parent_uncle_hash, + const int64_t& parent_timestamp, const int64_t& current_timestamp, const int64_t& block_num, + evmc_revision rev) +{ + if (rev >= EVMC_PARIS) + return 0; + + // TODO: Implement for older revisions + if (rev < EVMC_BYZANTIUM) + return 0x020000; + + static constexpr auto min_difficulty = int64_t{1} << 17; + + const auto kappa = get_bomb_delay(rev); + + const auto H_i_prime = kappa >= block_num ? 0 : block_num - kappa; + + const auto p = (H_i_prime / 100000) - 2; + assert(p < 63); + + const auto epsilon = p < 0 ? 0 : int64_t{1} << p; + + const auto y = parent_uncle_hash != state::EmptyListHash ? 2 : 1; + + const auto sigma_2 = std::max(y - (current_timestamp - parent_timestamp) / 9, int64_t{-99}); + + const int64_t x = parent_difficulty / 2048; + + return std::max(min_difficulty, (int64_t)parent_difficulty + x * sigma_2 + epsilon); +} +} // namespace + int main(int argc, const char* argv[]) { evmc_revision rev = {}; @@ -80,8 +135,36 @@ int main(int argc, const char* argv[]) } json::json j_result; - // FIXME: Calculate difficulty properly - j_result["currentDifficulty"] = "0x20000"; + + // Difficulty was received from upstream. No need to calc + // TODO: Check is it's needed by the blockchain test. If not remove if statement true branch + if (block.current_difficulty != 0) + j_result["currentDifficulty"] = hex0x(block.current_difficulty); + else + { + if (rev >= EVMC_SHANGHAI) + j_result["currentDifficulty"] = nullptr; + else + { + const auto current_difficulty = + calc_difficulty(block.parent_difficulty, block.parent_uncle_hash, + block.parent_timestamp, block.timestamp, block.number, rev); + + j_result["currentDifficulty"] = hex0x(current_difficulty); + block.current_difficulty = current_difficulty; + + // Override prev_randao with difficulty (swap bytes to BE) pre Merge + if (rev < EVMC_PARIS) + { + std::memset(block.prev_randao.bytes, 0, 32); + const auto s = sizeof(current_difficulty); + const auto diff_ptr = reinterpret_cast(¤t_difficulty); + for (size_t i = 0; i < s; ++i) + block.prev_randao.bytes[24 + i] = diff_ptr[s - 1 - i]; + } + } + }; + j_result["currentBaseFee"] = hex0x(block.base_fee); int64_t cumulative_gas_used = 0; diff --git a/test/unittests/statetest_loader_block_info_test.cpp b/test/unittests/statetest_loader_block_info_test.cpp index 053539e6bb..4cd057546a 100644 --- a/test/unittests/statetest_loader_block_info_test.cpp +++ b/test/unittests/statetest_loader_block_info_test.cpp @@ -131,7 +131,7 @@ TEST(statetest_loader, block_info_0_parent_difficulty) "parentBaseFee": "7", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "253", "blockHashes": { "0": "0xc305d826e3784046a7e9d31128ef98d3e96133fe454c16ef630574d967dfdb1a" }, @@ -147,6 +147,7 @@ TEST(statetest_loader, block_info_0_parent_difficulty) EXPECT_EQ(bi.base_fee, 7); EXPECT_EQ(bi.timestamp, 1000); EXPECT_EQ(bi.number, 1); + EXPECT_EQ(bi.parent_timestamp, 253); } TEST(statetest_loader, block_info_0_random)