From c20e4871cde75e8d85f62ed21ac7b0d5de50f71c Mon Sep 17 00:00:00 2001 From: Jonathan Harvey-Buschel Date: Thu, 26 Oct 2023 13:00:17 -0400 Subject: [PATCH] chainrpc+lncli: expose GetBlockHeader + add to CLI --- cmd/lncli/chainrpc_active.go | 40 ++++++++++++++++++++++++++++++++++ cmd/lncli/neutrino_active.go | 8 +++---- lnrpc/chainrpc/chain_server.go | 29 ++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/cmd/lncli/chainrpc_active.go b/cmd/lncli/chainrpc_active.go index 0d8b891ac..48946e0d5 100644 --- a/cmd/lncli/chainrpc_active.go +++ b/cmd/lncli/chainrpc_active.go @@ -25,6 +25,7 @@ func chainCommands() []cli.Command { getBlockCommand, getBestBlockCommand, getBlockHashCommand, + getBlockHeaderCommand, }, }, } @@ -113,6 +114,45 @@ func getBlock(ctx *cli.Context) error { return nil } +var getBlockHeaderCommand = cli.Command{ + Name: "getblockheader", + Usage: "Get a block header.", + Category: "On-chain", + Description: "Returns a block header with a particular block hash.", + ArgsUsage: "hash", + Action: actionDecorator(getBlockHeader), +} + +func getBlockHeader(ctx *cli.Context) error { + ctxc := getContext() + args := ctx.Args() + + // Display the command's help message if we do not have the expected + // number of arguments/flags. + if !args.Present() { + return cli.ShowCommandHelp(ctx, "getblockheader") + } + + blockHash, err := chainhash.NewHashFromStr(args.First()) + if err != nil { + return err + } + + req := &chainrpc.GetBlockHeaderRequest{BlockHash: blockHash[:]} + + client, cleanUp := getChainClient(ctx) + defer cleanUp() + + resp, err := client.GetBlockHeader(ctxc, req) + if err != nil { + return err + } + + printRespJSON(resp) + + return nil +} + var getBestBlockCommand = cli.Command{ Name: "getbestblock", Category: "On-chain", diff --git a/cmd/lncli/neutrino_active.go b/cmd/lncli/neutrino_active.go index 4267738e1..099da46c6 100644 --- a/cmd/lncli/neutrino_active.go +++ b/cmd/lncli/neutrino_active.go @@ -155,16 +155,16 @@ func isBanned(ctx *cli.Context) error { return nil } -var getBlockHeaderCommand = cli.Command{ +var getBlockHeaderNeutrinoCommand = cli.Command{ Name: "getblockheader", Usage: "Get a block header.", Category: "Neutrino", Description: "Returns a block header with a particular block hash.", ArgsUsage: "hash", - Action: actionDecorator(getBlockHeader), + Action: actionDecorator(getBlockHeaderNeutrino), } -func getBlockHeader(ctx *cli.Context) error { +func getBlockHeaderNeutrino(ctx *cli.Context) error { ctxc := getContext() args := ctx.Args() @@ -239,7 +239,7 @@ func neutrinoCommands() []cli.Command { addPeerCommand, disconnectPeerCommand, isBannedCommand, - getBlockHeaderCommand, + getBlockHeaderNeutrinoCommand, getCFilterCommand, }, }, diff --git a/lnrpc/chainrpc/chain_server.go b/lnrpc/chainrpc/chain_server.go index 89f480b8b..00a30c07c 100644 --- a/lnrpc/chainrpc/chain_server.go +++ b/lnrpc/chainrpc/chain_server.go @@ -46,6 +46,10 @@ var ( Entity: "onchain", Action: "read", }}, + "/chainrpc.ChainKit/GetBlockHeader": {{ + Entity: "onchain", + Action: "read", + }}, "/chainrpc.ChainKit/GetBestBlock": {{ Entity: "onchain", Action: "read", @@ -293,6 +297,31 @@ func (s *Server) GetBlock(_ context.Context, return &GetBlockResponse{RawBlock: rawBlock}, nil } +// GetBlockHeader returns a block header given the corresponding block hash. +func (s *Server) GetBlockHeader(_ context.Context, + in *GetBlockHeaderRequest) (*GetBlockHeaderResponse, error) { + + // We'll start by reconstructing the RPC request into what the + // underlying chain functionality expects. + var blockHash chainhash.Hash + copy(blockHash[:], in.BlockHash) + + blockHeader, err := s.cfg.Chain.GetBlockHeader(&blockHash) + if err != nil { + return nil, err + } + + // Serialize block header for RPC response. + var headerBuf bytes.Buffer + err = blockHeader.Serialize(&headerBuf) + if err != nil { + return nil, err + } + rawHeader := headerBuf.Bytes() + + return &GetBlockHeaderResponse{RawBlockHeader: rawHeader}, nil +} + // GetBestBlock returns the latest block hash and current height of the valid // most-work chain. func (s *Server) GetBestBlock(_ context.Context,