diff --git a/pkg/fetch/rpc.go b/pkg/fetch/rpc.go index ac60eb8..f3f61f8 100644 --- a/pkg/fetch/rpc.go +++ b/pkg/fetch/rpc.go @@ -12,26 +12,28 @@ import ( "github.com/grassrootseconomics/w3-celo-patch/w3types" ) +// RPCOpts reprsents the required paramters for an RPC fetcher. type RPCOpts struct { RPCProvider *celo.Provider } +// RPC is a RPC based block and transaction fetcher. type RPC struct { provider *celo.Provider } +// NewRPCFetcher returns a new RPC fetcher which implemnts Fetch. +// Note: No rate limiting feeature. func NewRPCFetcher(o RPCOpts) Fetch { return &RPC{ provider: o.RPCProvider, } } -// This method makes 2 calls. 1 for the block and 1 batched call for txs + receipts. -// Should work on free tier RPC services. +// Block fetches via RPC and transforms the response to adapt to the GraphQL JSON response struct. func (f *RPC) Block(ctx context.Context, blockNumber uint64) (FetchResponse, error) { var ( - block types.Block - + block types.Block fetchResponse FetchResponse ) @@ -39,7 +41,7 @@ func (f *RPC) Block(ctx context.Context, blockNumber uint64) (FetchResponse, err ctx, eth.BlockByNumber(big.NewInt(int64(blockNumber))).Returns(&block), ); err != nil { - return FetchResponse{}, err + return fetchResponse, err } txCount := len(block.Transactions()) @@ -48,6 +50,7 @@ func (f *RPC) Block(ctx context.Context, blockNumber uint64) (FetchResponse, err txs := make([]types.Transaction, txCount) txsReceipt := make([]types.Receipt, txCount) + // Prepare batch calls. for i, tx := range block.Transactions() { batchCalls[i] = eth.Tx(tx.Hash()).Returns(&txs[i]) batchCalls[txCount+i] = eth.TxReceipt(tx.Hash()).Returns(&txsReceipt[i]) @@ -57,32 +60,36 @@ func (f *RPC) Block(ctx context.Context, blockNumber uint64) (FetchResponse, err ctx, batchCalls..., ); err != nil { - return FetchResponse{}, nil + return fetchResponse, err } + // Transform response and adapt to FetchResponse. for i := 0; i < txCount; i++ { - tx := Transaction{} + var txObject Transaction - tx.Block.Number = block.NumberU64() - tx.Block.Timestamp = hexutil.EncodeUint64(block.Time()) - tx.Hash = txsReceipt[i].TxHash.Hex() - tx.Index = txsReceipt[i].TransactionIndex + txObject.Block.Number = block.NumberU64() + txObject.Block.Timestamp = hexutil.EncodeUint64(block.Time()) from, err := types.Sender(types.LatestSignerForChainID(txs[i].ChainId()), &txs[i]) if err != nil { - return FetchResponse{}, err + return fetchResponse, err } + txObject.From.Address = strings.ToLower(from.Hex()) + // This check ignores contract deployment transactions. + if txs[i].To() != nil { + txObject.To.Address = strings.ToLower(txs[i].To().Hex()) + } + txObject.Value = hexutil.EncodeBig(txs[i].Value()) + txObject.InputData = hexutil.Encode(txs[i].Data()) - tx.From.Address = strings.ToLower(from.Hex()) - tx.To.Address = strings.ToLower(txs[i].To().Hex()) - tx.Value = hexutil.EncodeBig(txs[i].Value()) - tx.InputData = hexutil.Encode(txs[i].Data()) - tx.Status = txsReceipt[i].Status - tx.GasUsed = txsReceipt[i].GasUsed + txObject.Hash = txsReceipt[i].TxHash.Hex() + txObject.Index = txsReceipt[i].TransactionIndex + txObject.Status = txsReceipt[i].Status + txObject.GasUsed = txsReceipt[i].GasUsed fetchResponse.Data.Block.Transactions = append( fetchResponse.Data.Block.Transactions, - tx, + txObject, ) }