cmd: add chain subcommand

Chain subcommand includes the commands: getblock, getbestblock, and getblockhash.

This commit removes conflicting neutrino cli commands.
This commit is contained in:
ffranr 2022-12-01 17:30:00 +00:00
parent 1345b3c0aa
commit bab526f655
No known key found for this signature in database
GPG key ID: B1F8848557AA29D2
6 changed files with 234 additions and 82 deletions

View file

@ -0,0 +1,219 @@
//go:build chainrpc
// +build chainrpc
package main
import (
"bytes"
"fmt"
"strconv"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/lnrpc/chainrpc"
"github.com/urfave/cli"
)
// chainCommands will return the set of commands to enable for chainrpc builds.
func chainCommands() []cli.Command {
return []cli.Command{
{
Name: "chain",
Category: "On-chain",
Usage: "Interact with the bitcoin blockchain.",
Subcommands: []cli.Command{
getBlockCommand,
getBestBlockCommand,
getBlockHashCommand,
},
},
}
}
func getChainClient(ctx *cli.Context) (chainrpc.ChainKitClient, func()) {
conn := getClientConn(ctx, false)
cleanUp := func() {
conn.Close()
}
return chainrpc.NewChainKitClient(conn), cleanUp
}
var getBlockCommand = cli.Command{
Name: "getblock",
Category: "On-chain",
Usage: "Get block by block hash.",
Description: "Returns a block given the corresponding block hash.",
Flags: []cli.Flag{
cli.StringFlag{
Name: "hash",
Usage: "the target block hash",
},
cli.BoolFlag{
Name: "verbose",
Usage: "print entire block as JSON",
},
},
Action: actionDecorator(getBlock),
}
func getBlock(ctx *cli.Context) error {
ctxc := getContext()
var (
args = ctx.Args()
blockHashString string
)
verbose := false
if ctx.IsSet("verbose") {
verbose = true
}
switch {
case ctx.IsSet("hash"):
blockHashString = ctx.String("hash")
case args.Present():
blockHashString = args.First()
default:
return fmt.Errorf("hash argument missing")
}
blockHash, err := chainhash.NewHashFromStr(blockHashString)
if err != nil {
return err
}
client, cleanUp := getChainClient(ctx)
defer cleanUp()
req := &chainrpc.GetBlockRequest{BlockHash: blockHash.CloneBytes()}
resp, err := client.GetBlock(ctxc, req)
if err != nil {
return err
}
// Convert raw block bytes into wire.MsgBlock.
msgBlock := &wire.MsgBlock{}
blockReader := bytes.NewReader(resp.RawBlock)
err = msgBlock.Deserialize(blockReader)
if err != nil {
return err
}
if verbose {
printJSON(msgBlock)
} else {
printJSON(msgBlock.Header)
}
return nil
}
var getBestBlockCommand = cli.Command{
Name: "getbestblock",
Category: "On-chain",
Usage: "Get best block.",
Description: "Returns the latest block hash and height from the " +
"valid most-work chain.",
Action: actionDecorator(getBestBlock),
}
func getBestBlock(ctx *cli.Context) error {
ctxc := getContext()
client, cleanUp := getChainClient(ctx)
defer cleanUp()
resp, err := client.GetBestBlock(ctxc, &chainrpc.GetBestBlockRequest{})
if err != nil {
return err
}
// Cast gRPC block hash bytes as chain hash type.
var blockHash chainhash.Hash
copy(blockHash[:], resp.BlockHash)
printJSON(struct {
BlockHash chainhash.Hash `json:"block_hash"`
BlockHeight int32 `json:"block_height"`
}{
BlockHash: blockHash,
BlockHeight: resp.BlockHeight,
})
return nil
}
var getBlockHashCommand = cli.Command{
Name: "getblockhash",
Category: "On-chain",
Usage: "Get block hash by block height.",
Description: "Returns the block hash from the best chain at a given " +
"height.",
Flags: []cli.Flag{
cli.Int64Flag{
Name: "height",
Usage: "target block height",
},
},
Action: actionDecorator(getBlockHash),
}
func getBlockHash(ctx *cli.Context) error {
ctxc := getContext()
// Display the command's help message if we do not have the expected
// number of arguments/flags.
if ctx.NArg()+ctx.NumFlags() != 1 {
return cli.ShowCommandHelp(ctx, "getblockhash")
}
var (
args = ctx.Args()
blockHeight int64
)
switch {
case ctx.IsSet("height"):
blockHeight = ctx.Int64("height")
case args.Present():
blockHeightString := args.First()
// Convert block height positional argument from string to
// int64.
var err error
blockHeight, err = strconv.ParseInt(blockHeightString, 10, 64)
if err != nil {
return err
}
default:
return fmt.Errorf("block height argument missing")
}
client, cleanUp := getChainClient(ctx)
defer cleanUp()
req := &chainrpc.GetBlockHashRequest{BlockHeight: blockHeight}
resp, err := client.GetBlockHash(ctxc, req)
if err != nil {
return err
}
// Cast gRPC block hash bytes as chain hash type.
var blockHash chainhash.Hash
copy(blockHash[:], resp.BlockHash)
printJSON(struct {
BlockHash chainhash.Hash `json:"block_hash"`
}{
BlockHash: blockHash,
})
return nil
}

