409 lines
12 KiB
Go
409 lines
12 KiB
Go
|
package backend
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"math/big"
|
||
|
|
||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||
|
"github.com/ethereum/go-ethereum/common"
|
||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||
|
tmrpcclient "github.com/tendermint/tendermint/rpc/client"
|
||
|
|
||
|
"github.com/cerc-io/laconicd/rpc/backend/mocks"
|
||
|
rpctypes "github.com/cerc-io/laconicd/rpc/types"
|
||
|
"github.com/cerc-io/laconicd/tests"
|
||
|
evmtypes "github.com/cerc-io/laconicd/x/evm/types"
|
||
|
)
|
||
|
|
||
|
func (suite *BackendTestSuite) TestGetCode() {
|
||
|
blockNr := rpctypes.NewBlockNumber(big.NewInt(1))
|
||
|
contractCode := []byte("0xef616c92f3cfc9e92dc270d6acff9cea213cecc7020a76ee4395af09bdceb4837a1ebdb5735e11e7d3adb6104e0c3ac55180b4ddf5e54d022cc5e8837f6a4f971b")
|
||
|
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
addr common.Address
|
||
|
blockNrOrHash rpctypes.BlockNumberOrHash
|
||
|
registerMock func(common.Address)
|
||
|
expPass bool
|
||
|
expCode hexutil.Bytes
|
||
|
}{
|
||
|
{
|
||
|
"fail - BlockHash and BlockNumber are both nil ",
|
||
|
tests.GenerateAddress(),
|
||
|
rpctypes.BlockNumberOrHash{},
|
||
|
func(addr common.Address) {},
|
||
|
false,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"fail - query client errors on getting Code",
|
||
|
tests.GenerateAddress(),
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
|
||
|
func(addr common.Address) {
|
||
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||
|
RegisterCodeError(queryClient, addr)
|
||
|
},
|
||
|
false,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"pass",
|
||
|
tests.GenerateAddress(),
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
|
||
|
func(addr common.Address) {
|
||
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||
|
RegisterCode(queryClient, addr, contractCode)
|
||
|
},
|
||
|
true,
|
||
|
contractCode,
|
||
|
},
|
||
|
}
|
||
|
for _, tc := range testCases {
|
||
|
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
||
|
suite.SetupTest() // reset
|
||
|
tc.registerMock(tc.addr)
|
||
|
|
||
|
code, err := suite.backend.GetCode(tc.addr, tc.blockNrOrHash)
|
||
|
if tc.expPass {
|
||
|
suite.Require().NoError(err)
|
||
|
suite.Require().Equal(tc.expCode, code)
|
||
|
} else {
|
||
|
suite.Require().Error(err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (suite *BackendTestSuite) TestGetProof() {
|
||
|
blockNrInvalid := rpctypes.NewBlockNumber(big.NewInt(1))
|
||
|
blockNr := rpctypes.NewBlockNumber(big.NewInt(4))
|
||
|
address1 := tests.GenerateAddress()
|
||
|
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
addr common.Address
|
||
|
storageKeys []string
|
||
|
blockNrOrHash rpctypes.BlockNumberOrHash
|
||
|
registerMock func(rpctypes.BlockNumber, common.Address)
|
||
|
expPass bool
|
||
|
expAccRes *rpctypes.AccountResult
|
||
|
}{
|
||
|
{
|
||
|
"fail - BlockNumeber = 1 (invalidBlockNumber)",
|
||
|
address1,
|
||
|
[]string{},
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNrInvalid},
|
||
|
func(bn rpctypes.BlockNumber, addr common.Address) {
|
||
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||
|
RegisterBlock(client, bn.Int64(), nil)
|
||
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||
|
RegisterAccount(queryClient, addr, blockNrInvalid.Int64())
|
||
|
},
|
||
|
false,
|
||
|
&rpctypes.AccountResult{},
|
||
|
},
|
||
|
{
|
||
|
"fail - Block doesn't exist)",
|
||
|
address1,
|
||
|
[]string{},
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNrInvalid},
|
||
|
func(bn rpctypes.BlockNumber, addr common.Address) {
|
||
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||
|
RegisterBlockError(client, bn.Int64())
|
||
|
},
|
||
|
false,
|
||
|
&rpctypes.AccountResult{},
|
||
|
},
|
||
|
{
|
||
|
"pass",
|
||
|
address1,
|
||
|
[]string{"0x0"},
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
|
||
|
func(bn rpctypes.BlockNumber, addr common.Address) {
|
||
|
suite.backend.ctx = rpctypes.ContextWithHeight(bn.Int64())
|
||
|
|
||
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||
|
RegisterBlock(client, bn.Int64(), nil)
|
||
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||
|
RegisterAccount(queryClient, addr, bn.Int64())
|
||
|
|
||
|
// Use the IAVL height if a valid tendermint height is passed in.
|
||
|
ivalHeight := bn.Int64() - 1
|
||
|
RegisterABCIQueryWithOptions(
|
||
|
client,
|
||
|
bn.Int64(),
|
||
|
"store/evm/key",
|
||
|
evmtypes.StateKey(address1, common.HexToHash("0x0").Bytes()),
|
||
|
tmrpcclient.ABCIQueryOptions{Height: ivalHeight, Prove: true},
|
||
|
)
|
||
|
RegisterABCIQueryWithOptions(
|
||
|
client,
|
||
|
bn.Int64(),
|
||
|
"store/acc/key",
|
||
|
authtypes.AddressStoreKey(sdk.AccAddress(address1.Bytes())),
|
||
|
tmrpcclient.ABCIQueryOptions{Height: ivalHeight, Prove: true},
|
||
|
)
|
||
|
},
|
||
|
true,
|
||
|
&rpctypes.AccountResult{
|
||
|
Address: address1,
|
||
|
AccountProof: []string{""},
|
||
|
Balance: (*hexutil.Big)(big.NewInt(0)),
|
||
|
CodeHash: common.HexToHash(""),
|
||
|
Nonce: 0x0,
|
||
|
StorageHash: common.Hash{},
|
||
|
StorageProof: []rpctypes.StorageResult{
|
||
|
{
|
||
|
Key: "0x0",
|
||
|
Value: (*hexutil.Big)(big.NewInt(2)),
|
||
|
Proof: []string{""},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
for _, tc := range testCases {
|
||
|
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
||
|
suite.SetupTest()
|
||
|
tc.registerMock(*tc.blockNrOrHash.BlockNumber, tc.addr)
|
||
|
|
||
|
accRes, err := suite.backend.GetProof(tc.addr, tc.storageKeys, tc.blockNrOrHash)
|
||
|
|
||
|
if tc.expPass {
|
||
|
suite.Require().NoError(err)
|
||
|
suite.Require().Equal(tc.expAccRes, accRes)
|
||
|
} else {
|
||
|
suite.Require().Error(err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (suite *BackendTestSuite) TestGetStorageAt() {
|
||
|
blockNr := rpctypes.NewBlockNumber(big.NewInt(1))
|
||
|
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
addr common.Address
|
||
|
key string
|
||
|
blockNrOrHash rpctypes.BlockNumberOrHash
|
||
|
registerMock func(common.Address, string, string)
|
||
|
expPass bool
|
||
|
expStorage hexutil.Bytes
|
||
|
}{
|
||
|
{
|
||
|
"fail - BlockHash and BlockNumber are both nil",
|
||
|
tests.GenerateAddress(),
|
||
|
"0x0",
|
||
|
rpctypes.BlockNumberOrHash{},
|
||
|
func(addr common.Address, key string, storage string) {},
|
||
|
false,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"fail - query client errors on getting Storage",
|
||
|
tests.GenerateAddress(),
|
||
|
"0x0",
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
|
||
|
func(addr common.Address, key string, storage string) {
|
||
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||
|
RegisterStorageAtError(queryClient, addr, key)
|
||
|
},
|
||
|
false,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"pass",
|
||
|
tests.GenerateAddress(),
|
||
|
"0x0",
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
|
||
|
func(addr common.Address, key string, storage string) {
|
||
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||
|
RegisterStorageAt(queryClient, addr, key, storage)
|
||
|
},
|
||
|
true,
|
||
|
hexutil.Bytes{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||
|
},
|
||
|
}
|
||
|
for _, tc := range testCases {
|
||
|
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
||
|
suite.SetupTest()
|
||
|
tc.registerMock(tc.addr, tc.key, tc.expStorage.String())
|
||
|
|
||
|
storage, err := suite.backend.GetStorageAt(tc.addr, tc.key, tc.blockNrOrHash)
|
||
|
if tc.expPass {
|
||
|
suite.Require().NoError(err)
|
||
|
suite.Require().Equal(tc.expStorage, storage)
|
||
|
} else {
|
||
|
suite.Require().Error(err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (suite *BackendTestSuite) TestGetBalance() {
|
||
|
blockNr := rpctypes.NewBlockNumber(big.NewInt(1))
|
||
|
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
addr common.Address
|
||
|
blockNrOrHash rpctypes.BlockNumberOrHash
|
||
|
registerMock func(rpctypes.BlockNumber, common.Address)
|
||
|
expPass bool
|
||
|
expBalance *hexutil.Big
|
||
|
}{
|
||
|
{
|
||
|
"fail - BlockHash and BlockNumber are both nil",
|
||
|
tests.GenerateAddress(),
|
||
|
rpctypes.BlockNumberOrHash{},
|
||
|
func(bn rpctypes.BlockNumber, addr common.Address) {
|
||
|
},
|
||
|
false,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"fail - tendermint client failed to get block",
|
||
|
tests.GenerateAddress(),
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
|
||
|
func(bn rpctypes.BlockNumber, addr common.Address) {
|
||
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||
|
RegisterBlockError(client, bn.Int64())
|
||
|
},
|
||
|
false,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"fail - query client failed to get balance",
|
||
|
tests.GenerateAddress(),
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
|
||
|
func(bn rpctypes.BlockNumber, addr common.Address) {
|
||
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||
|
RegisterBlock(client, bn.Int64(), nil)
|
||
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||
|
RegisterBalanceError(queryClient, addr, bn.Int64())
|
||
|
},
|
||
|
false,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"fail - invalid balance",
|
||
|
tests.GenerateAddress(),
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
|
||
|
func(bn rpctypes.BlockNumber, addr common.Address) {
|
||
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||
|
RegisterBlock(client, bn.Int64(), nil)
|
||
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||
|
RegisterBalanceInvalid(queryClient, addr, bn.Int64())
|
||
|
},
|
||
|
false,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"fail - pruned node state",
|
||
|
tests.GenerateAddress(),
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
|
||
|
func(bn rpctypes.BlockNumber, addr common.Address) {
|
||
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||
|
RegisterBlock(client, bn.Int64(), nil)
|
||
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||
|
RegisterBalanceNegative(queryClient, addr, bn.Int64())
|
||
|
},
|
||
|
false,
|
||
|
nil,
|
||
|
},
|
||
|
{
|
||
|
"pass",
|
||
|
tests.GenerateAddress(),
|
||
|
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
|
||
|
func(bn rpctypes.BlockNumber, addr common.Address) {
|
||
|
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||
|
RegisterBlock(client, bn.Int64(), nil)
|
||
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||
|
RegisterBalance(queryClient, addr, bn.Int64())
|
||
|
},
|
||
|
true,
|
||
|
(*hexutil.Big)(big.NewInt(1)),
|
||
|
},
|
||
|
}
|
||
|
for _, tc := range testCases {
|
||
|
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
||
|
suite.SetupTest()
|
||
|
|
||
|
// avoid nil pointer reference
|
||
|
if tc.blockNrOrHash.BlockNumber != nil {
|
||
|
tc.registerMock(*tc.blockNrOrHash.BlockNumber, tc.addr)
|
||
|
}
|
||
|
|
||
|
balance, err := suite.backend.GetBalance(tc.addr, tc.blockNrOrHash)
|
||
|
if tc.expPass {
|
||
|
suite.Require().NoError(err)
|
||
|
suite.Require().Equal(tc.expBalance, balance)
|
||
|
} else {
|
||
|
suite.Require().Error(err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (suite *BackendTestSuite) TestGetTransactionCount() {
|
||
|
testCases := []struct {
|
||
|
name string
|
||
|
accExists bool
|
||
|
blockNum rpctypes.BlockNumber
|
||
|
registerMock func(common.Address, rpctypes.BlockNumber)
|
||
|
expPass bool
|
||
|
expTxCount hexutil.Uint64
|
||
|
}{
|
||
|
{
|
||
|
"pass - account doesn't exist",
|
||
|
false,
|
||
|
rpctypes.NewBlockNumber(big.NewInt(1)),
|
||
|
func(addr common.Address, bn rpctypes.BlockNumber) {},
|
||
|
true,
|
||
|
hexutil.Uint64(0),
|
||
|
},
|
||
|
// TODO: Error mocking the GetAccount call - problem with Any type
|
||
|
//{
|
||
|
// "pass - returns the number of transactions at the given address up to the given block number",
|
||
|
// true,
|
||
|
// rpctypes.NewBlockNumber(big.NewInt(1)),
|
||
|
// func(addr common.Address, bn rpctypes.BlockNumber) {
|
||
|
// client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||
|
// account, err := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, suite.acc)
|
||
|
// suite.Require().NoError(err)
|
||
|
// request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(suite.acc.Bytes()).String()}
|
||
|
// requestMarshal, _ := request.Marshal()
|
||
|
// RegisterABCIQueryAccount(
|
||
|
// client,
|
||
|
// requestMarshal,
|
||
|
// tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false},
|
||
|
// account,
|
||
|
// )
|
||
|
// },
|
||
|
// true,
|
||
|
// hexutil.Uint64(0),
|
||
|
//},
|
||
|
}
|
||
|
for _, tc := range testCases {
|
||
|
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
||
|
suite.SetupTest()
|
||
|
|
||
|
addr := tests.GenerateAddress()
|
||
|
if tc.accExists {
|
||
|
addr = common.BytesToAddress(suite.acc.Bytes())
|
||
|
}
|
||
|
|
||
|
tc.registerMock(addr, tc.blockNum)
|
||
|
|
||
|
txCount, err := suite.backend.GetTransactionCount(addr, tc.blockNum)
|
||
|
if tc.expPass {
|
||
|
suite.Require().NoError(err)
|
||
|
suite.Require().Equal(tc.expTxCount, *txCount)
|
||
|
} else {
|
||
|
suite.Require().Error(err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|