laconicd/rpc/backend/backend.go

226 lines
7.0 KiB
Go
Raw Normal View History

package backend
import (
"context"
2021-04-17 10:00:07 +00:00
"errors"
"os"
"github.com/tendermint/tendermint/libs/log"
rpctypes "github.com/cosmos/ethermint/rpc/types"
evmtypes "github.com/cosmos/ethermint/x/evm/types"
2021-04-17 10:00:07 +00:00
"github.com/cosmos/cosmos-sdk/client"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
// Backend implements the functionality needed to filter changes.
// Implemented by EthermintBackend.
type Backend interface {
// Used by block filter; also used for polling
BlockNumber() (hexutil.Uint64, error)
Pending (#571) * add PendingBlockNumber -1 * increase block times * update bn * get pending balance * additional logic to check for pending state * add multiple balance query * pending state for getTransactionCount * fix lint * add getBlockTransactionCountByNumber code - commented * cleanup test * GetBlockTransactionCountByNumber * cleanup * getBlockByNumber * GetTransactionByBlockNumberAndIndex * conform to namespace changes * exportable FormatBlock method * eth_getTransactionByHash * eth_getTransactionByBlockNumberAndIndex * pending nonce * set nonce for pending and check for invalid * WIP: doCall * add pending tx test * cleanup + refactor * push first tests and init pending * pending changes (#600) * cleanup * updates * more fixes * lint * update call and send * comments and minor changes * add pending tests into sep package * fix latest case for eth_GetBlockTransactionCountByNumber * fix repeating null transactions in queue * remove repeated structs * latestblock case * revert init script back * fix to exportable method * automate pending tests; add make cmd * move and comment out pending call test * fix some golint * fix unlock issue * wip: linter stringer fix? * stringer lint * set arr instead of append * instantiate with length * sep if statement * edit pendingblocknumber note * switch statement * fix and update tests * move tests-pending into tests dir * remove commented test * revert to appending pendingtx * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * require no err * rename var * check result for eth_sendTransaction * update changelog * update * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/tests-pending/rpc_pending_test.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * changelog * remove redundant check Co-authored-by: noot <elizabethjbinks@gmail.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>
2020-12-15 19:52:09 +00:00
LatestBlockNumber() (int64, error)
HeaderByNumber(blockNum rpctypes.BlockNumber) (*ethtypes.Header, error)
HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error)
GetBlockByNumber(blockNum rpctypes.BlockNumber, fullTx bool) (map[string]interface{}, error)
GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error)
// returns the logs of a given block
GetLogs(blockHash common.Hash) ([][]*ethtypes.Log, error)
// Used by pending transaction filter
PendingTransactions() ([]*rpctypes.Transaction, error)
// Used by log filter
GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error)
BloomStatus() (uint64, uint64)
}
var _ Backend = (*EthermintBackend)(nil)
// EthermintBackend implements the Backend interface
type EthermintBackend struct {
2021-04-17 10:00:07 +00:00
ctx context.Context
clientCtx client.Context
queryClient *rpctypes.QueryClient // gRPC query client
logger log.Logger
}
// New creates a new EthermintBackend instance
2021-04-17 10:00:07 +00:00
func New(clientCtx client.Context) *EthermintBackend {
return &EthermintBackend{
2021-04-17 10:00:07 +00:00
ctx: context.Background(),
clientCtx: clientCtx,
queryClient: rpctypes.NewQueryClient(clientCtx),
logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "json-rpc"),
}
}
// BlockNumber returns the current block number.
func (b *EthermintBackend) BlockNumber() (hexutil.Uint64, error) {
2021-04-17 10:00:07 +00:00
// NOTE: using 0 as min and max height returns the blockchain info up to the latest block.
info, err := b.clientCtx.Client.BlockchainInfo(b.ctx, 0, 0)
if err != nil {
return hexutil.Uint64(0), err
}
2021-04-17 10:00:07 +00:00
return hexutil.Uint64(info.LastHeight), nil
}
// GetBlockByNumber returns the block identified by number.
func (b *EthermintBackend) GetBlockByNumber(blockNum rpctypes.BlockNumber, fullTx bool) (map[string]interface{}, error) {
2021-04-17 10:00:07 +00:00
var height *int64
// NOTE: here pending and latest are defined as a nil height, which fetches the latest block
if !(blockNum == rpctypes.PendingBlockNumber || blockNum == rpctypes.LatestBlockNumber) {
height = blockNum.TmHeight()
}
2021-04-17 10:00:07 +00:00
resBlock, err := b.clientCtx.Client.Block(b.ctx, height)
if err != nil {
return nil, err
}
2021-04-17 10:00:07 +00:00
if resBlock.BlockID.IsZero() {
return nil, errors.New("failed to query block by number: nil block returned")
}
return rpctypes.EthBlockFromTendermint(b.clientCtx, b.queryClient, resBlock.Block)
}
// GetBlockByHash returns the block identified by hash.
func (b *EthermintBackend) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) {
2021-04-17 10:00:07 +00:00
resBlock, err := b.clientCtx.Client.BlockByHash(b.ctx, hash.Bytes())
if err != nil {
return nil, err
}
2021-04-17 10:00:07 +00:00
return rpctypes.EthBlockFromTendermint(b.clientCtx, b.queryClient, resBlock.Block)
}
// HeaderByNumber returns the block header identified by height.
func (b *EthermintBackend) HeaderByNumber(blockNum rpctypes.BlockNumber) (*ethtypes.Header, error) {
2021-04-17 10:00:07 +00:00
var height *int64
// NOTE: here pending and latest are defined as a nil height, which fetches the latest header
if !(blockNum == rpctypes.PendingBlockNumber || blockNum == rpctypes.LatestBlockNumber) {
height = blockNum.TmHeight()
}
2021-04-17 10:00:07 +00:00
resBlock, err := b.clientCtx.Client.Block(b.ctx, height)
if err != nil {
return nil, err
}
2021-04-17 10:00:07 +00:00
req := &evmtypes.QueryBlockBloomRequest{}
res, err := b.queryClient.BlockBloom(rpctypes.ContextWithHeight(blockNum.Int64()), req)
if err != nil {
return nil, err
}
ethHeader := rpctypes.EthHeaderFromTendermint(resBlock.Block.Header)
2021-04-17 10:00:07 +00:00
ethHeader.Bloom = ethtypes.BytesToBloom(res.Bloom)
return ethHeader, nil
}
// HeaderByHash returns the block header identified by hash.
func (b *EthermintBackend) HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error) {
2021-04-17 10:00:07 +00:00
resBlock, err := b.clientCtx.Client.BlockByHash(b.ctx, blockHash.Bytes())
if err != nil {
return nil, err
}
2021-04-17 10:00:07 +00:00
req := &evmtypes.QueryBlockBloomRequest{}
2021-04-17 10:00:07 +00:00
res, err := b.queryClient.BlockBloom(rpctypes.ContextWithHeight(resBlock.Block.Height), req)
if err != nil {
return nil, err
}
ethHeader := rpctypes.EthHeaderFromTendermint(resBlock.Block.Header)
2021-04-17 10:00:07 +00:00
ethHeader.Bloom = ethtypes.BytesToBloom(res.Bloom)
return ethHeader, nil
}
// GetTransactionLogs returns the logs given a transaction hash.
// It returns an error if there's an encoding error.
// If no logs are found for the tx hash, the error is nil.
func (b *EthermintBackend) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) {
2021-04-17 10:00:07 +00:00
req := &evmtypes.QueryTxLogsRequest{
Hash: txHash.String(),
}
2021-04-17 10:00:07 +00:00
res, err := b.queryClient.TxLogs(b.ctx, req)
if err != nil {
return nil, err
}
2021-04-17 10:00:07 +00:00
return evmtypes.LogsToEthereum(res.Logs), nil
}
// PendingTransactions returns the transactions that are in the transaction pool
// and have a from address that is one of the accounts this node manages.
func (b *EthermintBackend) PendingTransactions() ([]*rpctypes.Transaction, error) {
2021-04-17 10:00:07 +00:00
limit := 1000
pendingTxs, err := b.clientCtx.Client.UnconfirmedTxs(b.ctx, &limit)
if err != nil {
return nil, err
}
Pending (#571) * add PendingBlockNumber -1 * increase block times * update bn * get pending balance * additional logic to check for pending state * add multiple balance query * pending state for getTransactionCount * fix lint * add getBlockTransactionCountByNumber code - commented * cleanup test * GetBlockTransactionCountByNumber * cleanup * getBlockByNumber * GetTransactionByBlockNumberAndIndex * conform to namespace changes * exportable FormatBlock method * eth_getTransactionByHash * eth_getTransactionByBlockNumberAndIndex * pending nonce * set nonce for pending and check for invalid * WIP: doCall * add pending tx test * cleanup + refactor * push first tests and init pending * pending changes (#600) * cleanup * updates * more fixes * lint * update call and send * comments and minor changes * add pending tests into sep package * fix latest case for eth_GetBlockTransactionCountByNumber * fix repeating null transactions in queue * remove repeated structs * latestblock case * revert init script back * fix to exportable method * automate pending tests; add make cmd * move and comment out pending call test * fix some golint * fix unlock issue * wip: linter stringer fix? * stringer lint * set arr instead of append * instantiate with length * sep if statement * edit pendingblocknumber note * switch statement * fix and update tests * move tests-pending into tests dir * remove commented test * revert to appending pendingtx * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * require no err * rename var * check result for eth_sendTransaction * update changelog * update * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/tests-pending/rpc_pending_test.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * changelog * remove redundant check Co-authored-by: noot <elizabethjbinks@gmail.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>
2020-12-15 19:52:09 +00:00
transactions := make([]*rpctypes.Transaction, 0)
for _, tx := range pendingTxs.Txs {
ethTx, err := rpctypes.RawTxToEthTx(b.clientCtx, tx)
if err != nil {
// ignore non Ethermint EVM transactions
continue
}
// TODO: check signer and reference against accounts the node manages
rpcTx, err := rpctypes.NewTransaction(ethTx, common.BytesToHash(tx.Hash()), common.Hash{}, 0, 0)
if err != nil {
return nil, err
}
transactions = append(transactions, rpcTx)
}
return transactions, nil
}
// GetLogs returns all the logs from all the ethereum transactions in a block.
func (b *EthermintBackend) GetLogs(blockHash common.Hash) ([][]*ethtypes.Log, error) {
2021-04-17 10:00:07 +00:00
// NOTE: we query the state in case the tx result logs are not persisted after an upgrade.
req := &evmtypes.QueryBlockLogsRequest{
Hash: blockHash.String(),
}
2021-04-17 10:00:07 +00:00
res, err := b.queryClient.BlockLogs(b.ctx, req)
if err != nil {
return nil, err
}
var blockLogs = [][]*ethtypes.Log{}
2021-04-17 10:00:07 +00:00
for _, txLog := range res.TxLogs {
blockLogs = append(blockLogs, txLog.EthLogs())
}
return blockLogs, nil
}
// BloomStatus returns the BloomBitsBlocks and the number of processed sections maintained
// by the chain indexer.
func (b *EthermintBackend) BloomStatus() (uint64, uint64) {
return 4096, 0
}
Pending (#571) * add PendingBlockNumber -1 * increase block times * update bn * get pending balance * additional logic to check for pending state * add multiple balance query * pending state for getTransactionCount * fix lint * add getBlockTransactionCountByNumber code - commented * cleanup test * GetBlockTransactionCountByNumber * cleanup * getBlockByNumber * GetTransactionByBlockNumberAndIndex * conform to namespace changes * exportable FormatBlock method * eth_getTransactionByHash * eth_getTransactionByBlockNumberAndIndex * pending nonce * set nonce for pending and check for invalid * WIP: doCall * add pending tx test * cleanup + refactor * push first tests and init pending * pending changes (#600) * cleanup * updates * more fixes * lint * update call and send * comments and minor changes * add pending tests into sep package * fix latest case for eth_GetBlockTransactionCountByNumber * fix repeating null transactions in queue * remove repeated structs * latestblock case * revert init script back * fix to exportable method * automate pending tests; add make cmd * move and comment out pending call test * fix some golint * fix unlock issue * wip: linter stringer fix? * stringer lint * set arr instead of append * instantiate with length * sep if statement * edit pendingblocknumber note * switch statement * fix and update tests * move tests-pending into tests dir * remove commented test * revert to appending pendingtx * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * require no err * rename var * check result for eth_sendTransaction * update changelog * update * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/tests-pending/rpc_pending_test.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * changelog * remove redundant check Co-authored-by: noot <elizabethjbinks@gmail.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>
2020-12-15 19:52:09 +00:00
// LatestBlockNumber gets the latest block height in int64 format.
func (b *EthermintBackend) LatestBlockNumber() (int64, error) {
// NOTE: using 0 as min and max height returns the blockchain info up to the latest block.
2021-04-17 10:00:07 +00:00
info, err := b.clientCtx.Client.BlockchainInfo(context.Background(), 0, 0)
Pending (#571) * add PendingBlockNumber -1 * increase block times * update bn * get pending balance * additional logic to check for pending state * add multiple balance query * pending state for getTransactionCount * fix lint * add getBlockTransactionCountByNumber code - commented * cleanup test * GetBlockTransactionCountByNumber * cleanup * getBlockByNumber * GetTransactionByBlockNumberAndIndex * conform to namespace changes * exportable FormatBlock method * eth_getTransactionByHash * eth_getTransactionByBlockNumberAndIndex * pending nonce * set nonce for pending and check for invalid * WIP: doCall * add pending tx test * cleanup + refactor * push first tests and init pending * pending changes (#600) * cleanup * updates * more fixes * lint * update call and send * comments and minor changes * add pending tests into sep package * fix latest case for eth_GetBlockTransactionCountByNumber * fix repeating null transactions in queue * remove repeated structs * latestblock case * revert init script back * fix to exportable method * automate pending tests; add make cmd * move and comment out pending call test * fix some golint * fix unlock issue * wip: linter stringer fix? * stringer lint * set arr instead of append * instantiate with length * sep if statement * edit pendingblocknumber note * switch statement * fix and update tests * move tests-pending into tests dir * remove commented test * revert to appending pendingtx * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * require no err * rename var * check result for eth_sendTransaction * update changelog * update * Update tests/utils.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update tests/tests-pending/rpc_pending_test.go Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * changelog * remove redundant check Co-authored-by: noot <elizabethjbinks@gmail.com> Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>
2020-12-15 19:52:09 +00:00
if err != nil {
return 0, err
}
return info.LastHeight, nil
}