From 7a8a9fef12965e9d410aa6c2c8bad70126978e34 Mon Sep 17 00:00:00 2001 From: dustinxie Date: Wed, 11 Sep 2024 17:09:59 -0700 Subject: [PATCH] [action] add access list tx (#4391) --- action/actctx.go | 12 ++ action/envelope.go | 2 + action/evm_transaction.go | 38 ---- action/execution_test.go | 4 +- action/protocol/execution/protocol_test.go | 27 ++- .../testdata-london/datacopy-accesslist.json | 52 ++++++ .../datacopy-accesslist.json | 53 ++++++ action/tx_access_list.go | 163 ++++++++++++++++++ action/tx_access_list_test.go | 109 ++++++++++++ action/tx_legacy.go | 3 +- action/tx_legacy_test.go | 63 +++++-- 11 files changed, 459 insertions(+), 67 deletions(-) create mode 100644 action/protocol/execution/testdata-london/datacopy-accesslist.json create mode 100644 action/protocol/execution/testdata-shanghai/datacopy-accesslist.json create mode 100644 action/tx_access_list.go create mode 100644 action/tx_access_list_test.go diff --git a/action/actctx.go b/action/actctx.go index a8e0ea544e..cc881748e8 100644 --- a/action/actctx.go +++ b/action/actctx.go @@ -173,6 +173,18 @@ func (act *AbstractAction) convertToTx() TxCommonWithProto { tx.gasPrice.Set(act.gasPrice) } return &tx + case AccessListTxType: + tx := AccessListTx{ + chainID: act.chainID, + nonce: act.nonce, + gasLimit: act.gasLimit, + gasPrice: &big.Int{}, + accessList: act.accessList, + } + if act.gasPrice != nil { + tx.gasPrice.Set(act.gasPrice) + } + return &tx default: panic(fmt.Sprintf("unsupported action version = %d", act.version)) } diff --git a/action/envelope.go b/action/envelope.go index 031c05c4a6..837b280333 100644 --- a/action/envelope.go +++ b/action/envelope.go @@ -300,6 +300,8 @@ func (elp *envelope) loadProtoTxCommon(pbAct *iotextypes.ActionCore) error { switch pbAct.Version { case LegacyTxType: elp.common, err = fromProtoLegacyTx(pbAct) + case AccessListTxType: + elp.common, err = fromProtoAccessListTx(pbAct) default: panic(fmt.Sprintf("unsupported action version = %d", pbAct.Version)) } diff --git a/action/evm_transaction.go b/action/evm_transaction.go index a6e8570719..4e7c286d49 100644 --- a/action/evm_transaction.go +++ b/action/evm_transaction.go @@ -6,11 +6,8 @@ package action import ( - "encoding/hex" "math/big" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/iotexproject/iotex-proto/golang/iotextypes" ) @@ -23,41 +20,6 @@ type ( } ) -func toAccessListProto(list types.AccessList) []*iotextypes.AccessTuple { - if len(list) == 0 { - return nil - } - proto := make([]*iotextypes.AccessTuple, len(list)) - for i, v := range list { - proto[i] = &iotextypes.AccessTuple{} - proto[i].Address = hex.EncodeToString(v.Address.Bytes()) - if numKey := len(v.StorageKeys); numKey > 0 { - proto[i].StorageKeys = make([]string, numKey) - for j, key := range v.StorageKeys { - proto[i].StorageKeys[j] = hex.EncodeToString(key.Bytes()) - } - } - } - return proto -} - -func fromAccessListProto(list []*iotextypes.AccessTuple) types.AccessList { - if len(list) == 0 { - return nil - } - accessList := make(types.AccessList, len(list)) - for i, v := range list { - accessList[i].Address = common.HexToAddress(v.Address) - if numKey := len(v.StorageKeys); numKey > 0 { - accessList[i].StorageKeys = make([]common.Hash, numKey) - for j, key := range v.StorageKeys { - accessList[i].StorageKeys[j] = common.HexToHash(key) - } - } - } - return accessList -} - // EffectiveGas returns the effective gas func EffectiveGasTip(tx TxDynamicGas, baseFee *big.Int) (*big.Int, error) { tip := tx.GasTipCap() diff --git a/action/execution_test.go b/action/execution_test.go index 34158bbff7..5a057c0f7e 100644 --- a/action/execution_test.go +++ b/action/execution_test.go @@ -125,8 +125,8 @@ func TestExecutionAccessList(t *testing.T) { identityset.Address(29).String(), big.NewInt(20), []byte("test")) - elp := (&EnvelopeBuilder{}).SetNonce(1).SetGasPrice(big.NewInt(1000000)). - SetAccessList(v.list).SetGasLimit(100).SetAction(ex).Build() + elp := (&EnvelopeBuilder{}).SetVersion(AccessListTxType).SetNonce(1).SetAccessList(v.list). + SetGasPrice(big.NewInt(1000000)).SetGasLimit(100).SetAction(ex).Build() require.NoError(ex1.LoadProto(ex.Proto())) require.Equal(ex, ex1) gas, err := elp.IntrinsicGas() diff --git a/action/protocol/execution/protocol_test.go b/action/protocol/execution/protocol_test.go index 480cf1e6de..50007b33ca 100644 --- a/action/protocol/execution/protocol_test.go +++ b/action/protocol/execution/protocol_test.go @@ -274,8 +274,13 @@ func readExecution( return nil, nil, err } exec := action.NewExecution(contractAddr, ecfg.Amount(), ecfg.ByteCode()) - elp := (&action.EnvelopeBuilder{}).SetNonce(state.PendingNonce()).SetGasPrice(ecfg.GasPrice()). - SetGasLimit(ecfg.GasLimit()).SetAccessList(ecfg.AccessList()).SetAction(exec).Build() + builder := (&action.EnvelopeBuilder{}).SetGasPrice(ecfg.GasPrice()).SetGasLimit(ecfg.GasLimit()). + SetNonce(state.PendingNonce()).SetAction(exec) + if len(ecfg.AccessList()) > 0 { + println("read acl") + builder.SetVersion(action.AccessListTxType).SetAccessList(ecfg.AccessList()) + } + elp := builder.Build() addr := ecfg.PrivateKey().PublicKey().Address() if addr == nil { return nil, nil, errors.New("failed to get address") @@ -320,15 +325,15 @@ func (sct *SmartContractTest) runExecutions( ecfg.Amount(), ecfg.ByteCode(), ) - builder := &action.EnvelopeBuilder{} - builder.SetAction(exec). - SetNonce(nonce). - SetGasLimit(ecfg.GasLimit()). - SetGasPrice(ecfg.GasPrice()). - SetAccessList(ecfg.AccessList()) + builder := (&action.EnvelopeBuilder{}).SetGasLimit(ecfg.GasLimit()).SetGasPrice(ecfg.GasPrice()). + SetNonce(nonce).SetAction(exec) if sct.InitGenesis.IsShanghai { builder.SetChainID(bc.ChainID()) } + if len(ecfg.AccessList()) > 0 { + println("write acl") + builder.SetVersion(action.AccessListTxType).SetAccessList(ecfg.AccessList()) + } elp := builder.Build() selp, err := action.Sign(elp, ecfg.PrivateKey()) if err != nil { @@ -1196,6 +1201,9 @@ func TestLondonEVM(t *testing.T) { t.Run("datacopy", func(t *testing.T) { NewSmartContractTest(t, "testdata-london/datacopy.json") }) + t.Run("datacopy-with-accesslist", func(t *testing.T) { + NewSmartContractTest(t, "testdata-london/datacopy-accesslist.json") + }) t.Run("CVE-2021-39137-attack-replay", func(t *testing.T) { NewSmartContractTest(t, "testdata-london/CVE-2021-39137-attack-replay.json") }) @@ -1229,6 +1237,9 @@ func TestShanghaiEVM(t *testing.T) { t.Run("datacopy", func(t *testing.T) { NewSmartContractTest(t, "testdata-shanghai/datacopy.json") }) + t.Run("datacopy-with-accesslist", func(t *testing.T) { + NewSmartContractTest(t, "testdata-shanghai/datacopy-accesslist.json") + }) t.Run("f.value", func(t *testing.T) { NewSmartContractTest(t, "testdata-shanghai/f.value.json") }) diff --git a/action/protocol/execution/testdata-london/datacopy-accesslist.json b/action/protocol/execution/testdata-london/datacopy-accesslist.json new file mode 100644 index 0000000000..75e3ae7b59 --- /dev/null +++ b/action/protocol/execution/testdata-london/datacopy-accesslist.json @@ -0,0 +1,52 @@ +{ + "initGenesis": { + "isBering" : true, + "isIceland" : true, + "isLondon" : true + }, + "initBalances": [{ + "account": "io1mflp9m6hcgm2qcghchsdqj3z3eccrnekx9p0ms", + "rawBalance": "1000000000000000000000000000" + }], + "deployments": [{ + "rawByteCode": "608060405234801561001057600080fd5b5061026d806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063574c807814610030575b600080fd5b61003861003a565b005b604080516003808252818301909252600091602082018180368337019050509050601160f81b81600081518110610073576100736101e7565b60200101906001600160f81b031916908160001a905350602260f81b816001815181106100a2576100a26101e7565b60200101906001600160f81b031916908160001a905350603360f81b816002815181106100d1576100d16101e7565b60200101906001600160f81b031916908160001a9053508051604080516003808252818301909252600091602082018180368337019050509050600082602185018460208701600462010000fa9050826000602084013e61013182610137565b50505050565b805161014a90600090602084019061014e565b5050565b82805461015a906101fd565b90600052602060002090601f01602090048101928261017c57600085556101c2565b82601f1061019557805160ff19168380011785556101c2565b828001600101855582156101c2579182015b828111156101c25782518255916020019190600101906101a7565b506101ce9291506101d2565b5090565b5b808211156101ce57600081556001016101d3565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061021157607f821691505b60208210810361023157634e487b7160e01b600052602260045260246000fd5b5091905056fea2646970667358221220cb76f887319bd2bf08ab8098cd53e02dcf9d2c8b311ffdae7d73f2c4b7e2442264736f6c634300080e0033", + "rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1", + "rawAmount": "0", + "rawGasLimit": 5000000, + "rawGasPrice": "0", + "rawExpectedGasConsumed": 199671, + "expectedStatus": 1, + "expectedBalances": [], + "comment": "deploy datacopy contract" + }], + "executions": [{ + "rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1", + "rawByteCode": "574c8078", + "rawAmount": "0", + "rawGasLimit": 1000000, + "rawGasPrice": "0", + "rawAccessList": [ + { + "address": "0x1234567890abcdef1234567890abcdef12345678", + "storageKeys": [ + "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef", + "0x1234567890123456789012345678901234567890123456789012345678901234" + ] + }, + { + "address": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef", + "storageKeys": [ + "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef" + ] + } + ], + "rawExpectedGasConsumed": 44220, + "expectedStatus": 1, + "comment": "the data of return is [0x11, 0x22, 0x33]", + "expectedBlockInfos" : { + "txRootHash" : "31da3e807a653dd42dc74d6d5a3dde2239b4c41859de6c65e044376a1020f9ce", + "stateRootHash" : "3595fffd9f80f99887e3108d84f3558e2691ab9dc1c73f6279e3da5735d02afa", + "receiptRootHash" : "6f9c949c391a25e324555d1592924d49d91d8883d8511f8db45fbae8b0bcde99" + } + }] +} diff --git a/action/protocol/execution/testdata-shanghai/datacopy-accesslist.json b/action/protocol/execution/testdata-shanghai/datacopy-accesslist.json new file mode 100644 index 0000000000..2759b93cf4 --- /dev/null +++ b/action/protocol/execution/testdata-shanghai/datacopy-accesslist.json @@ -0,0 +1,53 @@ +{ + "initGenesis": { + "isBering" : true, + "isIceland" : true, + "isLondon" : true, + "isShanghai" : true + }, + "initBalances": [{ + "account": "io1mflp9m6hcgm2qcghchsdqj3z3eccrnekx9p0ms", + "rawBalance": "1000000000000000000000000000" + }], + "deployments": [{ + "rawByteCode": "608060405234801561001057600080fd5b5061026d806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063574c807814610030575b600080fd5b61003861003a565b005b604080516003808252818301909252600091602082018180368337019050509050601160f81b81600081518110610073576100736101e7565b60200101906001600160f81b031916908160001a905350602260f81b816001815181106100a2576100a26101e7565b60200101906001600160f81b031916908160001a905350603360f81b816002815181106100d1576100d16101e7565b60200101906001600160f81b031916908160001a9053508051604080516003808252818301909252600091602082018180368337019050509050600082602185018460208701600462010000fa9050826000602084013e61013182610137565b50505050565b805161014a90600090602084019061014e565b5050565b82805461015a906101fd565b90600052602060002090601f01602090048101928261017c57600085556101c2565b82601f1061019557805160ff19168380011785556101c2565b828001600101855582156101c2579182015b828111156101c25782518255916020019190600101906101a7565b506101ce9291506101d2565b5090565b5b808211156101ce57600081556001016101d3565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168061021157607f821691505b60208210810361023157634e487b7160e01b600052602260045260246000fd5b5091905056fea2646970667358221220cb76f887319bd2bf08ab8098cd53e02dcf9d2c8b311ffdae7d73f2c4b7e2442264736f6c634300080e0033", + "rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1", + "rawAmount": "0", + "rawGasLimit": 5000000, + "rawGasPrice": "0", + "rawExpectedGasConsumed": 199671, + "expectedStatus": 1, + "expectedBalances": [], + "comment": "deploy datacopy contract" + }], + "executions": [{ + "rawPrivateKey": "cfa6ef757dee2e50351620dca002d32b9c090cfda55fb81f37f1d26b273743f1", + "rawByteCode": "574c8078", + "rawAmount": "0", + "rawGasLimit": 1000000, + "rawGasPrice": "0", + "rawAccessList": [ + { + "address": "0x1234567890abcdef1234567890abcdef12345678", + "storageKeys": [ + "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef", + "0x1234567890123456789012345678901234567890123456789012345678901234" + ] + }, + { + "address": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdef", + "storageKeys": [ + "0xabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef" + ] + } + ], + "rawExpectedGasConsumed": 44220, + "expectedStatus": 1, + "comment": "the data of return is [0x11, 0x22, 0x33]", + "expectedBlockInfos" : { + "txRootHash" : "6a61ad22579c0548af74a0c8ae6239b3950df05a6e69f758f566cb85111275fd", + "stateRootHash" : "3595fffd9f80f99887e3108d84f3558e2691ab9dc1c73f6279e3da5735d02afa", + "receiptRootHash" : "03b68bde2535bd4a933bea0a861d1756e31e7cda47be9bb1d126277d4c8c4c3f" + } + }] +} diff --git a/action/tx_access_list.go b/action/tx_access_list.go new file mode 100644 index 0000000000..5c171bebd6 --- /dev/null +++ b/action/tx_access_list.go @@ -0,0 +1,163 @@ +// Copyright (c) 2024 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package action + +import ( + "encoding/hex" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/pkg/errors" +) + +// AccessListTx represents EIP-2930 access list transaction +type AccessListTx struct { + chainID uint32 + nonce uint64 + gasLimit uint64 + gasPrice *big.Int + accessList types.AccessList +} + +func (tx *AccessListTx) Version() uint32 { + return AccessListTxType +} + +func (tx *AccessListTx) ChainID() uint32 { + return tx.chainID +} + +func (tx *AccessListTx) Nonce() uint64 { + return tx.nonce +} + +func (tx *AccessListTx) Gas() uint64 { + return tx.gasLimit +} + +func (tx *AccessListTx) GasPrice() *big.Int { + return tx.price() +} + +func (tx *AccessListTx) price() *big.Int { + p := &big.Int{} + if tx.gasPrice == nil { + return p + } + return p.Set(tx.gasPrice) +} + +func (tx *AccessListTx) AccessList() types.AccessList { + return tx.accessList +} + +func (tx *AccessListTx) GasTipCap() *big.Int { + return tx.price() +} + +func (tx *AccessListTx) GasFeeCap() *big.Int { + return tx.price() +} + +func (tx *AccessListTx) BlobGas() uint64 { return 0 } + +func (tx *AccessListTx) BlobGasFeeCap() *big.Int { return nil } + +func (tx *AccessListTx) BlobHashes() []common.Hash { return nil } + +func (tx *AccessListTx) BlobTxSidecar() *types.BlobTxSidecar { return nil } + +func (tx *AccessListTx) SanityCheck() error { + // Reject execution of negative gas price + if tx.gasPrice != nil && tx.gasPrice.Sign() < 0 { + return ErrNegativeValue + } + return nil +} + +func (tx *AccessListTx) toProto() *iotextypes.ActionCore { + actCore := iotextypes.ActionCore{ + Version: AccessListTxType, + Nonce: tx.nonce, + GasLimit: tx.gasLimit, + ChainID: tx.chainID, + } + if tx.gasPrice != nil { + actCore.GasPrice = tx.gasPrice.String() + } + if len(tx.accessList) > 0 { + actCore.AccessList = toAccessListProto(tx.accessList) + } + return &actCore +} + +func toAccessListProto(list types.AccessList) []*iotextypes.AccessTuple { + if len(list) == 0 { + return nil + } + proto := make([]*iotextypes.AccessTuple, len(list)) + for i, v := range list { + proto[i] = &iotextypes.AccessTuple{} + proto[i].Address = hex.EncodeToString(v.Address.Bytes()) + if numKey := len(v.StorageKeys); numKey > 0 { + proto[i].StorageKeys = make([]string, numKey) + for j, key := range v.StorageKeys { + proto[i].StorageKeys[j] = hex.EncodeToString(key.Bytes()) + } + } + } + return proto +} + +func fromAccessListProto(list []*iotextypes.AccessTuple) types.AccessList { + if len(list) == 0 { + return nil + } + accessList := make(types.AccessList, len(list)) + for i, v := range list { + accessList[i].Address = common.HexToAddress(v.Address) + if numKey := len(v.StorageKeys); numKey > 0 { + accessList[i].StorageKeys = make([]common.Hash, numKey) + for j, key := range v.StorageKeys { + accessList[i].StorageKeys[j] = common.HexToHash(key) + } + } + } + return accessList +} + +func fromProtoAccessListTx(pb *iotextypes.ActionCore) (*AccessListTx, error) { + var tx AccessListTx + tx.nonce = pb.GetNonce() + tx.gasLimit = pb.GetGasLimit() + tx.chainID = pb.GetChainID() + tx.gasPrice = &big.Int{} + + if price := pb.GetGasPrice(); len(price) > 0 { + var ok bool + if tx.gasPrice, ok = tx.gasPrice.SetString(price, 10); !ok { + return nil, errors.Errorf("invalid gasPrice %s", price) + } + } + if acl := pb.GetAccessList(); len(acl) > 0 { + tx.accessList = fromAccessListProto(acl) + } + return &tx, nil +} + +func (tx *AccessListTx) setNonce(n uint64) { + tx.nonce = n +} + +func (tx *AccessListTx) setGas(gas uint64) { + tx.gasLimit = gas +} + +func (tx *AccessListTx) setChainID(n uint32) { + tx.chainID = n +} diff --git a/action/tx_access_list_test.go b/action/tx_access_list_test.go new file mode 100644 index 0000000000..3a1ffe92a5 --- /dev/null +++ b/action/tx_access_list_test.go @@ -0,0 +1,109 @@ +// Copyright (c) 2024 IoTeX Foundation +// This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability +// or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. +// This source code is governed by Apache License 2.0 that can be found in the LICENSE file. + +package action + +import ( + "encoding/hex" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/iotexproject/iotex-proto/golang/iotextypes" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + + . "github.com/iotexproject/iotex-core/pkg/util/assertions" +) + +func TestAccessListTx(t *testing.T) { + r := require.New(t) + t.Run("proto", func(t *testing.T) { + tx := &AccessListTx{ + chainID: 3, + nonce: 8, + gasLimit: 1001, + gasPrice: big.NewInt(13), + accessList: types.AccessList{ + {Address: common.Address{}, StorageKeys: nil}, + {Address: _c1, StorageKeys: []common.Hash{_k1, {}, _k3}}, + {Address: _c2, StorageKeys: []common.Hash{_k2, _k3, _k4, _k1}}, + }, + } + r.EqualValues(AccessListTxType, tx.Version()) + r.EqualValues(8, tx.Nonce()) + r.EqualValues(1001, tx.Gas()) + r.Equal(big.NewInt(13), tx.GasPrice()) + r.Equal(big.NewInt(13), tx.GasTipCap()) + r.Equal(big.NewInt(13), tx.GasFeeCap()) + r.Equal(3, len(tx.AccessList())) + r.Zero(tx.BlobGas()) + r.Nil(tx.BlobGasFeeCap()) + r.Nil(tx.BlobHashes()) + r.Nil(tx.BlobTxSidecar()) + b := MustNoErrorV(proto.Marshal(tx.toProto())) + r.Equal("0802100818e9072202313328034a2a0a28303030303030303030303030303030303030303030303030303030303030303030303030303030304af0010a28303166633234363633333437306366363261653261393536643231653864343831633361363965311240303265393430646430666435623564663463666238643662636439633734656334333365396135633231616362373263626362356265396537313162363738661240303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030301240613631386561356234383965636134326633333161626362303833393466353831663265396461383963386565376537326337343732303438343261626538624ab2020a2833343730636636326165326139353664333864343831633361363965313231653031666332343636124065373730396161376161313631323436363734393139623266303239396539356362623663353438326535633334386431326466653232366637316636336436124061363138656135623438396563613432663333316162636230383339346635383166326539646138396338656537653732633734373230343834326162653862124038383164336264663265313362366538623664363835643232373761343866663337313431343935646464346533643732383966636661353537306632396631124030326539343064643066643562356466346366623864366263643963373465633433336539613563323161636237326362636235626539653731316236373866", hex.EncodeToString(b)) + pb := iotextypes.ActionCore{} + r.NoError(proto.Unmarshal(b, &pb)) + r.Equal(tx, MustNoErrorV(fromProtoAccessListTx(&pb))) + }) + ab := AbstractAction{ + version: AccessListTxType, + chainID: 3, + nonce: 8, + gasLimit: 1001, + gasTipCap: big.NewInt(10), + gasFeeCap: big.NewInt(30), + accessList: types.AccessList{ + {Address: common.Address{}, StorageKeys: nil}, + {Address: _c1, StorageKeys: []common.Hash{_k1, {}, _k3}}, + {Address: _c2, StorageKeys: []common.Hash{_k2, _k3, _k4, _k1}}, + }, + } + expect := &AccessListTx{ + chainID: 3, + nonce: 8, + gasLimit: 1001, + accessList: types.AccessList{ + {Address: common.Address{}, StorageKeys: nil}, + {Address: _c1, StorageKeys: []common.Hash{_k1, {}, _k3}}, + {Address: _c2, StorageKeys: []common.Hash{_k2, _k3, _k4, _k1}}, + }, + } + t.Run("convert", func(t *testing.T) { + for _, price := range []*big.Int{ + nil, big.NewInt(13), + } { + ab.gasPrice = price + tx := ab.convertToTx() + acl, ok := tx.(*AccessListTx) + r.True(ok) + if price == nil { + expect.gasPrice = new(big.Int) + } else { + expect.gasPrice = new(big.Int).Set(price) + } + r.EqualValues(AccessListTxType, acl.Version()) + r.Equal(expect, acl) + } + }) + t.Run("loadProtoTxCommon", func(t *testing.T) { + for _, price := range []*big.Int{ + nil, big.NewInt(13), + } { + expect.gasPrice = price + elp := envelope{} + r.NoError(elp.loadProtoTxCommon(expect.toProto())) + acl, ok := elp.common.(*AccessListTx) + r.True(ok) + r.EqualValues(AccessListTxType, acl.Version()) + if price == nil { + expect.gasPrice = new(big.Int) + } + r.Equal(expect, acl) + } + }) +} diff --git a/action/tx_legacy.go b/action/tx_legacy.go index ee3105190c..e2a22b1959 100644 --- a/action/tx_legacy.go +++ b/action/tx_legacy.go @@ -14,6 +14,7 @@ import ( "github.com/pkg/errors" ) +// LegacyTx is the legacy transaction type LegacyTx struct { chainID uint32 nonce uint64 @@ -79,7 +80,7 @@ func (tx *LegacyTx) SanityCheck() error { func (tx *LegacyTx) toProto() *iotextypes.ActionCore { actCore := iotextypes.ActionCore{ - Version: 1, + Version: LegacyTxType, Nonce: tx.nonce, GasLimit: tx.gasLimit, ChainID: tx.chainID, diff --git a/action/tx_legacy_test.go b/action/tx_legacy_test.go index 07fa1fc0a7..02e70f81d4 100644 --- a/action/tx_legacy_test.go +++ b/action/tx_legacy_test.go @@ -28,31 +28,42 @@ func TestLegacyTx(t *testing.T) { gasLimit: 1001, gasPrice: big.NewInt(13), } + r.EqualValues(LegacyTxType, tx.Version()) + r.EqualValues(8, tx.Nonce()) + r.EqualValues(1001, tx.Gas()) + r.Equal(big.NewInt(13), tx.GasPrice()) + r.Equal(big.NewInt(13), tx.GasTipCap()) + r.Equal(big.NewInt(13), tx.GasFeeCap()) + r.Nil(tx.AccessList()) + r.Zero(tx.BlobGas()) + r.Nil(tx.BlobGasFeeCap()) + r.Nil(tx.BlobHashes()) + r.Nil(tx.BlobTxSidecar()) b := MustNoErrorV(proto.Marshal(tx.toProto())) r.Equal("0801100818e907220231332803", hex.EncodeToString(b)) pb := iotextypes.ActionCore{} r.NoError(proto.Unmarshal(b, &pb)) r.Equal(tx, MustNoErrorV(fromProtoLegacyTx(&pb))) }) + ab := AbstractAction{ + version: LegacyTxType, + chainID: 3, + nonce: 8, + gasLimit: 1001, + gasTipCap: big.NewInt(10), + gasFeeCap: big.NewInt(30), + accessList: types.AccessList{ + {Address: common.Address{}, StorageKeys: nil}, + {Address: _c1, StorageKeys: []common.Hash{_k1, {}, _k3}}, + {Address: _c2, StorageKeys: []common.Hash{_k2, _k3, _k4, _k1}}, + }, + } + expect := &LegacyTx{ + chainID: 3, + nonce: 8, + gasLimit: 1001, + } t.Run("convert", func(t *testing.T) { - ab := AbstractAction{ - version: LegacyTxType, - chainID: 3, - nonce: 8, - gasLimit: 1001, - gasTipCap: big.NewInt(10), - gasFeeCap: big.NewInt(30), - accessList: types.AccessList{ - {Address: common.Address{}, StorageKeys: nil}, - {Address: _c1, StorageKeys: []common.Hash{_k1, {}, _k3}}, - {Address: _c2, StorageKeys: []common.Hash{_k2, _k3, _k4, _k1}}, - }, - } - expect := &LegacyTx{ - chainID: 3, - nonce: 8, - gasLimit: 1001, - } for _, price := range []*big.Int{ nil, big.NewInt(13), } { @@ -69,4 +80,20 @@ func TestLegacyTx(t *testing.T) { r.Equal(expect, legacy) } }) + t.Run("loadProtoTxCommon", func(t *testing.T) { + for _, price := range []*big.Int{ + nil, big.NewInt(13), + } { + expect.gasPrice = price + elp := envelope{} + r.NoError(elp.loadProtoTxCommon(expect.toProto())) + legacy, ok := elp.common.(*LegacyTx) + r.True(ok) + r.EqualValues(LegacyTxType, legacy.Version()) + if price == nil { + expect.gasPrice = new(big.Int) + } + r.Equal(expect, legacy) + } + }) }