Skip to content

Commit

Permalink
Merge pull request #78 from eosnetworkfoundation/elmato/chain-config-…
Browse files Browse the repository at this point in the history
…refactor

ChainConfig refactor
  • Loading branch information
elmato authored Jan 11, 2024
2 parents 579aaae + 624e7cc commit 2a480c9
Show file tree
Hide file tree
Showing 32 changed files with 577 additions and 415 deletions.
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

0 comments on commit 2a480c9

Please sign in to comment.