Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ChainConfig refactor #78

Merged
merged 9 commits into from
Jan 11, 2024
6 changes: 3 additions & 3 deletions cmd/state-transition/state_transition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ Block StateTransition::get_block(InMemoryState& state, ChainConfig& chain_config
block.header.prev_randao = to_bytes32(from_hex(get_env("currentRandom")).value_or(Bytes{}));
}

const evmc_revision rev{chain_config.revision(block.header.number, block.header.timestamp)};
const evmc_revision rev{chain_config.revision(block.header)};

// set difficulty only for revisions before The Merge
// current block difficulty cannot fall below miniumum: https://eips.ethereum.org/EIPS/eip-2
static constexpr uint64_t kMinDifficulty{0x20000};
if (!chain_config.terminal_total_difficulty.has_value()) {
if (!chain_config.terminal_total_difficulty().has_value()) {
block.header.difficulty = intx::from_string<intx::uint256>(get_env("currentDifficulty"));
if (block.header.difficulty < kMinDifficulty && rev <= EVMC_LONDON) {
block.header.difficulty = kMinDifficulty;
Expand Down Expand Up @@ -330,7 +330,7 @@ void StateTransition::run() {
ExecutionProcessor processor{block, *ruleSet, *state, config};
Receipt receipt;

const evmc_revision rev{config.revision(block.header.number, block.header.timestamp)};
const evmc_revision rev{config.revision(block.header)};

auto pre_block_validation = ruleSet->pre_validate_block_body(block, *state);
auto block_validation = ruleSet->validate_block_header(block.header, *state, true);
Expand Down
4 changes: 2 additions & 2 deletions cmd/test/ethereum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ RunResults transaction_test(const nlohmann::json& j) {
}

const ChainConfig& config{silkworm::test::kNetworkConfig.at(entry.key())};
const evmc_revision rev{config.revision(/*block_number=*/0, /*block_time=*/0)};
const evmc_revision rev{config.revision(BlockHeader{.number=0,.timestamp=0})};

/* pre_validate_transaction checks for invalid signature only if from is empty, which means sender recovery
* phase (which btw also verifies signature) was not triggered yet. In the context of tests, instead, from is
Expand Down Expand Up @@ -438,7 +438,7 @@ Status individual_difficulty_test(const nlohmann::json& j, const ChainConfig& co
}
}

intx::uint256 calculated_difficulty{EthashRuleSet::difficulty(block_number, current_timestamp, parent_difficulty,
intx::uint256 calculated_difficulty{EthashRuleSet::difficulty(BlockHeader{.number=block_number, .timestamp=current_timestamp}, parent_difficulty,
parent_timestamp, parent_has_uncles, config)};
if (calculated_difficulty == current_difficulty) {
return Status::kPassed;
Expand Down
6 changes: 5 additions & 1 deletion eosevm/block_mapping.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#pragma once
#include <cstdint>

#include <silkworm/core/types/block.hpp>
#include <silkworm/core/common/util.hpp>
#include <eosevm/version.hpp>
namespace eosevm {

struct block_mapping
Expand Down Expand Up @@ -61,13 +63,15 @@ struct block_mapping
inline void prepare_block_header(silkworm::BlockHeader& header,
const block_mapping& bm,
uint64_t evm_contract_name,
uint32_t evm_block_num)
uint32_t evm_block_num,
uint64_t version)
{
header.beneficiary = silkworm::make_reserved_address(evm_contract_name);
header.difficulty = 1;
header.number = evm_block_num;
header.gas_limit = 0x7ffffffffff;
header.timestamp = bm.evm_block_num_to_evm_timestamp(header.number);
header.nonce = eosevm::version_to_nonce(version);
}


Expand Down
29 changes: 29 additions & 0 deletions eosevm/version.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <silkworm/core/types/block.hpp>
#include <silkworm/core/common/endian.hpp>

namespace eosevm {

using NonceType=silkworm::BlockHeader::NonceType;

inline NonceType version_to_nonce(uint64_t version) {
NonceType nonce;
silkworm::endian::store_big_u64(nonce.data(), version);
return nonce;
}

inline uint64_t nonce_to_version(const NonceType& nonce) {
// The nonce will be treated as big-endian number for now.
return silkworm::endian::load_big_u64(nonce.data());
}

inline evmc_revision version_to_evmc_revision(uint64_t version) {
switch (version) {
case 0: return EVMC_ISTANBUL;
case 1: return EVMC_ISTANBUL;
default: return EVMC_ISTANBUL;
}
}

} // namespace eosevm
149 changes: 84 additions & 65 deletions silkworm/core/chain/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <set>

#include <silkworm/core/common/as_range.hpp>
#include <silkworm/core/types/block.hpp>
#include <eosevm/version.hpp>

namespace silkworm {

Expand Down Expand Up @@ -74,33 +76,35 @@ nlohmann::json ChainConfig::to_json() const noexcept {
break;
}

member_to_json(ret, "homesteadBlock", homestead_block);
member_to_json(ret, "daoForkBlock", dao_block);
member_to_json(ret, "eip150Block", tangerine_whistle_block);
member_to_json(ret, "eip155Block", spurious_dragon_block);
member_to_json(ret, "byzantiumBlock", byzantium_block);
member_to_json(ret, "constantinopleBlock", constantinople_block);
member_to_json(ret, "petersburgBlock", petersburg_block);
member_to_json(ret, "istanbulBlock", istanbul_block);
member_to_json(ret, "muirGlacierBlock", muir_glacier_block);
member_to_json(ret, "berlinBlock", berlin_block);
member_to_json(ret, "londonBlock", london_block);
member_to_json(ret, "arrowGlacierBlock", arrow_glacier_block);
member_to_json(ret, "grayGlacierBlock", gray_glacier_block);

if (terminal_total_difficulty) {
member_to_json(ret, "homesteadBlock", _homestead_block);
member_to_json(ret, "daoForkBlock", _dao_block);
member_to_json(ret, "eip150Block", _tangerine_whistle_block);
member_to_json(ret, "eip155Block", _spurious_dragon_block);
member_to_json(ret, "byzantiumBlock", _byzantium_block);
member_to_json(ret, "constantinopleBlock", _constantinople_block);
member_to_json(ret, "petersburgBlock", _petersburg_block);
member_to_json(ret, "istanbulBlock", _istanbul_block);
member_to_json(ret, "muirGlacierBlock", _muir_glacier_block);
member_to_json(ret, "berlinBlock", _berlin_block);
member_to_json(ret, "londonBlock", _london_block);
member_to_json(ret, "arrowGlacierBlock", _arrow_glacier_block);
member_to_json(ret, "grayGlacierBlock", _gray_glacier_block);

if (_terminal_total_difficulty) {
// TODO (Andrew) geth probably treats terminalTotalDifficulty as a JSON number
ret[kTerminalTotalDifficulty] = to_string(*terminal_total_difficulty);
ret[kTerminalTotalDifficulty] = to_string(*_terminal_total_difficulty);
}

member_to_json(ret, "mergeNetsplitBlock", merge_netsplit_block);
member_to_json(ret, "shanghaiTime", shanghai_time);
member_to_json(ret, "cancunTime", cancun_time);
member_to_json(ret, "mergeNetsplitBlock", _merge_netsplit_block);
member_to_json(ret, "shanghaiTime", _shanghai_time);
member_to_json(ret, "cancunTime", _cancun_time);

if (genesis_hash.has_value()) {
ret["genesisBlockHash"] = to_hex(*genesis_hash, /*with_prefix=*/true);
}

member_to_json(ret, "version", _version);

return ret;
}

Expand All @@ -124,42 +128,44 @@ std::optional<ChainConfig> ChainConfig::from_json(const nlohmann::json& json) no
config.protocol_rule_set = protocol::RuleSetType::kNoProof;
}

