diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index c003c4c844e..b7e5b691f75 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -466,7 +466,11 @@ func getTransaction(txJson jsonrpc.RPCTransaction) (types.Transaction, error) { auths := make([]types.Authorization, 0) for _, auth := range *txJson.Authorizations { - auths = append(auths, auth.ToAuthorization()) + a, err := auth.ToAuthorization() + if err != nil { + return nil, err + } + auths = append(auths, a) } return &types.SetCodeTransaction{ diff --git a/core/state_transition.go b/core/state_transition.go index 61e85f09822..806c0daa23a 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -364,7 +364,7 @@ func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (*evmtype data.Reset() // 1. chainId check - if auth.ChainID != nil && !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainRules().ChainID) != 0 { + if auth.ChainID != 0 && (!rules.ChainID.IsUint64() || rules.ChainID.Uint64() != auth.ChainID) { log.Debug("invalid chainID, skipping", "chainId", auth.ChainID, "auth index", i) continue } diff --git a/core/types/authorization.go b/core/types/authorization.go index 8cb95020db0..e171e095415 100644 --- a/core/types/authorization.go +++ b/core/types/authorization.go @@ -9,23 +9,21 @@ import ( "github.com/holiman/uint256" libcommon "github.com/ledgerwatch/erigon-lib/common" - libcrypto "github.com/ledgerwatch/erigon-lib/crypto" - "github.com/ledgerwatch/erigon-lib/common/length" + libcrypto "github.com/ledgerwatch/erigon-lib/crypto" rlp2 "github.com/ledgerwatch/erigon-lib/rlp" - "github.com/ledgerwatch/erigon/common/u256" "github.com/ledgerwatch/erigon/crypto" "github.com/ledgerwatch/erigon/params" "github.com/ledgerwatch/erigon/rlp" ) type Authorization struct { - ChainID *uint256.Int `json:"chainId"` - Address libcommon.Address `json:"address"` - Nonce uint64 `json:"nonce"` - V uint256.Int `json:"v"` - R uint256.Int `json:"r"` - S uint256.Int `json:"s"` + ChainID uint64 + Address libcommon.Address + Nonce uint64 + YParity uint8 + R uint256.Int + S uint256.Int } func (ath *Authorization) copy() *Authorization { @@ -33,14 +31,14 @@ func (ath *Authorization) copy() *Authorization { ChainID: ath.ChainID, Address: ath.Address, Nonce: ath.Nonce, - V: *ath.V.Clone(), + YParity: ath.YParity, R: *ath.R.Clone(), S: *ath.S.Clone(), } } func (ath *Authorization) RecoverSigner(data *bytes.Buffer, b []byte) (*libcommon.Address, error) { - authLen := 1 + rlp.Uint256LenExcludingHead(ath.ChainID) + authLen := rlp2.U64Len(ath.ChainID) authLen += (1 + length.Addr) authLen += rlp2.U64Len(ath.Nonce) @@ -49,7 +47,7 @@ func (ath *Authorization) RecoverSigner(data *bytes.Buffer, b []byte) (*libcommo } // chainId, address, nonce - if err := ath.ChainID.EncodeRLP(data); err != nil { + if err := rlp.EncodeInt(ath.ChainID, data, b); err != nil { return nil, err } @@ -72,19 +70,12 @@ func (ath *Authorization) RecoverSigner(data *bytes.Buffer, b []byte) (*libcommo copy(sig[64-len(s):64], s) if ath.Nonce == 1<<64-1 { - return nil, errors.New("Failed assertion: auth.nonce < 2**64 - 1") - } - if _, overflow := ath.ChainID.Uint64WithOverflow(); overflow { - return nil, errors.New("Failed assertion: auth.chain_id < 2**64") - } - if ath.V.GtUint64(1 << 8) { - return nil, errors.New("Failed assertion: auth.y_parity < 2**8") + return nil, errors.New("failed assertion: auth.nonce < 2**64 - 1") } - - if ath.V.Eq(u256.Num0) || ath.V.Eq(u256.Num1) { - sig[64] = byte(ath.V.Uint64()) + if ath.YParity == 0 || ath.YParity == 1 { + sig[64] = ath.YParity } else { - return nil, fmt.Errorf("invalid v value: %d", ath.V.Uint64()) + return nil, fmt.Errorf("invalid y parity value: %d", ath.YParity) } if !libcrypto.TransactionSignatureIsValid(sig[64], &ath.R, &ath.S, false /* allowPreEip2s */) { @@ -105,11 +96,11 @@ func (ath *Authorization) RecoverSigner(data *bytes.Buffer, b []byte) (*libcommo } func authorizationSize(auth Authorization) (authLen int) { - authLen = 1 + rlp.Uint256LenExcludingHead(auth.ChainID) + authLen = rlp2.U64Len(auth.ChainID) authLen += rlp2.U64Len(auth.Nonce) authLen += (1 + length.Addr) - authLen += (1 + rlp.Uint256LenExcludingHead(&auth.V)) + (1 + rlp.Uint256LenExcludingHead(&auth.R)) + (1 + rlp.Uint256LenExcludingHead(&auth.S)) + authLen += rlp2.U64Len(uint64(auth.YParity)) + (1 + rlp.Uint256LenExcludingHead(&auth.R)) + (1 + rlp.Uint256LenExcludingHead(&auth.S)) return } @@ -134,10 +125,9 @@ func decodeAuthorizations(auths *[]Authorization, s *rlp.Stream) error { auth := Authorization{} // chainId - if b, err = s.Uint256Bytes(); err != nil { + if auth.ChainID, err = s.Uint(); err != nil { return err } - auth.ChainID = new(uint256.Int).SetBytes(b) // address if b, err = s.Bytes(); err != nil { @@ -154,11 +144,15 @@ func decodeAuthorizations(auths *[]Authorization, s *rlp.Stream) error { return err } - // v - if b, err = s.Uint256Bytes(); err != nil { + // yParity + var yParity uint64 + if yParity, err = s.Uint(); err != nil { return err } - auth.V.SetBytes(b) + if yParity >= 1<<8 { + return fmt.Errorf("authorizations: y parity it too big: %d", yParity) + } + auth.YParity = uint8(yParity) // r if b, err = s.Uint256Bytes(); err != nil { @@ -197,7 +191,7 @@ func encodeAuthorizations(authorizations []Authorization, w io.Writer, b []byte) } // 1. encode ChainId - if err := auth.ChainID.EncodeRLP(w); err != nil { + if err := rlp.EncodeInt(auth.ChainID, w, b); err != nil { return err } // 2. encode Address @@ -208,8 +202,8 @@ func encodeAuthorizations(authorizations []Authorization, w io.Writer, b []byte) if err := rlp.EncodeInt(auth.Nonce, w, b); err != nil { return err } - // 4. encode V, R, S - if err := auth.V.EncodeRLP(w); err != nil { + // 4. encode YParity, R, S + if err := rlp.EncodeInt(uint64(auth.YParity), w, b); err != nil { return err } if err := auth.R.EncodeRLP(w); err != nil { diff --git a/core/types/encdec_test.go b/core/types/encdec_test.go index 99ef2a0d9f4..f5f8d553a11 100644 --- a/core/types/encdec_test.go +++ b/core/types/encdec_test.go @@ -120,10 +120,10 @@ func (tr *TRand) RandAuthorizations(size int) []Authorization { auths := make([]Authorization, size) for i := 0; i < size; i++ { auths[i] = Authorization{ - ChainID: uint256.NewInt(*tr.RandUint64()), + ChainID: *tr.RandUint64(), Address: tr.RandAddress(), Nonce: *tr.RandUint64(), - V: *uint256.NewInt(*tr.RandUint64()), + YParity: uint8(*tr.RandUint64()), R: *uint256.NewInt(*tr.RandUint64()), S: *uint256.NewInt(*tr.RandUint64()), } diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index e119a567ec4..16065df6d87 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -51,39 +51,47 @@ type txJSON struct { } type JsonAuthorization struct { - ChainID *hexutil.Big `json:"chainId"` + ChainID hexutil.Uint64 `json:"chainId"` Address libcommon.Address `json:"address"` - Nonce uint64 `json:"nonce"` - V hexutil.Big `json:"v"` + Nonce hexutil.Uint64 `json:"nonce"` + V hexutil.Uint64 `json:"v"` R hexutil.Big `json:"r"` S hexutil.Big `json:"s"` } func (a JsonAuthorization) FromAuthorization(authorization Authorization) JsonAuthorization { - chainId := hexutil.Big(*authorization.ChainID.ToBig()) - a.ChainID = &chainId + a.ChainID = (hexutil.Uint64)(authorization.ChainID) a.Address = authorization.Address - a.Nonce = authorization.Nonce + a.Nonce = (hexutil.Uint64)(authorization.Nonce) - a.V = hexutil.Big(*authorization.V.ToBig()) + a.V = (hexutil.Uint64)(authorization.YParity) a.R = hexutil.Big(*authorization.R.ToBig()) a.S = hexutil.Big(*authorization.S.ToBig()) return a } -func (a JsonAuthorization) ToAuthorization() Authorization { - v, _ := uint256.FromBig((*big.Int)(&a.V)) - r, _ := uint256.FromBig((*big.Int)(&a.R)) - s, _ := uint256.FromBig((*big.Int)(&a.S)) - chainId, _ := uint256.FromBig((*big.Int)(a.ChainID)) - return Authorization{ - ChainID: chainId, +func (a JsonAuthorization) ToAuthorization() (Authorization, error) { + auth := Authorization{ + ChainID: a.ChainID.Uint64(), Address: a.Address, - Nonce: a.Nonce, - V: *v, - R: *r, - S: *s, + Nonce: a.Nonce.Uint64(), } + yParity := a.V.Uint64() + if yParity >= 1<<8 { + return auth, errors.New("y parity in authorization does not fit in 8 bits") + } + auth.YParity = uint8(yParity) + r, overflow := uint256.FromBig((*big.Int)(&a.R)) + if overflow { + return auth, errors.New("r in authorization does not fit in 256 bits") + } + auth.R = *r + s, overflow := uint256.FromBig((*big.Int)(&a.S)) + if overflow { + return auth, errors.New("s in authorization does not fit in 256 bits") + } + auth.S = *s + return auth, nil } func (tx *LegacyTx) MarshalJSON() ([]byte, error) { @@ -471,7 +479,11 @@ func (tx *SetCodeTransaction) UnmarshalJSON(input []byte) error { } tx.Authorizations = make([]Authorization, len(*dec.Authorizations)) for i, auth := range *dec.Authorizations { - tx.Authorizations[i] = auth.ToAuthorization() + var err error + tx.Authorizations[i], err = auth.ToAuthorization() + if err != nil { + return err + } } return nil } diff --git a/erigon-lib/types/txn.go b/erigon-lib/types/txn.go index a211892eb2c..2be8b58498a 100644 --- a/erigon-lib/types/txn.go +++ b/erigon-lib/types/txn.go @@ -323,6 +323,9 @@ func parseSignature(payload []byte, pos int, legacy bool, cfgChainId *uint256.In } } } else { + if !sig.V.LtUint64(1 << 8) { + return 0, 0, fmt.Errorf("v is too big: %s", &sig.V) + } yParity = byte(sig.V.Uint64()) } @@ -512,6 +515,10 @@ func (ctx *TxParseContext) parseTransactionBody(payload []byte, pos, p0 int, slo if err != nil { return 0, fmt.Errorf("%w: authorization chainId: %s", ErrParseTxn, err) //nolint } + if !sig.ChainID.IsUint64() { + // https://github.com/ethereum/EIPs/pull/8929 + return 0, fmt.Errorf("%w: authorization chainId is too big: %s", ErrParseTxn, &sig.ChainID) + } p2, err = rlp.StringOfLen(payload, p2, 20) // address if err != nil { return 0, fmt.Errorf("%w: authorization address: %s", ErrParseTxn, err) //nolint @@ -585,7 +592,7 @@ func (ctx *TxParseContext) parseTransactionBody(payload []byte, pos, p0 int, slo } } else { if ctx.Signature.V.GtUint64(1) { - return 0, fmt.Errorf("%w: v is loo large: %s", ErrParseTxn, &ctx.Signature.V) + return 0, fmt.Errorf("%w: v is too big: %s", ErrParseTxn, &ctx.Signature.V) } } diff --git a/erigon-lib/types/txn_test.go b/erigon-lib/types/txn_test.go index c7765f2af34..4c53263d84f 100644 --- a/erigon-lib/types/txn_test.go +++ b/erigon-lib/types/txn_test.go @@ -405,13 +405,5 @@ func TestSetCodeTxParsingWithLargeAuthorizationValues(t *testing.T) { assert.Equal(t, SetCodeTxType, txType) _, err = ctx.ParseTransaction(bodyRlx, 0, &tx, nil, false /* hasEnvelope */, false, nil) - require.NoError(t, err) - assert.Equal(t, SetCodeTxType, tx.Type) - require.Equal(t, 1, len(tx.Authorizations)) - - maxUint256 := new(uint256.Int).SetAllOne() - assert.True(t, tx.Authorizations[0].ChainID.Eq(maxUint256)) - assert.True(t, tx.Authorizations[0].V.Eq(maxUint256)) - assert.True(t, tx.Authorizations[0].R.Eq(maxUint256)) - assert.True(t, tx.Authorizations[0].S.Eq(maxUint256)) + assert.ErrorContains(t, err, "chainId is too big") } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 54b7102272d..746dd5091d0 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -86,38 +86,18 @@ type stPostState struct { } type stTransaction struct { - GasPrice *math.HexOrDecimal256 `json:"gasPrice"` - MaxFeePerGas *math.HexOrDecimal256 `json:"maxFeePerGas"` - MaxPriorityFeePerGas *math.HexOrDecimal256 `json:"maxPriorityFeePerGas"` - Nonce math.HexOrDecimal64 `json:"nonce"` - GasLimit []math.HexOrDecimal64 `json:"gasLimit"` - PrivateKey hexutility.Bytes `json:"secretKey"` - To string `json:"to"` - Data []string `json:"data"` - Value []string `json:"value"` - AccessLists []*types2.AccessList `json:"accessLists,omitempty"` - BlobGasFeeCap *math.HexOrDecimal256 `json:"maxFeePerBlobGas,omitempty"` - Authorizations []stAuthorization `json:"authorizationList,omitempty"` -} - -type stAuthorization struct { - ChainID *math.HexOrDecimal256 `json:"chainId"` - Address string `json:"address"` - Nonce *math.HexOrDecimal256 `json:"nonce"` - V *math.HexOrDecimal256 `json:"v"` - R *math.HexOrDecimal256 `json:"r"` - S *math.HexOrDecimal256 `json:"s"` -} - -func (a *stAuthorization) ToAuthorization() types.Authorization { - return types.Authorization{ - ChainID: uint256.MustFromBig((*big.Int)(a.ChainID)), - Address: libcommon.HexToAddress(a.Address), - Nonce: ((*big.Int)(a.Nonce)).Uint64(), - V: *uint256.MustFromBig((*big.Int)(a.V)), - R: *uint256.MustFromBig((*big.Int)(a.R)), - S: *uint256.MustFromBig((*big.Int)(a.S)), - } + GasPrice *math.HexOrDecimal256 `json:"gasPrice"` + MaxFeePerGas *math.HexOrDecimal256 `json:"maxFeePerGas"` + MaxPriorityFeePerGas *math.HexOrDecimal256 `json:"maxPriorityFeePerGas"` + Nonce math.HexOrDecimal64 `json:"nonce"` + GasLimit []math.HexOrDecimal64 `json:"gasLimit"` + PrivateKey hexutility.Bytes `json:"secretKey"` + To string `json:"to"` + Data []string `json:"data"` + Value []string `json:"value"` + AccessLists []*types2.AccessList `json:"accessLists,omitempty"` + BlobGasFeeCap *math.HexOrDecimal256 `json:"maxFeePerBlobGas,omitempty"` + Authorizations []types.JsonAuthorization `json:"authorizationList,omitempty"` } //go:generate gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go @@ -506,7 +486,10 @@ func toMessage(tx stTransaction, ps stPostState, baseFee *big.Int) (core.Message if len(tx.Authorizations) > 0 { authorizations := make([]types.Authorization, len(tx.Authorizations)) for i, auth := range tx.Authorizations { - authorizations[i] = auth.ToAuthorization() + authorizations[i], err = auth.ToAuthorization() + if err != nil { + return nil, err + } } msg.SetAuthorizations(authorizations) }