diff --git a/rpc/blockchain.go b/rpc/blockchain.go index 36bf452e66..47d22aa40e 100644 --- a/rpc/blockchain.go +++ b/rpc/blockchain.go @@ -1020,6 +1020,42 @@ func (s *PublicBlockchainService) getBlockOptions(opts interface{}) (*rpc_common } } +func (s *PublicBlockchainService) GetFullHeader( + ctx context.Context, blockNumber BlockNumber, +) (response StructuredResponse, err error) { + // Process number based on version + blockNum := blockNumber.EthBlockNumber() + + // Ensure valid block number + if isBlockGreaterThanLatest(s.hmy, blockNum) { + return nil, ErrRequestedBlockTooHigh + } + + // Fetch Header + header, err := s.hmy.HeaderByNumber(ctx, blockNum) + if err != nil { + return nil, err + } + + var rpcHeader interface{} + switch s.version { + case V2: + rpcHeader, err = v2.NewBlockHeader(header) + default: + return nil, ErrUnknownRPCVersion + } + if err != nil { + return nil, err + } + + response, err = NewStructuredResponse(rpcHeader) + if err != nil { + return nil, err + } + + return response, nil +} + func isBlockGreaterThanLatest(hmy *hmy.Harmony, blockNum rpc.BlockNumber) bool { // rpc.BlockNumber is int64 (latest = -1. pending = -2) and currentBlockNum is uint64. if blockNum == rpc.PendingBlockNumber { diff --git a/rpc/v2/types.go b/rpc/v2/types.go index d7d22e6ce7..0ed710619b 100644 --- a/rpc/v2/types.go +++ b/rpc/v2/types.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/crypto/bls" internal_common "github.com/harmony-one/harmony/internal/common" @@ -46,6 +47,34 @@ type BlockWithTxHash struct { Signers []string `json:"signers,omitempty"` } +// BlockHeader represents a block header that will serialize to the RPC representation of a block header +type BlockHeader struct { + ParentHash common.Hash `json:"parentHash"` + Miner string `json:"miner"` + StateRoot common.Hash `json:"stateRoot"` + TransactionsRoot common.Hash `json:"transactionsRoot"` + ReceiptsRoot common.Hash `json:"receiptsRoot"` + OutgoingReceiptsRoot common.Hash `json:"outgoingReceiptsRoot"` + IncomingReceiptsRoot common.Hash `json:"incomingReceiptsRoot"` + LogsBloom ethtypes.Bloom `json:"logsBloom"` + Number *big.Int `json:"number"` + GasLimit uint64 `json:"gasLimit"` + GasUsed uint64 `json:"gasUsed"` + Timestamp *big.Int `json:"timestamp"` + ExtraData hexutil.Bytes `json:"extraData"` + MixHash common.Hash `json:"mixHash"` + ViewID *big.Int `json:"viewID"` + Epoch *big.Int `json:"epoch"` + ShardID uint32 `json:"shardID"` + LastCommitSignature hexutil.Bytes `json:"lastCommitSignature"` + LastCommitBitmap hexutil.Bytes `json:"lastCommitBitmap"` + Vrf hexutil.Bytes `json:"vrf"` + Vdf hexutil.Bytes `json:"vdf"` + ShardState hexutil.Bytes `json:"shardState"` + CrossLink hexutil.Bytes `json:"crossLink"` + Slashes hexutil.Bytes `json:"slashes"` +} + // BlockWithFullTx represents a block that will serialize to the RPC representation of a block // having FULL transactions in the Transaction & Staking transaction fields. type BlockWithFullTx struct { @@ -679,6 +708,42 @@ func blockWithFullTxFromBlock(b *types.Block) (*BlockWithFullTx, error) { return blk, nil } +func NewBlockHeader( + head *block.Header, +) (*BlockHeader, error) { + lastSig := head.LastCommitSignature() + blk := &BlockHeader{ + ParentHash: head.ParentHash(), + Miner: head.Coinbase().Hex(), + StateRoot: head.Root(), + TransactionsRoot: head.TxHash(), + ReceiptsRoot: head.ReceiptHash(), + OutgoingReceiptsRoot: head.OutgoingReceiptHash(), + IncomingReceiptsRoot: head.IncomingReceiptHash(), + LogsBloom: head.Bloom(), + + Number: head.Number(), + GasLimit: head.GasLimit(), + GasUsed: head.GasUsed(), + Timestamp: head.Time(), + ExtraData: hexutil.Bytes(head.Extra()), + MixHash: head.MixDigest(), + + ViewID: head.ViewID(), + Epoch: head.Epoch(), + ShardID: head.ShardID(), + + LastCommitSignature: hexutil.Bytes(lastSig[:]), + LastCommitBitmap: head.LastCommitBitmap(), + Vrf: head.Vrf(), + Vdf: head.Vdf(), + ShardState: head.ShardState(), + CrossLink: head.CrossLinks(), + Slashes: head.Slashes(), + } + return blk, nil +} + // NewTransactionFromHash returns a transaction that will serialize to the RPC representation. func NewTransactionFromHash(b *types.Block, hash common.Hash) (*Transaction, error) { for idx, tx := range b.Transactions() {