finish cache miss forwarding for new endpoints

This commit is contained in:
Ian Norden
2020-10-28 08:54:06 -05:00
parent b5d57b6afc
commit 1d4abcb69b
4 changed files with 380 additions and 138 deletions
+124
View File
@@ -17,8 +17,14 @@
package eth
import (
"context"
"encoding/json"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
@@ -87,6 +93,35 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]i
return fields, nil
}
// RPCMarshalBlockWithUncleHashes marshals the block with the provided uncle hashes
func RPCMarshalBlockWithUncleHashes(block *types.Block, uncleHashes []common.Hash, inclTx bool, fullTx bool) (map[string]interface{}, error) {
fields := RPCMarshalHeader(block.Header())
fields["size"] = hexutil.Uint64(block.Size())
if inclTx {
formatTx := func(tx *types.Transaction) (interface{}, error) {
return tx.Hash(), nil
}
if fullTx {
formatTx = func(tx *types.Transaction) (interface{}, error) {
return NewRPCTransactionFromBlockHash(block, tx.Hash()), nil
}
}
txs := block.Transactions()
transactions := make([]interface{}, len(txs))
var err error
for i, tx := range txs {
if transactions[i], err = formatTx(tx); err != nil {
return nil, err
}
}
fields["transactions"] = transactions
}
fields["uncles"] = uncleHashes
return fields, nil
}
// NewRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation.
func NewRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction {
for idx, tx := range b.Transactions() {
@@ -128,6 +163,67 @@ func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
return result
}
type rpcBlock struct {
Hash common.Hash `json:"hash"`
Transactions []rpcTransaction `json:"transactions"`
UncleHashes []common.Hash `json:"uncles"`
}
type rpcTransaction struct {
tx *types.Transaction
txExtraInfo
}
type txExtraInfo struct {
BlockNumber *string `json:"blockNumber,omitempty"`
BlockHash *common.Hash `json:"blockHash,omitempty"`
From *common.Address `json:"from,omitempty"`
}
func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
if err := json.Unmarshal(msg, &tx.tx); err != nil {
return err
}
return json.Unmarshal(msg, &tx.txExtraInfo)
}
func getBlockAndUncleHashes(cli *rpc.Client, ctx context.Context, method string, args ...interface{}) (*types.Block, []common.Hash, error) {
var raw json.RawMessage
err := cli.CallContext(ctx, &raw, method, args...)
if err != nil {
return nil, nil, err
} else if len(raw) == 0 {
return nil, nil, ethereum.NotFound
}
// Decode header and transactions.
var head *types.Header
var body rpcBlock
if err := json.Unmarshal(raw, &head); err != nil {
return nil, nil, err
}
if err := json.Unmarshal(raw, &body); err != nil {
return nil, nil, err
}
// Quick-verify transaction and uncle lists. This mostly helps with debugging the server.
if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 {
return nil, nil, fmt.Errorf("server returned non-empty uncle list but block header indicates no uncles")
}
if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 {
return nil, nil, fmt.Errorf("server returned empty uncle list but block header indicates uncles")
}
if head.TxHash == types.EmptyRootHash && len(body.Transactions) > 0 {
return nil, nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions")
}
if head.TxHash != types.EmptyRootHash && len(body.Transactions) == 0 {
return nil, nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions")
}
txs := make([]*types.Transaction, len(body.Transactions))
for i, tx := range body.Transactions {
txs[i] = tx.tx
}
return types.NewBlockWithHeader(head).WithBody(txs, nil), body.UncleHashes, nil
}
// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes {
txs := b.Transactions()
@@ -194,3 +290,31 @@ func sliceContainsHash(slice []string, hash common.Hash) int {
}
return 0
}
func toFilterArg(q ethereum.FilterQuery) (interface{}, error) {
arg := map[string]interface{}{
"address": q.Addresses,
"topics": q.Topics,
}
if q.BlockHash != nil {
arg["blockHash"] = *q.BlockHash
if q.FromBlock != nil || q.ToBlock != nil {
return nil, fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
}
} else {
if q.FromBlock == nil {
arg["fromBlock"] = "0x0"
} else {
arg["fromBlock"] = toBlockNumArg(q.FromBlock)
}
arg["toBlock"] = toBlockNumArg(q.ToBlock)
}
return arg, nil
}
func toBlockNumArg(number *big.Int) string {
if number == nil {
return "latest"
}
return hexutil.EncodeBig(number)
}