Skip to content

Commit

Permalink
7702 latest spec update (#11585)
Browse files Browse the repository at this point in the history
- implementation for delegated designation and other latest spec changes
- https://eips.ethereum.org/EIPS/eip-7702
- the integration tests updated to latest execution-spec-tests release -
[email protected]
  • Loading branch information
sudeepdino008 authored and somnathb1 committed Sep 4, 2024
1 parent 7d07ee8 commit 7181c87
Show file tree
Hide file tree
Showing 115 changed files with 565,176 additions and 386,555 deletions.
57 changes: 54 additions & 3 deletions core/state/intra_block_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ type revision struct {
// SystemAddress - sender address for internal state updates.
var SystemAddress = libcommon.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")

var EmptyAddress = libcommon.Address{}

// BalanceIncrease represents the increase of balance of an account that did not require
// reading the account first
type BalanceIncrease struct {
Expand Down Expand Up @@ -280,6 +282,44 @@ func (sdb *IntraBlockState) GetCodeHash(addr libcommon.Address) libcommon.Hash {
return stateObject.data.CodeHash
}

func (sdb *IntraBlockState) ResolveCodeHash(addr libcommon.Address) libcommon.Hash {
// eip-7702
if dd, ok := sdb.GetDelegatedDesignation(addr); ok {
return sdb.GetCodeHash(dd)
}

return sdb.GetCodeHash(addr)
}

func (sdb *IntraBlockState) ResolveCode(addr libcommon.Address) []byte {
// eip-7702
if dd, ok := sdb.GetDelegatedDesignation(addr); ok {
return sdb.GetCode(dd)
}

return sdb.GetCode(addr)
}

func (sdb *IntraBlockState) ResolveCodeSize(addr libcommon.Address) int {
// eip-7702
size := sdb.GetCodeSize(addr)
if size == types.DelegateDesignationCodeSize {
// might be delegated designation
return len(sdb.ResolveCode(addr))
}

return size
}

func (sdb *IntraBlockState) GetDelegatedDesignation(addr libcommon.Address) (libcommon.Address, bool) {
// eip-7702
code := sdb.GetCode(addr)
if delegation, ok := types.ParseDelegation(code); ok {
return delegation, true
}
return EmptyAddress, false
}

// GetState retrieves a value from the given account's storage trie.
// DESCRIBED: docs/programmers_guide/guide.md#address---identifier-of-an-account
func (sdb *IntraBlockState) GetState(addr libcommon.Address, key *libcommon.Hash, value *uint256.Int) {
Expand Down Expand Up @@ -448,9 +488,10 @@ func (sdb *IntraBlockState) Selfdestruct6780(addr libcommon.Address) {
if stateObject == nil {
return
}

if stateObject.newlyCreated {
sdb.Selfdestruct(addr)
if _, ok := types.ParseDelegation(sdb.GetCode(addr)); !ok {
sdb.Selfdestruct(addr)
}
}
}

Expand Down Expand Up @@ -804,6 +845,10 @@ func (sdb *IntraBlockState) clearJournalAndRefund() {
//
// Cancun fork:
// - Reset transient storage (EIP-1153)
//
// Prague fork:
// - Add authorities to access list (EIP-7702)
// - Add delegated designation (if it exists for dst) to access list (EIP-7702)
func (sdb *IntraBlockState) Prepare(rules *chain.Rules, sender, coinbase libcommon.Address, dst *libcommon.Address,
precompiles []libcommon.Address, list types2.AccessList, authorities []libcommon.Address) {
if sdb.trace {
Expand Down Expand Up @@ -836,7 +881,13 @@ func (sdb *IntraBlockState) Prepare(rules *chain.Rules, sender, coinbase libcomm
}
if rules.IsPrague {
for _, addr := range authorities {
sdb.accessList.AddAddress(addr)
sdb.AddAddressToAccessList(addr)
}

if dst != nil {
if dd, ok := sdb.GetDelegatedDesignation(*dst); ok {
sdb.AddAddressToAccessList(dd)
}
}
}
// Reset transient storage at the beginning of transaction execution
Expand Down
78 changes: 43 additions & 35 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (

"github.com/holiman/uint256"

"github.com/erigontech/erigon-lib/common"
libcommon "github.com/erigontech/erigon-lib/common"
"github.com/erigontech/erigon-lib/common/fixedgas"
"github.com/erigontech/erigon-lib/log/v3"
"github.com/erigontech/erigon-lib/txpool/txpoolcfg"
types2 "github.com/erigontech/erigon-lib/types"
Expand Down Expand Up @@ -270,8 +270,12 @@ func (st *StateTransition) preCheck(gasBailout bool) error {
// libcommon.Hash{} means that the sender is not in the state.
// Historically there were transactions with 0 gas price and non-existing sender,
// so we have to allow that.
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
st.msg.From().Hex(), codeHash)

// eip-7702 allows tx origination from accounts having delegated designation code.
if _, ok := st.state.GetDelegatedDesignation(st.msg.From()); !ok {
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
st.msg.From().Hex(), codeHash)
}
}
}

Expand Down Expand Up @@ -348,60 +352,66 @@ func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*evmtype
isEIP3860 := vmConfig.HasEip3860(rules)
accessTuples := slices.Clone[types2.AccessList](msg.AccessList())

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

// set code tx
auths := msg.Authorizations()
verifiedAuthorities := make([]common.Address, 0)
verifiedAuthorities := make([]libcommon.Address, 0)
if len(auths) > 0 {
var b [33]byte
data := bytes.NewBuffer(nil)
for i, auth := range auths {
data.Reset()

// 1. authority recover
// 1. chainId check
if auth.ChainID != nil && !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainRules().ChainID) != 0 {
log.Debug("invalid chainID, skipping", "chainId", auth.ChainID, "auth index", i)
continue
}

// 2. authority recover
authorityPtr, err := auth.RecoverSigner(data, b[:])
if err != nil {
log.Debug("authority recover failed, skipping", "err", err, "auth index", i)
continue
}
authority := *authorityPtr

// 2. chainId check
if auth.ChainID != nil && auth.ChainID.Uint64() != 0 && auth.ChainID.Uint64() != st.evm.ChainRules().ChainID.Uint64() {
log.Debug("invalid chainID, skipping", "chainId", auth.ChainID, "auth index", i)
continue
}
// 3. add authority account to accesses_addresses
verifiedAuthorities = append(verifiedAuthorities, authority)
// authority is added to accessed_address in prepare step

// 3. authority code should be empty
// 4. authority code should be empty or already delegated
if codeHash := st.state.GetCodeHash(authority); codeHash != emptyCodeHash && codeHash != (libcommon.Hash{}) {
log.Debug("authority code is not empty, skipping", "auth index", i)
continue
// check for delegation
if _, ok := st.state.GetDelegatedDesignation(authority); ok {
// noop: has delegated designation
} else {
log.Debug("authority code is not empty or not delegated, skipping", "auth index", i)
continue
}
}

// 4. nonce check
if len(auth.Nonce) > 0 && st.state.GetNonce(authority) != auth.Nonce[0] {
// 5. nonce check
authorityNonce := st.state.GetNonce(authority)
if authorityNonce != auth.Nonce {
log.Debug("invalid nonce, skipping", "auth index", i)
continue
}

// 5. set code of authority to code associated with address
st.state.SetCode(authority, st.state.GetCode(auth.Address))

// 6. add authority account to accesses_addresses
verifiedAuthorities = append(verifiedAuthorities, authority)
// authority is added to accessed_address in prepare step
}
}

if len(verifiedAuthorities) > 0 {
oldPostApplyMessage := st.evm.Context.PostApplyMessage
st.evm.Context.PostApplyMessage = func(ibs evmtypes.IntraBlockState, sender common.Address, coinbase common.Address, result *evmtypes.ExecutionResult) {
for _, authority := range verifiedAuthorities {
ibs.SetCode(authority, nil)
// 6. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie.
if st.state.Exist(authority) {
st.state.AddRefund(fixedgas.PerEmptyAccountCost - fixedgas.PerAuthBaseCost)
}

if oldPostApplyMessage != nil {
oldPostApplyMessage(ibs, sender, coinbase, result)
}
// 7. set authority code
st.state.SetCode(authority, types.AddressToDelegation(auth.Address))

// 8. increase the nonce of authority
st.state.SetNonce(authority, authorityNonce+1)
}
}

Expand Down Expand Up @@ -429,7 +439,7 @@ func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*evmtype
}

// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - prepare accessList(post-berlin; eip-7702)
// - reset transient storage(eip 1153)
st.state.Prepare(rules, msg.From(), coinbase, msg.To(), vm.ActivePrecompiles(rules), accessTuples, verifiedAuthorities)

Expand All @@ -444,8 +454,6 @@ func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*evmtype
// of the contract's address, but before the execution of the code.
ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, st.data, st.gasRemaining, st.value, bailout)
} 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(), st.data, st.gasRemaining, st.value, bailout)
}
if refunds {
Expand Down
7 changes: 4 additions & 3 deletions core/tracing/gen_gas_change_reason_stringer.go

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

2 changes: 2 additions & 0 deletions core/tracing/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ const (
GasChangeCallStorageColdAccess GasChangeReason = 13
// GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert.
GasChangeCallFailedExecution GasChangeReason = 14
// GasChangeDelegatedDesignation is the amount of gas that will be charged for resolution of delegated designation.
GasChangeDelegatedDesignation GasChangeReason = 15

// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
// it will be "manually" tracked by a direct emit of the gas change event.
Expand Down
Loading

0 comments on commit 7181c87

Please sign in to comment.