Implements eth_getProof (#122)
* Implemented eth_getProof and cleaned logs query types * Rename ethereum logs query type
This commit is contained in:
parent
5a19ae5706
commit
dc25d847c3
1
go.mod
1
go.mod
@ -53,7 +53,6 @@ require (
|
|||||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7
|
golang.org/x/net v0.0.0-20190628185345-da137c7871d7
|
||||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect
|
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect
|
||||||
golang.org/x/text v0.3.2 // indirect
|
golang.org/x/text v0.3.2 // indirect
|
||||||
google.golang.org/appengine v1.4.0 // indirect
|
|
||||||
google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 // indirect
|
google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 // indirect
|
||||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.2
|
gopkg.in/yaml.v2 v2.2.2
|
||||||
|
@ -14,6 +14,7 @@ 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"
|
||||||
|
|
||||||
|
"github.com/tendermint/tendermint/rpc/client"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
@ -599,7 +600,7 @@ func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]inter
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var logs types.QueryTxLogs
|
var logs types.QueryETHLogs
|
||||||
e.cliCtx.Codec.MustUnmarshalJSON(res, &logs)
|
e.cliCtx.Codec.MustUnmarshalJSON(res, &logs)
|
||||||
|
|
||||||
// TODO: change hard coded indexing of bytes
|
// TODO: change hard coded indexing of bytes
|
||||||
@ -639,6 +640,68 @@ func (e *PublicEthAPI) GetUncleByBlockNumberAndIndex(number hexutil.Uint, idx he
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AccountResult struct for account proof
|
||||||
|
type AccountResult struct {
|
||||||
|
Address common.Address `json:"address"`
|
||||||
|
AccountProof []string `json:"accountProof"`
|
||||||
|
Balance *hexutil.Big `json:"balance"`
|
||||||
|
CodeHash common.Hash `json:"codeHash"`
|
||||||
|
Nonce hexutil.Uint64 `json:"nonce"`
|
||||||
|
StorageHash common.Hash `json:"storageHash"`
|
||||||
|
StorageProof []StorageResult `json:"storageProof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StorageResult defines the format for storage proof return
|
||||||
|
type StorageResult struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Value *hexutil.Big `json:"value"`
|
||||||
|
Proof []string `json:"proof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProof returns an account object with proof and any storage proofs
|
||||||
|
func (e *PublicEthAPI) GetProof(address common.Address, storageKeys []string, block BlockNumber) (*AccountResult, error) {
|
||||||
|
opts := client.ABCIQueryOptions{Height: int64(block), Prove: true}
|
||||||
|
path := fmt.Sprintf("custom/%s/%s/%s", types.ModuleName, evm.QueryAccount, address.Hex())
|
||||||
|
pRes, err := e.cliCtx.Client.ABCIQueryWithOptions(path, nil, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: convert TM merkle proof to []string if needed in future
|
||||||
|
// proof := pRes.Response.GetProof()
|
||||||
|
|
||||||
|
account := new(types.QueryAccount)
|
||||||
|
e.cliCtx.Codec.MustUnmarshalJSON(pRes.Response.GetValue(), &account)
|
||||||
|
|
||||||
|
storageProofs := make([]StorageResult, len(storageKeys))
|
||||||
|
for i, k := range storageKeys {
|
||||||
|
// Get value for key
|
||||||
|
vPath := fmt.Sprintf("custom/%s/%s/%s/%s", types.ModuleName, evm.QueryStorage, address, k)
|
||||||
|
vRes, err := e.cliCtx.Client.ABCIQueryWithOptions(vPath, nil, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
value := new(types.QueryResStorage)
|
||||||
|
e.cliCtx.Codec.MustUnmarshalJSON(vRes.Response.GetValue(), &value)
|
||||||
|
|
||||||
|
storageProofs[i] = StorageResult{
|
||||||
|
Key: k,
|
||||||
|
Value: (*hexutil.Big)(common.BytesToHash(value.Value).Big()),
|
||||||
|
Proof: []string{""},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &AccountResult{
|
||||||
|
Address: address,
|
||||||
|
AccountProof: []string{""}, // This shouldn't be necessary (different proof formats)
|
||||||
|
Balance: (*hexutil.Big)(utils.MustUnmarshalBigInt(account.Balance)),
|
||||||
|
CodeHash: common.BytesToHash(account.CodeHash),
|
||||||
|
Nonce: hexutil.Uint64(account.Nonce),
|
||||||
|
StorageHash: common.Hash{}, // Ethermint doesn't have a storage hash
|
||||||
|
StorageProof: storageProofs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// getGasLimit returns the gas limit per block set in genesis
|
// getGasLimit returns the gas limit per block set in genesis
|
||||||
func (e *PublicEthAPI) getGasLimit() (int64, error) {
|
func (e *PublicEthAPI) getGasLimit() (int64, error) {
|
||||||
// Retrieve from gasLimit variable cache
|
// Retrieve from gasLimit variable cache
|
||||||
|
10
utils/int.go
10
utils/int.go
@ -17,3 +17,13 @@ func UnmarshalBigInt(s string) (*big.Int, error) {
|
|||||||
err := ret.UnmarshalText([]byte(s))
|
err := ret.UnmarshalText([]byte(s))
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustUnmarshalBigInt unmarshalls string from *big.Int
|
||||||
|
func MustUnmarshalBigInt(s string) *big.Int {
|
||||||
|
ret := new(big.Int)
|
||||||
|
err := ret.UnmarshalText([]byte(s))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
@ -25,6 +25,7 @@ const (
|
|||||||
QueryTxLogs = "txLogs"
|
QueryTxLogs = "txLogs"
|
||||||
QueryLogsBloom = "logsBloom"
|
QueryLogsBloom = "logsBloom"
|
||||||
QueryLogs = "logs"
|
QueryLogs = "logs"
|
||||||
|
QueryAccount = "account"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewQuerier is the module level router for state queries
|
// NewQuerier is the module level router for state queries
|
||||||
@ -50,7 +51,9 @@ func NewQuerier(keeper Keeper) sdk.Querier {
|
|||||||
case QueryLogsBloom:
|
case QueryLogsBloom:
|
||||||
return queryBlockLogsBloom(ctx, path, keeper)
|
return queryBlockLogsBloom(ctx, path, keeper)
|
||||||
case QueryLogs:
|
case QueryLogs:
|
||||||
return queryLogs(ctx, path, keeper)
|
return queryLogs(ctx, keeper)
|
||||||
|
case QueryAccount:
|
||||||
|
return queryAccount(ctx, path, keeper)
|
||||||
default:
|
default:
|
||||||
return nil, sdk.ErrUnknownRequest("unknown query endpoint")
|
return nil, sdk.ErrUnknownRequest("unknown query endpoint")
|
||||||
}
|
}
|
||||||
@ -162,7 +165,7 @@ func queryTxLogs(ctx sdk.Context, path []string, keeper Keeper) ([]byte, sdk.Err
|
|||||||
txHash := ethcmn.HexToHash(path[1])
|
txHash := ethcmn.HexToHash(path[1])
|
||||||
logs := keeper.GetLogs(ctx, txHash)
|
logs := keeper.GetLogs(ctx, txHash)
|
||||||
|
|
||||||
bRes := types.QueryTxLogs{Logs: logs}
|
bRes := types.QueryETHLogs{Logs: logs}
|
||||||
res, err := codec.MarshalJSONIndent(keeper.cdc, bRes)
|
res, err := codec.MarshalJSONIndent(keeper.cdc, bRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("could not marshal result to JSON: " + err.Error())
|
panic("could not marshal result to JSON: " + err.Error())
|
||||||
@ -171,10 +174,27 @@ func queryTxLogs(ctx sdk.Context, path []string, keeper Keeper) ([]byte, sdk.Err
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryLogs(ctx sdk.Context, path []string, keeper Keeper) ([]byte, sdk.Error) {
|
func queryLogs(ctx sdk.Context, keeper Keeper) ([]byte, sdk.Error) {
|
||||||
logs := keeper.Logs(ctx)
|
logs := keeper.Logs(ctx)
|
||||||
|
|
||||||
l, err := codec.MarshalJSONIndent(keeper.cdc, logs)
|
lRes := types.QueryETHLogs{Logs: logs}
|
||||||
|
l, err := codec.MarshalJSONIndent(keeper.cdc, lRes)
|
||||||
|
if err != nil {
|
||||||
|
panic("could not marshal result to JSON: " + err.Error())
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte, sdk.Error) {
|
||||||
|
addr := ethcmn.HexToAddress(path[1])
|
||||||
|
so := keeper.GetOrNewStateObject(ctx, addr)
|
||||||
|
|
||||||
|
lRes := types.QueryAccount{
|
||||||
|
Balance: utils.MarshalBigInt(so.Balance()),
|
||||||
|
CodeHash: so.CodeHash(),
|
||||||
|
Nonce: so.Nonce(),
|
||||||
|
}
|
||||||
|
l, err := codec.MarshalJSONIndent(keeper.cdc, lRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("could not marshal result to JSON: " + err.Error())
|
panic("could not marshal result to JSON: " + err.Error())
|
||||||
}
|
}
|
||||||
|
@ -60,12 +60,12 @@ func (q QueryResNonce) String() string {
|
|||||||
return string(q.Nonce)
|
return string(q.Nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryTxLogs is response type for tx logs query
|
// QueryETHLogs is response type for tx logs query
|
||||||
type QueryTxLogs struct {
|
type QueryETHLogs struct {
|
||||||
Logs []*ethtypes.Log `json:"logs"`
|
Logs []*ethtypes.Log `json:"logs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q QueryTxLogs) String() string {
|
func (q QueryETHLogs) String() string {
|
||||||
return string(fmt.Sprintf("%+v", q.Logs))
|
return string(fmt.Sprintf("%+v", q.Logs))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,3 +77,10 @@ type QueryBloomFilter struct {
|
|||||||
func (q QueryBloomFilter) String() string {
|
func (q QueryBloomFilter) String() string {
|
||||||
return string(q.Bloom.Bytes())
|
return string(q.Bloom.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryAccount is response type for querying Ethereum state objects
|
||||||
|
type QueryAccount struct {
|
||||||
|
Balance string `json:"balance"`
|
||||||
|
CodeHash []byte `json:"codeHash"`
|
||||||
|
Nonce uint64 `json:"nonce"`
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user