eth_getFilterLogs, eth_getLogs implementation (#248)
This commit is contained in:
parent
9b8dd598bb
commit
199484fc2e
@ -58,3 +58,9 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||||||
* Update uninstallFilter and getFilterChanges accordingly
|
* Update uninstallFilter and getFilterChanges accordingly
|
||||||
* uninstallFilter stops the polling goroutine
|
* uninstallFilter stops the polling goroutine
|
||||||
* getFilterChanges returns the filter's internal list of block hashes and resets it
|
* getFilterChanges returns the filter's internal list of block hashes and resets it
|
||||||
|
|
||||||
|
* (rpc) [\#54](https://github.com/ChainSafe/ethermint/issues/54) [\#55](https://github.com/ChainSafe/ethermint/issues/55)
|
||||||
|
Implement eth_getFilterLogs and eth_getLogs
|
||||||
|
* for a given filter, look through each block for transactions. If there are transactions in the block, get the logs from it, and filter using the filterLogs method
|
||||||
|
* eth_getLogs and eth_getFilterChanges for log filters use the same underlying method as eth_getFilterLogs
|
||||||
|
* update HandleMsgEthereumTx to store logs using the ethereum hash
|
@ -20,6 +20,7 @@ type Backend interface {
|
|||||||
// Used by block filter; also used for polling
|
// Used by block filter; also used for polling
|
||||||
BlockNumber() (hexutil.Uint64, error)
|
BlockNumber() (hexutil.Uint64, error)
|
||||||
GetBlockByNumber(blockNum BlockNumber, fullTx bool) (map[string]interface{}, error)
|
GetBlockByNumber(blockNum BlockNumber, fullTx bool) (map[string]interface{}, error)
|
||||||
|
GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error)
|
||||||
getEthBlockByNumber(height int64, fullTx bool) (map[string]interface{}, error)
|
getEthBlockByNumber(height int64, fullTx bool) (map[string]interface{}, error)
|
||||||
getGasLimit() (int64, error)
|
getGasLimit() (int64, error)
|
||||||
|
|
||||||
@ -62,6 +63,21 @@ func (e *EthermintBackend) GetBlockByNumber(blockNum BlockNumber, fullTx bool) (
|
|||||||
return e.getEthBlockByNumber(value, fullTx)
|
return e.getEthBlockByNumber(value, fullTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBlockByHash returns the block identified by hash.
|
||||||
|
func (e *EthermintBackend) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
||||||
|
res, _, err := e.cliCtx.Query(fmt.Sprintf("custom/%s/%s/%s", types.ModuleName, evm.QueryHashToHeight, hash.Hex()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var out types.QueryResBlockNumber
|
||||||
|
if err := e.cliCtx.Codec.UnmarshalJSON(res, &out); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.getEthBlockByNumber(out.Number, fullTx)
|
||||||
|
}
|
||||||
|
|
||||||
func (e *EthermintBackend) getEthBlockByNumber(height int64, fullTx bool) (map[string]interface{}, error) {
|
func (e *EthermintBackend) getEthBlockByNumber(height int64, fullTx bool) (map[string]interface{}, error) {
|
||||||
// Remove this check when 0 query is fixed ref: (https://github.com/tendermint/tendermint/issues/4014)
|
// Remove this check when 0 query is fixed ref: (https://github.com/tendermint/tendermint/issues/4014)
|
||||||
var blkNumPtr *int64
|
var blkNumPtr *int64
|
||||||
@ -82,7 +98,7 @@ func (e *EthermintBackend) getEthBlockByNumber(height int64, fullTx bool) (map[s
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
gasUsed *big.Int
|
gasUsed *big.Int
|
||||||
transactions []interface{}
|
transactions []common.Hash
|
||||||
)
|
)
|
||||||
|
|
||||||
if fullTx {
|
if fullTx {
|
||||||
@ -96,7 +112,7 @@ func (e *EthermintBackend) getEthBlockByNumber(height int64, fullTx bool) (map[s
|
|||||||
} else {
|
} else {
|
||||||
// TODO: Gas used not saved and cannot be calculated by hashes
|
// TODO: Gas used not saved and cannot be calculated by hashes
|
||||||
// Return slice of transaction hashes
|
// Return slice of transaction hashes
|
||||||
transactions = make([]interface{}, len(block.Block.Txs))
|
transactions = make([]common.Hash, len(block.Block.Txs))
|
||||||
for i, tx := range block.Block.Txs {
|
for i, tx := range block.Block.Txs {
|
||||||
transactions[i] = common.BytesToHash(tx.Hash())
|
transactions[i] = common.BytesToHash(tx.Hash())
|
||||||
}
|
}
|
||||||
@ -142,13 +158,17 @@ func (e *EthermintBackend) getGasLimit() (int64, error) {
|
|||||||
func (e *EthermintBackend) GetTxLogs(txHash common.Hash) ([]*ethtypes.Log, error) {
|
func (e *EthermintBackend) GetTxLogs(txHash common.Hash) ([]*ethtypes.Log, error) {
|
||||||
// do we need to use the block height somewhere?
|
// do we need to use the block height somewhere?
|
||||||
ctx := e.cliCtx
|
ctx := e.cliCtx
|
||||||
|
|
||||||
res, _, err := ctx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s", types.ModuleName, evm.QueryTxLogs, txHash.Hex()), nil)
|
res, _, err := ctx.QueryWithData(fmt.Sprintf("custom/%s/%s/%s", types.ModuleName, evm.QueryTxLogs, txHash.Hex()), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var out types.QueryETHLogs
|
out := new(types.QueryETHLogs)
|
||||||
e.cliCtx.Codec.MustUnmarshalJSON(res, &out)
|
if err := e.cliCtx.Codec.UnmarshalJSON(res, &out); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return out.Logs, nil
|
return out.Logs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,8 +293,6 @@ func (e *PublicEthAPI) SendTransaction(args params.SendTxArgs) (common.Hash, err
|
|||||||
// Broadcast transaction
|
// Broadcast transaction
|
||||||
res, err := e.cliCtx.BroadcastTx(txBytes)
|
res, err := e.cliCtx.BroadcastTx(txBytes)
|
||||||
// If error is encountered on the node, the broadcast will not return an error
|
// If error is encountered on the node, the broadcast will not return an error
|
||||||
// TODO: Remove res log
|
|
||||||
fmt.Println(res.RawLog)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
@ -471,14 +469,7 @@ func (e *PublicEthAPI) EstimateGas(args CallArgs) (hexutil.Uint64, error) {
|
|||||||
|
|
||||||
// GetBlockByHash returns the block identified by hash.
|
// GetBlockByHash returns the block identified by hash.
|
||||||
func (e *PublicEthAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
func (e *PublicEthAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
||||||
res, _, err := e.cliCtx.Query(fmt.Sprintf("custom/%s/%s/%s", types.ModuleName, evm.QueryHashToHeight, hash.Hex()))
|
return e.backend.GetBlockByHash(hash, fullTx)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var out types.QueryResBlockNumber
|
|
||||||
e.cliCtx.Codec.MustUnmarshalJSON(res, &out)
|
|
||||||
return e.backend.getEthBlockByNumber(out.Number, fullTx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockByNumber returns the block identified by number.
|
// GetBlockByNumber returns the block identified by number.
|
||||||
@ -488,7 +479,7 @@ func (e *PublicEthAPI) GetBlockByNumber(blockNum BlockNumber, fullTx bool) (map[
|
|||||||
|
|
||||||
func formatBlock(
|
func formatBlock(
|
||||||
header tmtypes.Header, size int, gasLimit int64,
|
header tmtypes.Header, size int, gasLimit int64,
|
||||||
gasUsed *big.Int, transactions []interface{}, bloom ethtypes.Bloom,
|
gasUsed *big.Int, transactions interface{}, bloom ethtypes.Bloom,
|
||||||
) map[string]interface{} {
|
) map[string]interface{} {
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"number": hexutil.Uint64(header.Height),
|
"number": hexutil.Uint64(header.Height),
|
||||||
@ -507,13 +498,13 @@ func formatBlock(
|
|||||||
"gasLimit": hexutil.Uint64(gasLimit), // Static gas limit
|
"gasLimit": hexutil.Uint64(gasLimit), // Static gas limit
|
||||||
"gasUsed": (*hexutil.Big)(gasUsed),
|
"gasUsed": (*hexutil.Big)(gasUsed),
|
||||||
"timestamp": hexutil.Uint64(header.Time.Unix()),
|
"timestamp": hexutil.Uint64(header.Time.Unix()),
|
||||||
"transactions": transactions,
|
"transactions": transactions.([]common.Hash),
|
||||||
"uncles": nil,
|
"uncles": nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertTransactionsToRPC(cliCtx context.CLIContext, txs []tmtypes.Tx, blockHash common.Hash, height uint64) ([]interface{}, *big.Int, error) {
|
func convertTransactionsToRPC(cliCtx context.CLIContext, txs []tmtypes.Tx, blockHash common.Hash, height uint64) ([]common.Hash, *big.Int, error) {
|
||||||
transactions := make([]interface{}, len(txs))
|
transactions := make([]common.Hash, len(txs))
|
||||||
gasUsed := big.NewInt(0)
|
gasUsed := big.NewInt(0)
|
||||||
|
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
@ -523,10 +514,11 @@ func convertTransactionsToRPC(cliCtx context.CLIContext, txs []tmtypes.Tx, block
|
|||||||
}
|
}
|
||||||
// TODO: Remove gas usage calculation if saving gasUsed per block
|
// TODO: Remove gas usage calculation if saving gasUsed per block
|
||||||
gasUsed.Add(gasUsed, ethTx.Fee())
|
gasUsed.Add(gasUsed, ethTx.Fee())
|
||||||
transactions[i], err = newRPCTransaction(*ethTx, blockHash, &height, uint64(i))
|
tx, err := newRPCTransaction(*ethTx, blockHash, &height, uint64(i))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
transactions[i] = tx.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
return transactions, gasUsed, nil
|
return transactions, gasUsed, nil
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
"github.com/cosmos/ethermint/x/evm/types"
|
|
||||||
|
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
@ -62,11 +59,14 @@ func (e *PublicFilterAPI) UninstallFilter(id rpc.ID) bool {
|
|||||||
// If the filter is a block filter, it returns an array of block hashes.
|
// If the filter is a block filter, it returns an array of block hashes.
|
||||||
// If the filter is a pending transaction filter, it returns an array of transaction hashes.
|
// If the filter is a pending transaction filter, it returns an array of transaction hashes.
|
||||||
func (e *PublicFilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) {
|
func (e *PublicFilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) {
|
||||||
|
if e.filters[id] == nil {
|
||||||
|
return nil, errors.New("invalid filter ID")
|
||||||
|
}
|
||||||
return e.filters[id].getFilterChanges()
|
return e.filters[id].getFilterChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFilterLogs returns an array of all logs matching filter with given id.
|
// GetFilterLogs returns an array of all logs matching filter with given id.
|
||||||
func (e *PublicFilterAPI) GetFilterLogs(id rpc.ID) []*ethtypes.Log {
|
func (e *PublicFilterAPI) GetFilterLogs(id rpc.ID) ([]*ethtypes.Log, error) {
|
||||||
return e.filters[id].getFilterLogs()
|
return e.filters[id].getFilterLogs()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,50 +74,6 @@ func (e *PublicFilterAPI) GetFilterLogs(id rpc.ID) []*ethtypes.Log {
|
|||||||
//
|
//
|
||||||
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
|
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
|
||||||
func (e *PublicFilterAPI) GetLogs(criteria filters.FilterCriteria) ([]*ethtypes.Log, error) {
|
func (e *PublicFilterAPI) GetLogs(criteria filters.FilterCriteria) ([]*ethtypes.Log, error) {
|
||||||
var filter *Filter
|
filter := NewFilter(e.backend, &criteria)
|
||||||
if criteria.BlockHash != nil {
|
return filter.getFilterLogs()
|
||||||
/*
|
|
||||||
Still need to add blockhash in prepare function for log entry
|
|
||||||
*/
|
|
||||||
filter = NewFilterWithBlockHash(e.backend, &criteria)
|
|
||||||
results := e.getLogs()
|
|
||||||
logs := filterLogs(results, nil, nil, filter.addresses, filter.topics)
|
|
||||||
return logs, nil
|
|
||||||
}
|
|
||||||
// Convert the RPC block numbers into internal representations
|
|
||||||
begin := rpc.LatestBlockNumber.Int64()
|
|
||||||
if criteria.FromBlock != nil {
|
|
||||||
begin = criteria.FromBlock.Int64()
|
|
||||||
}
|
|
||||||
from := big.NewInt(begin)
|
|
||||||
end := rpc.LatestBlockNumber.Int64()
|
|
||||||
if criteria.ToBlock != nil {
|
|
||||||
end = criteria.ToBlock.Int64()
|
|
||||||
}
|
|
||||||
to := big.NewInt(end)
|
|
||||||
results := e.getLogs()
|
|
||||||
logs := filterLogs(results, from, to, criteria.Addresses, criteria.Topics)
|
|
||||||
|
|
||||||
return returnLogs(logs), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *PublicFilterAPI) getLogs() (results []*ethtypes.Log) {
|
|
||||||
l, _, err := e.cliCtx.QueryWithData(fmt.Sprintf("custom/%s/logs", types.ModuleName), nil)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("error from querier %e ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(l, &results); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
|
|
||||||
// returnLogs is a helper that will return an empty log array in case the given logs array is nil,
|
|
||||||
// otherwise the given logs array is returned.
|
|
||||||
func returnLogs(logs []*ethtypes.Log) []*ethtypes.Log {
|
|
||||||
if logs == nil {
|
|
||||||
return []*ethtypes.Log{}
|
|
||||||
}
|
|
||||||
return logs
|
|
||||||
}
|
}
|
||||||
|
116
rpc/filters.go
116
rpc/filters.go
@ -8,6 +8,7 @@ import (
|
|||||||
"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/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -37,7 +38,7 @@ type Filter struct {
|
|||||||
|
|
||||||
// NewFilter returns a new Filter
|
// NewFilter returns a new Filter
|
||||||
func NewFilter(backend Backend, criteria *filters.FilterCriteria) *Filter {
|
func NewFilter(backend Backend, criteria *filters.FilterCriteria) *Filter {
|
||||||
return &Filter{
|
filter := &Filter{
|
||||||
backend: backend,
|
backend: backend,
|
||||||
fromBlock: criteria.FromBlock,
|
fromBlock: criteria.FromBlock,
|
||||||
toBlock: criteria.ToBlock,
|
toBlock: criteria.ToBlock,
|
||||||
@ -46,6 +47,8 @@ func NewFilter(backend Backend, criteria *filters.FilterCriteria) *Filter {
|
|||||||
typ: logFilter,
|
typ: logFilter,
|
||||||
stopped: false,
|
stopped: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return filter
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFilterWithBlockHash returns a new Filter with a blockHash.
|
// NewFilterWithBlockHash returns a new Filter with a blockHash.
|
||||||
@ -139,28 +142,107 @@ func (f *Filter) getFilterChanges() (interface{}, error) {
|
|||||||
case pendingTxFilter:
|
case pendingTxFilter:
|
||||||
// TODO
|
// TODO
|
||||||
case logFilter:
|
case logFilter:
|
||||||
// TODO
|
return f.getFilterLogs()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, errors.New("unsupported filter")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Filter) getFilterLogs() []*ethtypes.Log {
|
func (f *Filter) getFilterLogs() ([]*ethtypes.Log, error) {
|
||||||
// TODO
|
ret := []*ethtypes.Log{}
|
||||||
return nil
|
|
||||||
|
// filter specific block only
|
||||||
|
if f.blockHash != nil {
|
||||||
|
block, err := f.backend.GetBlockByHash(*f.blockHash, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the logsBloom == 0, there are no logs in that block
|
||||||
|
if txs, ok := block["transactions"].([]common.Hash); !ok {
|
||||||
|
return ret, nil
|
||||||
|
} else if len(txs) != 0 {
|
||||||
|
return f.checkMatches(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// filter range of blocks
|
||||||
|
num, err := f.backend.BlockNumber()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// if f.fromBlock is set to 0, set it to the latest block number
|
||||||
|
if f.fromBlock == nil || f.fromBlock.Cmp(big.NewInt(0)) == 0 {
|
||||||
|
f.fromBlock = big.NewInt(int64(num))
|
||||||
|
}
|
||||||
|
|
||||||
|
// if f.toBlock is set to 0, set it to the latest block number
|
||||||
|
if f.toBlock == nil || f.toBlock.Cmp(big.NewInt(0)) == 0 {
|
||||||
|
f.toBlock = big.NewInt(int64(num))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("[ethAPI] Retrieving filter logs", "fromBlock", f.fromBlock, "toBlock", f.toBlock,
|
||||||
|
"topics", f.topics, "addresses", f.addresses)
|
||||||
|
|
||||||
|
from := f.fromBlock.Int64()
|
||||||
|
to := f.toBlock.Int64()
|
||||||
|
|
||||||
|
for i := from; i <= to; i++ {
|
||||||
|
block, err := f.backend.GetBlockByNumber(NewBlockNumber(big.NewInt(i)), true)
|
||||||
|
if err != nil {
|
||||||
|
f.err = err
|
||||||
|
log.Debug("[ethAPI] Cannot get block", "block", block["number"], "error", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("[ethAPI] filtering", "block", block)
|
||||||
|
|
||||||
|
// TODO: block logsBloom is often set in the wrong block
|
||||||
|
// if the logsBloom == 0, there are no logs in that block
|
||||||
|
|
||||||
|
if txs, ok := block["transactions"].([]common.Hash); !ok {
|
||||||
|
continue
|
||||||
|
} else if len(txs) != 0 {
|
||||||
|
logs, err := f.checkMatches(block)
|
||||||
|
if err != nil {
|
||||||
|
f.err = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = append(ret, logs...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func includes(addresses []common.Address, a common.Address) bool {
|
func (f *Filter) checkMatches(block map[string]interface{}) ([]*ethtypes.Log, error) {
|
||||||
for _, addr := range addresses {
|
transactions, ok := block["transactions"].([]common.Hash)
|
||||||
if addr == a {
|
if !ok {
|
||||||
return true
|
return nil, errors.New("invalid block transactions")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
unfiltered := []*ethtypes.Log{}
|
||||||
|
|
||||||
|
for _, tx := range transactions {
|
||||||
|
logs, err := f.backend.GetTxLogs(common.BytesToHash(tx[:]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
unfiltered = append(unfiltered, logs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return filterLogs(unfiltered, f.fromBlock, f.toBlock, f.addresses, f.topics), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterLogs creates a slice of logs matching the given criteria.
|
// filterLogs creates a slice of logs matching the given criteria.
|
||||||
|
// [] -> anything
|
||||||
|
// [A] -> A in first position of log topics, anything after
|
||||||
|
// [null, B] -> anything in first position, B in second position
|
||||||
|
// [A, B] -> A in first position and B in second position
|
||||||
|
// [[A, B], [A, B]] -> A or B in first position, A or B in second position
|
||||||
func filterLogs(logs []*ethtypes.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*ethtypes.Log {
|
func filterLogs(logs []*ethtypes.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*ethtypes.Log {
|
||||||
var ret []*ethtypes.Log
|
var ret []*ethtypes.Log
|
||||||
Logs:
|
Logs:
|
||||||
@ -194,3 +276,13 @@ Logs:
|
|||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func includes(addresses []common.Address, a common.Address) bool {
|
||||||
|
for _, addr := range addresses {
|
||||||
|
if addr == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -15,9 +15,11 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/cosmos/ethermint/version"
|
"github.com/cosmos/ethermint/version"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,6 +31,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var addr = fmt.Sprintf("http://%s:%d", host, port)
|
var addr = fmt.Sprintf("http://%s:%d", host, port)
|
||||||
|
var zeroString = "0x0"
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
Version string `json:"jsonrpc"`
|
Version string `json:"jsonrpc"`
|
||||||
@ -78,7 +81,7 @@ func call(t *testing.T, method string, params interface{}) (*Response, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if rpcRes.Error != nil {
|
if rpcRes.Error != nil {
|
||||||
t.Fatal(errors.New(rpcRes.Error.Message))
|
return nil, errors.New(rpcRes.Error.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = res.Body.Close()
|
err = res.Body.Close()
|
||||||
@ -115,7 +118,7 @@ func TestEth_blockNumber(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEth_GetBalance(t *testing.T) {
|
func TestEth_GetBalance(t *testing.T) {
|
||||||
rpcRes, err := call(t, "eth_getBalance", []string{addrA, "0x0"})
|
rpcRes, err := call(t, "eth_getBalance", []string{addrA, zeroString})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var res hexutil.Big
|
var res hexutil.Big
|
||||||
@ -132,7 +135,7 @@ func TestEth_GetBalance(t *testing.T) {
|
|||||||
|
|
||||||
func TestEth_GetStorageAt(t *testing.T) {
|
func TestEth_GetStorageAt(t *testing.T) {
|
||||||
expectedRes := hexutil.Bytes{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
expectedRes := hexutil.Bytes{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
rpcRes, err := call(t, "eth_getStorageAt", []string{addrA, string(addrAStoreKey), "0x0"})
|
rpcRes, err := call(t, "eth_getStorageAt", []string{addrA, string(addrAStoreKey), zeroString})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var storage hexutil.Bytes
|
var storage hexutil.Bytes
|
||||||
@ -146,7 +149,7 @@ func TestEth_GetStorageAt(t *testing.T) {
|
|||||||
|
|
||||||
func TestEth_GetCode(t *testing.T) {
|
func TestEth_GetCode(t *testing.T) {
|
||||||
expectedRes := hexutil.Bytes{}
|
expectedRes := hexutil.Bytes{}
|
||||||
rpcRes, err := call(t, "eth_getCode", []string{addrA, "0x0"})
|
rpcRes, err := call(t, "eth_getCode", []string{addrA, zeroString})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var code hexutil.Bytes
|
var code hexutil.Bytes
|
||||||
@ -158,6 +161,33 @@ func TestEth_GetCode(t *testing.T) {
|
|||||||
require.True(t, bytes.Equal(expectedRes, code), "expected: %X got: %X", expectedRes, code)
|
require.True(t, bytes.Equal(expectedRes, code), "expected: %X got: %X", expectedRes, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getAddress(t *testing.T) []byte {
|
||||||
|
rpcRes, err := call(t, "eth_accounts", []string{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var res []hexutil.Bytes
|
||||||
|
err = json.Unmarshal(rpcRes.Result, &res)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return res[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_SendTransaction(t *testing.T) {
|
||||||
|
from := getAddress(t)
|
||||||
|
|
||||||
|
param := make([]map[string]string, 1)
|
||||||
|
param[0] = make(map[string]string)
|
||||||
|
param[0]["from"] = "0x" + fmt.Sprintf("%x", from)
|
||||||
|
param[0]["data"] = "0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029"
|
||||||
|
|
||||||
|
rpcRes, err := call(t, "eth_sendTransaction", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var hash hexutil.Bytes
|
||||||
|
err = json.Unmarshal(rpcRes.Result, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestEth_NewFilter(t *testing.T) {
|
func TestEth_NewFilter(t *testing.T) {
|
||||||
param := make([]map[string][]string, 1)
|
param := make([]map[string][]string, 1)
|
||||||
param[0] = make(map[string][]string)
|
param[0] = make(map[string][]string)
|
||||||
@ -165,7 +195,299 @@ func TestEth_NewFilter(t *testing.T) {
|
|||||||
rpcRes, err := call(t, "eth_newFilter", param)
|
rpcRes, err := call(t, "eth_newFilter", param)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var code hexutil.Bytes
|
var ID hexutil.Bytes
|
||||||
err = code.UnmarshalJSON(rpcRes.Result)
|
err = json.Unmarshal(rpcRes.Result, &ID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEth_NewBlockFilter(t *testing.T) {
|
||||||
|
rpcRes, err := call(t, "eth_newBlockFilter", []string{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var ID hexutil.Bytes
|
||||||
|
err = json.Unmarshal(rpcRes.Result, &ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetFilterChanges_NoLogs(t *testing.T) {
|
||||||
|
param := make([]map[string][]string, 1)
|
||||||
|
param[0] = make(map[string][]string)
|
||||||
|
param[0]["topics"] = []string{}
|
||||||
|
rpcRes, err := call(t, "eth_newFilter", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var ID hexutil.Bytes
|
||||||
|
err = json.Unmarshal(rpcRes.Result, &ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
changesRes, err := call(t, "eth_getFilterChanges", []string{ID.String()})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var logs []*ethtypes.Log
|
||||||
|
err = json.Unmarshal(changesRes.Result, &logs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetFilterChanges_WrongID(t *testing.T) {
|
||||||
|
_, err := call(t, "eth_getFilterChanges", []string{"0x1122334400000077"})
|
||||||
|
require.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// deployTestContract deploys a contract that emits an event in the constructor
|
||||||
|
func deployTestContract(t *testing.T) hexutil.Bytes {
|
||||||
|
from := getAddress(t)
|
||||||
|
|
||||||
|
param := make([]map[string]string, 1)
|
||||||
|
param[0] = make(map[string]string)
|
||||||
|
param[0]["from"] = "0x" + fmt.Sprintf("%x", from)
|
||||||
|
param[0]["data"] = "0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029"
|
||||||
|
|
||||||
|
rpcRes, err := call(t, "eth_sendTransaction", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var hash hexutil.Bytes
|
||||||
|
err = json.Unmarshal(rpcRes.Result, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetTransactionReceipt(t *testing.T) {
|
||||||
|
hash := deployTestContract(t)
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
|
||||||
|
param := []string{hash.String()}
|
||||||
|
rpcRes, err := call(t, "eth_getTransactionReceipt", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Log(rpcRes.Result)
|
||||||
|
// TODO: why does this not return a receipt?
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetTxLogs(t *testing.T) {
|
||||||
|
// currently fails due to eth_sendTransaction returning the tendermint hash,
|
||||||
|
// while the logs are stored in the db using the ethereum hash
|
||||||
|
t.Skip()
|
||||||
|
hash := deployTestContract(t)
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
|
||||||
|
param := []string{hash.String()}
|
||||||
|
rpcRes, err := call(t, "eth_getTxLogs", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
logs := new([]*ethtypes.Log)
|
||||||
|
err = json.Unmarshal(rpcRes.Result, logs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, 1, len(*logs))
|
||||||
|
t.Log((*logs)[0])
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetFilterChanges_NoTopics(t *testing.T) {
|
||||||
|
rpcRes, err := call(t, "eth_blockNumber", []string{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var res hexutil.Uint64
|
||||||
|
err = res.UnmarshalJSON(rpcRes.Result)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
param := make([]map[string]interface{}, 1)
|
||||||
|
param[0] = make(map[string]interface{})
|
||||||
|
param[0]["topics"] = []string{}
|
||||||
|
param[0]["fromBlock"] = res.String()
|
||||||
|
param[0]["toBlock"] = zeroString // latest
|
||||||
|
|
||||||
|
// deploy contract, emitting some event
|
||||||
|
deployTestContract(t)
|
||||||
|
|
||||||
|
rpcRes, err = call(t, "eth_newFilter", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var ID hexutil.Bytes
|
||||||
|
err = json.Unmarshal(rpcRes.Result, &ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
// get filter changes
|
||||||
|
changesRes, err := call(t, "eth_getFilterChanges", []string{ID.String()})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var logs []*ethtypes.Log
|
||||||
|
err = json.Unmarshal(changesRes.Result, &logs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, 1, len(logs))
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
//t.Log(logs[0])
|
||||||
|
// TODO: why is the tx hash in the log not the same as the tx hash of the transaction?
|
||||||
|
//require.Equal(t, logs[0].TxHash, common.BytesToHash(hash))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetFilterChanges_Addresses(t *testing.T) {
|
||||||
|
// TODO: need transaction receipts to determine contract deployment address
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetFilterChanges_BlockHash(t *testing.T) {
|
||||||
|
// TODO: need transaction receipts to determine tx block
|
||||||
|
}
|
||||||
|
|
||||||
|
// hash of Hello event
|
||||||
|
var helloTopic = "0x775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd738898"
|
||||||
|
|
||||||
|
// world parameter in Hello event
|
||||||
|
var worldTopic = "0x0000000000000000000000000000000000000000000000000000000000000011"
|
||||||
|
|
||||||
|
func deployTestContractWithFunction(t *testing.T) hexutil.Bytes {
|
||||||
|
// pragma solidity ^0.5.1;
|
||||||
|
|
||||||
|
// contract Test {
|
||||||
|
// event Hello(uint256 indexed world);
|
||||||
|
// event Test(uint256 indexed a, uint256 indexed b);
|
||||||
|
|
||||||
|
// constructor() public {
|
||||||
|
// emit Hello(17);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function test(uint256 a, uint256 b) public {
|
||||||
|
// emit Test(a, b);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
bytecode := "0x608060405234801561001057600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a260c98061004d6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063eb8ac92114602d575b600080fd5b606060048036036040811015604157600080fd5b8101908080359060200190929190803590602001909291905050506062565b005b80827f91916a5e2c96453ddf6b585497262675140eb9f7a774095fb003d93e6dc6921660405160405180910390a3505056fea265627a7a72315820ef746422e676b3ed22147cd771a6f689e7c33ef17bf5cd91921793b5dd01e3e064736f6c63430005110032"
|
||||||
|
|
||||||
|
from := getAddress(t)
|
||||||
|
|
||||||
|
param := make([]map[string]string, 1)
|
||||||
|
param[0] = make(map[string]string)
|
||||||
|
param[0]["from"] = "0x" + fmt.Sprintf("%x", from)
|
||||||
|
param[0]["data"] = bytecode
|
||||||
|
|
||||||
|
rpcRes, err := call(t, "eth_sendTransaction", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var hash hexutil.Bytes
|
||||||
|
err = json.Unmarshal(rpcRes.Result, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests topics case where there are topics in first two positions
|
||||||
|
func TestEth_GetFilterChanges_Topics_AB(t *testing.T) {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
rpcRes, err := call(t, "eth_blockNumber", []string{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var res hexutil.Uint64
|
||||||
|
err = res.UnmarshalJSON(rpcRes.Result)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
param := make([]map[string]interface{}, 1)
|
||||||
|
param[0] = make(map[string]interface{})
|
||||||
|
param[0]["topics"] = []string{helloTopic, worldTopic}
|
||||||
|
param[0]["fromBlock"] = res.String()
|
||||||
|
param[0]["toBlock"] = zeroString // latest
|
||||||
|
|
||||||
|
deployTestContractWithFunction(t)
|
||||||
|
|
||||||
|
rpcRes, err = call(t, "eth_newFilter", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var ID hexutil.Bytes
|
||||||
|
err = json.Unmarshal(rpcRes.Result, &ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
|
||||||
|
// get filter changes
|
||||||
|
changesRes, err := call(t, "eth_getFilterChanges", []string{ID.String()})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var logs []*ethtypes.Log
|
||||||
|
err = json.Unmarshal(changesRes.Result, &logs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, 1, len(logs))
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetFilterChanges_Topics_XB(t *testing.T) {
|
||||||
|
rpcRes, err := call(t, "eth_blockNumber", []string{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var res hexutil.Uint64
|
||||||
|
err = res.UnmarshalJSON(rpcRes.Result)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
param := make([]map[string]interface{}, 1)
|
||||||
|
param[0] = make(map[string]interface{})
|
||||||
|
param[0]["topics"] = []interface{}{nil, worldTopic}
|
||||||
|
param[0]["fromBlock"] = res.String()
|
||||||
|
param[0]["toBlock"] = "0x0" // latest
|
||||||
|
|
||||||
|
deployTestContractWithFunction(t)
|
||||||
|
|
||||||
|
rpcRes, err = call(t, "eth_newFilter", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var ID hexutil.Bytes
|
||||||
|
err = json.Unmarshal(rpcRes.Result, &ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
|
||||||
|
// get filter changes
|
||||||
|
changesRes, err := call(t, "eth_getFilterChanges", []string{ID.String()})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var logs []*ethtypes.Log
|
||||||
|
err = json.Unmarshal(changesRes.Result, &logs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, 1, len(logs))
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetFilterChanges_Topics_XXC(t *testing.T) {
|
||||||
|
// TODO: call test function, need tx receipts to determine contract address
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetLogs_NoLogs(t *testing.T) {
|
||||||
|
param := make([]map[string][]string, 1)
|
||||||
|
param[0] = make(map[string][]string)
|
||||||
|
param[0]["topics"] = []string{}
|
||||||
|
_, err := call(t, "eth_getLogs", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEth_GetLogs_Topics_AB(t *testing.T) {
|
||||||
|
rpcRes, err := call(t, "eth_blockNumber", []string{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var res hexutil.Uint64
|
||||||
|
err = res.UnmarshalJSON(rpcRes.Result)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
param := make([]map[string]interface{}, 1)
|
||||||
|
param[0] = make(map[string]interface{})
|
||||||
|
param[0]["topics"] = []string{helloTopic, worldTopic}
|
||||||
|
param[0]["fromBlock"] = res.String()
|
||||||
|
param[0]["toBlock"] = zeroString // latest
|
||||||
|
|
||||||
|
deployTestContractWithFunction(t)
|
||||||
|
|
||||||
|
rpcRes, err = call(t, "eth_getLogs", param)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var logs []*ethtypes.Log
|
||||||
|
err = json.Unmarshal(rpcRes.Result, &logs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, 1, len(logs))
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package rpc
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
@ -19,6 +20,10 @@ const (
|
|||||||
EarliestBlockNumber = BlockNumber(1)
|
EarliestBlockNumber = BlockNumber(1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewBlockNumber(n *big.Int) BlockNumber {
|
||||||
|
return BlockNumber(n.Int64())
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports:
|
// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports:
|
||||||
// - "latest", "earliest" or "pending" as string arguments
|
// - "latest", "earliest" or "pending" as string arguments
|
||||||
// - the block number
|
// - the block number
|
||||||
|
@ -43,8 +43,7 @@ func HandleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) sdk
|
|||||||
return sdk.ResultFromError(err)
|
return sdk.ResultFromError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
txHash := tmtypes.Tx(ctx.TxBytes()).Hash()
|
txHash := msg.Hash()
|
||||||
ethHash := common.BytesToHash(txHash)
|
|
||||||
|
|
||||||
st := types.StateTransition{
|
st := types.StateTransition{
|
||||||
Sender: sender,
|
Sender: sender,
|
||||||
@ -56,11 +55,12 @@ func HandleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) sdk
|
|||||||
Payload: msg.Data.Payload,
|
Payload: msg.Data.Payload,
|
||||||
Csdb: k.CommitStateDB.WithContext(ctx),
|
Csdb: k.CommitStateDB.WithContext(ctx),
|
||||||
ChainID: intChainID,
|
ChainID: intChainID,
|
||||||
THash: ðHash,
|
THash: &txHash,
|
||||||
Simulate: ctx.IsCheckTx(),
|
Simulate: ctx.IsCheckTx(),
|
||||||
}
|
}
|
||||||
// Prepare db for logs
|
// Prepare db for logs
|
||||||
k.CommitStateDB.Prepare(ethHash, common.Hash{}, k.TxCount)
|
// TODO: block hash
|
||||||
|
k.CommitStateDB.Prepare(txHash, txHash, k.TxCount)
|
||||||
k.TxCount++
|
k.TxCount++
|
||||||
|
|
||||||
// TODO: move to keeper
|
// TODO: move to keeper
|
||||||
@ -73,7 +73,7 @@ func HandleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) sdk
|
|||||||
k.Bloom.Or(k.Bloom, returnData.Bloom)
|
k.Bloom.Or(k.Bloom, returnData.Bloom)
|
||||||
|
|
||||||
// update transaction logs in KVStore
|
// update transaction logs in KVStore
|
||||||
err = k.SetTransactionLogs(ctx, returnData.Logs, txHash)
|
err = k.SetTransactionLogs(ctx, returnData.Logs, txHash[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdk.ResultFromError(err)
|
return sdk.ResultFromError(err)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@ type ReturnData struct {
|
|||||||
// TODO: update godoc, it doesn't explain what it does in depth.
|
// TODO: update godoc, it doesn't explain what it does in depth.
|
||||||
func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*ReturnData, error) {
|
func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*ReturnData, error) {
|
||||||
returnData := new(ReturnData)
|
returnData := new(ReturnData)
|
||||||
|
|
||||||
contractCreation := st.Recipient == nil
|
contractCreation := st.Recipient == nil
|
||||||
|
|
||||||
cost, err := core.IntrinsicGas(st.Payload, contractCreation, true)
|
cost, err := core.IntrinsicGas(st.Payload, contractCreation, true)
|
||||||
@ -123,11 +122,13 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*ReturnData, error) {
|
|||||||
bloomInt := big.NewInt(0)
|
bloomInt := big.NewInt(0)
|
||||||
var bloomFilter ethtypes.Bloom
|
var bloomFilter ethtypes.Bloom
|
||||||
var logs []*ethtypes.Log
|
var logs []*ethtypes.Log
|
||||||
|
|
||||||
if st.THash != nil && !st.Simulate {
|
if st.THash != nil && !st.Simulate {
|
||||||
logs, err = csdb.GetLogs(*st.THash)
|
logs, err = csdb.GetLogs(*st.THash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
bloomInt = ethtypes.LogsBloom(logs)
|
bloomInt = ethtypes.LogsBloom(logs)
|
||||||
bloomFilter = ethtypes.BytesToBloom(bloomInt.Bytes())
|
bloomFilter = ethtypes.BytesToBloom(bloomInt.Bytes())
|
||||||
}
|
}
|
||||||
@ -171,6 +172,11 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*ReturnData, error) {
|
|||||||
// Out of gas check does not need to be done here since it is done within the EVM execution
|
// Out of gas check does not need to be done here since it is done within the EVM execution
|
||||||
ctx.WithGasMeter(currentGasMeter).GasMeter().ConsumeGas(gasConsumed, "EVM execution consumption")
|
ctx.WithGasMeter(currentGasMeter).GasMeter().ConsumeGas(gasConsumed, "EVM execution consumption")
|
||||||
|
|
||||||
|
err = st.Csdb.SetLogs(*st.THash, logs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
returnData.Logs = logs
|
returnData.Logs = logs
|
||||||
returnData.Bloom = bloomInt
|
returnData.Bloom = bloomInt
|
||||||
returnData.Result = &sdk.Result{Data: resultData, GasUsed: gasConsumed}
|
returnData.Result = &sdk.Result{Data: resultData, GasUsed: gasConsumed}
|
||||||
|
@ -157,6 +157,18 @@ func (csdb *CommitStateDB) SetCode(addr ethcmn.Address, code []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLogs sets the logs for a transaction in the KVStore.
|
||||||
|
func (csdb *CommitStateDB) SetLogs(hash ethcmn.Hash, logs []*ethtypes.Log) error {
|
||||||
|
store := csdb.ctx.KVStore(csdb.storeKey)
|
||||||
|
enc, err := EncodeLogs(logs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
store.Set(LogsKey(hash[:]), enc)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AddLog adds a new log to the state and sets the log metadata from the state.
|
// AddLog adds a new log to the state and sets the log metadata from the state.
|
||||||
func (csdb *CommitStateDB) AddLog(log *ethtypes.Log) {
|
func (csdb *CommitStateDB) AddLog(log *ethtypes.Log) {
|
||||||
csdb.journal.append(addLogChange{txhash: csdb.thash})
|
csdb.journal.append(addLogChange{txhash: csdb.thash})
|
||||||
@ -288,7 +300,7 @@ func (csdb *CommitStateDB) GetCommittedState(addr ethcmn.Address, hash ethcmn.Ha
|
|||||||
return ethcmn.Hash{}
|
return ethcmn.Hash{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLogs returns the current logs for a given hash in the state.
|
// GetLogs returns the current logs for a given transaction hash from the KVStore.
|
||||||
func (csdb *CommitStateDB) GetLogs(hash ethcmn.Hash) ([]*ethtypes.Log, error) {
|
func (csdb *CommitStateDB) GetLogs(hash ethcmn.Hash) ([]*ethtypes.Log, error) {
|
||||||
if csdb.logs[hash] != nil {
|
if csdb.logs[hash] != nil {
|
||||||
return csdb.logs[hash], nil
|
return csdb.logs[hash], nil
|
||||||
|
Loading…
Reference in New Issue
Block a user