rpc: transaction receipt test (#678)
* Problem: No test on the transaction receipt api Closes: #582 - add receipt rpc test for erc20 transfer logs * lower gas fee * build with go 1.17 in CI * use go 1.17 in test-solidity * fix merge
This commit is contained in:
parent
c644dd6707
commit
1000461a55
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@ -17,6 +17,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.5
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
id: git_diff
|
||||
with:
|
||||
|
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
@ -81,6 +81,9 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.5
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
- uses: technote-space/get-diff-action@v5
|
||||
id: git_diff
|
||||
with:
|
||||
|
@ -3,4 +3,4 @@
|
||||
# prepare sloc v0.5.17 in PATH
|
||||
solc --combined-json bin,abi --allow-paths . ./tests/solidity/suites/staking/contracts/test/mocks/StandardTokenMock.sol \
|
||||
| jq ".contracts.\"./tests/solidity/suites/staking/contracts/test/mocks/StandardTokenMock.sol:StandardTokenMock\"" \
|
||||
> x/evm/keeper/ERC20Contract.json
|
||||
> x/evm/types/ERC20Contract.json
|
||||
|
@ -527,6 +527,84 @@ func TestEth_GetTransactionReceipt(t *testing.T) {
|
||||
require.Equal(t, []interface{}{}, receipt["logs"].([]interface{}))
|
||||
}
|
||||
|
||||
// deployTestERC20Contract deploys a contract that emits an event in the constructor
|
||||
func deployTestERC20Contract(t *testing.T) common.Address {
|
||||
param := make([]map[string]string, 1)
|
||||
param[0] = make(map[string]string)
|
||||
param[0]["from"] = "0x" + fmt.Sprintf("%x", from)
|
||||
|
||||
ctorArgs, err := evmtypes.ERC20Contract.ABI.Pack("", common.BytesToAddress(from), big.NewInt(100000000))
|
||||
require.NoError(t, err)
|
||||
data := append(evmtypes.ERC20Contract.Bin, ctorArgs...)
|
||||
param[0]["data"] = hexutil.Encode(data)
|
||||
|
||||
param[0]["gas"] = "0x200000"
|
||||
param[0]["gasPrice"] = "0x1"
|
||||
|
||||
rpcRes := call(t, "eth_sendTransaction", param)
|
||||
|
||||
var hash hexutil.Bytes
|
||||
err = json.Unmarshal(rpcRes.Result, &hash)
|
||||
require.NoError(t, err)
|
||||
|
||||
receipt := expectSuccessReceipt(t, hash)
|
||||
contractAddress := common.HexToAddress(receipt["contractAddress"].(string))
|
||||
require.NotEqual(t, common.Address{}, contractAddress)
|
||||
|
||||
require.NotNil(t, receipt["logs"])
|
||||
|
||||
return contractAddress
|
||||
}
|
||||
|
||||
// sendTestERC20Transaction sends a typical erc20 transfer transaction
|
||||
func sendTestERC20Transaction(t *testing.T, contract common.Address, amount *big.Int) hexutil.Bytes {
|
||||
// transfer
|
||||
param := make([]map[string]string, 1)
|
||||
param[0] = make(map[string]string)
|
||||
param[0]["from"] = "0x" + fmt.Sprintf("%x", from)
|
||||
param[0]["to"] = contract.Hex()
|
||||
data, err := evmtypes.ERC20Contract.ABI.Pack("transfer", common.BigToAddress(big.NewInt(1)), amount)
|
||||
require.NoError(t, err)
|
||||
param[0]["data"] = hexutil.Encode(data)
|
||||
param[0]["gas"] = "0x50000"
|
||||
param[0]["gasPrice"] = "0x1"
|
||||
|
||||
rpcRes := call(t, "eth_sendTransaction", param)
|
||||
|
||||
var hash hexutil.Bytes
|
||||
err = json.Unmarshal(rpcRes.Result, &hash)
|
||||
require.NoError(t, err)
|
||||
return hash
|
||||
}
|
||||
|
||||
func TestEth_GetTransactionReceipt_ERC20Transfer(t *testing.T) {
|
||||
// deploy erc20 contract
|
||||
contract := deployTestERC20Contract(t)
|
||||
amount := big.NewInt(10)
|
||||
hash := sendTestERC20Transaction(t, contract, amount)
|
||||
receipt := expectSuccessReceipt(t, hash)
|
||||
|
||||
require.Equal(t, 1, len(receipt["logs"].([]interface{})))
|
||||
log := receipt["logs"].([]interface{})[0].(map[string]interface{})
|
||||
|
||||
require.Equal(t, contract, common.HexToAddress(log["address"].(string)))
|
||||
|
||||
valueBz, err := hexutil.Decode(log["data"].(string))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, amount, big.NewInt(0).SetBytes(valueBz))
|
||||
|
||||
require.Equal(t, false, log["removed"].(bool))
|
||||
require.Equal(t, "0x0", log["logIndex"].(string))
|
||||
require.Equal(t, "0x0", log["transactionIndex"].(string))
|
||||
|
||||
expectedTopics := []interface{}{
|
||||
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
||||
"0x000000000000000000000000" + fmt.Sprintf("%x", from),
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000001",
|
||||
}
|
||||
require.Equal(t, expectedTopics, log["topics"].([]interface{}))
|
||||
}
|
||||
|
||||
// deployTestContract deploys a contract that emits an event in the constructor
|
||||
func deployTestContract(t *testing.T) (hexutil.Bytes, map[string]interface{}) {
|
||||
param := make([]map[string]string, 1)
|
||||
@ -592,6 +670,13 @@ func waitForReceipt(t *testing.T, hash hexutil.Bytes) map[string]interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
func expectSuccessReceipt(t *testing.T, hash hexutil.Bytes) map[string]interface{} {
|
||||
receipt := waitForReceipt(t, hash)
|
||||
require.NotNil(t, receipt, "transaction failed")
|
||||
require.Equal(t, "0x1", receipt["status"].(string))
|
||||
return receipt
|
||||
}
|
||||
|
||||
func TestEth_GetFilterChanges_NoTopics(t *testing.T) {
|
||||
rpcRes := call(t, "eth_blockNumber", []string{})
|
||||
|
||||
|
@ -63,7 +63,7 @@ func DoBenchmark(b *testing.B, txBuilder TxBuilder) {
|
||||
|
||||
func BenchmarkTokenTransfer(b *testing.B) {
|
||||
DoBenchmark(b, func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx {
|
||||
input, err := ContractABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
|
||||
input, err := types.ERC20Contract.ABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
|
||||
require.NoError(b, err)
|
||||
nonce := suite.app.EvmKeeper.GetNonce(suite.address)
|
||||
return types.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &contract, big.NewInt(0), 410000, big.NewInt(1), nil, nil, input, nil)
|
||||
@ -72,7 +72,7 @@ func BenchmarkTokenTransfer(b *testing.B) {
|
||||
|
||||
func BenchmarkEmitLogs(b *testing.B) {
|
||||
DoBenchmark(b, func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx {
|
||||
input, err := ContractABI.Pack("benchmarkLogs", big.NewInt(1000))
|
||||
input, err := types.ERC20Contract.ABI.Pack("benchmarkLogs", big.NewInt(1000))
|
||||
require.NoError(b, err)
|
||||
nonce := suite.app.EvmKeeper.GetNonce(suite.address)
|
||||
return types.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &contract, big.NewInt(0), 4100000, big.NewInt(1), nil, nil, input, nil)
|
||||
@ -81,7 +81,7 @@ func BenchmarkEmitLogs(b *testing.B) {
|
||||
|
||||
func BenchmarkTokenTransferFrom(b *testing.B) {
|
||||
DoBenchmark(b, func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx {
|
||||
input, err := ContractABI.Pack("transferFrom", suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(0))
|
||||
input, err := types.ERC20Contract.ABI.Pack("transferFrom", suite.address, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(0))
|
||||
require.NoError(b, err)
|
||||
nonce := suite.app.EvmKeeper.GetNonce(suite.address)
|
||||
return types.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &contract, big.NewInt(0), 410000, big.NewInt(1), nil, nil, input, nil)
|
||||
@ -90,7 +90,7 @@ func BenchmarkTokenTransferFrom(b *testing.B) {
|
||||
|
||||
func BenchmarkTokenMint(b *testing.B) {
|
||||
DoBenchmark(b, func(suite *KeeperTestSuite, contract common.Address) *types.MsgEthereumTx {
|
||||
input, err := ContractABI.Pack("mint", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
|
||||
input, err := types.ERC20Contract.ABI.Pack("mint", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
|
||||
require.NoError(b, err)
|
||||
nonce := suite.app.EvmKeeper.GetNonce(suite.address)
|
||||
return types.NewTx(suite.app.EvmKeeper.ChainID(), nonce, &contract, big.NewInt(0), 410000, big.NewInt(1), nil, nil, input, nil)
|
||||
|
@ -514,9 +514,9 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
|
||||
}, false, 0, false},
|
||||
// estimate gas of an erc20 contract deployment, the exact gas number is checked with geth
|
||||
{"contract deployment", func() {
|
||||
ctorArgs, err := ContractABI.Pack("", &suite.address, sdk.NewIntWithDecimal(1000, 18).BigInt())
|
||||
ctorArgs, err := types.ERC20Contract.ABI.Pack("", &suite.address, sdk.NewIntWithDecimal(1000, 18).BigInt())
|
||||
suite.Require().NoError(err)
|
||||
data := append(ContractBin, ctorArgs...)
|
||||
data := append(types.ERC20Contract.Bin, ctorArgs...)
|
||||
args = types.TransactionArgs{
|
||||
From: &suite.address,
|
||||
Data: (*hexutil.Bytes)(&data),
|
||||
@ -526,7 +526,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
|
||||
{"erc20 transfer", func() {
|
||||
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdk.NewIntWithDecimal(1000, 18).BigInt())
|
||||
suite.Commit()
|
||||
transferData, err := ContractABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
|
||||
transferData, err := types.ERC20Contract.ABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
|
||||
suite.Require().NoError(err)
|
||||
args = types.TransactionArgs{To: &contractAddr, From: &suite.address, Data: (*hexutil.Bytes)(&transferData)}
|
||||
}, true, 51880, false},
|
||||
@ -549,9 +549,9 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
|
||||
gasCap = 20000
|
||||
}, false, 0, true},
|
||||
{"contract deployment w/ dynamicTxFee", func() {
|
||||
ctorArgs, err := ContractABI.Pack("", &suite.address, sdk.NewIntWithDecimal(1000, 18).BigInt())
|
||||
ctorArgs, err := types.ERC20Contract.ABI.Pack("", &suite.address, sdk.NewIntWithDecimal(1000, 18).BigInt())
|
||||
suite.Require().NoError(err)
|
||||
data := append(ContractBin, ctorArgs...)
|
||||
data := append(types.ERC20Contract.Bin, ctorArgs...)
|
||||
args = types.TransactionArgs{
|
||||
From: &suite.address,
|
||||
Data: (*hexutil.Bytes)(&data),
|
||||
@ -560,7 +560,7 @@ func (suite *KeeperTestSuite) TestEstimateGas() {
|
||||
{"erc20 transfer w/ dynamicTxFee", func() {
|
||||
contractAddr := suite.DeployTestContract(suite.T(), suite.address, sdk.NewIntWithDecimal(1000, 18).BigInt())
|
||||
suite.Commit()
|
||||
transferData, err := ContractABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
|
||||
transferData, err := types.ERC20Contract.ABI.Pack("transfer", common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(1000))
|
||||
suite.Require().NoError(err)
|
||||
args = types.TransactionArgs{To: &contractAddr, From: &suite.address, Data: (*hexutil.Bytes)(&transferData)}
|
||||
}, true, 51880, true},
|
||||
|
@ -27,7 +27,6 @@ import (
|
||||
ethermint "github.com/tharsis/ethermint/types"
|
||||
"github.com/tharsis/ethermint/x/evm/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
@ -40,29 +39,6 @@ import (
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed ERC20Contract.json
|
||||
compiledContractJSON []byte
|
||||
ContractBin []byte
|
||||
ContractABI abi.ABI
|
||||
)
|
||||
|
||||
func init() {
|
||||
var tmp struct {
|
||||
Abi string
|
||||
Bin string
|
||||
}
|
||||
err := json.Unmarshal(compiledContractJSON, &tmp)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ContractBin = common.FromHex(tmp.Bin)
|
||||
err = json.Unmarshal([]byte(tmp.Abi), &ContractABI)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
var testTokens = sdk.NewIntWithDecimal(1000, 18)
|
||||
|
||||
type KeeperTestSuite struct {
|
||||
@ -193,10 +169,10 @@ func (suite *KeeperTestSuite) DeployTestContract(t require.TestingT, owner commo
|
||||
ctx := sdk.WrapSDKContext(suite.ctx)
|
||||
chainID := suite.app.EvmKeeper.ChainID()
|
||||
|
||||
ctorArgs, err := ContractABI.Pack("", owner, supply)
|
||||
ctorArgs, err := types.ERC20Contract.ABI.Pack("", owner, supply)
|
||||
require.NoError(t, err)
|
||||
|
||||
data := append(ContractBin, ctorArgs...)
|
||||
data := append(types.ERC20Contract.Bin, ctorArgs...)
|
||||
args, err := json.Marshal(&types.TransactionArgs{
|
||||
From: &suite.address,
|
||||
Data: (*hexutil.Bytes)(&data),
|
||||
@ -250,7 +226,7 @@ func (suite *KeeperTestSuite) TransferERC20Token(t require.TestingT, contractAdd
|
||||
ctx := sdk.WrapSDKContext(suite.ctx)
|
||||
chainID := suite.app.EvmKeeper.ChainID()
|
||||
|
||||
transferData, err := ContractABI.Pack("transfer", to, amount)
|
||||
transferData, err := types.ERC20Contract.ABI.Pack("transfer", to, amount)
|
||||
require.NoError(t, err)
|
||||
args, err := json.Marshal(&types.TransactionArgs{To: &contractAddr, From: &from, Data: (*hexutil.Bytes)(&transferData)})
|
||||
require.NoError(t, err)
|
||||
|
88
x/evm/types/compiled_contract.go
Normal file
88
x/evm/types/compiled_contract.go
Normal file
@ -0,0 +1,88 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
// embed compiled smart contract
|
||||
_ "embed"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
)
|
||||
|
||||
// HexString is a byte array that serializes to hex
|
||||
type HexString []byte
|
||||
|
||||
// MarshalJSON serializes ByteArray to hex
|
||||
func (s HexString) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(fmt.Sprintf("%x", string(s)))
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes ByteArray to hex
|
||||
func (s *HexString) UnmarshalJSON(data []byte) error {
|
||||
var x string
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
str, err := hex.DecodeString(x)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*s = str
|
||||
return nil
|
||||
}
|
||||
|
||||
// CompiledContract contains compiled bytecode and abi
|
||||
type CompiledContract struct {
|
||||
ABI abi.ABI
|
||||
Bin HexString
|
||||
}
|
||||
|
||||
type jsonCompiledContract struct {
|
||||
ABI string
|
||||
Bin HexString
|
||||
}
|
||||
|
||||
// MarshalJSON serializes ByteArray to hex
|
||||
func (s CompiledContract) MarshalJSON() ([]byte, error) {
|
||||
abi1, err := json.Marshal(s.ABI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(jsonCompiledContract{ABI: string(abi1), Bin: s.Bin})
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserializes ByteArray to hex
|
||||
func (s *CompiledContract) UnmarshalJSON(data []byte) error {
|
||||
var x jsonCompiledContract
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.Bin = x.Bin
|
||||
if err := json.Unmarshal([]byte(x.ABI), &s.ABI); err != nil {
|
||||
fmt.Println("unmarshal abi fail", x.ABI, string(data))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
//go:embed ERC20Contract.json
|
||||
erc20JSON []byte
|
||||
|
||||
// ERC20Contract is the compiled test erc20 contract
|
||||
ERC20Contract CompiledContract
|
||||
)
|
||||
|
||||
func init() {
|
||||
err := json.Unmarshal(erc20JSON, &ERC20Contract)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(ERC20Contract.Bin) == 0 {
|
||||
panic("load contract failed")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user