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 e3834ac
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 109 deletions.
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
46 changes: 26 additions & 20 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,40 +434,46 @@ 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)

// 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
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
31 changes: 25 additions & 6 deletions core/types/tx_setcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,25 @@ import (
"github.com/holiman/uint256"
)

// DelegationPrefix is used by code to denote the account is delegating to
// another account.
var DelegationPrefix = []byte{0xef, 0x01, 0x00}

// ParseDelegation tries to parse the address from a delegation slice.
func ParseDelegation(b []byte) (common.Address, bool) {
if len(b) != 23 || !bytes.HasPrefix(b, DelegationPrefix) {
return common.Address{}, false
}
var addr common.Address
copy(addr[:], b[len(DelegationPrefix):])
return addr, true
}

// AddressToDelegation adds the delegation prefix to the specified address.
func AddressToDelegation(addr common.Address) []byte {
return append(DelegationPrefix, addr.Bytes()...)
}

// SetCodeTx implements the EIP-7702 transaction type which temporarily installs
// the code at the signer's address.
type SetCodeTx struct {
Expand All @@ -21,7 +40,7 @@ type SetCodeTx struct {
GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas
GasFeeCap *uint256.Int // a.k.a. maxFeePerGas
Gas uint64
To *common.Address `rlp:"nil"` // nil means contract creation
To common.Address
Value *uint256.Int
Data []byte
AccessList AccessList
Expand All @@ -40,7 +59,7 @@ type SetCodeTx struct {
type Authorization struct {
ChainID *big.Int
Address common.Address `json:"address" gencodec:"required"`
Nonce []uint64 `json:"nonce" gencodec:"required"`
Nonce uint64 `json:"nonce" gencodec:"required"`
V *big.Int `json:"v" gencodec:"required"`
R *big.Int `json:"r" gencodec:"required"`
S *big.Int `json:"s" gencodec:"required"`
Expand All @@ -49,7 +68,7 @@ type Authorization struct {
// field type overrides for gencodec
type authorizationMarshaling struct {
ChainID *hexutil.Big
Nonce []hexutil.Uint64
Nonce hexutil.Uint64
V *hexutil.Big
R *hexutil.Big
S *hexutil.Big
Expand Down Expand Up @@ -121,7 +140,7 @@ func (a Authorization) Authority() (common.Address, error) {

type SetCodeDelegation struct {
From common.Address
Nonce *uint64
Nonce uint64
Target common.Address
}

Expand Down Expand Up @@ -153,7 +172,7 @@ func (a AuthorizationList) WithAddress() []AuthorizationTuple {
func (tx *SetCodeTx) copy() TxData {
cpy := &SetCodeTx{
Nonce: tx.Nonce,
To: copyAddressPtr(tx.To),
To: tx.To,
Data: common.CopyBytes(tx.Data),
Gas: tx.Gas,
// These are copied below.
Expand Down Expand Up @@ -204,7 +223,7 @@ func (tx *SetCodeTx) gasTipCap() *big.Int { return tx.GasTipCap.ToBig() }
func (tx *SetCodeTx) gasPrice() *big.Int { return tx.GasFeeCap.ToBig() }
func (tx *SetCodeTx) value() *big.Int { return tx.Value.ToBig() }
func (tx *SetCodeTx) nonce() uint64 { return tx.Nonce }
func (tx *SetCodeTx) to() *common.Address { return tx.To }
func (tx *SetCodeTx) to() *common.Address { tmp := tx.To; return &tmp }

func (tx *SetCodeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
if baseFee == nil {
Expand Down
Loading

0 comments on commit e3834ac

Please sign in to comment.