Compare commits
5 Commits
6b9004ff63
...
4040b5fbc5
Author | SHA1 | Date |
---|---|---|
|
4040b5fbc5 | |
|
dab746b3ef | |
|
b87d5399a7 | |
|
9025557278 | |
|
15b8b82328 |
|
@ -156,6 +156,7 @@ type Message struct {
|
|||
BlobGasFeeCap *big.Int
|
||||
BlobHashes []common.Hash
|
||||
SetCodeAuthorizations []types.SetCodeAuthorization
|
||||
AuthorityCache *types.AuthorityCache
|
||||
|
||||
// When SkipNonceChecks is true, the message nonce is not checked against the
|
||||
// account nonce in state.
|
||||
|
@ -179,6 +180,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
|
|||
Data: tx.Data(),
|
||||
AccessList: tx.AccessList(),
|
||||
SetCodeAuthorizations: tx.SetCodeAuthorizations(),
|
||||
AuthorityCache: tx.AuthorityCache(),
|
||||
SkipNonceChecks: false,
|
||||
SkipFromEOACheck: false,
|
||||
BlobHashes: tx.BlobHashes(),
|
||||
|
@ -490,9 +492,13 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
|
||||
// Apply EIP-7702 authorizations.
|
||||
if msg.SetCodeAuthorizations != nil {
|
||||
for _, auth := range msg.SetCodeAuthorizations {
|
||||
for i, auth := range msg.SetCodeAuthorizations {
|
||||
// Note errors are ignored, we simply skip invalid authorizations here.
|
||||
st.applyAuthorization(&auth)
|
||||
authority, err := msg.AuthorityCache.Authority(i)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
st.applyAuthorization(&auth, authority)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -557,7 +563,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
}
|
||||
|
||||
// validateAuthorization validates an EIP-7702 authorization against the state.
|
||||
func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, err error) {
|
||||
func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization, preDerivedAuthority common.Address) (authority common.Address, err error) {
|
||||
// Verify chain ID is null or equal to current chain ID.
|
||||
if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 {
|
||||
return authority, ErrAuthorizationWrongChainID
|
||||
|
@ -566,11 +572,9 @@ func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio
|
|||
if auth.Nonce+1 < auth.Nonce {
|
||||
return authority, ErrAuthorizationNonceOverflow
|
||||
}
|
||||
// Validate signature values and recover authority.
|
||||
authority, err = auth.Authority()
|
||||
if err != nil {
|
||||
return authority, fmt.Errorf("%w: %v", ErrAuthorizationInvalidSignature, err)
|
||||
}
|
||||
|
||||
authority = preDerivedAuthority
|
||||
|
||||
// Check the authority account
|
||||
// 1) doesn't have code or has exisiting delegation
|
||||
// 2) matches the auth's nonce
|
||||
|
@ -588,8 +592,8 @@ func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio
|
|||
}
|
||||
|
||||
// applyAuthorization applies an EIP-7702 code delegation to the state.
|
||||
func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) error {
|
||||
authority, err := st.validateAuthorization(auth)
|
||||
func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization, preDerivedAuthority common.Address) error {
|
||||
authority, err := st.validateAuthorization(auth, preDerivedAuthority)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -489,13 +489,25 @@ func (tx *Transaction) SetCodeAuthorities() []common.Address {
|
|||
if !ok {
|
||||
return nil
|
||||
}
|
||||
auths := make([]common.Address, 0, len(setcodetx.AuthList))
|
||||
for _, auth := range setcodetx.AuthList {
|
||||
if addr, err := auth.Authority(); err == nil {
|
||||
auths = append(auths, addr)
|
||||
}
|
||||
if authorityCache := setcodetx.authorityCache.Load(); authorityCache != nil {
|
||||
return authorityCache.authorities
|
||||
}
|
||||
return auths
|
||||
cache := ToAuthorityCache(setcodetx.AuthList)
|
||||
setcodetx.authorityCache.Store(cache)
|
||||
return cache.authorities
|
||||
}
|
||||
|
||||
func (tx *Transaction) AuthorityCache() *AuthorityCache {
|
||||
setcodetx, ok := tx.inner.(*SetCodeTx)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if authorityCache := setcodetx.authorityCache.Load(); authorityCache != nil {
|
||||
return authorityCache
|
||||
}
|
||||
cache := ToAuthorityCache(setcodetx.AuthList)
|
||||
setcodetx.authorityCache.Store(cache)
|
||||
return cache
|
||||
}
|
||||
|
||||
// SetTime sets the decoding time of a transaction. This is used by tests to set
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
|
@ -64,6 +65,51 @@ type SetCodeTx struct {
|
|||
V *uint256.Int
|
||||
R *uint256.Int
|
||||
S *uint256.Int
|
||||
|
||||
// caches
|
||||
authorityCache atomic.Pointer[AuthorityCache]
|
||||
}
|
||||
|
||||
func ToAuthorityCache(authList []SetCodeAuthorization) *AuthorityCache {
|
||||
auths := make([]common.Address, 0, len(authList))
|
||||
var invalid []invalidAuth // empty since it's expected to be empty most of the time
|
||||
for i, auth := range authList {
|
||||
if addr, err := auth.Authority(); err == nil {
|
||||
auths = append(auths, addr)
|
||||
} else {
|
||||
invalid = append(invalid, invalidAuth{index: i, error: err})
|
||||
}
|
||||
}
|
||||
return &AuthorityCache{authorities: auths, invalidAuths: invalid}
|
||||
}
|
||||
|
||||
type AuthorityCache struct {
|
||||
authorities []common.Address
|
||||
invalidAuths []invalidAuth
|
||||
}
|
||||
|
||||
type invalidAuth struct {
|
||||
index int
|
||||
error error
|
||||
}
|
||||
|
||||
func (ac *AuthorityCache) Authority(i int) (common.Address, error) {
|
||||
indexToSub := 0
|
||||
for _, invalid := range ac.invalidAuths {
|
||||
if i == invalid.index {
|
||||
return common.Address{}, invalid.error
|
||||
}
|
||||
if i > invalid.index {
|
||||
indexToSub++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
targetIndex := i - indexToSub
|
||||
if targetIndex < 0 || targetIndex >= len(ac.authorities) {
|
||||
return common.Address{}, errors.New("index out of range")
|
||||
}
|
||||
return ac.authorities[i-indexToSub], nil
|
||||
}
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type SetCodeAuthorization -field-override authorizationMarshaling -out gen_authorization.go
|
||||
|
|
|
@ -33,6 +33,8 @@ import (
|
|||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/params/forks"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
|
@ -95,6 +97,16 @@ type SimulatedBeacon struct {
|
|||
lastBlockTime uint64
|
||||
}
|
||||
|
||||
func payloadVersion(config *params.ChainConfig, time uint64) engine.PayloadVersion {
|
||||
switch config.LatestFork(time) {
|
||||
case forks.Prague, forks.Cancun:
|
||||
return engine.PayloadV3
|
||||
case forks.Paris, forks.Shanghai:
|
||||
return engine.PayloadV2
|
||||
}
|
||||
panic("invalid fork, simulated beacon needs to be started post-merge")
|
||||
}
|
||||
|
||||
// NewSimulatedBeacon constructs a new simulated beacon chain.
|
||||
func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, error) {
|
||||
block := eth.BlockChain().CurrentBlock()
|
||||
|
@ -107,7 +119,8 @@ func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, err
|
|||
|
||||
// if genesis block, send forkchoiceUpdated to trigger transition to PoS
|
||||
if block.Number.Sign() == 0 {
|
||||
if _, err := engineAPI.ForkchoiceUpdatedV3(current, nil); err != nil {
|
||||
version := payloadVersion(eth.BlockChain().Config(), block.Time)
|
||||
if _, err := engineAPI.forkchoiceUpdated(current, nil, version, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
@ -171,6 +184,8 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
|||
return fmt.Errorf("failed to sync txpool: %w", err)
|
||||
}
|
||||
|
||||
version := payloadVersion(c.eth.BlockChain().Config(), timestamp)
|
||||
|
||||
var random [32]byte
|
||||
rand.Read(random[:])
|
||||
fcResponse, err := c.engineAPI.forkchoiceUpdated(c.curForkchoiceState, &engine.PayloadAttributes{
|
||||
|
@ -179,7 +194,7 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
|||
Withdrawals: withdrawals,
|
||||
Random: random,
|
||||
BeaconRoot: &common.Hash{},
|
||||
}, engine.PayloadV3, false)
|
||||
}, version, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -204,28 +219,39 @@ func (c *SimulatedBeacon) sealBlock(withdrawals []*types.Withdrawal, timestamp u
|
|||
}
|
||||
}
|
||||
|
||||
// Independently calculate the blob hashes from sidecars.
|
||||
blobHashes := make([]common.Hash, 0)
|
||||
if envelope.BlobsBundle != nil {
|
||||
hasher := sha256.New()
|
||||
for _, commit := range envelope.BlobsBundle.Commitments {
|
||||
var c kzg4844.Commitment
|
||||
if len(commit) != len(c) {
|
||||
return errors.New("invalid commitment length")
|
||||
var (
|
||||
blobHashes []common.Hash
|
||||
beaconRoot *common.Hash
|
||||
requests [][]byte
|
||||
)
|
||||
// Compute post-shanghai fields
|
||||
if version > engine.PayloadV2 {
|
||||
// Independently calculate the blob hashes from sidecars.
|
||||
blobHashes = make([]common.Hash, 0)
|
||||
if envelope.BlobsBundle != nil {
|
||||
hasher := sha256.New()
|
||||
for _, commit := range envelope.BlobsBundle.Commitments {
|
||||
var c kzg4844.Commitment
|
||||
if len(commit) != len(c) {
|
||||
return errors.New("invalid commitment length")
|
||||
}
|
||||
copy(c[:], commit)
|
||||
blobHashes = append(blobHashes, kzg4844.CalcBlobHashV1(hasher, &c))
|
||||
}
|
||||
copy(c[:], commit)
|
||||
blobHashes = append(blobHashes, kzg4844.CalcBlobHashV1(hasher, &c))
|
||||
}
|
||||
beaconRoot = &common.Hash{}
|
||||
requests = envelope.Requests
|
||||
}
|
||||
|
||||
// Mark the payload as canon
|
||||
_, err = c.engineAPI.newPayload(*payload, blobHashes, &common.Hash{}, envelope.Requests, false)
|
||||
_, err = c.engineAPI.newPayload(*payload, blobHashes, beaconRoot, requests, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.setCurrentState(payload.BlockHash, finalizedHash)
|
||||
|
||||
// Mark the block containing the payload as canonical
|
||||
if _, err = c.engineAPI.ForkchoiceUpdatedV3(c.curForkchoiceState, nil); err != nil {
|
||||
if _, err = c.engineAPI.forkchoiceUpdated(c.curForkchoiceState, nil, version, false); err != nil {
|
||||
return err
|
||||
}
|
||||
c.lastBlockTime = payload.Timestamp
|
||||
|
|
|
@ -161,11 +161,7 @@ func (t *prestateTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction
|
|||
t.lookupAccount(env.Coinbase)
|
||||
|
||||
// Add accounts with authorizations to the prestate before they get applied.
|
||||
for _, auth := range tx.SetCodeAuthorizations() {
|
||||
addr, err := auth.Authority()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, addr := range tx.SetCodeAuthorities() {
|
||||
t.lookupAccount(addr)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -461,6 +461,7 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int, skipNonceCheck, skipEoA
|
|||
BlobGasFeeCap: (*big.Int)(args.BlobFeeCap),
|
||||
BlobHashes: args.BlobHashes,
|
||||
SetCodeAuthorizations: args.AuthorizationList,
|
||||
AuthorityCache: types.ToAuthorityCache(args.AuthorizationList),
|
||||
SkipNonceChecks: skipNonceCheck,
|
||||
SkipFromEOACheck: skipEoACheck,
|
||||
}
|
||||
|
|
|
@ -477,6 +477,7 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess
|
|||
BlobHashes: tx.BlobVersionedHashes,
|
||||
BlobGasFeeCap: tx.BlobGasFeeCap,
|
||||
SetCodeAuthorizations: authList,
|
||||
AuthorityCache: types.ToAuthorityCache(authList),
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue