Skip to content

Commit

Permalink
all: update to new 7702 spec
Browse files Browse the repository at this point in the history
  • Loading branch information
lightclient committed Aug 21, 2024
1 parent 955384a commit 20ea148
Show file tree
Hide file tree
Showing 16 changed files with 289 additions and 136 deletions.
41 changes: 20 additions & 21 deletions core/setcode_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package core

import (
"bytes"
"math/big"
"os"
"testing"
Expand Down Expand Up @@ -74,26 +75,24 @@ func TestEIP7702(t *testing.T) {
gspec.Config.PragueTime = u64(0)
signer := types.LatestSigner(gspec.Config)

_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
b.SetCoinbase(aa)
// One transaction to Coinbase

auth1, _ := types.SignAuth(&types.Authorization{
ChainID: new(big.Int).Set(gspec.Config.ChainID),
Address: aa,
Nonce: nil,
}, key1)
auth1, _ := types.SignAuth(&types.Authorization{
ChainID: new(big.Int).Set(gspec.Config.ChainID),
Address: aa,
Nonce: 1,
}, key1)

auth2, _ := types.SignAuth(&types.Authorization{
ChainID: new(big.Int).Set(gspec.Config.ChainID),
Address: bb,
Nonce: []uint64{0},
}, key2)
auth2, _ := types.SignAuth(&types.Authorization{
ChainID: new(big.Int),
Address: bb,
Nonce: 0,
}, key2)

_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
b.SetCoinbase(aa)
txdata := &types.SetCodeTx{
ChainID: uint256.MustFromBig(gspec.Config.ChainID),
Nonce: 0,
To: &addr1,
To: addr1,
Gas: 500000,
GasFeeCap: uint256.MustFromBig(newGwei(5)),
GasTipCap: uint256.NewInt(2),
Expand All @@ -120,13 +119,13 @@ func TestEIP7702(t *testing.T) {
fortyTwo = common.BytesToHash([]byte{0x42})
actual = state.GetState(addr2, fortyTwo)
)
if actual.Cmp(fortyTwo) != 0 {
t.Fatalf("addr2 storage wrong: expected %d, got %d", fortyTwo, actual)
if code, want := state.GetCode(addr1), types.AddressToDelegation(auth1.Address); !bytes.Equal(code, want) {
t.Fatalf("addr1 code incorrect: got %s, want %s", common.Bytes2Hex(code), common.Bytes2Hex(want))
}
if code := state.GetCode(addr1); code != nil {
t.Fatalf("addr1 code not cleared: got %s", common.Bytes2Hex(code))
if code, want := state.GetCode(addr2), types.AddressToDelegation(auth2.Address); !bytes.Equal(code, want) {
t.Fatalf("addr2 code incorrect: got %s, want %s", common.Bytes2Hex(code), common.Bytes2Hex(want))
}
if code := state.GetCode(addr2); code != nil {
t.Fatalf("addr2 code not cleared: got %s", common.Bytes2Hex(code))
if actual.Cmp(fortyTwo) != 0 {
t.Fatalf("addr2 storage wrong: expected %d, got %d", fortyTwo, actual)
}
}
61 changes: 29 additions & 32 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,6 @@ func (m *mutation) isDelete() bool {
return m.typ == deletion
}

type delegation struct {
code []byte
codeHash common.Hash
}

// StateDB structs within the ethereum protocol are used to store anything
// within the merkle trie. StateDBs take care of caching and storing
// nested states. It's the general query interface to retrieve:
Expand Down Expand Up @@ -146,9 +141,6 @@ type StateDB struct {
// Transient storage
transientStorage transientStorage

// Transient delegation of accounts to code
transientDelegation map[common.Address]delegation

// Journal of state modifications. This is the backbone of
// Snapshot and RevertToSnapshot.
journal *journal
Expand Down Expand Up @@ -327,9 +319,6 @@ func (s *StateDB) SubRefund(gas uint64) {
// Exist reports whether the given account address exists in the state.
// Notably this also returns true for self-destructed accounts.
func (s *StateDB) Exist(addr common.Address) bool {
if _, ok := s.transientDelegation[addr]; ok {
return true
}
return s.getStateObject(addr) != nil
}

Expand Down Expand Up @@ -375,9 +364,6 @@ func (s *StateDB) TxIndex() int {
}

func (s *StateDB) GetCode(addr common.Address) []byte {
if d, ok := s.transientDelegation[addr]; ok {
return d.code
}
stateObject := s.getStateObject(addr)
if stateObject != nil {
return stateObject.Code()
Expand All @@ -386,9 +372,6 @@ func (s *StateDB) GetCode(addr common.Address) []byte {
}

func (s *StateDB) GetCodeSize(addr common.Address) int {
if d, ok := s.transientDelegation[addr]; ok {
return len(d.code)
}
stateObject := s.getStateObject(addr)
if stateObject != nil {
return stateObject.CodeSize()
Expand All @@ -397,16 +380,29 @@ func (s *StateDB) GetCodeSize(addr common.Address) int {
}

func (s *StateDB) GetCodeHash(addr common.Address) common.Hash {
if d, ok := s.transientDelegation[addr]; ok {
return d.codeHash
}
stateObject := s.getStateObject(addr)
if stateObject != nil {
return common.BytesToHash(stateObject.CodeHash())
}
return common.Hash{}
}

func (s *StateDB) ResolveCode(addr common.Address) []byte {
stateObject := s.resolveStateObject(addr)
if stateObject != nil {
return stateObject.Code()
}
return nil
}

func (s *StateDB) ResolveCodeHash(addr common.Address) common.Hash {
stateObject := s.resolveStateObject(addr)
if stateObject != nil {
return common.BytesToHash(stateObject.CodeHash())
}
return common.Hash{}
}

// GetState retrieves the value associated with the specific key.
func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
stateObject := s.getStateObject(addr)
Expand Down Expand Up @@ -658,6 +654,18 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
return obj
}

func (s *StateDB) resolveStateObject(addr common.Address) *stateObject {
obj := s.getStateObject(addr)
if obj == nil {
return nil
}
addr, ok := types.ParseDelegation(obj.Code())
if !ok {
return obj
}
return s.getStateObject(addr)
}

func (s *StateDB) setStateObject(object *stateObject) {
s.stateObjects[object.Address()] = object
}
Expand Down Expand Up @@ -1411,7 +1419,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
// - Reset access list (Berlin)
// - Add coinbase to access list (EIP-3651)
// - Reset transient storage (EIP-1153)
func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList, authList []types.SetCodeDelegation) {
func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
if rules.IsEIP2929 && rules.IsEIP4762 {
panic("eip2929 and eip4762 are both activated")
}
Expand Down Expand Up @@ -1440,17 +1448,6 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d
}
// Reset transient storage at the beginning of transaction execution
s.transientStorage = newTransientStorage()

// Set temporary code delegations.
s.transientDelegation = nil
if authList != nil {
td := make(map[common.Address]delegation)
for _, auth := range authList {
td[auth.From] = delegation{s.GetCode(auth.Target), s.GetCodeHash(auth.Target)}
s.accessList.AddAddress(auth.From)
}
s.transientDelegation = td
}
}

// AddAddressToAccessList adds the given address to the access list
Expand Down
53 changes: 31 additions & 22 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList types.Autho
gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas
}
if authList != nil {
gas += uint64(len(authList)) * params.TxAuthTupleGas
gas += uint64(len(authList)) * params.CallNewAccountGas
}
return gas, nil
}
Expand Down Expand Up @@ -434,49 +434,58 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize)
}

// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)

if !contractCreation {
// Increment the nonce for the next transaction
st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1)
}

// Check authorizations list validity.
var delegations []types.SetCodeDelegation
if msg.AuthList != nil {
seen := make(map[common.Address]bool)
for _, auth := range msg.AuthList {
// Verify chain ID is 0 or equal to current chain ID.
if auth.ChainID.Sign() != 0 && st.evm.ChainConfig().ChainID.Cmp(auth.ChainID) != 0 {
continue
}
authority, err := auth.Authority()
if err != nil {
continue
}
var nonce *uint64
if len(auth.Nonce) > 1 {
return nil, fmt.Errorf("authorization must be either empty list or contain exactly one element")
// Check the authority account 1) doesn't have code or has exisiting
// delegation 2) matches the auth's nonce
code := st.state.GetCode(authority)
if _, ok := types.ParseDelegation(code); len(code) != 0 && !ok {
continue
}
if len(auth.Nonce) == 1 {
tmp := auth.Nonce[0]
nonce = &tmp
if have := st.state.GetNonce(authority); have != auth.Nonce {
continue
}
if nonce != nil {
if have := st.state.GetNonce(authority); have != *nonce {
continue
}
// If the account already exists in state, refund the new account cost
// charged in the initrinsic calculation.
if exists := st.state.Exist(authority); exists {
st.state.AddRefund(params.CallNewAccountGas - params.TxAuthTupleGas)
}
if _, ok := seen[authority]; !ok {
seen[authority] = true
delegations = append(delegations, types.SetCodeDelegation{From: authority, Nonce: nonce, Target: auth.Address})
// Only the first valid occurrence should be used.
if _, ok := seen[authority]; ok {
continue
}
seen[authority] = true
st.state.SetCode(authority, types.AddressToDelegation(auth.Address))
}
}

// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList, delegations)

var (
ret []byte
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
)
if contractCreation {
ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, value)
} else {
// Increment the nonce for the next transaction
st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1)
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value)
}

Expand Down
32 changes: 12 additions & 20 deletions core/types/gen_authorization.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions core/types/transaction_marshalling.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,9 +438,10 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
return errors.New("missing required field 'nonce' in transaction")
}
itx.Nonce = uint64(*dec.Nonce)
if dec.To != nil {
itx.To = dec.To
if dec.To == nil {
return errors.New("missing required field 'to' in transaction")
}
itx.To = *dec.To
if dec.Gas == nil {
return errors.New("missing required field 'gas' for txdata")
}
Expand Down
Loading

0 comments on commit 20ea148

Please sign in to comment.