From 30f3a2d20f2e7bdd0b5b465bfa6b91acd61b1657 Mon Sep 17 00:00:00 2001 From: drklee3 Date: Tue, 27 Feb 2024 12:03:31 -0800 Subject: [PATCH] test: Add EIP-158 & EIP-161 self destruct test --- contract/contracts/EIP161Test.sol | 2 +- x/evm/keeper/integration_test.go | 74 +++++++++++++++++++++++++++++++ x/evm/testutil/EIP161Test.json | 4 +- x/evm/testutil/contract.go | 7 +-- 4 files changed, 81 insertions(+), 6 deletions(-) diff --git a/contract/contracts/EIP161Test.sol b/contract/contracts/EIP161Test.sol index 5de9ac1f81..4d52b888c6 100644 --- a/contract/contracts/EIP161Test.sol +++ b/contract/contracts/EIP161Test.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; contract EIP161Test { - function selfDestructTo(address target) public { + function selfDestructTo(address target) public payable { // This contract will self-destruct and send its balance to the target address selfdestruct(payable(target)); } diff --git a/x/evm/keeper/integration_test.go b/x/evm/keeper/integration_test.go index badd538a2e..d3cfd71a93 100644 --- a/x/evm/keeper/integration_test.go +++ b/x/evm/keeper/integration_test.go @@ -178,3 +178,77 @@ func (suite *IntegrationTestSuite) TestEIP161_CallGas() { ) }) } + +// Same as TestEIP161_CallGas but with self destruct +func (suite *IntegrationTestSuite) TestEIP161_SuicideGas() { + suite.MintCoinsForAccount( + suite.Ctx, + sdk.AccAddress(suite.Address.Bytes()), + sdk.NewCoins( + sdk.NewCoin(types.AttoPhoton, sdk.NewInt(100000000000)), + ), + ) + + addr := suite.DeployContract(testutil.EIP161TestContract) + + // Non-existent account + targetAddr := common.Address{10} + targetAcc := suite.App.EvmKeeper.GetAccount(suite.Ctx, targetAddr) + suite.Require().Nil(targetAcc, "target should not exist") + + value := big.NewInt(10000) + + var gasUsed1 uint64 + + suite.Run("suicide - non-existent destination", func() { + _, rsp, err := suite.CallContract( + testutil.EIP161TestContract, + addr, + value, // >0 value transfer + "selfDestructTo", + targetAddr, + ) + suite.Require().NoError(err) + suite.Require().Empty(rsp.VmError) + + gasUsed1 = rsp.GasUsed + }) + + // Deploy again since contract self destructed + addr = suite.DeployContract(testutil.EIP161TestContract) + + suite.Run("suicide - existing destination", func() { + targetAcc := suite.App.EvmKeeper.GetAccount(suite.Ctx, targetAddr) + suite.Require().NotNil(targetAcc, "target should exist") + + _, rsp, err := suite.CallContract( + testutil.EIP161TestContract, + addr, + value, // >0 value transfer + "selfDestructTo", + targetAddr, // same target + ) + suite.Require().NoError(err) + suite.Require().Empty(rsp.VmError) + + // Check destination balances + targetAccAfter := suite.App.EvmKeeper.GetAccount(suite.Ctx, targetAddr) + suite.Require().Equal( + new(big.Int).Add(targetAcc.Balance, value), + targetAccAfter.Balance, + "balance should be transferred", + ) + + // Check gas + suite.Require().Greater( + gasUsed1, + rsp.GasUsed, + "first call should use more gas - created account", + ) + suite.Require().GreaterOrEqual( + gasUsed1, + rsp.GasUsed+gethparams.CallNewAccountGas, + "EIP-161: additional 25k gas charge for first call", + ) + }) +} diff --git a/x/evm/testutil/EIP161Test.json b/x/evm/testutil/EIP161Test.json index 77895e913a..b80d788f62 100644 --- a/x/evm/testutil/EIP161Test.json +++ b/x/evm/testutil/EIP161Test.json @@ -1,4 +1,4 @@ { - "abi": "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"callAccount\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"selfDestructTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - "bin": "608060405234801561001057600080fd5b506103bb806100206000396000f3fe6080604052600436106100295760003560e01c80636f43e2db1461002e578063a28bf7cc1461005e575b600080fd5b610048600480360381019061004391906101bd565b610087565b604051610055919061027a565b60405180910390f35b34801561006a57600080fd5b50610085600480360381019061008091906101bd565b610141565b005b60606000808373ffffffffffffffffffffffffffffffffffffffff16346040516100b0906102cd565b60006040518083038185875af1925050503d80600081146100ed576040519150601f19603f3d011682016040523d82523d6000602084013e6100f2565b606091505b509150915081610137576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161012e90610365565b60405180910390fd5b8092505050919050565b8073ffffffffffffffffffffffffffffffffffffffff16ff5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061018a8261015f565b9050919050565b61019a8161017f565b81146101a557600080fd5b50565b6000813590506101b781610191565b92915050565b6000602082840312156101d3576101d261015a565b5b60006101e1848285016101a8565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610224578082015181840152602081019050610209565b60008484015250505050565b6000601f19601f8301169050919050565b600061024c826101ea565b61025681856101f5565b9350610266818560208601610206565b61026f81610230565b840191505092915050565b600060208201905081810360008301526102948184610241565b905092915050565b600081905092915050565b50565b60006102b760008361029c565b91506102c2826102a7565b600082019050919050565b60006102d8826102aa565b9150819050919050565b600082825260208201905092915050565b7f4661696c656420746f2063616c6c20656d707479206163636f756e742077697460008201527f682076616c756500000000000000000000000000000000000000000000000000602082015250565b600061034f6027836102e2565b915061035a826102f3565b604082019050919050565b6000602082019050818103600083015261037e81610342565b905091905056fea2646970667358221220cfb5ccd351026e6ecddfda020c8ce00e3714e0a5722fd897396563e259d8b1db64736f6c63430008180033" + "abi": "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"callAccount\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"selfDestructTo\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + "bin": "608060405234801561001057600080fd5b506103ae806100206000396000f3fe6080604052600436106100295760003560e01c80636f43e2db1461002e578063a28bf7cc1461005e575b600080fd5b610048600480360381019061004391906101b0565b61007a565b604051610055919061026d565b60405180910390f35b610078600480360381019061007391906101b0565b610134565b005b60606000808373ffffffffffffffffffffffffffffffffffffffff16346040516100a3906102c0565b60006040518083038185875af1925050503d80600081146100e0576040519150601f19603f3d011682016040523d82523d6000602084013e6100e5565b606091505b50915091508161012a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161012190610358565b60405180910390fd5b8092505050919050565b8073ffffffffffffffffffffffffffffffffffffffff16ff5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061017d82610152565b9050919050565b61018d81610172565b811461019857600080fd5b50565b6000813590506101aa81610184565b92915050565b6000602082840312156101c6576101c561014d565b5b60006101d48482850161019b565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156102175780820151818401526020810190506101fc565b60008484015250505050565b6000601f19601f8301169050919050565b600061023f826101dd565b61024981856101e8565b93506102598185602086016101f9565b61026281610223565b840191505092915050565b600060208201905081810360008301526102878184610234565b905092915050565b600081905092915050565b50565b60006102aa60008361028f565b91506102b58261029a565b600082019050919050565b60006102cb8261029d565b9150819050919050565b600082825260208201905092915050565b7f4661696c656420746f2063616c6c20656d707479206163636f756e742077697460008201527f682076616c756500000000000000000000000000000000000000000000000000602082015250565b60006103426027836102d5565b915061034d826102e6565b604082019050919050565b6000602082019050818103600083015261037181610335565b905091905056fea26469706673582212202a7ff12686e1e561ab3024f725bae2847933ad8957693f8abe9cacfef441546a64736f6c63430008180033" } diff --git a/x/evm/testutil/contract.go b/x/evm/testutil/contract.go index d0015562a7..78837186e1 100644 --- a/x/evm/testutil/contract.go +++ b/x/evm/testutil/contract.go @@ -4,6 +4,7 @@ import ( // embed compiled smart contract _ "embed" "encoding/json" + "fmt" "math/big" sdk "github.com/cosmos/cosmos-sdk/types" @@ -137,7 +138,7 @@ func (suite *TestSuite) CallContract( ProposerAddress: suite.Ctx.BlockHeader().ProposerAddress, }) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("EstimateGas failed: %w", err) } nonce := suite.App.EvmKeeper.GetNonce(suite.Ctx, suite.Address) @@ -173,11 +174,11 @@ func (suite *TestSuite) CallContract( ercTransferTx.From = suite.Address.Hex() err = ercTransferTx.Sign(ethtypes.LatestSignerForChainID(chainID), suite.Signer) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed Sign: %w", err) } rsp, err := suite.App.EvmKeeper.EthereumTx(ctx, ercTransferTx) if err != nil { - return nil, rsp, err + return nil, rsp, fmt.Errorf("failed EthereumTx: %w", err) } return ercTransferTx, rsp, nil