read_json_config_member(json, "homesteadBlock", config.homestead_block);
read_json_config_member(json, "daoForkBlock", config.dao_block);
read_json_config_member(json, "eip150Block", config.tangerine_whistle_block);
read_json_config_member(json, "eip155Block", config.spurious_dragon_block);
read_json_config_member(json, "byzantiumBlock", config.byzantium_block);
read_json_config_member(json, "constantinopleBlock", config.constantinople_block);
read_json_config_member(json, "petersburgBlock", config.petersburg_block);
read_json_config_member(json, "istanbulBlock", config.istanbul_block);
read_json_config_member(json, "muirGlacierBlock", config.muir_glacier_block);
read_json_config_member(json, "berlinBlock", config.berlin_block);
read_json_config_member(json, "londonBlock", config.london_block);
read_json_config_member(json, "arrowGlacierBlock", config.arrow_glacier_block);
read_json_config_member(json, "grayGlacierBlock", config.gray_glacier_block);
read_json_config_member(json, "homesteadBlock", config._homestead_block);
read_json_config_member(json, "daoForkBlock", config._dao_block);
read_json_config_member(json, "eip150Block", config._tangerine_whistle_block);
read_json_config_member(json, "eip155Block", config._spurious_dragon_block);
read_json_config_member(json, "byzantiumBlock", config._byzantium_block);
read_json_config_member(json, "constantinopleBlock", config._constantinople_block);
read_json_config_member(json, "petersburgBlock", config._petersburg_block);
read_json_config_member(json, "istanbulBlock", config._istanbul_block);
read_json_config_member(json, "muirGlacierBlock", config._muir_glacier_block);
read_json_config_member(json, "berlinBlock", config._berlin_block);
read_json_config_member(json, "londonBlock", config._london_block);
read_json_config_member(json, "arrowGlacierBlock", config._arrow_glacier_block);
read_json_config_member(json, "grayGlacierBlock", config._gray_glacier_block);

