-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Implement EIP-1702 Generalized Account Versioning Scheme #5640
Changes from all commits
a116550
4988876
4d68732
3eaebc4
854b157
aa72ac3
fc4fd42
e668993
2e74886
e95dff3
4d438f8
5c12f9f
50c7156
0554648
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,7 +34,7 @@ using namespace dev::eth::validation; | |
|
|
||
| namespace fs = boost::filesystem; | ||
|
|
||
| void Account::setCode(bytes&& _code) | ||
| void Account::setCode(bytes&& _code, u256 const& _version) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not related to your changes, but why do we have a setCode function rather than only allowing code to be set in a ctor since from what I understand smart contracts can't be redeployed at the same address?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think because contract creation has init code execution phase. First init code (provided in the contract deployment transaction or in CREATE/CREATE2 params) is executed, and it returns in the end another code, which becomes the code of new contract, saved into the state (with So init code execution is performed in the context of the newly created contract, and so this new contract should already exist, but its code is empty until init code is finished.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gumb0 Ah okay, thanks for the clarification! Still not clear on this:
What is this other code that is returned by init code execution, how does it differ from the code supplied in the contract creation tx?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code supplied in the contract creation tx (or in In other words the code supplied in the contract creation tx is only constructor code (in solidity terms) and it returns the code that becomes the actual contract code. |
||
| { | ||
| auto const newHash = sha3(_code); | ||
| if (newHash != m_codeHash) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should have done this check before, too, because without it in case init code returns empty code, Here it also helps with the same problem in case of empty init code. In this case
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Separate PR?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah can be separate |
||
|
|
@@ -43,13 +43,16 @@ void Account::setCode(bytes&& _code) | |
| m_hasNewCode = true; | ||
| m_codeHash = newHash; | ||
| } | ||
| m_version = _version; | ||
| } | ||
|
|
||
| void Account::resetCode() | ||
| { | ||
| m_codeCache.clear(); | ||
| m_hasNewCode = false; | ||
| m_codeHash = EmptySHA3; | ||
| // Reset the version, as it was set together with code | ||
| m_version = 0; | ||
chfast marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| u256 Account::originalStorageValue(u256 const& _key, OverlayDB const& _db) const | ||
|
|
@@ -166,7 +169,7 @@ AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _def | |
| cerr << "Error importing code of account " << a | ||
| << "! Code needs to be hex bytecode prefixed by \"0x\"."; | ||
| else | ||
| ret[a].setCode(fromHex(codeStr)); | ||
| ret[a].setCode(fromHex(codeStr), 0); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll create an issue to handle this properly. We should have the ability to set contract's version in config file.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| } | ||
| else | ||
| cerr << "Error importing code of account " << a | ||
|
|
@@ -186,7 +189,7 @@ AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _def | |
| if (code.empty()) | ||
| cerr << "Error importing code of account " << a << "! Code file " | ||
| << codePath << " empty or does not exist.\n"; | ||
| ret[a].setCode(std::move(code)); | ||
| ret[a].setCode(std::move(code), 0); | ||
| } | ||
| else | ||
| cerr << "Error importing code of account " << a | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -342,9 +342,11 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co | |
| { | ||
| bytes const& c = m_s.code(_p.codeAddress); | ||
| h256 codeHash = m_s.codeHash(_p.codeAddress); | ||
| // Contract will be executed with the version stored in account | ||
| auto const version = m_s.version(_p.codeAddress); | ||
| m_ext = make_shared<ExtVM>(m_s, m_envInfo, m_sealEngine, _p.receiveAddress, | ||
| _p.senderAddress, _origin, _p.apparentValue, _gasPrice, _p.data, &c, codeHash, | ||
| m_depth, false, _p.staticCall); | ||
| version, m_depth, false, _p.staticCall); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -355,24 +357,38 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co | |
|
|
||
| bool Executive::create(Address const& _txSender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin) | ||
| { | ||
| // Contract creation by an external account is the same as CREATE opcode | ||
| return createOpcode(_txSender, _endowment, _gasPrice, _gas, _init, _origin); | ||
| // Contract will be created with the version corresponding to latest hard fork | ||
| auto const latestVersion = m_sealEngine.evmSchedule(m_envInfo.number()).accountVersion; | ||
| return createWithAddressFromNonceAndSender( | ||
| _txSender, _endowment, _gasPrice, _gas, _init, _origin, latestVersion); | ||
| } | ||
|
|
||
| bool Executive::createOpcode(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin) | ||
| { | ||
| // Contract will be created with the version equal to parent's version | ||
| return createWithAddressFromNonceAndSender( | ||
| _sender, _endowment, _gasPrice, _gas, _init, _origin, m_s.version(_sender)); | ||
| } | ||
|
|
||
| bool Executive::createWithAddressFromNonceAndSender(Address const& _sender, u256 const& _endowment, | ||
| u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin, | ||
| u256 const& _version) | ||
| { | ||
| u256 nonce = m_s.getNonce(_sender); | ||
| m_newAddress = right160(sha3(rlpList(_sender, nonce))); | ||
| return executeCreate(_sender, _endowment, _gasPrice, _gas, _init, _origin); | ||
| return executeCreate(_sender, _endowment, _gasPrice, _gas, _init, _origin, _version); | ||
| } | ||
|
|
||
| bool Executive::create2Opcode(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin, u256 const& _salt) | ||
| { | ||
| m_newAddress = right160(sha3(bytes{0xff} +_sender.asBytes() + toBigEndian(_salt) + sha3(_init))); | ||
| return executeCreate(_sender, _endowment, _gasPrice, _gas, _init, _origin); | ||
| // Contract will be created with the version equal to parent's version | ||
| return executeCreate( | ||
| _sender, _endowment, _gasPrice, _gas, _init, _origin, m_s.version(_sender)); | ||
| } | ||
|
|
||
| bool Executive::executeCreate(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin) | ||
| bool Executive::executeCreate(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, | ||
| u256 const& _gas, bytesConstRef _init, Address const& _origin, u256 const& _version) | ||
| { | ||
| if (_sender != MaxAddress || | ||
| m_envInfo.number() < m_sealEngine.chainParams().experimentalForkBlock) // EIP86 | ||
|
|
@@ -411,7 +427,11 @@ bool Executive::executeCreate(Address const& _sender, u256 const& _endowment, u2 | |
| // Schedule _init execution if not empty. | ||
| if (!_init.empty()) | ||
| m_ext = make_shared<ExtVM>(m_s, m_envInfo, m_sealEngine, m_newAddress, _sender, _origin, | ||
| _endowment, _gasPrice, bytesConstRef(), _init, sha3(_init), m_depth, true, false); | ||
| _endowment, _gasPrice, bytesConstRef(), _init, sha3(_init), _version, m_depth, true, | ||
| false); | ||
| else | ||
| // code stays empty, but we set the version | ||
| m_s.setCode(m_newAddress, {}, _version); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the point of setting the version if there's no code?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This question might be delegated to the EIP.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I discussed this with EIP author here sorpaas/EIPs#2 (comment) |
||
|
|
||
| return !m_ext; | ||
| } | ||
|
|
@@ -476,7 +496,7 @@ bool Executive::go(OnOpFunc const& _onOp) | |
| } | ||
| if (m_res) | ||
| m_res->output = out.toVector(); // copy output to execution result | ||
| m_s.setCode(m_ext->myAddress, out.toVector()); | ||
| m_s.setCode(m_ext->myAddress, out.toVector(), m_ext->version); | ||
| } | ||
| else | ||
| m_output = vm->exec(m_gas, *m_ext, _onOp); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.