Skip to content

Commit db8a08c

Browse files
cloudgrayaljo242
andauthored
test(x/vm): add unit test cases for EIP-7702 (#684)
* test(eip7702): add unit test case with ApplyMessageWithConfig * test(eip-7702): add unit test case for EthereumTx * test(eip7702): add failure case * chore: update CHANGELOG.md * chore: modify comment --------- Co-authored-by: Alex | Cosmos Labs <[email protected]>
1 parent fcfdff7 commit db8a08c

File tree

5 files changed

+204
-12
lines changed

5 files changed

+204
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
- [\#648](https://github.com/cosmos/evm/pull/648) Move all `ante` logic such as `NewAnteHandler` from the `evmd` package to `evm/ante` so it can be used as library functions.
4545
- [\#659](https://github.com/cosmos/evm/pull/659) Move configs out of EVMD and deduplicate configs
4646
- [\#664](https://github.com/cosmos/evm/pull/664) Add EIP-7702 integration test
47+
- [\#684](https://github.com/cosmos/evm/pull/684) Add unit test cases for EIP-7702
4748

4849
### FEATURES
4950

tests/integration/x/vm/test_msg_server.go

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@ package vm
33
import (
44
"math/big"
55

6+
ethtypes "github.com/ethereum/go-ethereum/core/types"
7+
"github.com/holiman/uint256"
8+
69
"github.com/cosmos/evm/testutil/integration/evm/utils"
710
"github.com/cosmos/evm/x/vm/types"
811

12+
sdkmath "cosmossdk.io/math"
13+
914
sdktypes "github.com/cosmos/cosmos-sdk/types"
1015
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
1116
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
@@ -27,10 +32,11 @@ func (s *KeeperTestSuite) TestEthereumTx() {
2732
name string
2833
getMsg func() *types.MsgEthereumTx
2934
expectedErr error
35+
postCheck func()
3036
}{
3137
{
32-
"success - transfer funds tx",
33-
func() *types.MsgEthereumTx {
38+
name: "success - transfer funds tx",
39+
getMsg: func() *types.MsgEthereumTx {
3440
recipient := s.Keyring.GetAddr(1)
3541
args := types.EvmTxArgs{
3642
To: &recipient,
@@ -40,12 +46,90 @@ func (s *KeeperTestSuite) TestEthereumTx() {
4046
s.Require().NoError(err)
4147
return tx.GetMsgs()[0].(*types.MsgEthereumTx)
4248
},
43-
nil,
49+
expectedErr: nil,
50+
postCheck: nil,
51+
},
52+
{
53+
name: "success - set code authorization tx (EIP-7702)",
54+
getMsg: func() *types.MsgEthereumTx {
55+
authority := s.Keyring.GetKey(0)
56+
target := s.Keyring.GetAddr(1)
57+
58+
accResp, err := s.Handler.GetEvmAccount(authority.Addr)
59+
s.Require().NoError(err)
60+
61+
auth := ethtypes.SetCodeAuthorization{
62+
ChainID: *uint256.NewInt(types.GetChainConfig().GetChainId()),
63+
Address: target,
64+
Nonce: accResp.GetNonce(),
65+
}
66+
signedAuth := s.SignSetCodeAuthorization(authority, auth)
67+
68+
args := types.EvmTxArgs{
69+
To: &target,
70+
AuthorizationList: []ethtypes.SetCodeAuthorization{signedAuth},
71+
}
72+
tx, err := s.Factory.GenerateSignedEthTx(s.Keyring.GetPrivKey(0), args)
73+
s.Require().NoError(err)
74+
return tx.GetMsgs()[0].(*types.MsgEthereumTx)
75+
},
76+
expectedErr: nil,
77+
postCheck: func() {
78+
authorityAddr := s.Keyring.GetAddr(0)
79+
targetAddr := s.Keyring.GetAddr(1)
80+
codeHash := s.Network.App.GetEVMKeeper().GetCodeHash(s.Network.GetContext(), authorityAddr)
81+
code := s.Network.App.GetEVMKeeper().GetCode(s.Network.GetContext(), codeHash)
82+
delegationAddr, ok := ethtypes.ParseDelegation(code)
83+
s.Require().True(ok)
84+
s.Require().Equal(targetAddr, delegationAddr)
85+
},
86+
},
87+
{
88+
name: "fail - unsigned set code authorization",
89+
getMsg: func() *types.MsgEthereumTx {
90+
authority := s.Keyring.GetKey(0)
91+
target := s.Keyring.GetAddr(1)
92+
93+
accResp, err := s.Handler.GetEvmAccount(authority.Addr)
94+
s.Require().NoError(err)
95+
96+
auth := ethtypes.SetCodeAuthorization{
97+
ChainID: *uint256.NewInt(types.GetChainConfig().GetChainId()),
98+
Address: target,
99+
Nonce: accResp.GetNonce(),
100+
}
101+
102+
args := types.EvmTxArgs{
103+
To: &target,
104+
AuthorizationList: []ethtypes.SetCodeAuthorization{auth},
105+
}
106+
tx, err := s.Factory.GenerateSignedEthTx(s.Keyring.GetPrivKey(0), args)
107+
s.Require().NoError(err)
108+
return tx.GetMsgs()[0].(*types.MsgEthereumTx)
109+
},
110+
expectedErr: nil,
111+
postCheck: func() {
112+
authorityAddr := s.Keyring.GetAddr(0)
113+
codeHash := s.Network.App.GetEVMKeeper().GetCodeHash(s.Network.GetContext(), authorityAddr)
114+
code := s.Network.App.GetEVMKeeper().GetCode(s.Network.GetContext(), codeHash)
115+
_, ok := ethtypes.ParseDelegation(code)
116+
s.Require().False(ok)
117+
s.Require().Len(code, 0)
118+
},
44119
},
45120
}
46121

47122
for _, tc := range testCases {
48123
s.Run(tc.name, func() {
124+
// Fund fee collector account
125+
ctx := s.Network.GetContext()
126+
coins := sdktypes.NewCoins(sdktypes.NewCoin(types.GetEVMCoinDenom(), sdkmath.NewInt(1e18)))
127+
err := s.Network.App.GetBankKeeper().MintCoins(ctx, "mint", coins)
128+
s.Require().NoError(err)
129+
err = s.Network.App.GetBankKeeper().SendCoinsFromModuleToModule(ctx, "mint", "fee_collector", coins)
130+
s.Require().NoError(err)
131+
132+
// Get EthereumTx msg
49133
msg := tc.getMsg()
50134

51135
// Function to be tested
@@ -66,6 +150,10 @@ func (s *KeeperTestSuite) TestEthereumTx() {
66150
s.Require().True(utils.ContainsEventType(events.ToABCIEvents(), sdktypes.EventTypeMessage))
67151
}
68152

153+
if tc.postCheck != nil {
154+
tc.postCheck()
155+
}
156+
69157
err = s.Network.NextBlock()
70158
s.Require().NoError(err)
71159
})

tests/integration/x/vm/test_state_transition.go

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
ethtypes "github.com/ethereum/go-ethereum/core/types"
1212
gethtypes "github.com/ethereum/go-ethereum/core/types"
1313
"github.com/ethereum/go-ethereum/params"
14+
"github.com/holiman/uint256"
1415

1516
"github.com/cometbft/cometbft/crypto/tmhash"
1617
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
@@ -837,6 +838,7 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() {
837838
expErr bool
838839
expVMErr bool
839840
expectedGasUsed uint64
841+
postCheck func()
840842
}{
841843
{
842844
"success - messsage applied ok with default params",
@@ -855,6 +857,87 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() {
855857
false,
856858
false,
857859
params.TxGas,
860+
nil,
861+
},
862+
{
863+
"success - applies set code authorization (EIP-7702)",
864+
func() core.Message {
865+
authority := s.Keyring.GetKey(0)
866+
target := s.Keyring.GetAddr(1)
867+
868+
accResp, err := s.Handler.GetEvmAccount(authority.Addr)
869+
s.Require().NoError(err)
870+
871+
auth := ethtypes.SetCodeAuthorization{
872+
ChainID: *uint256.NewInt(types.GetChainConfig().GetChainId()),
873+
Address: target,
874+
Nonce: accResp.GetNonce(),
875+
}
876+
877+
signedAuth := s.SignSetCodeAuthorization(authority, auth)
878+
879+
msg, err := s.Factory.GenerateGethCoreMsg(authority.Priv, types.EvmTxArgs{
880+
To: &common.Address{},
881+
AuthorizationList: []ethtypes.SetCodeAuthorization{signedAuth},
882+
})
883+
s.Require().NoError(err)
884+
return *msg
885+
},
886+
types.DefaultParams,
887+
feemarkettypes.DefaultParams,
888+
false,
889+
false,
890+
params.TxGas + params.CallNewAccountGas -
891+
keeper.GasToRefund(
892+
params.CallNewAccountGas-params.TxAuthTupleGas,
893+
params.TxGas+params.CallNewAccountGas,
894+
params.RefundQuotientEIP3529,
895+
),
896+
func() {
897+
authorityAddr := s.Keyring.GetAddr(0)
898+
targetAddr := s.Keyring.GetAddr(1)
899+
codeHash := s.Network.App.GetEVMKeeper().GetCodeHash(s.Network.GetContext(), authorityAddr)
900+
code := s.Network.App.GetEVMKeeper().GetCode(s.Network.GetContext(), codeHash)
901+
delegationAddr, ok := ethtypes.ParseDelegation(code)
902+
s.Require().True(ok)
903+
s.Require().Equal(targetAddr, delegationAddr)
904+
},
905+
},
906+
{
907+
"fail - unsigned set code authorization is ignored (EIP-7702)",
908+
func() core.Message {
909+
authority := s.Keyring.GetKey(0)
910+
target := s.Keyring.GetAddr(1)
911+
912+
accResp, err := s.Handler.GetEvmAccount(authority.Addr)
913+
s.Require().NoError(err)
914+
915+
auth := ethtypes.SetCodeAuthorization{
916+
ChainID: *uint256.NewInt(types.GetChainConfig().GetChainId()),
917+
Address: target,
918+
Nonce: accResp.GetNonce(),
919+
}
920+
921+
msg, err := s.Factory.GenerateGethCoreMsg(authority.Priv, types.EvmTxArgs{
922+
To: &common.Address{},
923+
AuthorizationList: []ethtypes.SetCodeAuthorization{auth},
924+
})
925+
s.Require().NoError(err)
926+
return *msg
927+
},
928+
types.DefaultParams,
929+
feemarkettypes.DefaultParams,
930+
false,
931+
false,
932+
params.TxGas + params.CallNewAccountGas,
933+
func() {
934+
authorityAddr := s.Keyring.GetAddr(0)
935+
codeHash := s.Network.App.GetEVMKeeper().GetCodeHash(s.Network.GetContext(), authorityAddr)
936+
code := s.Network.App.GetEVMKeeper().GetCode(s.Network.GetContext(), codeHash)
937+
_, ok := ethtypes.ParseDelegation(code)
938+
s.Require().False(ok)
939+
s.Require().Len(code, 0)
940+
},
858941
},
859942
{
860943
"call contract tx with config param EnableCall = false",
@@ -882,6 +965,7 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() {
882965
false,
883966
true,
884967
0,
968+
nil,
885969
},
886970
{
887971
"create contract tx with config param EnableCreate = false",
@@ -907,6 +991,7 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() {
907991
false,
908992
true,
909993
0,
994+
nil,
910995
},
911996
{
912997
"fail - fix panic when minimumGasUsed is not uint64",
@@ -931,6 +1016,7 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() {
9311016
true,
9321017
false,
9331018
0,
1019+
nil,
9341020
},
9351021
}
9361022

@@ -970,14 +1056,13 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() {
9701056
s.Require().NoError(err)
9711057
s.Require().False(res.Failed())
9721058
s.Require().Equal(tc.expectedGasUsed, res.GasUsed)
973-
}
9741059

975-
err = s.Network.NextBlock()
976-
if tc.expVMErr {
977-
s.Require().NotEmpty(res.VmError)
978-
return
1060+
if tc.postCheck != nil {
1061+
tc.postCheck()
1062+
}
9791063
}
9801064

1065+
err = s.Network.NextBlock()
9811066
if tc.expVMErr {
9821067
s.Require().NotEmpty(res.VmError)
9831068
return

tests/integration/x/vm/utils.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import (
1010
"github.com/ethereum/go-ethereum/crypto"
1111
"github.com/stretchr/testify/require"
1212

13+
"github.com/cosmos/evm/crypto/ethsecp256k1"
1314
servercfg "github.com/cosmos/evm/server/config"
15+
testKeyring "github.com/cosmos/evm/testutil/keyring"
1416
utiltx "github.com/cosmos/evm/testutil/tx"
1517
"github.com/cosmos/evm/x/vm/keeper/testdata"
1618
"github.com/cosmos/evm/x/vm/statedb"
@@ -204,3 +206,18 @@ func (s *KeeperTestSuite) DeployTestMessageCall(t require.TestingT) common.Addre
204206
require.Empty(t, rsp.VmError)
205207
return crypto.CreateAddress(addr, nonce)
206208
}
209+
210+
func (s *KeeperTestSuite) SignSetCodeAuthorization(authority testKeyring.Key, auth ethtypes.SetCodeAuthorization) ethtypes.SetCodeAuthorization {
211+
s.T().Helper()
212+
213+
privKey, ok := authority.Priv.(*ethsecp256k1.PrivKey)
214+
s.Require().True(ok)
215+
216+
ecdsaPriv, err := privKey.ToECDSA()
217+
s.Require().NoError(err)
218+
219+
signedAuth, err := ethtypes.SignSetCode(ecdsaPriv, auth)
220+
s.Require().NoError(err)
221+
222+
return signedAuth
223+
}

testutil/integration/evm/factory/build.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,11 @@ func (tf *IntegrationTxFactory) GenerateDefaultTxTypeArgs(sender common.Address,
4343
// EstimateGasLimit estimates the gas limit for a tx with the provided address and txArgs
4444
func (tf *IntegrationTxFactory) EstimateGasLimit(from *common.Address, txArgs *evmtypes.EvmTxArgs) (uint64, error) {
4545
args, err := json.Marshal(evmtypes.TransactionArgs{
46-
Data: (*hexutil.Bytes)(&txArgs.Input),
47-
From: from,
48-
To: txArgs.To,
49-
AccessList: txArgs.Accesses,
46+
Data: (*hexutil.Bytes)(&txArgs.Input),
47+
From: from,
48+
To: txArgs.To,
49+
AccessList: txArgs.Accesses,
50+
AuthorizationList: txArgs.AuthorizationList,
5051
})
5152
if err != nil {
5253
return 0, errorsmod.Wrap(err, "failed to marshal tx args")

0 commit comments

Comments
 (0)