diff --git a/eth/api_backend.go b/eth/api_backend.go index 55a8980c25..548169270b 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -76,16 +76,16 @@ func (b *EthAPIBackend) SetHead(number uint64) { b.eth.blockchain.SetHead(number) } -func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) { +func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { // Pending block is only known by the miner - if blockNr == rpc.PendingBlockNumber { - blockNr = rpc.LatestBlockNumber + if number == rpc.PendingBlockNumber { + number = rpc.LatestBlockNumber } // Otherwise resolve and return the block - if blockNr == rpc.LatestBlockNumber { + if number == rpc.LatestBlockNumber { return b.eth.blockchain.CurrentBlock().Header(), nil } - if blockNr == rpc.CommittedBlockNumber { + if number == rpc.CommittedBlockNumber { if b.eth.chainConfig.XDPoS == nil { return nil, errors.New("PoW does not support confirmed block lookup") } @@ -102,7 +102,7 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNum return nil, errors.New("PoS V1 does not support confirmed block lookup") } } - header := b.eth.blockchain.GetHeaderByNumber(uint64(blockNr)) + header := b.eth.blockchain.GetHeaderByNumber(uint64(number)) if header == nil { return nil, errors.New("header for number not found") } @@ -130,16 +130,16 @@ func (b *EthAPIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*ty return b.eth.blockchain.GetHeaderByHash(hash), nil } -func (b *EthAPIBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) { +func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { // Pending block is only known by the miner - if blockNr == rpc.PendingBlockNumber { - blockNr = rpc.LatestBlockNumber + if number == rpc.PendingBlockNumber { + number = rpc.LatestBlockNumber } // Otherwise resolve and return the block - if blockNr == rpc.LatestBlockNumber { + if number == rpc.LatestBlockNumber { return b.eth.blockchain.CurrentBlock(), nil } - if blockNr == rpc.CommittedBlockNumber { + if number == rpc.CommittedBlockNumber { if b.eth.chainConfig.XDPoS == nil { return nil, errors.New("PoW does not support confirmed block lookup") } @@ -156,7 +156,7 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumb return nil, errors.New("PoS V1 does not support confirmed block lookup") } } - return b.eth.blockchain.GetBlockByNumber(uint64(blockNr)), nil + return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil } func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { @@ -199,13 +199,13 @@ func (b *EthAPIBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) return b.eth.miner.PendingBlockAndReceipts() } -func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) { +func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) { // Pending state is only known by the miner - if blockNr == rpc.PendingBlockNumber { - blockNr = rpc.LatestBlockNumber + if number == rpc.PendingBlockNumber { + number = rpc.LatestBlockNumber } // Otherwise resolve the block number and return its state - header, err := b.HeaderByNumber(ctx, blockNr) + header, err := b.HeaderByNumber(ctx, number) if err != nil { return nil, nil, err } @@ -243,8 +243,12 @@ func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockN return nil, nil, errors.New("invalid arguments; neither block nor hash specified") } -func (b *EthAPIBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) { - return b.eth.blockchain.GetBlockByHash(blockHash), nil +func (b *EthAPIBackend) GetHeader(ctx context.Context, hash common.Hash) *types.Header { + return b.eth.blockchain.GetHeaderByHash(hash) +} + +func (b *EthAPIBackend) GetBlock(ctx context.Context, hash common.Hash) (*types.Block, error) { + return b.eth.blockchain.GetBlockByHash(hash), nil } func (b *EthAPIBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index c4ddc99068..d1ae5f3f8f 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -377,13 +377,42 @@ func (s *BlockChainAPI) GetTransactionAndReceiptProof(ctx context.Context, hash return fields, nil } +// GetHeaderByNumber returns the requested canonical block header. +// - When blockNr is -1 the chain pending header is returned. +// - When blockNr is -2 the chain latest header is returned. +// - When blockNr is -3 the chain finalized header is returned. +// - When blockNr is -4 the chain safe header is returned. +func (api *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) { + header, err := api.b.HeaderByNumber(ctx, number) + if header != nil && err == nil { + response := RPCMarshalHeader(header) + if number == rpc.PendingBlockNumber { + // Pending header need to nil out a few fields + for _, field := range []string{"hash", "nonce", "miner"} { + response[field] = nil + } + } + return response, err + } + return nil, err +} + +// GetHeaderByHash returns the requested header by hash. +func (api *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} { + header, _ := api.b.HeaderByHash(ctx, hash) + if header != nil { + return RPCMarshalHeader(header) + } + return nil +} + // GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all // transactions in the block are returned in full detail, otherwise only the transaction hash is returned. -func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { - block, err := s.b.BlockByNumber(ctx, blockNr) +func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { + block, err := s.b.BlockByNumber(ctx, number) if block != nil { - response, err := s.rpcOutputBlock(block, true, fullTx) - if err == nil && blockNr == rpc.PendingBlockNumber { + response, err := s.rpcMarshalBlock(block, true, fullTx) + if err == nil && number == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { response[field] = nil @@ -396,10 +425,10 @@ func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockN // GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full // detail, otherwise only the transaction hash is returned. -func (s *BlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) { - block, err := s.b.GetBlock(ctx, blockHash) +func (s *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { + block, err := s.b.GetBlock(ctx, hash) if block != nil { - return s.rpcOutputBlock(block, true, fullTx) + return s.rpcMarshalBlock(block, true, fullTx) } return nil, err } @@ -415,7 +444,7 @@ func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, block return nil, nil } block = types.NewBlockWithHeader(uncles[index]) - return s.rpcOutputBlock(block, false, false) + return s.rpcMarshalBlock(block, false, false) } return nil, err } @@ -432,7 +461,7 @@ func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHa return nil, nil } block = types.NewBlockWithHeader(uncles[index]) - return s.rpcOutputBlock(block, false, false) + return s.rpcMarshalBlock(block, false, false) } return nil, err } @@ -1311,9 +1340,9 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { // RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // transaction hashes. -func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields := RPCMarshalHeader(b.Header()) - fields["size"] = hexutil.Uint64(b.Size()) +func RPCMarshalBlock(block *types.Block, 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) { @@ -1321,10 +1350,10 @@ func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]inter } if fullTx { formatTx = func(tx *types.Transaction) (interface{}, error) { - return newRPCTransactionFromBlockHash(b, tx.Hash()), nil + return newRPCTransactionFromBlockHash(block, tx.Hash()), nil } } - txs := b.Transactions() + txs := block.Transactions() transactions := make([]interface{}, len(txs)) var err error for i, tx := range txs { @@ -1334,20 +1363,18 @@ func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]inter } fields["transactions"] = transactions } - - uncles := b.Uncles() + uncles := block.Uncles() uncleHashes := make([]common.Hash, len(uncles)) for i, uncle := range uncles { uncleHashes[i] = uncle.Hash() } fields["uncles"] = uncleHashes - return fields, nil } -// rpcOutputBlock uses the generalized output filler, then adds the total difficulty field, which requires +// rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires // a `BlockChainAPI`. -func (s *BlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { +func (s *BlockChainAPI) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { fields, err := RPCMarshalBlock(b, inclTx, fullTx) if err != nil { return nil, err diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 70157564c8..40f07ec025 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -62,19 +62,19 @@ type Backend interface { // BlockChain API SetHead(number uint64) - HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) + HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) CurrentHeader() *types.Header - BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) + BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) - StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error) + StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) - GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) + GetBlock(ctx context.Context, hash common.Hash) (*types.Block, error) PendingBlockAndReceipts() (*types.Block, types.Receipts) - GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) - GetTd(ctx context.Context, blockHash common.Hash) *big.Int + GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) + GetTd(ctx context.Context, hash common.Hash) *big.Int GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, XDCxState *tradingstate.TradingStateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 4d83ed708d..1dd31ee74c 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -521,6 +521,29 @@ web3._extend({ params: 1, inputFormatter: [web3._extend.formatters.inputTransactionFormatter] }), + new web3._extend.Method({ + name: 'getHeaderByNumber', + call: 'eth_getHeaderByNumber', + params: 1, + inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] + }), + new web3._extend.Method({ + name: 'getHeaderByHash', + call: 'eth_getHeaderByHash', + params: 1 + }), + new web3._extend.Method({ + name: 'getBlockByNumber', + call: 'eth_getBlockByNumber', + params: 2, + inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter, function (val) { return !!val; }] + }), + new web3._extend.Method({ + name: 'getBlockByHash', + call: 'eth_getBlockByHash', + params: 2, + inputFormatter: [null, function (val) { return !!val; }] + }), new web3._extend.Method({ name: 'getRawTransaction', call: 'eth_getRawTransactionByHash',