diff --git a/CHANGELOG.md b/CHANGELOG.md index 70795a57a17..105a5a7049e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ - Added: [#5624](https://github.com/ethereum/aleth/pull/5624) Remove useless peers from peer list. - Added: [#5634](https://github.com/ethereum/aleth/pull/5634) Bootnodes for Rinkeby and Goerli. - Added: [#5640](https://github.com/ethereum/aleth/pull/5640) Support EIP-1702 Generalized Account Versioning Scheme (active only in Experimental fork.) -- Added: [#5690](https://github.com/ethereum/aleth/issues/5690) Istanbul support: EIP-2028 transaction data gas cost reduction. +- Added: [#5691](https://github.com/ethereum/aleth/pull/5691) Istanbul support: EIP-2028 Transaction data gas cost reduction. +- Added: [#5696](https://github.com/ethereum/aleth/pull/5696) Istanbul support: EIP-1344 ChainID opcode. - Added: [#5701](https://github.com/ethereum/aleth/issues/5701) Outputs ENR text representation in admin.nodeInfo RPC. - Changed: [#5532](https://github.com/ethereum/aleth/pull/5532) The leveldb is upgraded to 1.22. This is breaking change on Windows and the old databases are not compatible. - Changed: [#5559](https://github.com/ethereum/aleth/pull/5559) Update peer validation error messages. diff --git a/aleth-vm/main.cpp b/aleth-vm/main.cpp index b36d1059134..24af03582bc 100644 --- a/aleth-vm/main.cpp +++ b/aleth-vm/main.cpp @@ -262,7 +262,7 @@ int main(int argc, char** argv) unique_ptr se(ChainParams(genesisInfo(networkName)).createSealEngine()); LastBlockHashes lastBlockHashes; - EnvInfo const envInfo(blockHeader, lastBlockHashes, 0); + EnvInfo const envInfo(blockHeader, lastBlockHashes, 0 /* gasUsed */, se->chainParams().chainID); Transaction t; Address contractDestination("1122334455667788991011121314151617181920"); diff --git a/libethcore/EVMSchedule.h b/libethcore/EVMSchedule.h index a13c4ac640a..ace5b47970c 100644 --- a/libethcore/EVMSchedule.h +++ b/libethcore/EVMSchedule.h @@ -41,6 +41,7 @@ struct EVMSchedule bool haveStaticCall = false; bool haveCreate2 = false; bool haveExtcodehash = false; + bool haveChainID = false; std::array tierStepGas; unsigned expGas = 10; unsigned expByteGas = 10; @@ -150,6 +151,7 @@ static const EVMSchedule ConstantinopleFixSchedule = [] { static const EVMSchedule IstanbulSchedule = [] { EVMSchedule schedule = ConstantinopleFixSchedule; schedule.txDataNonZeroGas = 16; + schedule.haveChainID = true; return schedule; }(); diff --git a/libethereum/Block.cpp b/libethereum/Block.cpp index 5549445ac30..c58691c7b99 100644 --- a/libethereum/Block.cpp +++ b/libethereum/Block.cpp @@ -629,7 +629,8 @@ u256 Block::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) return tdIncrease; } -ExecutionResult Block::execute(LastBlockHashesFace const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp) +ExecutionResult Block::execute( + LastBlockHashesFace const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp) { if (isSealed()) BOOST_THROW_EXCEPTION(InvalidOperationOnSealedBlock()); @@ -638,7 +639,9 @@ ExecutionResult Block::execute(LastBlockHashesFace const& _lh, Transaction const // transaction as possible. uncommitToSeal(); - std::pair resultReceipt = m_state.execute(EnvInfo(info(), _lh, gasUsed()), *m_sealEngine, _t, _p, _onOp); + EnvInfo const envInfo{info(), _lh, gasUsed(), m_sealEngine->chainParams().chainID}; + std::pair resultReceipt = + m_state.execute(envInfo, *m_sealEngine, _t, _p, _onOp); if (_p == Permanence::Committed) { diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index c238c2926ca..58cbe5c1d0f 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -185,6 +185,8 @@ class BlockChain LastBlockHashesFace const& lastBlockHashes() const { return *m_lastBlockHashes; } + int chainID() const { return m_params.chainID; } + /** Get the block blooms for a number of blocks. Thread-safe. * @returns the object pertaining to the blocks: * level 0: diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 3aae475d181..c33cf483179 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -180,25 +180,27 @@ string StandardTrace::multilineTrace() const [](std::string a, Json::Value b) { return a + Json::FastWriter().write(b); }); } -Executive::Executive(Block& _s, BlockChain const& _bc, unsigned _level): - m_s(_s.mutableState()), - m_envInfo(_s.info(), _bc.lastBlockHashes(), 0), +Executive::Executive(Block& _s, BlockChain const& _bc, unsigned _level) + : m_s(_s.mutableState()), + m_envInfo(_s.info(), _bc.lastBlockHashes(), 0, _bc.chainID()), m_depth(_level), m_sealEngine(*_bc.sealEngine()) { } -Executive::Executive(Block& _s, LastBlockHashesFace const& _lh, unsigned _level): - m_s(_s.mutableState()), - m_envInfo(_s.info(), _lh, 0), +Executive::Executive(Block& _s, LastBlockHashesFace const& _lh, unsigned _level) + : m_s(_s.mutableState()), + m_envInfo(_s.info(), _lh, 0, _s.sealEngine()->chainParams().chainID), m_depth(_level), m_sealEngine(*_s.sealEngine()) { } -Executive::Executive(State& io_s, Block const& _block, unsigned _txIndex, BlockChain const& _bc, unsigned _level): - m_s(createIntermediateState(io_s, _block, _txIndex, _bc)), - m_envInfo(_block.info(), _bc.lastBlockHashes(), _txIndex ? _block.receipt(_txIndex - 1).cumulativeGasUsed() : 0), +Executive::Executive( + State& io_s, Block const& _block, unsigned _txIndex, BlockChain const& _bc, unsigned _level) + : m_s(createIntermediateState(io_s, _block, _txIndex, _bc)), + m_envInfo(_block.info(), _bc.lastBlockHashes(), + _txIndex ? _block.receipt(_txIndex - 1).cumulativeGasUsed() : 0, _bc.chainID()), m_depth(_level), m_sealEngine(*_bc.sealEngine()) { diff --git a/libethereum/State.cpp b/libethereum/State.cpp index f6fe6824386..cf7ff1780b2 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -656,12 +656,13 @@ std::pair State::execute(EnvInfo const& _en return make_pair(res, receipt); } -void State::executeBlockTransactions(Block const& _block, unsigned _txCount, LastBlockHashesFace const& _lastHashes, SealEngineFace const& _sealEngine) +void State::executeBlockTransactions(Block const& _block, unsigned _txCount, + LastBlockHashesFace const& _lastHashes, SealEngineFace const& _sealEngine) { u256 gasUsed = 0; for (unsigned i = 0; i < _txCount; ++i) { - EnvInfo envInfo(_block.info(), _lastHashes, gasUsed); + EnvInfo envInfo(_block.info(), _lastHashes, gasUsed, _sealEngine.chainParams().chainID); Executive e(*this, envInfo, _sealEngine); executeTransaction(e, _block.pending()[i], OnOpFunc()); diff --git a/libevm/EVMC.cpp b/libevm/EVMC.cpp index ef6e7bf96af..c7e4ddff1ed 100644 --- a/libevm/EVMC.cpp +++ b/libevm/EVMC.cpp @@ -14,7 +14,7 @@ namespace { evmc_revision toRevision(EVMSchedule const& _schedule) noexcept { - if (_schedule.txDataNonZeroGas == 16) + if (_schedule.haveChainID) return EVMC_ISTANBUL; if (_schedule.haveCreate2 && !_schedule.eip1283Mode) return EVMC_PETERSBURG; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index da6b748ebd5..96ecd08cd3c 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -141,14 +141,15 @@ struct CallParameters class EnvInfo { public: - EnvInfo(BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed) - : m_headerInfo(_current), m_lastHashes(_lh), m_gasUsed(_gasUsed) + EnvInfo(BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed, + u256 const& _chainID) + : m_headerInfo(_current), m_lastHashes(_lh), m_gasUsed(_gasUsed), m_chainID(_chainID) {} // Constructor with custom gasLimit - used in some synthetic scenarios like eth_estimateGas RPC // method EnvInfo(BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed, - u256 const& _gasLimit) - : EnvInfo(_current, _lh, _gasUsed) + u256 const& _gasLimit, u256 const& _chainID) + : EnvInfo(_current, _lh, _gasUsed, _chainID) { m_headerInfo.setGasLimit(_gasLimit); } @@ -162,11 +163,13 @@ class EnvInfo u256 const& gasLimit() const { return m_headerInfo.gasLimit(); } LastBlockHashesFace const& lastHashes() const { return m_lastHashes; } u256 const& gasUsed() const { return m_gasUsed; } + u256 const& chainID() const { return m_chainID; } private: BlockHeader m_headerInfo; LastBlockHashesFace const& m_lastHashes; u256 m_gasUsed; + u256 m_chainID; }; /// Represents a call result. diff --git a/libevm/Instruction.cpp b/libevm/Instruction.cpp index 032c0c705ae..2409cfabd87 100644 --- a/libevm/Instruction.cpp +++ b/libevm/Instruction.cpp @@ -22,7 +22,7 @@ namespace dev { namespace eth { - +// clang-format off static const std::map c_instructionInfo = { // Args, Ret, GasPriceTier { Instruction::STOP, { "STOP", 0, 0, Tier::Zero } }, @@ -74,6 +74,7 @@ static const std::map c_instructionInfo = { Instruction::NUMBER, { "NUMBER", 0, 1, Tier::Base } }, { Instruction::DIFFICULTY, { "DIFFICULTY", 0, 1, Tier::Base } }, { Instruction::GASLIMIT, { "GASLIMIT", 0, 1, Tier::Base } }, + { Instruction::CHAINID, { "CHAINID", 0, 1, Tier::Base } }, { Instruction::POP, { "POP", 1, 0, Tier::Base } }, { Instruction::MLOAD, { "MLOAD", 1, 1, Tier::VeryLow } }, { Instruction::MSTORE, { "MSTORE", 2, 0, Tier::VeryLow } }, @@ -215,8 +216,9 @@ static const std::map c_instructionInfo = { Instruction::PUSHC, { "PUSHC", 0, 1, Tier::VeryLow } }, { Instruction::JUMPC, { "JUMPC", 1, 0, Tier::Mid } }, { Instruction::JUMPCI, { "JUMPCI", 2, 0, Tier::High } }, -}; - +}; +// clang-format on + InstructionInfo instructionInfo(Instruction _inst) { auto it = c_instructionInfo.find(_inst); diff --git a/libevm/Instruction.h b/libevm/Instruction.h index 867931824a0..f5780bf4278 100644 --- a/libevm/Instruction.h +++ b/libevm/Instruction.h @@ -81,6 +81,7 @@ enum class Instruction : uint8_t NUMBER, ///< get the block's number DIFFICULTY, ///< get the block's difficulty GASLIMIT, ///< get the block's gas limit + CHAINID, ///< get the network's ChainID POP = 0x50, ///< remove item from stack MLOAD, ///< load word from memory diff --git a/libevm/LegacyVM.cpp b/libevm/LegacyVM.cpp index eab7bf48b49..033e63fa710 100644 --- a/libevm/LegacyVM.cpp +++ b/libevm/LegacyVM.cpp @@ -1439,6 +1439,19 @@ void LegacyVM::interpretCases() } NEXT + CASE(CHAINID) + { + ON_OP(); + + if (!m_schedule->haveChainID) + throwBadInstruction(); + + updateIOGas(); + + m_SPP[0] = m_ext->envInfo().chainID(); + } + NEXT + CASE(POP) { ON_OP(); diff --git a/libevm/LegacyVMConfig.h b/libevm/LegacyVMConfig.h index 5ab9ca50636..6c4c669932f 100644 --- a/libevm/LegacyVMConfig.h +++ b/libevm/LegacyVMConfig.h @@ -226,14 +226,14 @@ namespace dev &&EXTCODECOPY, \ &&RETURNDATASIZE, \ &&RETURNDATACOPY, \ - &&EXTCODEHASH, \ + &&EXTCODEHASH, \ &&BLOCKHASH, /* 40, */ \ &&COINBASE, \ &&TIMESTAMP, \ &&NUMBER, \ &&DIFFICULTY, \ &&GASLIMIT, \ - &&INVALID, \ + &&CHAINID, \ &&INVALID, \ &&INVALID, \ &&INVALID, \ diff --git a/libweb3jsonrpc/Debug.cpp b/libweb3jsonrpc/Debug.cpp index 42aed769c40..38519bb265c 100644 --- a/libweb3jsonrpc/Debug.cpp +++ b/libweb3jsonrpc/Debug.cpp @@ -88,8 +88,9 @@ Json::Value Debug::traceBlock(Block const& _block, Json::Value const& _json) Transaction t = _block.pending()[k]; u256 const gasUsed = k ? _block.receipt(k - 1).cumulativeGasUsed() : 0; - EnvInfo envInfo(_block.info(), m_eth.blockChain().lastBlockHashes(), gasUsed); - Executive e(s, envInfo, *m_eth.blockChain().sealEngine()); + auto const& bc = m_eth.blockChain(); + EnvInfo envInfo(_block.info(), bc.lastBlockHashes(), gasUsed, bc.chainID()); + Executive e(s, envInfo, *bc.sealEngine()); eth::ExecutionResult er; e.setResultRecipient(er); diff --git a/test/tools/jsontests/vm.cpp b/test/tools/jsontests/vm.cpp index 39666ac222f..ef2dce4e091 100644 --- a/test/tools/jsontests/vm.cpp +++ b/test/tools/jsontests/vm.cpp @@ -110,7 +110,7 @@ EnvInfo FakeExtVM::importEnv(mObject const& _o, LastBlockHashesFace const& _last blockHeader.setTimestamp(toInt64(_o.at("currentTimestamp"))); blockHeader.setAuthor(Address(_o.at("currentCoinbase").get_str())); blockHeader.setNumber(toUint64(_o.at("currentNumber"))); - return EnvInfo(blockHeader, _lastBlockHashes, 0); + return {blockHeader, _lastBlockHashes, 0, 0}; } mObject FakeExtVM::exportState() @@ -443,7 +443,7 @@ json_spirit::mValue VmTestSuite::doTests(json_spirit::mValue const& _input, bool BOOST_REQUIRE_MESSAGE(testInput.count("logs") > 0, testname + " logs field is missing."); BOOST_REQUIRE_MESSAGE(testInput.at("logs").type() == str_type, testname + " logs field is not a string."); - dev::test::FakeExtVM test(eth::EnvInfo{BlockHeader{}, lastBlockHashes, 0}); + dev::test::FakeExtVM test(eth::EnvInfo{BlockHeader{}, lastBlockHashes, 0, 0}); test.importState(testInput.at("post").get_obj()); test.importCallCreates(testInput.at("callcreates").get_array()); diff --git a/test/tools/libtesteth/ImportTest.cpp b/test/tools/libtesteth/ImportTest.cpp index 79c5aaeb2dd..3d5ccae9136 100644 --- a/test/tools/libtesteth/ImportTest.cpp +++ b/test/tools/libtesteth/ImportTest.cpp @@ -386,7 +386,7 @@ void ImportTest::importEnv(json_spirit::mObject const& _o) header.setAuthor(Address(_o.at("currentCoinbase").get_str())); m_lastBlockHashes.reset(new TestLastBlockHashes(lastHashes(header.number()))); - m_envInfo.reset(new EnvInfo(header, *m_lastBlockHashes, 0)); + m_envInfo.reset(new EnvInfo(header, *m_lastBlockHashes, 0, 0)); } // import state from not fully declared json_spirit::mObject, writing to _stateOptionsMap which fields were defined in json diff --git a/test/unittests/libethereum/ExecutiveTest.cpp b/test/unittests/libethereum/ExecutiveTest.cpp index a600ceb4e91..6a6af86499b 100644 --- a/test/unittests/libethereum/ExecutiveTest.cpp +++ b/test/unittests/libethereum/ExecutiveTest.cpp @@ -23,6 +23,12 @@ class ExecutiveTest : public testing::Test ethash.setChainParams(ChainParams{genesisInfo(eth::Network::IstanbulTransitionTest)}); } + // called after blockHeader is set up + EnvInfo envInfo() const + { + return {blockHeader, lastBlockHashes, 0, ethash.chainParams().chainID}; + } + Ethash ethash; BlockHeader blockHeader; TestLastBlockHashes lastBlockHashes{{}}; @@ -39,14 +45,12 @@ class ExecutiveTest : public testing::Test TEST_F(ExecutiveTest, callUsesAccountVersion) { - EnvInfo envInfo(blockHeader, lastBlockHashes, 0); - state.createContract(receiveAddress); u256 version = 1; state.setCode(receiveAddress, bytes{code}, version); state.commit(State::CommitBehaviour::RemoveEmptyAccounts); - Executive executive(state, envInfo, ethash); + Executive executive(state, envInfo(), ethash); bool done = executive.call(receiveAddress, txSender, txValue, gasPrice, txData, gas); @@ -59,9 +63,7 @@ TEST_F(ExecutiveTest, createUsesLatestForkVersion) // block in Istanbul fork blockHeader.setNumber(10); - EnvInfo envInfo(blockHeader, lastBlockHashes, 0); - - Executive executive(state, envInfo, ethash); + Executive executive(state, envInfo(), ethash); bool done = executive.create(txSender, txValue, gasPrice, gas, ref(code), txSender); @@ -71,14 +73,12 @@ TEST_F(ExecutiveTest, createUsesLatestForkVersion) TEST_F(ExecutiveTest, createOpcodeUsesParentVersion) { - EnvInfo envInfo(blockHeader, lastBlockHashes, 0); - state.createContract(txSender); u256 version = 1; state.setCode(txSender, bytes{code}, version); state.commit(State::CommitBehaviour::RemoveEmptyAccounts); - Executive executive(state, envInfo, ethash); + Executive executive(state, envInfo(), ethash); bool done = executive.createOpcode(txSender, txValue, gasPrice, gas, ref(code), txSender); @@ -88,14 +88,12 @@ TEST_F(ExecutiveTest, createOpcodeUsesParentVersion) TEST_F(ExecutiveTest, create2OpcodeUsesParentVersion) { - EnvInfo envInfo(blockHeader, lastBlockHashes, 0); - state.createContract(txSender); u256 version = 1; state.setCode(txSender, bytes{code}, version); state.commit(State::CommitBehaviour::RemoveEmptyAccounts); - Executive executive(state, envInfo, ethash); + Executive executive(state, envInfo(), ethash); bool done = executive.create2Opcode(txSender, txValue, gasPrice, gas, ref(code), txSender, 0); @@ -105,14 +103,12 @@ TEST_F(ExecutiveTest, create2OpcodeUsesParentVersion) TEST_F(ExecutiveTest, emptyInitCodeSetsParentVersion) { - EnvInfo envInfo(blockHeader, lastBlockHashes, 0); - state.createContract(txSender); u256 version = 1; state.setCode(txSender, bytes{code}, version); state.commit(State::CommitBehaviour::RemoveEmptyAccounts); - Executive executive(state, envInfo, ethash); + Executive executive(state, envInfo(), ethash); bytes initCode; bool done = executive.createOpcode(txSender, txValue, gasPrice, gas, ref(initCode), txSender); @@ -124,14 +120,12 @@ TEST_F(ExecutiveTest, emptyInitCodeSetsParentVersion) TEST_F(ExecutiveTest, createdContractHasParentVersion) { - EnvInfo envInfo(blockHeader, lastBlockHashes, 0); - state.createContract(txSender); u256 version = 1; state.setCode(txSender, bytes{code}, version); state.commit(State::CommitBehaviour::RemoveEmptyAccounts); - Executive executive(state, envInfo, ethash); + Executive executive(state, envInfo(), ethash); // mstore(0, 0x60) // return(0, 0x20) diff --git a/test/unittests/libethereum/ExtVMTest.cpp b/test/unittests/libethereum/ExtVMTest.cpp index 7820c63a08e..e9d6230d5ba 100644 --- a/test/unittests/libethereum/ExtVMTest.cpp +++ b/test/unittests/libethereum/ExtVMTest.cpp @@ -48,6 +48,11 @@ class ExtVMExperimentalTestFixture : public TestOutputHelperFixture experimentalBlockHash = testBlock.blockHeader().hash(); } + EnvInfo createEnvInfo(BlockHeader const& _header) const + { + return {_header, lastBlockHashes, 0, blockchain.chainID()}; + } + NetworkSelector networkSelector; TestBlockChain testBlockchain; TestBlock const& genesisBlock; @@ -55,6 +60,7 @@ class ExtVMExperimentalTestFixture : public TestOutputHelperFixture BlockChain const& blockchain; h256 preExperimentalBlockHash; h256 experimentalBlockHash; + TestLastBlockHashes lastBlockHashes{{}}; }; BOOST_FIXTURE_TEST_SUITE(ExtVmExperimentalSuite, ExtVMExperimentalTestFixture) @@ -64,8 +70,7 @@ BOOST_AUTO_TEST_CASE(BlockhashOutOfBoundsRetunsZero) Block block = blockchain.genesisBlock(genesisDB); block.sync(blockchain); - TestLastBlockHashes lastBlockHashes({}); - EnvInfo envInfo(block.info(), lastBlockHashes, 0); + EnvInfo envInfo(createEnvInfo(block.info())); Address addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); ExtVM extVM(block.mutableState(), envInfo, *blockchain.sealEngine(), addr, addr, addr, 0, 0, {}, {}, {}, 0, 0, false, false); @@ -80,7 +85,7 @@ BOOST_AUTO_TEST_CASE(BlockhashBeforeExperimentalReliesOnLastHashes) h256s lastHashes{h256("0xaaabbbccc"), h256("0xdddeeefff")}; TestLastBlockHashes lastBlockHashes(lastHashes); - EnvInfo envInfo(block.info(), lastBlockHashes, 0); + EnvInfo envInfo{block.info(), lastBlockHashes, 0, blockchain.chainID()}; Address addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); ExtVM extVM(block.mutableState(), envInfo, *blockchain.sealEngine(), addr, addr, addr, 0, 0, {}, {}, {}, 0, 0, false, false); @@ -102,8 +107,7 @@ BOOST_AUTO_TEST_CASE(BlockhashDoesntNeedLastHashesInExperimental) Block block = blockchain.genesisBlock(genesisDB); block.sync(blockchain); - TestLastBlockHashes lastBlockHashes({}); - EnvInfo envInfo(block.info(), lastBlockHashes, 0); + EnvInfo envInfo(createEnvInfo(block.info())); Address addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); ExtVM extVM(block.mutableState(), envInfo, *blockchain.sealEngine(), addr, addr, addr, 0, 0, {}, {}, {}, 0, 0, false, false); @@ -120,8 +124,7 @@ BOOST_AUTO_TEST_CASE(ScheduleAccordingToForkBeforeExperimental) Block block = blockchain.genesisBlock(genesisDB); block.sync(blockchain, preExperimentalBlockHash); - TestLastBlockHashes lastBlockHashes({}); - EnvInfo envInfo(block.info(), lastBlockHashes, 0); + EnvInfo envInfo(createEnvInfo(block.info())); Address addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); ExtVM extVM(block.mutableState(), envInfo, *blockchain.sealEngine(), addr, addr, addr, 0, 0, {}, {}, {}, 0, 0, false, false); @@ -136,8 +139,7 @@ BOOST_AUTO_TEST_CASE(IstanbulScheduleForVersionZeroInExperimental) Block block = blockchain.genesisBlock(genesisDB); block.sync(blockchain, experimentalBlockHash); - TestLastBlockHashes lastBlockHashes({}); - EnvInfo envInfo(block.info(), lastBlockHashes, 0); + EnvInfo envInfo(createEnvInfo(block.info())); Address addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); u256 const version = 0; ExtVM extVM(block.mutableState(), envInfo, *blockchain.sealEngine(), addr, addr, addr, 0, 0, {}, @@ -153,8 +155,7 @@ BOOST_AUTO_TEST_CASE(ExperimentalScheduleForVersionOneInExperimental) Block block = blockchain.genesisBlock(genesisDB); block.sync(blockchain, experimentalBlockHash); - TestLastBlockHashes lastBlockHashes({}); - EnvInfo envInfo(block.info(), lastBlockHashes, 0); + EnvInfo envInfo(createEnvInfo(block.info())); Address addr("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"); u256 const version = 1; ExtVM extVM(block.mutableState(), envInfo, *blockchain.sealEngine(), addr, addr, addr, 0, 0, {}, diff --git a/test/unittests/libevm/VMTest.cpp b/test/unittests/libevm/VMTest.cpp index b9681402977..4df014aec5e 100644 --- a/test/unittests/libevm/VMTest.cpp +++ b/test/unittests/libevm/VMTest.cpp @@ -181,11 +181,11 @@ class Create2TestFixture: public TestOutputHelperFixture BlockHeader blockHeader{initBlockHeader()}; LastBlockHashes lastBlockHashes; - EnvInfo envInfo{blockHeader, lastBlockHashes, 0}; Address address{KeyPair::create().address()}; State state{0}; std::unique_ptr se{ ChainParams(genesisInfo(Network::ConstantinopleTest)).createSealEngine()}; + EnvInfo envInfo{blockHeader, lastBlockHashes, 0, se->chainParams().chainID}; u256 value = 0; u256 gasPrice = 1; @@ -348,12 +348,12 @@ class ExtcodehashTestFixture : public TestOutputHelperFixture BlockHeader blockHeader{initBlockHeader()}; LastBlockHashes lastBlockHashes; - EnvInfo envInfo{blockHeader, lastBlockHashes, 0}; Address address{KeyPair::create().address()}; Address extAddress{KeyPair::create().address()}; State state{0}; std::unique_ptr se{ ChainParams(genesisInfo(Network::ConstantinopleTest)).createSealEngine()}; + EnvInfo envInfo{blockHeader, lastBlockHashes, 0, se->chainParams().chainID}; u256 value = 0; u256 gasPrice = 1; @@ -461,12 +461,12 @@ class SstoreTestFixture : public TestOutputHelperFixture BlockHeader blockHeader{initBlockHeader()}; LastBlockHashes lastBlockHashes; - EnvInfo envInfo{blockHeader, lastBlockHashes, 0}; Address from{KeyPair::create().address()}; Address to{KeyPair::create().address()}; State state{0}; std::unique_ptr se{ ChainParams(genesisInfo(Network::ConstantinopleTest)).createSealEngine()}; + EnvInfo envInfo{blockHeader, lastBlockHashes, 0, se->chainParams().chainID}; u256 value = 0; u256 gasPrice = 1; @@ -492,6 +492,84 @@ class AlethInterpreterSstoreTestFixture : public SstoreTestFixture AlethInterpreterSstoreTestFixture() : SstoreTestFixture{new EVMC{evmc_create_interpreter()}} {} }; +class ChainIDTestFixture : public TestOutputHelperFixture +{ +public: + explicit ChainIDTestFixture(VMFace* _vm) : vm{_vm} { state.addBalance(address, 1 * ether); } + + void testChainIDWorksInIstanbul() + { + ExtVM extVm(state, envInfo, *se, address, address, address, value, gasPrice, {}, ref(code), + sha3(code), version, depth, isCreate, staticCall); + + owning_bytes_ref ret = vm->exec(gas, extVm, OnOpFunc{}); + + BOOST_REQUIRE_EQUAL(fromBigEndian(ret), 1); + } + + void testChainIDHasCorrectCost() + { + ExtVM extVm(state, envInfo, *se, address, address, address, value, gasPrice, {}, ref(code), + sha3(code), version, depth, isCreate, staticCall); + + bigint gasBefore; + bigint gasAfter; + auto onOp = [&gasBefore, &gasAfter](uint64_t /*steps*/, uint64_t /* PC */, + Instruction _instr, bigint /*newMemSize*/, bigint /*gasCost*/, bigint _gas, + VMFace const*, ExtVMFace const*) { + if (_instr == Instruction::CHAINID) + gasBefore = _gas; + else if (gasBefore != 0 && gasAfter == 0) + gasAfter = _gas; + }; + + vm->exec(gas, extVm, onOp); + + BOOST_REQUIRE_EQUAL(gasBefore - gasAfter, 2); + } + + void testChainIDisInvalidBeforeIstanbul() + { + se.reset(ChainParams(genesisInfo(Network::ConstantinopleFixTest)).createSealEngine()); + version = ConstantinopleFixSchedule.accountVersion; + + ExtVM extVm(state, envInfo, *se, address, address, address, value, gasPrice, {}, ref(code), + sha3(code), version, depth, isCreate, staticCall); + + BOOST_REQUIRE_THROW(vm->exec(gas, extVm, OnOpFunc{}), BadInstruction); + } + + + BlockHeader blockHeader{initBlockHeader()}; + LastBlockHashes lastBlockHashes; + Address address{KeyPair::create().address()}; + State state{0}; + std::unique_ptr se{ + ChainParams(genesisInfo(Network::IstanbulTest)).createSealEngine()}; + EnvInfo envInfo{blockHeader, lastBlockHashes, 0, se->chainParams().chainID}; + + u256 value = 0; + u256 gasPrice = 1; + u256 version = IstanbulSchedule.accountVersion; + int depth = 0; + bool isCreate = false; + bool staticCall = false; + u256 gas = 1000000; + + // let id : = chainid() + // mstore(0, id) + // return(0, 32) + bytes code = fromHex("468060005260206000f350"); + + std::unique_ptr vm; +}; + +class LegacyVMChainIDTestFixture : public ChainIDTestFixture +{ +public: + LegacyVMChainIDTestFixture() : ChainIDTestFixture{new LegacyVM} {} +}; + } // namespace BOOST_FIXTURE_TEST_SUITE(LegacyVMSuite, TestOutputHelperFixture) @@ -671,6 +749,24 @@ BOOST_AUTO_TEST_CASE(LegacyVMSstoreEip1283Case17) } BOOST_AUTO_TEST_SUITE_END() +BOOST_FIXTURE_TEST_SUITE(LegacyVMChainIDSuite, LegacyVMChainIDTestFixture) + +BOOST_AUTO_TEST_CASE(LegacyVMChainIDworksInIstanbul) +{ + testChainIDWorksInIstanbul(); +} + +BOOST_AUTO_TEST_CASE(LegacyVMChainIDHasCorrectCost) +{ + testChainIDHasCorrectCost(); +} + +BOOST_AUTO_TEST_CASE(LegacyVMChainIDisInvalidBeforeIstanbul) +{ + testChainIDisInvalidBeforeIstanbul(); +} +BOOST_AUTO_TEST_SUITE_END() + BOOST_AUTO_TEST_SUITE_END() BOOST_FIXTURE_TEST_SUITE(AlethInterpreterSuite, TestOutputHelperFixture)