View file

@ -0,0 +1,11 @@
//go:build !chainrpc
// +build !chainrpc
package main
import "github.com/urfave/cli"
// chainCommands will return nil for non-chainrpc builds.
func chainCommands() []cli.Command {
return nil
}

View file

@ -500,6 +500,7 @@ func main() {
app.Commands = append(app.Commands, wtclientCommands()...)
app.Commands = append(app.Commands, devCommands()...)
app.Commands = append(app.Commands, peersCommands()...)
app.Commands = append(app.Commands, chainCommands()...)
if err := app.Run(os.Args); err != nil {
fatal(err)

View file

@ -4,8 +4,6 @@
package main
import (
"strconv"
"github.com/lightningnetwork/lnd/lnrpc/neutrinorpc"
"github.com/urfave/cli"
)
@ -193,42 +191,6 @@ func getBlockHeader(ctx *cli.Context) error {
return nil
}
var getBlockCommand = cli.Command{
Name: "getblock",
Usage: "Get a block.",
Category: "Neutrino",
Description: "Returns a block with a particular block hash.",
ArgsUsage: "hash",
Action: actionDecorator(getBlock),
}
func getBlock(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, "getblock")
}
client, cleanUp := getNeutrinoKitClient(ctx)
defer cleanUp()
req := &neutrinorpc.GetBlockRequest{
Hash: args.First(),
}
resp, err := client.GetBlock(ctxc, req)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}
var getCFilterCommand = cli.Command{
Name: "getcfilter",
Usage: "Get a compact filter.",
@ -263,47 +225,6 @@ func getCFilter(ctx *cli.Context) error {
return nil
}
var getBlockHashCommand = cli.Command{
Name: "getblockhash",
Usage: "Get a block hash.",
Category: "Neutrino",
Description: "Returns the header hash of a block at a given height.",
ArgsUsage: "height",
Action: actionDecorator(getBlockHash),
}
func getBlockHash(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, "getblockhash")
}
client, cleanUp := getNeutrinoKitClient(ctx)
defer cleanUp()
height, err := strconv.ParseInt(args.First(), 10, 32)
if err != nil {
return err
}
req := &neutrinorpc.GetBlockHashRequest{
Height: int32(height),
}
resp, err := client.GetBlockHash(ctxc, req)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}
// neutrinoCommands will return the set of commands to enable for neutrinorpc
// builds.
func neutrinoCommands() []cli.Command {
@ -318,10 +239,8 @@ func neutrinoCommands() []cli.Command {
addPeerCommand,
disconnectPeerCommand,
isBannedCommand,
getBlockCommand,
getBlockHeaderCommand,
getCFilterCommand,
getBlockHashCommand,
},
},
}

2
go.mod
View file

@ -7,7 +7,7 @@ require (
github.com/btcsuite/btcd/btcec/v2 v2.2.2
github.com/btcsuite/btcd/btcutil v1.1.3
github.com/btcsuite/btcd/btcutil/psbt v1.1.5
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f
github.com/btcsuite/btcwallet v0.16.6-0.20221203002441-6c7480c8a46b
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.2

2
go.sum
View file

@ -96,6 +96,8 @@ github.com/btcsuite/btcd/btcutil/psbt v1.1.5/go.mod h1:kA6FLH/JfUx++j9pYU0pyu+Z8
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=