Skip to content
This repository was archived by the owner on Oct 28, 2021. It is now read-only.

Commit d169557

Browse files
authored
Implement EIP-1702 Generalized Account Versioning Scheme (#5640)
Implement EIP-1702 Generalized Account Versioning Scheme
2 parents e1f8a1f + 0554648 commit d169557

File tree

21 files changed

+462
-75
lines changed

21 files changed

+462
-75
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
- Added: [#5588](https://github.com/ethereum/aleth/pull/5588) Testeth prints similar test suite name suggestions, when the name passed in `-t` argument is not found.
1313
- Added: [#5593](https://github.com/ethereum/aleth/pull/5593) Dynamically updating host ENR.
1414
- Added: [#5624](https://github.com/ethereum/aleth/pull/5624) Remove useless peers from peer list.
15-
- Added: [#5634](https://github.com/ethereum/aleth/pull/5634) Bootnodes for Rinkeby and Goerli
15+
- Added: [#5634](https://github.com/ethereum/aleth/pull/5634) Bootnodes for Rinkeby and Goerli.
16+
- Added: [#5640](https://github.com/ethereum/aleth/pull/5640) Istanbul support: EIP-1702 Generalized Account Versioning Scheme.
1617
- 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.
1718
- Changed: [#5559](https://github.com/ethereum/aleth/pull/5559) Update peer validation error messages.
1819
- Changed: [#5568](https://github.com/ethereum/aleth/pull/5568) Improve rlpx handshake log messages and create new rlpx log channel.

aleth-vm/main.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -259,13 +259,18 @@ int main(int argc, char** argv)
259259
} // Ignore decoding errors.
260260
}
261261

262+
unique_ptr<SealEngineFace> se(ChainParams(genesisInfo(networkName)).createSealEngine());
263+
LastBlockHashes lastBlockHashes;
264+
EnvInfo const envInfo(blockHeader, lastBlockHashes, 0);
265+
262266
Transaction t;
263267
Address contractDestination("1122334455667788991011121314151617181920");
264268
if (!code.empty())
265269
{
266270
// Deploy the code on some fake account to be called later.
267271
Account account(0, 0);
268-
account.setCode(bytes{code});
272+
auto const latestVersion = se->evmSchedule(envInfo.number()).accountVersion;
273+
account.setCode(bytes{code}, latestVersion);
269274
std::unordered_map<Address, Account> map;
270275
map[contractDestination] = account;
271276
state.populateFrom(map);
@@ -278,9 +283,6 @@ int main(int argc, char** argv)
278283

279284
state.addBalance(sender, value);
280285

281-
unique_ptr<SealEngineFace> se(ChainParams(genesisInfo(networkName)).createSealEngine());
282-
LastBlockHashes lastBlockHashes;
283-
EnvInfo const envInfo(blockHeader, lastBlockHashes, 0);
284286
Executive executive(state, envInfo, *se);
285287
ExecutionResult res;
286288
executive.setResultRecipient(res);

libethcore/ChainOperationParams.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ EVMSchedule const& ChainOperationParams::scheduleForBlockNumber(u256 const& _blo
5757
{
5858
if (_blockNumber >= experimentalForkBlock)
5959
return ExperimentalSchedule;
60+
else if (_blockNumber >= istanbulForkBlock)
61+
return IstanbulSchedule;
6062
else if (_blockNumber >= constantinopleFixForkBlock)
6163
return ConstantinopleFixSchedule;
6264
else if (_blockNumber >= constantinopleForkBlock)

libethcore/EVMSchedule.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ struct EVMSchedule
2929
{
3030
EVMSchedule(): tierStepGas(std::array<unsigned, 8>{{0, 2, 3, 5, 8, 10, 20, 0}}) {}
3131
EVMSchedule(bool _efcd, bool _hdc, unsigned const& _txCreateGas): exceptionalFailedCodeDeposit(_efcd), haveDelegateCall(_hdc), tierStepGas(std::array<unsigned, 8>{{0, 2, 3, 5, 8, 10, 20, 0}}), txCreateGas(_txCreateGas) {}
32+
unsigned accountVersion = 0;
3233
bool exceptionalFailedCodeDeposit = true;
3334
bool haveDelegateCall = true;
3435
bool eip150Mode = false;
@@ -146,10 +147,31 @@ static const EVMSchedule ConstantinopleFixSchedule = [] {
146147
return schedule;
147148
}();
148149

150+
static const EVMSchedule IstanbulSchedule = [] {
151+
EVMSchedule schedule = ConstantinopleFixSchedule;
152+
schedule.accountVersion = 1;
153+
return schedule;
154+
}();
155+
149156
static const EVMSchedule ExperimentalSchedule = [] {
150-
EVMSchedule schedule = ConstantinopleSchedule;
157+
EVMSchedule schedule = IstanbulSchedule;
151158
schedule.blockhashGas = 800;
152159
return schedule;
153160
}();
161+
162+
inline EVMSchedule const& latestScheduleForAccountVersion(u256 const& _version)
163+
{
164+
if (_version == 0)
165+
return ConstantinopleFixSchedule;
166+
else if (_version == IstanbulSchedule.accountVersion)
167+
return IstanbulSchedule;
168+
else
169+
{
170+
// This should not happen, as all existing accounts
171+
// are created either with version 0 or with one of fork's versions
172+
assert(false);
173+
return DefaultSchedule;
174+
}
175+
}
154176
}
155177
}

libethereum/Account.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ using namespace dev::eth::validation;
3434

3535
namespace fs = boost::filesystem;
3636

37-
void Account::setCode(bytes&& _code)
37+
void Account::setCode(bytes&& _code, u256 const& _version)
3838
{
3939
auto const newHash = sha3(_code);
4040
if (newHash != m_codeHash)
@@ -43,13 +43,16 @@ void Account::setCode(bytes&& _code)
4343
m_hasNewCode = true;
4444
m_codeHash = newHash;
4545
}
46+
m_version = _version;
4647
}
4748

4849
void Account::resetCode()
4950
{
5051
m_codeCache.clear();
5152
m_hasNewCode = false;
5253
m_codeHash = EmptySHA3;
54+
// Reset the version, as it was set together with code
55+
m_version = 0;
5356
}
5457

5558
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
166169
cerr << "Error importing code of account " << a
167170
<< "! Code needs to be hex bytecode prefixed by \"0x\".";
168171
else
169-
ret[a].setCode(fromHex(codeStr));
172+
ret[a].setCode(fromHex(codeStr), 0);
170173
}
171174
else
172175
cerr << "Error importing code of account " << a
@@ -186,7 +189,7 @@ AccountMap dev::eth::jsonToAccountMap(std::string const& _json, u256 const& _def
186189
if (code.empty())
187190
cerr << "Error importing code of account " << a << "! Code file "
188191
<< codePath << " empty or does not exist.\n";
189-
ret[a].setCode(std::move(code));
192+
ret[a].setCode(std::move(code), 0);
190193
}
191194
else
192195
cerr << "Error importing code of account " << a

libethereum/Account.h

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,23 @@ class Account
6868
/// Construct a dead Account.
6969
Account() {}
7070

71-
/// Construct an alive Account, with given endowment, for either a normal (non-contract) account or for a
72-
/// contract account in the
73-
/// conception phase, where the code is not yet known.
71+
/// Construct an alive Account, with given endowment, for either a normal (non-contract) account
72+
/// or for a contract account in the conception phase, where the code is not yet known.
7473
Account(u256 _nonce, u256 _balance, Changedness _c = Changed): m_isAlive(true), m_isUnchanged(_c == Unchanged), m_nonce(_nonce), m_balance(_balance) {}
7574

7675
/// Explicit constructor for wierd cases of construction or a contract account.
77-
Account(u256 _nonce, u256 _balance, h256 _contractRoot, h256 _codeHash, Changedness _c): m_isAlive(true), m_isUnchanged(_c == Unchanged), m_nonce(_nonce), m_balance(_balance), m_storageRoot(_contractRoot), m_codeHash(_codeHash) { assert(_contractRoot); }
76+
Account(u256 const& _nonce, u256 const& _balance, h256 const& _contractRoot,
77+
h256 const& _codeHash, u256 const& _version, Changedness _c)
78+
: m_isAlive(true),
79+
m_isUnchanged(_c == Unchanged),
80+
m_nonce(_nonce),
81+
m_balance(_balance),
82+
m_storageRoot(_contractRoot),
83+
m_codeHash(_codeHash),
84+
m_version(_version)
85+
{
86+
assert(_contractRoot);
87+
}
7888

7989

8090
/// Kill this account. Useful for the suicide opcode. Following this call, isAlive() returns
@@ -88,6 +98,7 @@ class Account
8898
m_storageRoot = EmptyTrie;
8999
m_balance = 0;
90100
m_nonce = 0;
101+
m_version = 0;
91102
changed();
92103
}
93104

@@ -171,7 +182,7 @@ class Account
171182
bool hasNewCode() const { return m_hasNewCode; }
172183

173184
/// Sets the code of the account. Used by "create" messages.
174-
void setCode(bytes&& _code);
185+
void setCode(bytes&& _code, u256 const& _version);
175186

176187
/// Reset the code set by previous setCode
177188
void resetCode();
@@ -183,6 +194,8 @@ class Account
183194
/// @returns the account's code.
184195
bytes const& code() const { return m_codeCache; }
185196

197+
u256 version() const { return m_version; }
198+
186199
private:
187200
/// Note that we've altered the account.
188201
void changed() { m_isUnchanged = false; }
@@ -214,6 +227,9 @@ class Account
214227
*/
215228
h256 m_codeHash = EmptySHA3;
216229

230+
/// Account's version
231+
u256 m_version = 0;
232+
217233
/// The map with is overlaid onto whatever storage is implied by the m_storageRoot in the trie.
218234
mutable std::unordered_map<u256, u256> m_storageOverlay;
219235

libethereum/Block.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,8 @@ void Block::updateBlockhashContract()
683683
if (blockNumber == forkBlock)
684684
{
685685
m_state.createContract(c_blockhashContractAddress);
686-
m_state.setCode(c_blockhashContractAddress, bytes(c_blockhashContractCode));
686+
m_state.setCode(c_blockhashContractAddress, bytes(c_blockhashContractCode),
687+
m_sealEngine->evmSchedule(blockNumber).accountVersion);
687688
m_state.commit(State::CommitBehaviour::KeepEmptyAccounts);
688689
}
689690

libethereum/Executive.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,11 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co
342342
{
343343
bytes const& c = m_s.code(_p.codeAddress);
344344
h256 codeHash = m_s.codeHash(_p.codeAddress);
345+
// Contract will be executed with the version stored in account
346+
auto const version = m_s.version(_p.codeAddress);
345347
m_ext = make_shared<ExtVM>(m_s, m_envInfo, m_sealEngine, _p.receiveAddress,
346348
_p.senderAddress, _origin, _p.apparentValue, _gasPrice, _p.data, &c, codeHash,
347-
m_depth, false, _p.staticCall);
349+
version, m_depth, false, _p.staticCall);
348350
}
349351
}
350352

@@ -355,24 +357,38 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co
355357

356358
bool Executive::create(Address const& _txSender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin)
357359
{
358-
// Contract creation by an external account is the same as CREATE opcode
359-
return createOpcode(_txSender, _endowment, _gasPrice, _gas, _init, _origin);
360+
// Contract will be created with the version corresponding to latest hard fork
361+
auto const latestVersion = m_sealEngine.evmSchedule(m_envInfo.number()).accountVersion;
362+
return createWithAddressFromNonceAndSender(
363+
_txSender, _endowment, _gasPrice, _gas, _init, _origin, latestVersion);
360364
}
361365

362366
bool Executive::createOpcode(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin)
367+
{
368+
// Contract will be created with the version equal to parent's version
369+
return createWithAddressFromNonceAndSender(
370+
_sender, _endowment, _gasPrice, _gas, _init, _origin, m_s.version(_sender));
371+
}
372+
373+
bool Executive::createWithAddressFromNonceAndSender(Address const& _sender, u256 const& _endowment,
374+
u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin,
375+
u256 const& _version)
363376
{
364377
u256 nonce = m_s.getNonce(_sender);
365378
m_newAddress = right160(sha3(rlpList(_sender, nonce)));
366-
return executeCreate(_sender, _endowment, _gasPrice, _gas, _init, _origin);
379+
return executeCreate(_sender, _endowment, _gasPrice, _gas, _init, _origin, _version);
367380
}
368381

369382
bool Executive::create2Opcode(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin, u256 const& _salt)
370383
{
371384
m_newAddress = right160(sha3(bytes{0xff} +_sender.asBytes() + toBigEndian(_salt) + sha3(_init)));
372-
return executeCreate(_sender, _endowment, _gasPrice, _gas, _init, _origin);
385+
// Contract will be created with the version equal to parent's version
386+
return executeCreate(
387+
_sender, _endowment, _gasPrice, _gas, _init, _origin, m_s.version(_sender));
373388
}
374389

375-
bool Executive::executeCreate(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin)
390+
bool Executive::executeCreate(Address const& _sender, u256 const& _endowment, u256 const& _gasPrice,
391+
u256 const& _gas, bytesConstRef _init, Address const& _origin, u256 const& _version)
376392
{
377393
if (_sender != MaxAddress ||
378394
m_envInfo.number() < m_sealEngine.chainParams().experimentalForkBlock) // EIP86
@@ -411,7 +427,11 @@ bool Executive::executeCreate(Address const& _sender, u256 const& _endowment, u2
411427
// Schedule _init execution if not empty.
412428
if (!_init.empty())
413429
m_ext = make_shared<ExtVM>(m_s, m_envInfo, m_sealEngine, m_newAddress, _sender, _origin,
414-
_endowment, _gasPrice, bytesConstRef(), _init, sha3(_init), m_depth, true, false);
430+
_endowment, _gasPrice, bytesConstRef(), _init, sha3(_init), _version, m_depth, true,
431+
false);
432+
else
433+
// code stays empty, but we set the version
434+
m_s.setCode(m_newAddress, {}, _version);
415435

416436
return !m_ext;
417437
}
@@ -476,7 +496,7 @@ bool Executive::go(OnOpFunc const& _onOp)
476496
}
477497
if (m_res)
478498
m_res->output = out.toVector(); // copy output to execution result
479-
m_s.setCode(m_ext->myAddress, out.toVector());
499+
m_s.setCode(m_ext->myAddress, out.toVector(), m_ext->version);
480500
}
481501
else
482502
m_output = vm->exec(m_gas, *m_ext, _onOp);

libethereum/Executive.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,17 @@ class Executive
186186
/// Revert all changes made to the state by this execution.
187187
void revert();
188188

189+
/// Used only in tests
190+
ExtVM const& extVM() const { return *m_ext; }
191+
189192
private:
190193
/// @returns false iff go() must be called (and thus a VM execution in required).
191-
bool executeCreate(Address const& _txSender, u256 const& _endowment, u256 const& _gasPrice, u256 const& _gas, bytesConstRef _code, Address const& _originAddress);
194+
bool createWithAddressFromNonceAndSender(Address const& _sender, u256 const& _endowment,
195+
u256 const& _gasPrice, u256 const& _gas, bytesConstRef _init, Address const& _origin,
196+
u256 const& _version);
197+
/// @returns false iff go() must be called (and thus a VM execution in required).
198+
bool executeCreate(Address const& _txSender, u256 const& _endowment, u256 const& _gasPrice,
199+
u256 const& _gas, bytesConstRef _code, Address const& _originAddress, u256 const& _version);
192200

193201
State& m_s; ///< The state to which this operation/transaction is applied.
194202
// TODO: consider changign to EnvInfo const& to avoid LastHashes copy at every CALL/CREATE

libethereum/ExtVM.h

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,13 @@ class ExtVM : public ExtVMFace
4141
/// Full constructor.
4242
ExtVM(State& _s, EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, Address _myAddress,
4343
Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data,
44-
bytesConstRef _code, h256 const& _codeHash, unsigned _depth, bool _isCreate,
45-
bool _staticCall)
44+
bytesConstRef _code, h256 const& _codeHash, u256 const& _version, unsigned _depth,
45+
bool _isCreate, bool _staticCall)
4646
: ExtVMFace(_envInfo, _myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(),
47-
_codeHash, _depth, _isCreate, _staticCall),
47+
_codeHash, _version, _depth, _isCreate, _staticCall),
4848
m_s(_s),
49-
m_sealEngine(_sealEngine)
49+
m_sealEngine(_sealEngine),
50+
m_evmSchedule(initEvmSchedule(envInfo().number(), _version))
5051
{
5152
// Contract: processing account must exist. In case of CALL, the ExtVM
5253
// is created only if an account has code (so exist). In case of CREATE
@@ -97,19 +98,29 @@ class ExtVM : public ExtVMFace
9798
void suicide(Address _a) final;
9899

99100
/// Return the EVM gas-price schedule for this execution context.
100-
EVMSchedule const& evmSchedule() const final
101-
{
102-
return m_sealEngine.evmSchedule(envInfo().number());
103-
}
101+
EVMSchedule const& evmSchedule() const final { return m_evmSchedule; }
104102

105103
State const& state() const { return m_s; }
106104

107105
/// Hash of a block if within the last 256 blocks, or h256() otherwise.
108106
h256 blockHash(u256 _number) final;
109107

110108
private:
109+
EVMSchedule const& initEvmSchedule(int64_t _blockNumber, u256 const& _version) const
110+
{
111+
// If _version is latest for the block, select corresponding latest schedule.
112+
// Otherwise run with the latest schedule known to correspond to the _version.
113+
EVMSchedule const& currentBlockSchedule = m_sealEngine.evmSchedule(_blockNumber);
114+
if (currentBlockSchedule.accountVersion == _version)
115+
return currentBlockSchedule;
116+
else
117+
return latestScheduleForAccountVersion(_version);
118+
}
119+
120+
111121
State& m_s; ///< A reference to the base state.
112122
SealEngineFace const& m_sealEngine;
123+
EVMSchedule const& m_evmSchedule;
113124
};
114125

115126
}

0 commit comments

Comments
 (0)