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
168 changes: 103 additions & 65 deletions silkworm/core/chain/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <set>

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

namespace silkworm {

Expand All @@ -36,6 +37,19 @@ static const std::vector<std::pair<std::string, const ChainConfig*>> kKnownChain

constexpr const char* kTerminalTotalDifficulty{"terminalTotalDifficulty"};

static inline uint64_t nonce_to_eos_evm_version(BlockHeader::NonceType nonce) {
// The nonce will be treated as big-endian number for now.
return endian::load_big_u64(nonce.data());
}

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

#if not defined(ANTELOPE)

static inline void member_to_json(nlohmann::json& json, const std::string& key, const std::optional<uint64_t>& source) {
Expand All @@ -51,6 +65,13 @@ static inline void read_json_config_member(const nlohmann::json& json, const std
}
}

static inline void read_json_config_member(const nlohmann::json& json, const std::string& key,
elmato marked this conversation as resolved.
Show resolved Hide resolved
std::optional<evmc_revision>& target) {
if (json.contains(key)) {
target = json[key].get<evmc_revision>();
}
}

nlohmann::json ChainConfig::to_json() const noexcept {
nlohmann::json ret;

Expand All @@ -74,28 +95,28 @@ 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);
Expand Down Expand Up @@ -124,42 +145,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, "revision", config._revision);
elmato marked this conversation as resolved.
Show resolved Hide resolved

return config;
}

Expand All @@ -169,41 +192,56 @@ 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);
}

// Genesis nonce does not contain version info. Default to istambul.
if(header.number == 0) {
return *_revision ? *_revision : EVMC_ISTANBUL;
elmato marked this conversation as resolved.
Show resolved Hide resolved
}

uint64_t evm_version = nonce_to_eos_evm_version(header.nonce);

return eos_evm_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 +251,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