if (json.contains(kTerminalTotalDifficulty)) {
// We handle terminalTotalDifficulty serialized both as JSON string *and* as JSON number
if (json[kTerminalTotalDifficulty].is_string()) {
/* This is still present to maintain compatibility with previous Silkworm format */
config.terminal_total_difficulty =
config._terminal_total_difficulty =
intx::from_string<intx::uint256>(json[kTerminalTotalDifficulty].get<std::string>());
} else if (json[kTerminalTotalDifficulty].is_number()) {
/* This is for compatibility with Erigon that uses a JSON number */
// nlohmann::json treats JSON numbers that overflow 64-bit unsigned integer as floating-point numbers and
// intx::uint256 cannot currently be constructed from a floating-point number or string in scientific notation
config.terminal_total_difficulty =
config._terminal_total_difficulty =
from_string_sci<intx::uint256>(json[kTerminalTotalDifficulty].dump().c_str());
}
}

read_json_config_member(json, "mergeNetsplitBlock", config.merge_netsplit_block);
read_json_config_member(json, "shanghaiTime", config.shanghai_time);
read_json_config_member(json, "cancunTime", config.cancun_time);
read_json_config_member(json, "mergeNetsplitBlock", config._merge_netsplit_block);
read_json_config_member(json, "shanghaiTime", config._shanghai_time);
read_json_config_member(json, "cancunTime", config._cancun_time);

/* Note ! genesis_hash is purposely omitted. It must be loaded from db after the
* effective genesis block has been persisted */

read_json_config_member(json, "version", config._version);

return config;
}

