This commit is contained in:
Hadrien Croubois 2022-10-21 13:04:32 +02:00
parent d4d88f9bce
commit ef06b2955d
5 changed files with 137 additions and 4 deletions

View file

@ -139,6 +139,7 @@ type Message struct {
AccessList types.AccessList
BlobGasFeeCap *big.Int
BlobHashes []common.Hash
Delegate bool
// When SkipAccountChecks is true, the message nonce is not checked against the
// account nonce in state. It also disables checking that the sender is an EOA.
@ -161,6 +162,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
SkipAccountChecks: false,
BlobHashes: tx.BlobHashes(),
BlobGasFeeCap: tx.BlobGasFeeCap(),
Delegate: tx.Delegate(),
}
// If baseFee provided, set gasPrice to effectiveGasPrice.
if baseFee != nil {
@ -416,7 +418,12 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
} 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, msg.Value)
if !msg.Delegate {
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
} else {
var contract = vm.NewContract(sender, sender, nil, st.gasRemaining)
ret, st.gasRemaining, vmerr = st.evm.DelegateCall(contract, st.to(), msg.Data, st.gasRemaining)
}
}
if !rules.IsLondon {

View file

@ -66,6 +66,9 @@ func ValidateTransaction(tx *types.Transaction, blobs []kzg4844.Blob, commits []
if !opts.Config.IsCancun(head.Number, head.Time) && tx.Type() == types.BlobTxType {
return fmt.Errorf("%w: type %d rejected, pool not yet in Cancun", core.ErrTxTypeNotSupported, tx.Type())
}
if !opts.Config.IsPrague(head.Number, head.Time) && tx.Type() == types.DelegateTxType {
return fmt.Errorf("%w: type %d rejected, pool not yet in Prague", core.ErrTxTypeNotSupported, tx.Type())
}
// Check whether the init code size has been exceeded
if opts.Config.IsShanghai(head.Number, head.Time) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize)

View file

@ -194,7 +194,7 @@ func (r *Receipt) decodeTyped(b []byte) error {
return errShortTypedReceipt
}
switch b[0] {
case DynamicFeeTxType, AccessListTxType, BlobTxType:
case DynamicFeeTxType, AccessListTxType, BlobTxType, DelegateTxType:
var data receiptRLP
err := rlp.DecodeBytes(b[1:], &data)
if err != nil {
@ -302,7 +302,7 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
}
w.WriteByte(r.Type)
switch r.Type {
case AccessListTxType, DynamicFeeTxType, BlobTxType:
case AccessListTxType, DynamicFeeTxType, BlobTxType, DelegateTxType:
rlp.Encode(w, data)
default:
// For unsupported types, write nothing. Since this is for

View file

@ -46,6 +46,7 @@ const (
AccessListTxType = 0x01
DynamicFeeTxType = 0x02
BlobTxType = 0x03
DelegateTxType = 0x04
)
// Transaction is an Ethereum transaction.
@ -68,7 +69,7 @@ func NewTx(inner TxData) *Transaction {
// TxData is the underlying data of a transaction.
//
// This is implemented by DynamicFeeTx, LegacyTx and AccessListTx.
// This is implemented by DynamicFeeTx, LegacyTx, AccessListTx and DelegateTx.
type TxData interface {
txType() byte // returns the type ID
copy() TxData // creates a deep copy and initializes all fields
@ -200,6 +201,10 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
var inner BlobTx
err := rlp.DecodeBytes(b[1:], &inner)
return &inner, err
case DelegateTxType:
var inner DelegateTx
err := rlp.DecodeBytes(b[1:], &inner)
return &inner, err
default:
return nil, ErrTxTypeNotSupported
}
@ -264,6 +269,11 @@ func (tx *Transaction) Type() uint8 {
return tx.inner.txType()
}
// Delegate returns wether the transaction type corresponds to a delegate operation or not. (see EIP-5806)
func (tx *Transaction) Delegate() bool {
return tx.inner.txType() == DelegateTxType
}
// ChainId returns the EIP155 chain ID of the transaction. The return value will always be
// non-nil. For legacy transactions which are not replay-protected, the return value is
// zero.

113
core/types/tx_delegate.go Normal file
View file

@ -0,0 +1,113 @@
// Copyright 2021 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package types
import (
"math/big"
"github.com/ethereum/go-ethereum/common"
)
// DelegateTx represents an EIP-5806 transaction.
type DelegateTx struct {
ChainID *big.Int
Nonce uint64
GasTipCap *big.Int // a.k.a. maxPriorityFeePerGas
GasFeeCap *big.Int // a.k.a. maxFeePerGas
Gas uint64
To *common.Address `rlp:"nil"` // nil means contract creation
Data []byte
AccessList AccessList
// Signature values
V *big.Int `json:"v" gencodec:"required"`
R *big.Int `json:"r" gencodec:"required"`
S *big.Int `json:"s" gencodec:"required"`
}
// copy creates a deep copy of the transaction data and initializes all fields.
func (tx *DelegateTx) copy() TxData {
cpy := &DelegateTx{
Nonce: tx.Nonce,
To: copyAddressPtr(tx.To),
Data: common.CopyBytes(tx.Data),
Gas: tx.Gas,
// These are copied below.
AccessList: make(AccessList, len(tx.AccessList)),
ChainID: new(big.Int),
GasTipCap: new(big.Int),
GasFeeCap: new(big.Int),
V: new(big.Int),
R: new(big.Int),
S: new(big.Int),
}
copy(cpy.AccessList, tx.AccessList)
if tx.ChainID != nil {
cpy.ChainID.Set(tx.ChainID)
}
if tx.GasTipCap != nil {
cpy.GasTipCap.Set(tx.GasTipCap)
}
if tx.GasFeeCap != nil {
cpy.GasFeeCap.Set(tx.GasFeeCap)
}
if tx.V != nil {
cpy.V.Set(tx.V)
}
if tx.R != nil {
cpy.R.Set(tx.R)
}
if tx.S != nil {
cpy.S.Set(tx.S)
}
return cpy
}
// accessors for innerTx.
func (tx *DelegateTx) txType() byte { return DelegateTxType }
func (tx *DelegateTx) chainID() *big.Int { return tx.ChainID }
func (tx *DelegateTx) accessList() AccessList { return tx.AccessList }
func (tx *DelegateTx) data() []byte { return tx.Data }
func (tx *DelegateTx) gas() uint64 { return tx.Gas }
func (tx *DelegateTx) gasFeeCap() *big.Int { return tx.GasFeeCap }
func (tx *DelegateTx) gasTipCap() *big.Int { return tx.GasTipCap }
func (tx *DelegateTx) gasPrice() *big.Int { return tx.GasFeeCap }
func (tx *DelegateTx) value() *big.Int { return big.NewInt(0) }
func (tx *DelegateTx) nonce() uint64 { return tx.Nonce }
func (tx *DelegateTx) to() *common.Address { return tx.To }
func (tx *DelegateTx) blobGas() uint64 { return 0 }
func (tx *DelegateTx) blobGasFeeCap() *big.Int { return nil }
func (tx *DelegateTx) blobHashes() []common.Hash { return nil }
func (tx *DelegateTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
if baseFee == nil {
return dst.Set(tx.GasFeeCap)
}
tip := dst.Sub(tx.GasFeeCap, baseFee)
if tip.Cmp(tx.GasTipCap) > 0 {
tip.Set(tx.GasTipCap)
}
return tip.Add(tip, baseFee)
}
func (tx *DelegateTx) rawSignatureValues() (v, r, s *big.Int) {
return tx.V, tx.R, tx.S
}
func (tx *DelegateTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s
}