From 75fd756a258e015bf49234c715ee0e29b6283d95 Mon Sep 17 00:00:00 2001 From: Alex Forshtat Date: Tue, 30 Apr 2024 15:14:21 +0200 Subject: [PATCH] Remove code related to EOA-based RIP-7560 transactions --- core/state_processor_rip7560.go | 114 ++++------------------ core/types/transaction.go | 2 + core/types/transaction_signing.go | 2 + core/types/transaction_signing_rip7560.go | 47 +++++++++ internal/ethapi/transaction_args.go | 39 ++++++++ params/config.go | 8 ++ 6 files changed, 116 insertions(+), 96 deletions(-) create mode 100644 core/types/transaction_signing_rip7560.go diff --git a/core/state_processor_rip7560.go b/core/state_processor_rip7560.go index c0c3d9f7ae..b5d55ef716 100644 --- a/core/state_processor_rip7560.go +++ b/core/state_processor_rip7560.go @@ -27,7 +27,6 @@ type ValidationPhaseResult struct { SenderValidUntil uint64 PmValidAfter uint64 PmValidUntil uint64 - IsEOA bool } // HandleRip7560Transactions apply state changes of all sequential RIP-7560 transactions and return @@ -38,22 +37,13 @@ func HandleRip7560Transactions(transactions []*types.Transaction, index int, sta receipts := make([]*types.Receipt, 0) allLogs := make([]*types.Log, 0) - i := index - for { - if i >= len(transactions) { - break - } - if transactions[i].Type() != types.Rip7560Type { - break - } - iTransactions, iReceipts, iLogs, err := handleRip7560Transactions(transactions, index, statedb, coinbase, header, gp, chainConfig, bc, cfg) - if err != nil { - return nil, nil, nil, err - } - validatedTransactions = append(validatedTransactions, iTransactions...) - receipts = append(receipts, iReceipts...) - allLogs = append(allLogs, iLogs...) + iTransactions, iReceipts, iLogs, err := handleRip7560Transactions(transactions, index, statedb, coinbase, header, gp, chainConfig, bc, cfg) + if err != nil { + return nil, nil, nil, err } + validatedTransactions = append(validatedTransactions, iTransactions...) + receipts = append(receipts, iReceipts...) + allLogs = append(allLogs, iLogs...) return validatedTransactions, receipts, allLogs, nil } @@ -62,47 +52,31 @@ func handleRip7560Transactions(transactions []*types.Transaction, index int, sta validatedTransactions := make([]*types.Transaction, 0) receipts := make([]*types.Receipt, 0) allLogs := make([]*types.Log, 0) - signer := types.MakeSigner(chainConfig, header.Number, header.Time) for i, tx := range transactions[index:] { if tx.Type() != types.Rip7560Type { break } aatx := tx.Rip7560TransactionData() - isEoa, err := isTransactionEOA(tx, statedb, signer) + statedb.SetTxContext(tx.Hash(), index+i) + err := BuyGasRip7560Transaction(aatx, statedb) + var vpr *ValidationPhaseResult if err != nil { return nil, nil, nil, err } - statedb.SetTxContext(tx.Hash(), index+i) - err = BuyGasRip7560Transaction(aatx, statedb) - var vpr *ValidationPhaseResult - if isEoa { - blockContext := NewEVMBlockContext(header, bc, coinbase) - tmpMsg, err := TransactionToMessage(tx, signer, header.BaseFee) - txContext := NewEVMTxContext(tmpMsg) - evm := vm.NewEVM(blockContext, txContext, statedb, chainConfig, cfg) - //signer := types.MakeSigner(chainConfig, header.Number, header.Time) - signingHash := signer.Hash(tx) - vpr, err = validateRip7560TransactionFromEOA(tx, signingHash, statedb, evm, coinbase, header, gp, chainConfig) - if err != nil { - return nil, nil, nil, err - } - } else { - if err != nil { - return nil, nil, nil, err - } - vpr, err = ApplyRip7560ValidationPhases(chainConfig, bc, coinbase, gp, statedb, header, tx, cfg) - if err != nil { - return nil, nil, nil, err - } + vpr, err = ApplyRip7560ValidationPhases(chainConfig, bc, coinbase, gp, statedb, header, tx, cfg) + if err != nil { + return nil, nil, nil, err } validationPhaseResults = append(validationPhaseResults, vpr) validatedTransactions = append(validatedTransactions, tx) - } - for i, vpr := range validationPhaseResults { + + // This is the line separating the Validation and Execution phases + // It should be separated to implement the mempool-friendly AA RIP (number not assigned yet) + // for i, vpr := range validationPhaseResults // TODO: this will miss all validation phase events - pass in 'vpr' - statedb.SetTxContext(vpr.Tx.Hash(), i) + // statedb.SetTxContext(vpr.Tx.Hash(), i) receipt, err := ApplyRip7560ExecutionPhase(chainConfig, vpr, bc, coinbase, gp, statedb, header, cfg) @@ -139,49 +113,6 @@ func BuyGasRip7560Transaction(st *types.Rip7560AccountAbstractionTx, state vm.St return nil } -// TODO: not needed with subtype - only use to validate transaction, maybe -func isTransactionEOA(tx *types.Transaction, statedb *state.StateDB, signer types.Signer) (bool, error) { - aatx := tx.Rip7560TransactionData() - senderHasCode := statedb.GetCodeSize(*aatx.Sender) != 0 || len(aatx.DeployerData) != 0 - if senderHasCode { - return false, nil - } - address, err := signer.Sender(tx) - if err != nil { - return false, err - } - if address.Cmp(*tx.Rip7560TransactionData().Sender) != 0 { - return false, errors.New("recovered signature does not match the claimed EOA sender") - } - return true, nil -} - -func validateRip7560TransactionFromEOA(tx *types.Transaction, signingHash common.Hash, statedb *state.StateDB, evm *vm.EVM, coinbase *common.Address, header *types.Header, gp *GasPool, chainConfig *params.ChainConfig) (*ValidationPhaseResult, error) { - // TODO: paymaste is actually optional for eoa-type-4 -> check paymaster data len() - paymasterContext, pmValidationUsedGas, pmValidAfter, pmValidUntil, err := applyPaymasterValidationFrame(tx, chainConfig, signingHash, evm, gp, statedb, header) - if err != nil { - return nil, err - } - err = validateValidityTimeRange(header.Time, pmValidAfter, pmValidUntil) - if err != nil { - return nil, err - } - vpr := &ValidationPhaseResult{ - Tx: tx, - TxHash: tx.Hash(), - PaymasterContext: paymasterContext, - DeploymentUsedGas: 0, - ValidationUsedGas: 0, - PmValidationUsedGas: pmValidationUsedGas, - SenderValidAfter: 0, - SenderValidUntil: 0, - PmValidAfter: pmValidAfter, - PmValidUntil: pmValidUntil, - IsEOA: true, - } - return vpr, nil -} - func ApplyRip7560FrameMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) { return NewRip7560StateTransition(evm, msg, gp).TransitionDb() } @@ -311,7 +242,6 @@ func ApplyRip7560ValidationPhases(chainConfig *params.ChainConfig, bc ChainConte SenderValidUntil: validUntil, PmValidAfter: pmValidAfter, PmValidUntil: pmValidUntil, - IsEOA: false, } return vpr, nil @@ -373,15 +303,7 @@ func ApplyRip7560ExecutionPhase(config *params.ChainConfig, vpr *ValidationPhase txContext.Origin = *vpr.Tx.Rip7560TransactionData().Sender evm := vm.NewEVM(blockContext, txContext, statedb, config, cfg) - var accountExecutionMsg *Message - if vpr.IsEOA { - accountExecutionMsg, err = prepareEOATargetExecutionMessage(vpr.Tx) - if err != nil { - return nil, err - } - } else { - accountExecutionMsg = prepareAccountExecutionMessage(vpr.Tx, evm.ChainConfig()) - } + accountExecutionMsg := prepareAccountExecutionMessage(vpr.Tx, evm.ChainConfig()) executionResult, err := ApplyRip7560FrameMessage(evm, accountExecutionMsg, gp) if err != nil { return nil, err diff --git a/core/types/transaction.go b/core/types/transaction.go index e8b389d8e6..996fee8e76 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -207,6 +207,8 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { inner = new(DynamicFeeTx) case BlobTxType: inner = new(BlobTx) + case Rip7560Type: + inner = new(Rip7560AccountAbstractionTx) default: return nil, ErrTxTypeNotSupported } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 6e5f6712f8..eed9e35c99 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -40,6 +40,8 @@ type sigCache struct { func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer { var signer Signer switch { + case config.IsRIP7560(blockNumber): + signer = NewRIP7560Signer(config.ChainID) case config.IsCancun(blockNumber, blockTime): signer = NewCancunSigner(config.ChainID) case config.IsLondon(blockNumber): diff --git a/core/types/transaction_signing_rip7560.go b/core/types/transaction_signing_rip7560.go new file mode 100644 index 0000000000..32fd2c1681 --- /dev/null +++ b/core/types/transaction_signing_rip7560.go @@ -0,0 +1,47 @@ +package types + +import ( + "github.com/ethereum/go-ethereum/common" + "math/big" +) + +type rip7560Signer struct{ londonSigner } + +func NewRIP7560Signer(chainId *big.Int) Signer { + return rip7560Signer{londonSigner{eip2930Signer{NewEIP155Signer(chainId)}}} +} + +func (s rip7560Signer) Sender(tx *Transaction) (common.Address, error) { + if tx.Type() != Rip7560Type { + return s.londonSigner.Sender(tx) + } + return [20]byte{}, nil +} + +// Hash returns the hash to be signed by the sender. +// It does not uniquely identify the transaction. +func (s rip7560Signer) Hash(tx *Transaction) common.Hash { + if tx.Type() != Rip7560Type { + return s.londonSigner.Hash(tx) + } + aatx := tx.Rip7560TransactionData() + return prefixedRlpHash( + tx.Type(), + []interface{}{ + s.chainId, + tx.GasTipCap(), + tx.GasFeeCap(), + tx.Gas(), + //tx.To(), + tx.Data(), + tx.AccessList(), + + aatx.Sender, + aatx.PaymasterData, + aatx.DeployerData, + aatx.BuilderFee, + aatx.ValidationGas, + aatx.PaymasterGas, + aatx.BigNonce, + }) +} diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index f199f9d912..e6b7cd13b9 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -74,6 +74,17 @@ type TransactionArgs struct { // This configures whether blobs are allowed to be passed. blobSidecarAllowed bool + + // Introduced by RIP-7560 Transaction + Subtype *hexutil.Uint64 + Sender *common.Address `json:"sender"` + Signature *hexutil.Bytes + PaymasterData *hexutil.Bytes `json:"paymasterData"` + DeployerData *hexutil.Bytes + BuilderFee *hexutil.Big + ValidationGas *hexutil.Uint64 + PaymasterGas *hexutil.Uint64 + BigNonce *hexutil.Big // AA nonce is 256 bits wide } // from retrieves the transaction sender address. @@ -472,6 +483,34 @@ func (args *TransactionArgs) ToMessage(baseFee *big.Int) *core.Message { func (args *TransactionArgs) ToTransaction() *types.Transaction { var data types.TxData switch { + case args.Sender != nil: + al := types.AccessList{} + if args.AccessList != nil { + al = *args.AccessList + } + aatx := types.Rip7560AccountAbstractionTx{ + Subtype: byte(*args.Subtype), + To: &common.Address{}, + ChainID: (*big.Int)(args.ChainID), + Gas: uint64(*args.Gas), + GasFeeCap: (*big.Int)(args.MaxFeePerGas), + GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas), + Value: (*big.Int)(args.Value), + Data: args.data(), + AccessList: al, + // RIP-7560 parameters + Sender: args.Sender, + Signature: *args.Signature, + PaymasterData: *args.PaymasterData, + DeployerData: *args.DeployerData, + BuilderFee: (*big.Int)(args.BuilderFee), + ValidationGas: uint64(*args.ValidationGas), + PaymasterGas: uint64(*args.PaymasterGas), + BigNonce: (*big.Int)(args.BigNonce), + } + data = &aatx + hash := types.NewTx(data).Hash() + log.Error("RIP-7560 transaction created", "sender", aatx.Sender.Hex(), "hash", hash) case args.BlobHashes != nil: al := types.AccessList{} if args.AccessList != nil { diff --git a/params/config.go b/params/config.go index 9d9fc242bc..eeb666eb77 100644 --- a/params/config.go +++ b/params/config.go @@ -173,6 +173,7 @@ var ( EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), + RIP7560Block: big.NewInt(0), ByzantiumBlock: big.NewInt(0), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), @@ -336,6 +337,8 @@ type ChainConfig struct { EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block + RIP7560Block *big.Int `json:"rip7560block,omitempty"` // RIP7560 HF block + ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated) PetersburgBlock *big.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople) @@ -586,6 +589,11 @@ func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) } +// IsRIP7560 returns whether num is either equal to the RIP7560 fork block or greater. +func (c *ChainConfig) IsRIP7560(num *big.Int) bool { + return isBlockForked(c.RIP7560Block, num) +} + // CheckCompatible checks whether scheduled fork transitions have been imported // with a mismatching chain configuration. func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64, time uint64) *ConfigCompatError {