Expand All @@ -169,41 +175,54 @@ std::ostream& operator<<(std::ostream& out, const ChainConfig& obj) { return out

#endif

evmc_revision ChainConfig::revision(uint64_t block_number, uint64_t block_time) const noexcept {
if (cancun_time && block_time >= cancun_time) return EVMC_CANCUN;
if (shanghai_time && block_time >= shanghai_time) return EVMC_SHANGHAI;
evmc_revision ChainConfig::determine_revision_by_block(uint64_t block_number, uint64_t block_time) const noexcept {
if (_cancun_time && block_time >= _cancun_time) return EVMC_CANCUN;
if (_shanghai_time && block_time >= _shanghai_time) return EVMC_SHANGHAI;

if (london_block && block_number >= london_block) return EVMC_LONDON;
if (berlin_block && block_number >= berlin_block) return EVMC_BERLIN;
if (istanbul_block && block_number >= istanbul_block) return EVMC_ISTANBUL;
if (petersburg_block && block_number >= petersburg_block) return EVMC_PETERSBURG;
if (constantinople_block && block_number >= constantinople_block) return EVMC_CONSTANTINOPLE;
if (byzantium_block && block_number >= byzantium_block) return EVMC_BYZANTIUM;
if (spurious_dragon_block && block_number >= spurious_dragon_block) return EVMC_SPURIOUS_DRAGON;
if (tangerine_whistle_block && block_number >= tangerine_whistle_block) return EVMC_TANGERINE_WHISTLE;
if (homestead_block && block_number >= homestead_block) return EVMC_HOMESTEAD;
if (_london_block && block_number >= _london_block) return EVMC_LONDON;
if (_berlin_block && block_number >= _berlin_block) return EVMC_BERLIN;
if (_istanbul_block && block_number >= _istanbul_block) return EVMC_ISTANBUL;
if (_petersburg_block && block_number >= _petersburg_block) return EVMC_PETERSBURG;
if (_constantinople_block && block_number >= _constantinople_block) return EVMC_CONSTANTINOPLE;
if (_byzantium_block && block_number >= _byzantium_block) return EVMC_BYZANTIUM;
if (_spurious_dragon_block && block_number >= _spurious_dragon_block) return EVMC_SPURIOUS_DRAGON;
if (_tangerine_whistle_block && block_number >= _tangerine_whistle_block) return EVMC_TANGERINE_WHISTLE;
if (_homestead_block && block_number >= _homestead_block) return EVMC_HOMESTEAD;

return EVMC_FRONTIER;
}

evmc_revision ChainConfig::revision(const BlockHeader& header) const noexcept {
if(protocol_rule_set != protocol::RuleSetType::kTrust) {
return determine_revision_by_block(header.number, header.timestamp);
}
uint64_t evm_version = 0;
if(header.number == 0) {
evm_version = _version.has_value() ? *_version : 0;
} else {
evm_version = eosevm::nonce_to_version(header.nonce);
}
return eosevm::version_to_evmc_revision(evm_version);
}

std::vector<BlockNum> ChainConfig::distinct_fork_numbers() const {
std::set<BlockNum> ret;

// Add forks identified by *block number* in ascending order
ret.insert(homestead_block.value_or(0));
ret.insert(dao_block.value_or(0));
ret.insert(tangerine_whistle_block.value_or(0));
ret.insert(spurious_dragon_block.value_or(0));
ret.insert(byzantium_block.value_or(0));
ret.insert(constantinople_block.value_or(0));
ret.insert(petersburg_block.value_or(0));
ret.insert(istanbul_block.value_or(0));
ret.insert(muir_glacier_block.value_or(0));
ret.insert(berlin_block.value_or(0));
ret.insert(london_block.value_or(0));
ret.insert(arrow_glacier_block.value_or(0));
ret.insert(gray_glacier_block.value_or(0));
ret.insert(merge_netsplit_block.value_or(0));
ret.insert(_homestead_block.value_or(0));
ret.insert(_dao_block.value_or(0));
ret.insert(_tangerine_whistle_block.value_or(0));
ret.insert(_spurious_dragon_block.value_or(0));
ret.insert(_byzantium_block.value_or(0));
ret.insert(_constantinople_block.value_or(0));
ret.insert(_petersburg_block.value_or(0));
ret.insert(_istanbul_block.value_or(0));
ret.insert(_muir_glacier_block.value_or(0));
ret.insert(_berlin_block.value_or(0));
ret.insert(_london_block.value_or(0));
ret.insert(_arrow_glacier_block.value_or(0));
ret.insert(_gray_glacier_block.value_or(0));
ret.insert(_merge_netsplit_block.value_or(0));

ret.erase(0); // Block 0 is not a fork number
return {ret.cbegin(), ret.cend()};
Expand All @@ -213,8 +232,8 @@ std::vector<BlockTime> ChainConfig::distinct_fork_times() const {
std::set<BlockTime> ret;

// Add forks identified by *block timestamp* in ascending order
ret.insert(shanghai_time.value_or(0));
ret.insert(cancun_time.value_or(0));
ret.insert(_shanghai_time.value_or(0));
ret.insert(_cancun_time.value_or(0));

ret.erase(0); // Block 0 is not a fork timestamp
return {ret.cbegin(), ret.cend()};
Expand Down
Loading