From 80a6c22c9abb34f0846fcbace0e1cc1801f630cd Mon Sep 17 00:00:00 2001 From: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com> Date: Thu, 27 May 2021 15:16:10 +0200 Subject: [PATCH] EIP-3541: Reject new contracts starting with the 0xEF byte (#247) * EIP-3541: Reject new contracts starting with the 0xEF byte * Little more readability over std::optional and reuse bool contract_creation Co-authored-by: Andrea Lanfranchi --- core/silkworm/chain/config.cpp | 6 +++++ core/silkworm/chain/config.hpp | 2 ++ core/silkworm/execution/evm.cpp | 31 ++++++++++++++------------ core/silkworm/execution/evm_test.cpp | 33 +++++++++++++++++++++++++++- wasm/silkworm_wasm_api.cpp | 4 +--- 5 files changed, 58 insertions(+), 18 deletions(-) diff --git a/core/silkworm/chain/config.cpp b/core/silkworm/chain/config.cpp index 8418feb0ab..6179e92931 100644 --- a/core/silkworm/chain/config.cpp +++ b/core/silkworm/chain/config.cpp @@ -104,6 +104,12 @@ std::optional ChainConfig::revision_block(evmc_revision rev) const noe return fork_blocks.at(i); } +void ChainConfig::set_revision_block(evmc_revision rev, std::optional block) { + if (rev > 0) { // Frontier block is always 0 + fork_blocks[rev - 1] = block; + } +} + bool operator==(const ChainConfig& a, const ChainConfig& b) { return a.to_json() == b.to_json(); } std::ostream& operator<<(std::ostream& out, const ChainConfig& obj) { return out << obj.to_json(); } diff --git a/core/silkworm/chain/config.hpp b/core/silkworm/chain/config.hpp index 67b5c430ab..6062f31a47 100644 --- a/core/silkworm/chain/config.hpp +++ b/core/silkworm/chain/config.hpp @@ -73,6 +73,8 @@ struct ChainConfig { // it means the actual chain either does not support such revision std::optional revision_block(evmc_revision rev) const noexcept; + void set_revision_block(evmc_revision rev, std::optional block); + nlohmann::json to_json() const noexcept; /*Sample JSON input: diff --git a/core/silkworm/execution/evm.cpp b/core/silkworm/execution/evm.cpp index 077f030435..56ae27b61f 100644 --- a/core/silkworm/execution/evm.cpp +++ b/core/silkworm/execution/evm.cpp @@ -45,18 +45,18 @@ EVM::~EVM() { evm1_->destroy(evm1_); } CallResult EVM::execute(const Transaction& txn, uint64_t gas) noexcept { txn_ = &txn; - bool contract_creation{!txn.to}; + bool contract_creation{!txn.to.has_value()}; evmc_message message{ - contract_creation ? EVMC_CREATE : EVMC_CALL, // kind - 0, // flags - 0, // depth - static_cast(gas), // gas - txn.to ? *txn.to : evmc::address{}, // destination - *txn.from, // sender - &txn.data[0], // input_data - txn.data.size(), // input_size - intx::be::store(txn.value), // value + contract_creation ? EVMC_CREATE : EVMC_CALL, // kind + 0, // flags + 0, // depth + static_cast(gas), // gas + contract_creation ? evmc::address{} : *txn.to, // destination + *txn.from, // sender + &txn.data[0], // input_data + txn.data.size(), // input_size + intx::be::store(txn.value), // value }; evmc::result res{contract_creation ? create(message) : call(message)}; @@ -105,7 +105,7 @@ evmc::result EVM::create(const evmc_message& message) noexcept { state_.subtract_from_balance(message.sender, value); state_.add_to_balance(contract_addr, value); - evmc_message deploy_message{ + const evmc_message deploy_message{ EVMC_CALL, // kind 0, // flags message.depth, // depth @@ -120,10 +120,13 @@ evmc::result EVM::create(const evmc_message& message) noexcept { res = execute(deploy_message, ByteView{message.input_data, message.input_size}, /*code_hash=*/std::nullopt); if (res.status_code == EVMC_SUCCESS) { - size_t code_len{res.output_size}; - uint64_t code_deploy_gas{code_len * fee::kGCodeDeposit}; + const size_t code_len{res.output_size}; + const uint64_t code_deploy_gas{code_len * fee::kGCodeDeposit}; - if (rev >= EVMC_SPURIOUS_DRAGON && code_len > param::kMaxCodeSize) { + if (rev >= EVMC_LONDON && code_len > 0 && res.output_data[0] == 0xEF) { + // https://eips.ethereum.org/EIPS/eip-3541 + res.status_code = EVMC_CONTRACT_VALIDATION_FAILURE; + } else if (rev >= EVMC_SPURIOUS_DRAGON && code_len > param::kMaxCodeSize) { // https://eips.ethereum.org/EIPS/eip-170 res.status_code = EVMC_OUT_OF_GAS; } else if (res.gas_left >= 0 && static_cast(res.gas_left) >= code_deploy_gas) { diff --git a/core/silkworm/execution/evm_test.cpp b/core/silkworm/execution/evm_test.cpp index a7285fabf7..b7af1a7938 100644 --- a/core/silkworm/execution/evm_test.cpp +++ b/core/silkworm/execution/evm_test.cpp @@ -18,8 +18,8 @@ #include -#include #include +#include #include #include "address.hpp" @@ -328,4 +328,35 @@ TEST_CASE("Contract overwrite") { CHECK(res.data == Bytes{}); } +TEST_CASE("EIP-3541: Reject new contracts starting with the 0xEF byte") { + ChainConfig config{kMainnetConfig}; + config.set_revision_block(EVMC_LONDON, 13'000'000); + + Block block; + block.header.number = 13'500'000; + + MemoryBuffer db; + IntraBlockState state{db}; + EVM evm{block, state, config}; + + Transaction txn; + const uint64_t gas{50'000}; + + // https://eips.ethereum.org/EIPS/eip-3541#test-cases + txn.data = *from_hex("0x60ef60005360016000f3"); + CHECK(evm.execute(txn, gas).status == EVMC_CONTRACT_VALIDATION_FAILURE); + + txn.data = *from_hex("0x60ef60005360026000f3"); + CHECK(evm.execute(txn, gas).status == EVMC_CONTRACT_VALIDATION_FAILURE); + + txn.data = *from_hex("0x60ef60005360036000f3"); + CHECK(evm.execute(txn, gas).status == EVMC_CONTRACT_VALIDATION_FAILURE); + + txn.data = *from_hex("0x60ef60005360206000f3"); + CHECK(evm.execute(txn, gas).status == EVMC_CONTRACT_VALIDATION_FAILURE); + + txn.data = *from_hex("0x60fe60005360016000f3"); + CHECK(evm.execute(txn, gas).status == EVMC_SUCCESS); +} + } // namespace silkworm diff --git a/wasm/silkworm_wasm_api.cpp b/wasm/silkworm_wasm_api.cpp index 5526e9b384..b0649c67fe 100644 --- a/wasm/silkworm_wasm_api.cpp +++ b/wasm/silkworm_wasm_api.cpp @@ -66,9 +66,7 @@ ChainConfig* new_config(uint64_t chain_id) { void delete_config(ChainConfig* x) { delete x; } void config_set_fork_block(ChainConfig* config, evmc_revision fork, uint64_t block) { - if (fork > 0) { // Frontier block is always 0 - config->fork_blocks[fork - 1] = block; - } + config->set_revision_block(fork, block); } void config_set_muir_glacier_block(ChainConfig* config, uint64_t block) { config->muir_glacier_block = block; }