251 lines
8.3 KiB
Go
251 lines
8.3 KiB
Go
package backend
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
|
"github.com/cerc-io/laconicd/indexer"
|
|
"github.com/cerc-io/laconicd/rpc/backend/mocks"
|
|
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
|
"github.com/cosmos/cosmos-sdk/crypto"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
tmlog "github.com/tendermint/tendermint/libs/log"
|
|
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
|
"github.com/tendermint/tendermint/types"
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
|
dbm "github.com/tendermint/tm-db"
|
|
)
|
|
|
|
func (suite *BackendTestSuite) TestTraceTransaction() {
|
|
msgEthereumTx, _ := suite.buildEthereumTx()
|
|
msgEthereumTx2, _ := suite.buildEthereumTx()
|
|
|
|
txHash := msgEthereumTx.AsTransaction().Hash()
|
|
txHash2 := msgEthereumTx2.AsTransaction().Hash()
|
|
|
|
priv, _ := ethsecp256k1.GenerateKey()
|
|
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
|
|
|
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
|
RegisterParamsWithoutHeader(queryClient, 1)
|
|
|
|
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
|
|
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
|
|
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
|
|
|
|
txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
|
|
|
|
msgEthereumTx.From = from.String()
|
|
msgEthereumTx.Sign(ethSigner, suite.signer)
|
|
tx, _ := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
|
|
txBz, _ := txEncoder(tx)
|
|
|
|
msgEthereumTx2.From = from.String()
|
|
msgEthereumTx2.Sign(ethSigner, suite.signer)
|
|
tx2, _ := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
|
|
txBz2, _ := txEncoder(tx2)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
registerMock func()
|
|
block *types.Block
|
|
responseBlock []*abci.ResponseDeliverTx
|
|
expResult interface{}
|
|
expPass bool
|
|
}{
|
|
{
|
|
"fail - tx not found",
|
|
func() {},
|
|
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{}}},
|
|
[]*abci.ResponseDeliverTx{
|
|
{
|
|
Code: 0,
|
|
Events: []abci.Event{
|
|
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
|
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
|
|
{Key: []byte("txIndex"), Value: []byte("0")},
|
|
{Key: []byte("amount"), Value: []byte("1000")},
|
|
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
|
{Key: []byte("txHash"), Value: []byte("")},
|
|
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
nil,
|
|
false,
|
|
},
|
|
{
|
|
"fail - block not found",
|
|
func() {
|
|
// var header metadata.MD
|
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
|
RegisterBlockError(client, 1)
|
|
},
|
|
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}},
|
|
[]*abci.ResponseDeliverTx{
|
|
{
|
|
Code: 0,
|
|
Events: []abci.Event{
|
|
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
|
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
|
|
{Key: []byte("txIndex"), Value: []byte("0")},
|
|
{Key: []byte("amount"), Value: []byte("1000")},
|
|
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
|
{Key: []byte("txHash"), Value: []byte("")},
|
|
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
map[string]interface{}{"test": "hello"},
|
|
false,
|
|
},
|
|
{
|
|
"pass - transaction found in a block with multiple transactions",
|
|
func() {
|
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
|
RegisterBlockMultipleTxs(client, 1, []types.Tx{txBz, txBz2})
|
|
RegisterTraceTransactionWithPredecessors(queryClient, msgEthereumTx, []*evmtypes.MsgEthereumTx{msgEthereumTx})
|
|
},
|
|
&types.Block{Header: types.Header{Height: 1, ChainID: ChainID}, Data: types.Data{Txs: []types.Tx{txBz, txBz2}}},
|
|
[]*abci.ResponseDeliverTx{
|
|
{
|
|
Code: 0,
|
|
Events: []abci.Event{
|
|
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
|
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
|
|
{Key: []byte("txIndex"), Value: []byte("0")},
|
|
{Key: []byte("amount"), Value: []byte("1000")},
|
|
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
|
{Key: []byte("txHash"), Value: []byte("")},
|
|
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
|
}},
|
|
},
|
|
},
|
|
{
|
|
Code: 0,
|
|
Events: []abci.Event{
|
|
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
|
{Key: []byte("ethereumTxHash"), Value: []byte(txHash2.Hex())},
|
|
{Key: []byte("txIndex"), Value: []byte("1")},
|
|
{Key: []byte("amount"), Value: []byte("1000")},
|
|
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
|
{Key: []byte("txHash"), Value: []byte("")},
|
|
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
map[string]interface{}{"test": "hello"},
|
|
true,
|
|
},
|
|
{
|
|
"pass - transaction found",
|
|
func() {
|
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
|
RegisterBlock(client, 1, txBz)
|
|
RegisterTraceTransaction(queryClient, msgEthereumTx)
|
|
},
|
|
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}},
|
|
[]*abci.ResponseDeliverTx{
|
|
{
|
|
Code: 0,
|
|
Events: []abci.Event{
|
|
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
|
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
|
|
{Key: []byte("txIndex"), Value: []byte("0")},
|
|
{Key: []byte("amount"), Value: []byte("1000")},
|
|
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
|
{Key: []byte("txHash"), Value: []byte("")},
|
|
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
map[string]interface{}{"test": "hello"},
|
|
true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
|
suite.SetupTest() // reset test and queries
|
|
tc.registerMock()
|
|
|
|
db := dbm.NewMemDB()
|
|
suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx)
|
|
|
|
err := suite.backend.indexer.IndexBlock(tc.block, tc.responseBlock)
|
|
suite.Require().NoError(err)
|
|
txResult, err := suite.backend.TraceTransaction(txHash, nil)
|
|
|
|
if tc.expPass {
|
|
suite.Require().NoError(err)
|
|
suite.Require().Equal(tc.expResult, txResult)
|
|
} else {
|
|
suite.Require().Error(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *BackendTestSuite) TestTraceBlock() {
|
|
msgEthTx, bz := suite.buildEthereumTx()
|
|
emptyBlock := tmtypes.MakeBlock(1, []tmtypes.Tx{}, nil, nil)
|
|
emptyBlock.ChainID = ChainID
|
|
filledBlock := tmtypes.MakeBlock(1, []tmtypes.Tx{bz}, nil, nil)
|
|
filledBlock.ChainID = ChainID
|
|
resBlockEmpty := tmrpctypes.ResultBlock{Block: emptyBlock, BlockID: emptyBlock.LastBlockID}
|
|
resBlockFilled := tmrpctypes.ResultBlock{Block: filledBlock, BlockID: filledBlock.LastBlockID}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
registerMock func()
|
|
expTraceResults []*evmtypes.TxTraceResult
|
|
resBlock *tmrpctypes.ResultBlock
|
|
config *evmtypes.TraceConfig
|
|
expPass bool
|
|
}{
|
|
{
|
|
"pass - no transaction returning empty array",
|
|
func() {},
|
|
[]*evmtypes.TxTraceResult{},
|
|
&resBlockEmpty,
|
|
&evmtypes.TraceConfig{},
|
|
true,
|
|
},
|
|
{
|
|
"fail - cannot unmarshal data",
|
|
func() {
|
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
|
RegisterTraceBlock(queryClient, []*evmtypes.MsgEthereumTx{msgEthTx})
|
|
},
|
|
[]*evmtypes.TxTraceResult{},
|
|
&resBlockFilled,
|
|
&evmtypes.TraceConfig{},
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
|
suite.SetupTest() // reset test and queries
|
|
tc.registerMock()
|
|
|
|
traceResults, err := suite.backend.TraceBlock(1, tc.config, tc.resBlock)
|
|
|
|
if tc.expPass {
|
|
suite.Require().NoError(err)
|
|
suite.Require().Equal(tc.expTraceResults, traceResults)
|
|
} else {
|
|
suite.Require().Error(err)
|
|
}
|
|
})
|
|
}
|
|
}
|