rpc: fix eth_getProof (#286)

This commit is contained in:
Federico Kunze 2020-05-12 15:12:52 -04:00 committed by GitHub
parent 8fa866482e
commit c7d89e3d56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 11 deletions

View File

@ -160,7 +160,7 @@ test-import:
# TODO: remove tmp directory after test run to avoid subsequent errors # TODO: remove tmp directory after test run to avoid subsequent errors
test-rpc: test-rpc:
@${GO_MOD} go test -v --vet=off ./rpc/tester @${GO_MOD} go test -v --vet=off ./tests/rpc_test
it-tests: it-tests:
./scripts/integration-test-all.sh -q 1 -z 1 -s 10 ./scripts/integration-test-all.sh -q 1 -z 1 -s 10

View File

@ -21,6 +21,8 @@ import (
"github.com/cosmos/ethermint/x/evm" "github.com/cosmos/ethermint/x/evm"
"github.com/cosmos/ethermint/x/evm/types" "github.com/cosmos/ethermint/x/evm/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/tendermint/tendermint/rpc/client" "github.com/tendermint/tendermint/rpc/client"
tmtypes "github.com/tendermint/tendermint/types" tmtypes "github.com/tendermint/tendermint/types"
@ -36,6 +38,7 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client" authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
) )
@ -748,6 +751,9 @@ func (e *PublicEthAPI) GetUncleByBlockNumberAndIndex(number hexutil.Uint, idx he
return nil return nil
} }
// Copied the Account and StorageResult types since they are registered under an
// internal pkg on geth.
// AccountResult struct for account proof // AccountResult struct for account proof
type AccountResult struct { type AccountResult struct {
Address common.Address `json:"address"` Address common.Address `json:"address"`
@ -768,20 +774,20 @@ type StorageResult struct {
// GetProof returns an account object with proof and any storage proofs // GetProof returns an account object with proof and any storage proofs
func (e *PublicEthAPI) GetProof(address common.Address, storageKeys []string, block BlockNumber) (*AccountResult, error) { func (e *PublicEthAPI) GetProof(address common.Address, storageKeys []string, block BlockNumber) (*AccountResult, error) {
opts := client.ABCIQueryOptions{Height: int64(block), Prove: true} e.cliCtx = e.cliCtx.WithHeight(int64(block))
path := fmt.Sprintf("custom/%s/%s/%s", types.ModuleName, evm.QueryAccount, address.Hex()) path := fmt.Sprintf("custom/%s/%s/%s", types.ModuleName, evm.QueryAccount, address.Hex())
pRes, err := e.cliCtx.Client.ABCIQueryWithOptions(path, nil, opts)
// query eth account at block height
resBz, _, err := e.cliCtx.Query(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: convert TM merkle proof to []string if needed in future
// proof := pRes.Response.GetProof()
var account types.QueryResAccount var account types.QueryResAccount
e.cliCtx.Codec.MustUnmarshalJSON(pRes.Response.GetValue(), &account) e.cliCtx.Codec.MustUnmarshalJSON(resBz, &account)
storageProofs := make([]StorageResult, len(storageKeys)) storageProofs := make([]StorageResult, len(storageKeys))
opts := client.ABCIQueryOptions{Height: int64(block), Prove: true}
for i, k := range storageKeys { for i, k := range storageKeys {
// Get value for key // Get value for key
vPath := fmt.Sprintf("custom/%s/%s/%s/%s", types.ModuleName, evm.QueryStorage, address, k) vPath := fmt.Sprintf("custom/%s/%s/%s/%s", types.ModuleName, evm.QueryStorage, address, k)
@ -789,19 +795,46 @@ func (e *PublicEthAPI) GetProof(address common.Address, storageKeys []string, bl
if err != nil { if err != nil {
return nil, err return nil, err
} }
var value types.QueryResStorage var value types.QueryResStorage
e.cliCtx.Codec.MustUnmarshalJSON(vRes.Response.GetValue(), &value) e.cliCtx.Codec.MustUnmarshalJSON(vRes.Response.GetValue(), &value)
// check for proof
proof := vRes.Response.GetProof()
proofStr := new(merkle.Proof).String()
if proof != nil {
proofStr = proof.String()
}
storageProofs[i] = StorageResult{ storageProofs[i] = StorageResult{
Key: k, Key: k,
Value: (*hexutil.Big)(common.BytesToHash(value.Value).Big()), Value: (*hexutil.Big)(common.BytesToHash(value.Value).Big()),
Proof: []string{""}, Proof: []string{proofStr},
} }
} }
req := abci.RequestQuery{
Path: fmt.Sprintf("store/%s/key", auth.StoreKey),
Data: auth.AddressStoreKey(sdk.AccAddress(address.Bytes())),
Height: int64(block),
Prove: true,
}
res, err := e.cliCtx.QueryABCI(req)
if err != nil {
return nil, err
}
// check for proof
accountProof := res.GetProof()
accProofStr := new(merkle.Proof).String()
if accountProof != nil {
accProofStr = accountProof.String()
}
return &AccountResult{ return &AccountResult{
Address: address, Address: address,
AccountProof: []string{""}, // This shouldn't be necessary (different proof formats) AccountProof: []string{accProofStr},
Balance: (*hexutil.Big)(utils.MustUnmarshalBigInt(account.Balance)), Balance: (*hexutil.Big)(utils.MustUnmarshalBigInt(account.Balance)),
CodeHash: common.BytesToHash(account.CodeHash), CodeHash: common.BytesToHash(account.CodeHash),
Nonce: hexutil.Uint64(account.Nonce), Nonce: hexutil.Uint64(account.Nonce),

View File

@ -19,11 +19,14 @@ import (
"testing" "testing"
"time" "time"
"github.com/cosmos/ethermint/version" "github.com/stretchr/testify/require"
ethcmn "github.com/ethereum/go-ethereum/common" ethcmn "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types" ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
"github.com/cosmos/ethermint/rpc"
"github.com/cosmos/ethermint/version"
) )
const ( const (
@ -155,6 +158,23 @@ func TestEth_GetStorageAt(t *testing.T) {
require.True(t, bytes.Equal(storage, expectedRes), "expected: %d (%d bytes) got: %d (%d bytes)", expectedRes, len(expectedRes), storage, len(storage)) require.True(t, bytes.Equal(storage, expectedRes), "expected: %d (%d bytes) got: %d (%d bytes)", expectedRes, len(expectedRes), storage, len(storage))
} }
func TestEth_GetProof(t *testing.T) {
params := make([]interface{}, 3)
params[0] = addrA
params[1] = []string{string(addrAStoreKey)}
params[2] = "latest"
rpcRes := call(t, "eth_getProof", params)
require.NotNil(t, rpcRes)
var accRes rpc.AccountResult
err := json.Unmarshal(rpcRes.Result, &accRes)
require.NoError(t, err)
require.NotEmpty(t, accRes.AccountProof)
require.NotEmpty(t, accRes.StorageProof)
t.Logf("Got AccountResult %s", rpcRes.Result)
}
func TestEth_GetCode(t *testing.T) { func TestEth_GetCode(t *testing.T) {
expectedRes := hexutil.Bytes{} expectedRes := hexutil.Bytes{}
rpcRes := call(t, "eth_getCode", []string{addrA, zeroString}) rpcRes := call(t, "eth_getCode", []string{addrA, zeroString})