Merge pull request #7197 from ffranr/add_chain_rpc_calls

lncli+chainrpc: add chainkit RPC service with endpoints GetBlock, GetBestBlock, GetBlockHash
This commit is contained in:
Oliver Gugger 2022-12-07 17:32:54 +01:00 committed by GitHub
commit a0385a535b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1771 additions and 90 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,
},
},
}

View File

@ -73,6 +73,11 @@
`ListInvoiceRequest` and
`ListPaymentsRequest`](https://github.com/lightningnetwork/lnd/pull/7159).
* [Add chainkit RPC endpoints](https://github.com/lightningnetwork/lnd/pull/7197):
GetBlock, GetBestBlock, GetBlockHash. These endpoints provide access to chain
block data.
## Wallet
* [Allows Taproot public keys and tap scripts to be imported as watch-only
@ -205,6 +210,11 @@ certain large transactions](https://github.com/lightningnetwork/lnd/pull/7100).
* [Allow lncli to read binary PSBTs](https://github.com/lightningnetwork/lnd/pull/7122)
from a file during PSBT channel funding flow to comply with [BIP 174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#specification)
* [Add interface to chainkit RPC](https://github.com/lightningnetwork/lnd/pull/7197).
This addition consists of the `chain` subcommand group: `getblock`,
`getblockhash`, and `getbestblock`. These commands provide access to chain
block data.
## Code Health
* [test: use `T.TempDir` to create temporary test

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=

View File

@ -42,6 +42,18 @@ var (
// macPermissions maps RPC calls to the permissions they require.
macPermissions = map[string][]bakery.Op{
"/chainrpc.ChainKit/GetBlock": {{
Entity: "onchain",
Action: "read",
}},
"/chainrpc.ChainKit/GetBestBlock": {{
Entity: "onchain",
Action: "read",
}},
"/chainrpc.ChainKit/GetBlockHash": {{
Entity: "onchain",
Action: "read",
}},
"/chainrpc.ChainNotifier/RegisterConfirmationsNtfn": {{
Entity: "onchain",
Action: "read",
@ -77,17 +89,19 @@ var (
// It is used to register the gRPC sub-server with the root server before we
// have the necessary dependencies to populate the actual sub-server.
type ServerShell struct {
ChainKitServer
ChainNotifierServer
}
// Server is a sub-server of the main RPC server: the chain notifier RPC. This
// RPC sub-server allows external callers to access the full chain notifier
// capabilities of lnd. This allows callers to create custom protocols, external
// to lnd, even backed by multiple distinct lnd across independent failure
// domains.
// Server is a sub-server of the main RPC server. It serves the chainkit RPC
// and chain notifier RPC. This RPC sub-server allows external callers to access
// the full chainkit and chain notifier capabilities of lnd. This allows callers
// to create custom protocols, external to lnd, even backed by multiple distinct
// lnd across independent failure domains.
type Server struct {
// Required by the grpc-gateway/v2 library for forward compatibility.
UnimplementedChainNotifierServer
UnimplementedChainKitServer
started sync.Once
stopped sync.Once
@ -149,8 +163,10 @@ func New(cfg *Config) (*Server, lnrpc.MacaroonPerms, error) {
}
// Compile-time checks to ensure that Server fully implements the
// ChainNotifierServer gRPC service and lnrpc.SubServer interface.
// ChainNotifierServer gRPC service, ChainKitServer gRPC service, and
// lnrpc.SubServer interface.
var _ ChainNotifierServer = (*Server)(nil)
var _ ChainKitServer = (*Server)(nil)
var _ lnrpc.SubServer = (*Server)(nil)
// Start launches any helper goroutines required for the server to function.
@ -188,10 +204,13 @@ func (r *ServerShell) RegisterWithRootServer(grpcServer *grpc.Server) error {
// We make sure that we register it with the main gRPC server to ensure
// all our methods are routed properly.
RegisterChainNotifierServer(grpcServer, r)
log.Debug("ChainNotifier RPC server successfully register with root " +
"gRPC server")
RegisterChainKitServer(grpcServer, r)
log.Debug("ChainKit RPC server successfully register with root gRPC " +
"server")
return nil
}
@ -214,6 +233,18 @@ func (r *ServerShell) RegisterWithRestServer(ctx context.Context,
log.Debugf("ChainNotifier REST server successfully registered with " +
"root REST server")
// Register chainkit with the main REST server to ensure all our methods
// are routed properly.
err = RegisterChainKitHandlerFromEndpoint(ctx, mux, dest, opts)
if err != nil {
log.Errorf("Could not register ChainKit REST server with root "+
"REST server: %v", err)
return err
}
log.Debugf("ChainKit REST server successfully registered with root " +
"REST server")
return nil
}
@ -233,9 +264,66 @@ func (r *ServerShell) CreateSubServer(configRegistry lnrpc.SubServerConfigDispat
}
r.ChainNotifierServer = subServer
r.ChainKitServer = subServer
return subServer, macPermissions, nil
}
// GetBlock returns a block given the corresponding block hash.
func (s *Server) GetBlock(ctx context.Context,
in *GetBlockRequest) (*GetBlockResponse, error) {
// We'll start by reconstructing the RPC request into what the
// underlying chain functionality expects.
var blockHash chainhash.Hash
copy(blockHash[:], in.BlockHash)
block, err := s.cfg.Chain.GetBlock(&blockHash)
if err != nil {
return nil, err
}
// Serialize block for RPC response.
var blockBuf bytes.Buffer
err = block.Serialize(&blockBuf)
if err != nil {
return nil, err
}
rawBlock := blockBuf.Bytes()
return &GetBlockResponse{RawBlock: rawBlock}, nil
}
// GetBestBlock returns the latest block hash and current height of the valid
// most-work chain.
func (s *Server) GetBestBlock(ctx context.Context,
req *GetBestBlockRequest) (*GetBestBlockResponse, error) {
blockHash, blockHeight, err := s.cfg.Chain.GetBestBlock()
if err != nil {
return nil, err
}
return &GetBestBlockResponse{
BlockHash: blockHash[:],
BlockHeight: blockHeight,
}, nil
}
// GetBlockHash returns the hash of the block in the best blockchain
// at the given height.
func (s *Server) GetBlockHash(ctx context.Context,
req *GetBlockHashRequest) (*GetBlockHashResponse, error) {
blockHash, err := s.cfg.Chain.GetBlockHash(req.BlockHeight)
if err != nil {
return nil, err
}
return &GetBlockHashResponse{
BlockHash: blockHash[:],
}, nil
}
// RegisterConfirmationsNtfn is a synchronous response-streaming RPC that
// registers an intent for a client to be notified once a confirmation request
// has reached its required number of confirmations on-chain.

View File

@ -0,0 +1,490 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.6.1
// source: chainrpc/chainkit.proto
package chainrpc
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GetBlockRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The hash of the requested block.
BlockHash []byte `protobuf:"bytes,1,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"`
}
func (x *GetBlockRequest) Reset() {
*x = GetBlockRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_chainrpc_chainkit_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetBlockRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetBlockRequest) ProtoMessage() {}
func (x *GetBlockRequest) ProtoReflect() protoreflect.Message {
mi := &file_chainrpc_chainkit_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetBlockRequest.ProtoReflect.Descriptor instead.
func (*GetBlockRequest) Descriptor() ([]byte, []int) {
return file_chainrpc_chainkit_proto_rawDescGZIP(), []int{0}
}
func (x *GetBlockRequest) GetBlockHash() []byte {
if x != nil {
return x.BlockHash
}
return nil
}
// TODO(ffranr): The neutrino GetBlock response includes many
// additional helpful fields. Consider adding them here also.
type GetBlockResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The raw bytes of the requested block.
RawBlock []byte `protobuf:"bytes,1,opt,name=raw_block,json=rawBlock,proto3" json:"raw_block,omitempty"`
}
func (x *GetBlockResponse) Reset() {
*x = GetBlockResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_chainrpc_chainkit_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetBlockResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetBlockResponse) ProtoMessage() {}
func (x *GetBlockResponse) ProtoReflect() protoreflect.Message {
mi := &file_chainrpc_chainkit_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetBlockResponse.ProtoReflect.Descriptor instead.
func (*GetBlockResponse) Descriptor() ([]byte, []int) {
return file_chainrpc_chainkit_proto_rawDescGZIP(), []int{1}
}
func (x *GetBlockResponse) GetRawBlock() []byte {
if x != nil {
return x.RawBlock
}
return nil
}
type GetBestBlockRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *GetBestBlockRequest) Reset() {
*x = GetBestBlockRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_chainrpc_chainkit_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetBestBlockRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetBestBlockRequest) ProtoMessage() {}
func (x *GetBestBlockRequest) ProtoReflect() protoreflect.Message {
mi := &file_chainrpc_chainkit_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetBestBlockRequest.ProtoReflect.Descriptor instead.
func (*GetBestBlockRequest) Descriptor() ([]byte, []int) {
return file_chainrpc_chainkit_proto_rawDescGZIP(), []int{2}
}
type GetBestBlockResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The hash of the best block.
BlockHash []byte `protobuf:"bytes,1,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"`
// The height of the best block.
BlockHeight int32 `protobuf:"varint,2,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"`
}
func (x *GetBestBlockResponse) Reset() {
*x = GetBestBlockResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_chainrpc_chainkit_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetBestBlockResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetBestBlockResponse) ProtoMessage() {}
func (x *GetBestBlockResponse) ProtoReflect() protoreflect.Message {
mi := &file_chainrpc_chainkit_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetBestBlockResponse.ProtoReflect.Descriptor instead.
func (*GetBestBlockResponse) Descriptor() ([]byte, []int) {
return file_chainrpc_chainkit_proto_rawDescGZIP(), []int{3}
}
func (x *GetBestBlockResponse) GetBlockHash() []byte {
if x != nil {
return x.BlockHash
}
return nil
}
func (x *GetBestBlockResponse) GetBlockHeight() int32 {
if x != nil {
return x.BlockHeight
}
return 0
}
type GetBlockHashRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Block height of the target best chain block.
BlockHeight int64 `protobuf:"varint,1,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"`
}
func (x *GetBlockHashRequest) Reset() {
*x = GetBlockHashRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_chainrpc_chainkit_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetBlockHashRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetBlockHashRequest) ProtoMessage() {}
func (x *GetBlockHashRequest) ProtoReflect() protoreflect.Message {
mi := &file_chainrpc_chainkit_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetBlockHashRequest.ProtoReflect.Descriptor instead.
func (*GetBlockHashRequest) Descriptor() ([]byte, []int) {
return file_chainrpc_chainkit_proto_rawDescGZIP(), []int{4}
}
func (x *GetBlockHashRequest) GetBlockHeight() int64 {
if x != nil {
return x.BlockHeight
}
return 0
}
type GetBlockHashResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The hash of the best block at the specified height.
BlockHash []byte `protobuf:"bytes,1,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"`
}
func (x *GetBlockHashResponse) Reset() {
*x = GetBlockHashResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_chainrpc_chainkit_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetBlockHashResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetBlockHashResponse) ProtoMessage() {}
func (x *GetBlockHashResponse) ProtoReflect() protoreflect.Message {
mi := &file_chainrpc_chainkit_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetBlockHashResponse.ProtoReflect.Descriptor instead.
func (*GetBlockHashResponse) Descriptor() ([]byte, []int) {
return file_chainrpc_chainkit_proto_rawDescGZIP(), []int{5}
}
func (x *GetBlockHashResponse) GetBlockHash() []byte {
if x != nil {
return x.BlockHash
}
return nil
}
var File_chainrpc_chainkit_proto protoreflect.FileDescriptor
var file_chainrpc_chainkit_proto_rawDesc = []byte{
0x0a, 0x17, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e,
0x6b, 0x69, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e,
0x72, 0x70, 0x63, 0x22, 0x30, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f,
0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0x2f, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63,
0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x61, 0x77,
0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x61,
0x77, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x15, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x42, 0x65, 0x73,
0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x58, 0x0a,
0x14, 0x47, 0x65, 0x74, 0x42, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68,
0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x48, 0x61, 0x73, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65,
0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x38, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21,
0x0a, 0x0c, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x01,
0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x69, 0x67, 0x68,
0x74, 0x22, 0x35, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73,
0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6c, 0x6f,
0x63, 0x6b, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x32, 0xeb, 0x01, 0x0a, 0x08, 0x43, 0x68, 0x61,
0x69, 0x6e, 0x4b, 0x69, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63,
0x6b, 0x12, 0x19, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74,
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x63,
0x68, 0x61, 0x69, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x42,
0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x1d, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e,
0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72,
0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x65, 0x73, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1d, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72,
0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x70,
0x63, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6e, 0x65,
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x72, 0x70, 0x63, 0x2f,
0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_chainrpc_chainkit_proto_rawDescOnce sync.Once
file_chainrpc_chainkit_proto_rawDescData = file_chainrpc_chainkit_proto_rawDesc
)
func file_chainrpc_chainkit_proto_rawDescGZIP() []byte {
file_chainrpc_chainkit_proto_rawDescOnce.Do(func() {
file_chainrpc_chainkit_proto_rawDescData = protoimpl.X.CompressGZIP(file_chainrpc_chainkit_proto_rawDescData)
})
return file_chainrpc_chainkit_proto_rawDescData
}
var file_chainrpc_chainkit_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_chainrpc_chainkit_proto_goTypes = []interface{}{
(*GetBlockRequest)(nil), // 0: chainrpc.GetBlockRequest
(*GetBlockResponse)(nil), // 1: chainrpc.GetBlockResponse
(*GetBestBlockRequest)(nil), // 2: chainrpc.GetBestBlockRequest
(*GetBestBlockResponse)(nil), // 3: chainrpc.GetBestBlockResponse
(*GetBlockHashRequest)(nil), // 4: chainrpc.GetBlockHashRequest
(*GetBlockHashResponse)(nil), // 5: chainrpc.GetBlockHashResponse
}
var file_chainrpc_chainkit_proto_depIdxs = []int32{
0, // 0: chainrpc.ChainKit.GetBlock:input_type -> chainrpc.GetBlockRequest
2, // 1: chainrpc.ChainKit.GetBestBlock:input_type -> chainrpc.GetBestBlockRequest
4, // 2: chainrpc.ChainKit.GetBlockHash:input_type -> chainrpc.GetBlockHashRequest
1, // 3: chainrpc.ChainKit.GetBlock:output_type -> chainrpc.GetBlockResponse
3, // 4: chainrpc.ChainKit.GetBestBlock:output_type -> chainrpc.GetBestBlockResponse
5, // 5: chainrpc.ChainKit.GetBlockHash:output_type -> chainrpc.GetBlockHashResponse
3, // [3:6] is the sub-list for method output_type
0, // [0:3] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_chainrpc_chainkit_proto_init() }
func file_chainrpc_chainkit_proto_init() {
if File_chainrpc_chainkit_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_chainrpc_chainkit_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetBlockRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_chainrpc_chainkit_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetBlockResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_chainrpc_chainkit_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetBestBlockRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_chainrpc_chainkit_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetBestBlockResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_chainrpc_chainkit_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetBlockHashRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_chainrpc_chainkit_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetBlockHashResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_chainrpc_chainkit_proto_rawDesc,
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_chainrpc_chainkit_proto_goTypes,
DependencyIndexes: file_chainrpc_chainkit_proto_depIdxs,
MessageInfos: file_chainrpc_chainkit_proto_msgTypes,
}.Build()
File_chainrpc_chainkit_proto = out.File
file_chainrpc_chainkit_proto_rawDesc = nil
file_chainrpc_chainkit_proto_goTypes = nil
file_chainrpc_chainkit_proto_depIdxs = nil
}

View File

@ -0,0 +1,317 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: chainrpc/chainkit.proto
/*
Package chainrpc is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package chainrpc
import (
"context"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = metadata.Join
var (
filter_ChainKit_GetBlock_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_ChainKit_GetBlock_0(ctx context.Context, marshaler runtime.Marshaler, client ChainKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetBlockRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ChainKit_GetBlock_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GetBlock(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ChainKit_GetBlock_0(ctx context.Context, marshaler runtime.Marshaler, server ChainKitServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetBlockRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ChainKit_GetBlock_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.GetBlock(ctx, &protoReq)
return msg, metadata, err
}
func request_ChainKit_GetBestBlock_0(ctx context.Context, marshaler runtime.Marshaler, client ChainKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetBestBlockRequest
var metadata runtime.ServerMetadata
msg, err := client.GetBestBlock(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ChainKit_GetBestBlock_0(ctx context.Context, marshaler runtime.Marshaler, server ChainKitServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetBestBlockRequest
var metadata runtime.ServerMetadata
msg, err := server.GetBestBlock(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_ChainKit_GetBlockHash_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_ChainKit_GetBlockHash_0(ctx context.Context, marshaler runtime.Marshaler, client ChainKitClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetBlockHashRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ChainKit_GetBlockHash_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GetBlockHash(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ChainKit_GetBlockHash_0(ctx context.Context, marshaler runtime.Marshaler, server ChainKitServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetBlockHashRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ChainKit_GetBlockHash_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.GetBlockHash(ctx, &protoReq)
return msg, metadata, err
}
// RegisterChainKitHandlerServer registers the http handlers for service ChainKit to "mux".
// UnaryRPC :call ChainKitServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterChainKitHandlerFromEndpoint instead.
func RegisterChainKitHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ChainKitServer) error {
mux.Handle("GET", pattern_ChainKit_GetBlock_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/chainrpc.ChainKit/GetBlock", runtime.WithHTTPPathPattern("/v2/chainkit/block"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ChainKit_GetBlock_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ChainKit_GetBlock_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ChainKit_GetBestBlock_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/chainrpc.ChainKit/GetBestBlock", runtime.WithHTTPPathPattern("/v2/chainkit/bestblock"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ChainKit_GetBestBlock_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ChainKit_GetBestBlock_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ChainKit_GetBlockHash_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/chainrpc.ChainKit/GetBlockHash", runtime.WithHTTPPathPattern("/v2/chainkit/blockhash"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ChainKit_GetBlockHash_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ChainKit_GetBlockHash_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterChainKitHandlerFromEndpoint is same as RegisterChainKitHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterChainKitHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterChainKitHandler(ctx, mux, conn)
}
// RegisterChainKitHandler registers the http handlers for service ChainKit to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterChainKitHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterChainKitHandlerClient(ctx, mux, NewChainKitClient(conn))
}
// RegisterChainKitHandlerClient registers the http handlers for service ChainKit
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ChainKitClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ChainKitClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "ChainKitClient" to call the correct interceptors.
func RegisterChainKitHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ChainKitClient) error {
mux.Handle("GET", pattern_ChainKit_GetBlock_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/chainrpc.ChainKit/GetBlock", runtime.WithHTTPPathPattern("/v2/chainkit/block"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ChainKit_GetBlock_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ChainKit_GetBlock_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ChainKit_GetBestBlock_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/chainrpc.ChainKit/GetBestBlock", runtime.WithHTTPPathPattern("/v2/chainkit/bestblock"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ChainKit_GetBestBlock_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ChainKit_GetBestBlock_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ChainKit_GetBlockHash_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/chainrpc.ChainKit/GetBlockHash", runtime.WithHTTPPathPattern("/v2/chainkit/blockhash"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ChainKit_GetBlockHash_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ChainKit_GetBlockHash_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_ChainKit_GetBlock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "chainkit", "block"}, ""))
pattern_ChainKit_GetBestBlock_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "chainkit", "bestblock"}, ""))
pattern_ChainKit_GetBlockHash_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v2", "chainkit", "blockhash"}, ""))
)
var (
forward_ChainKit_GetBlock_0 = runtime.ForwardResponseMessage
forward_ChainKit_GetBestBlock_0 = runtime.ForwardResponseMessage
forward_ChainKit_GetBlockHash_0 = runtime.ForwardResponseMessage
)

View File

@ -0,0 +1,98 @@
// Code generated by falafel 0.9.1. DO NOT EDIT.
// source: chainkit.proto
package chainrpc
import (
"context"
gateway "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/protobuf/encoding/protojson"
)
func RegisterChainKitJSONCallbacks(registry map[string]func(ctx context.Context,
conn *grpc.ClientConn, reqJSON string, callback func(string, error))) {
marshaler := &gateway.JSONPb{
MarshalOptions: protojson.MarshalOptions{
UseProtoNames: true,
EmitUnpopulated: true,
},
}
registry["chainrpc.ChainKit.GetBlock"] = func(ctx context.Context,
conn *grpc.ClientConn, reqJSON string, callback func(string, error)) {
req := &GetBlockRequest{}
err := marshaler.Unmarshal([]byte(reqJSON), req)
if err != nil {
callback("", err)
return
}
client := NewChainKitClient(conn)
resp, err := client.GetBlock(ctx, req)
if err != nil {
callback("", err)
return
}
respBytes, err := marshaler.Marshal(resp)
if err != nil {
callback("", err)
return
}
callback(string(respBytes), nil)
}
registry["chainrpc.ChainKit.GetBestBlock"] = func(ctx context.Context,
conn *grpc.ClientConn, reqJSON string, callback func(string, error)) {
req := &GetBestBlockRequest{}
err := marshaler.Unmarshal([]byte(reqJSON), req)
if err != nil {
callback("", err)
return
}
client := NewChainKitClient(conn)
resp, err := client.GetBestBlock(ctx, req)
if err != nil {
callback("", err)
return
}
respBytes, err := marshaler.Marshal(resp)
if err != nil {
callback("", err)
return
}
callback(string(respBytes), nil)
}
registry["chainrpc.ChainKit.GetBlockHash"] = func(ctx context.Context,
conn *grpc.ClientConn, reqJSON string, callback func(string, error)) {
req := &GetBlockHashRequest{}
err := marshaler.Unmarshal([]byte(reqJSON), req)
if err != nil {
callback("", err)
return
}
client := NewChainKitClient(conn)
resp, err := client.GetBlockHash(ctx, req)
if err != nil {
callback("", err)
return
}
respBytes, err := marshaler.Marshal(resp)
if err != nil {
callback("", err)
return
}
callback(string(respBytes), nil)
}
}

View File

@ -0,0 +1,59 @@
syntax = "proto3";
package chainrpc;
option go_package = "github.com/lightningnetwork/lnd/lnrpc/chainrpc";
// ChainKit is a service that can be used to get information from the
// chain backend.
service ChainKit {
/* lncli: `chain getblock`
GetBlock returns a block given the corresponding block hash.
*/
rpc GetBlock (GetBlockRequest) returns (GetBlockResponse);
/* lncli: `chain getbestblock`
GetBestBlock returns the block hash and current height from the valid
most-work chain.
*/
rpc GetBestBlock (GetBestBlockRequest) returns (GetBestBlockResponse);
/* lncli: `chain getblockhash`
GetBlockHash returns the hash of the block in the best blockchain
at the given height.
*/
rpc GetBlockHash (GetBlockHashRequest) returns (GetBlockHashResponse);
}
message GetBlockRequest {
// The hash of the requested block.
bytes block_hash = 1;
}
// TODO(ffranr): The neutrino GetBlock response includes many
// additional helpful fields. Consider adding them here also.
message GetBlockResponse {
// The raw bytes of the requested block.
bytes raw_block = 1;
}
message GetBestBlockRequest {
}
message GetBestBlockResponse {
// The hash of the best block.
bytes block_hash = 1;
// The height of the best block.
int32 block_height = 2;
}
message GetBlockHashRequest {
// Block height of the target best chain block.
int64 block_height = 1;
}
message GetBlockHashResponse {
// The hash of the best block at the specified height.
bytes block_hash = 1;
}

View File

@ -0,0 +1,177 @@
{
"swagger": "2.0",
"info": {
"title": "chainrpc/chainkit.proto",
"version": "version not set"
},
"tags": [
{
"name": "ChainKit"
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/v2/chainkit/bestblock": {
"get": {
"summary": "lncli: `chain getbestblock`\nGetBestBlock returns the block hash and current height from the valid\nmost-work chain.",
"operationId": "ChainKit_GetBestBlock",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/chainrpcGetBestBlockResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"tags": [
"ChainKit"
]
}
},
"/v2/chainkit/block": {
"get": {
"summary": "lncli: `chain getblock`\nGetBlock returns a block given the corresponding block hash.",
"operationId": "ChainKit_GetBlock",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/chainrpcGetBlockResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "block_hash",
"description": "The hash of the requested block.",
"in": "query",
"required": false,
"type": "string",
"format": "byte"
}
],
"tags": [
"ChainKit"
]
}
},
"/v2/chainkit/blockhash": {
"get": {
"summary": "lncli: `chain getblockhash`\nGetBlockHash returns the hash of the block in the best blockchain\nat the given height.",
"operationId": "ChainKit_GetBlockHash",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/chainrpcGetBlockHashResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "block_height",
"description": "Block height of the target best chain block.",
"in": "query",
"required": false,
"type": "string",
"format": "int64"
}
],
"tags": [
"ChainKit"
]
}
}
},
"definitions": {
"chainrpcGetBestBlockResponse": {
"type": "object",
"properties": {
"block_hash": {
"type": "string",
"format": "byte",
"description": "The hash of the best block."
},
"block_height": {
"type": "integer",
"format": "int32",
"description": "The height of the best block."
}
}
},
"chainrpcGetBlockHashResponse": {
"type": "object",
"properties": {
"block_hash": {
"type": "string",
"format": "byte",
"description": "The hash of the best block at the specified height."
}
}
},
"chainrpcGetBlockResponse": {
"type": "object",
"properties": {
"raw_block": {
"type": "string",
"format": "byte",
"description": "The raw bytes of the requested block."
}
},
"description": "TODO(ffranr): The neutrino GetBlock response includes many\nadditional helpful fields. Consider adding them here also."
},
"protobufAny": {
"type": "object",
"properties": {
"type_url": {
"type": "string"
},
"value": {
"type": "string",
"format": "byte"
}
}
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufAny"
}
}
}
}
}
}

View File

@ -0,0 +1,11 @@
type: google.api.Service
config_version: 3
http:
rules:
- selector: chainrpc.ChainKit.GetBlock
get: "/v2/chainkit/block"
- selector: chainrpc.ChainKit.GetBestBlock
get: "/v2/chainkit/bestblock"
- selector: chainrpc.ChainKit.GetBlockHash
get: "/v2/chainkit/blockhash"

View File

@ -0,0 +1,189 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package chainrpc
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// ChainKitClient is the client API for ChainKit service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ChainKitClient interface {
// lncli: `chain getblock`
// GetBlock returns a block given the corresponding block hash.
GetBlock(ctx context.Context, in *GetBlockRequest, opts ...grpc.CallOption) (*GetBlockResponse, error)
// lncli: `chain getbestblock`
// GetBestBlock returns the block hash and current height from the valid
// most-work chain.
GetBestBlock(ctx context.Context, in *GetBestBlockRequest, opts ...grpc.CallOption) (*GetBestBlockResponse, error)
// lncli: `chain getblockhash`
// GetBlockHash returns the hash of the block in the best blockchain
// at the given height.
GetBlockHash(ctx context.Context, in *GetBlockHashRequest, opts ...grpc.CallOption) (*GetBlockHashResponse, error)
}
type chainKitClient struct {
cc grpc.ClientConnInterface
}
func NewChainKitClient(cc grpc.ClientConnInterface) ChainKitClient {
return &chainKitClient{cc}
}
func (c *chainKitClient) GetBlock(ctx context.Context, in *GetBlockRequest, opts ...grpc.CallOption) (*GetBlockResponse, error) {
out := new(GetBlockResponse)
err := c.cc.Invoke(ctx, "/chainrpc.ChainKit/GetBlock", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *chainKitClient) GetBestBlock(ctx context.Context, in *GetBestBlockRequest, opts ...grpc.CallOption) (*GetBestBlockResponse, error) {
out := new(GetBestBlockResponse)
err := c.cc.Invoke(ctx, "/chainrpc.ChainKit/GetBestBlock", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *chainKitClient) GetBlockHash(ctx context.Context, in *GetBlockHashRequest, opts ...grpc.CallOption) (*GetBlockHashResponse, error) {
out := new(GetBlockHashResponse)
err := c.cc.Invoke(ctx, "/chainrpc.ChainKit/GetBlockHash", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ChainKitServer is the server API for ChainKit service.
// All implementations must embed UnimplementedChainKitServer
// for forward compatibility
type ChainKitServer interface {
// lncli: `chain getblock`
// GetBlock returns a block given the corresponding block hash.
GetBlock(context.Context, *GetBlockRequest) (*GetBlockResponse, error)
// lncli: `chain getbestblock`
// GetBestBlock returns the block hash and current height from the valid
// most-work chain.
GetBestBlock(context.Context, *GetBestBlockRequest) (*GetBestBlockResponse, error)
// lncli: `chain getblockhash`
// GetBlockHash returns the hash of the block in the best blockchain
// at the given height.
GetBlockHash(context.Context, *GetBlockHashRequest) (*GetBlockHashResponse, error)
mustEmbedUnimplementedChainKitServer()
}
// UnimplementedChainKitServer must be embedded to have forward compatible implementations.
type UnimplementedChainKitServer struct {
}
func (UnimplementedChainKitServer) GetBlock(context.Context, *GetBlockRequest) (*GetBlockResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBlock not implemented")
}
func (UnimplementedChainKitServer) GetBestBlock(context.Context, *GetBestBlockRequest) (*GetBestBlockResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBestBlock not implemented")
}
func (UnimplementedChainKitServer) GetBlockHash(context.Context, *GetBlockHashRequest) (*GetBlockHashResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetBlockHash not implemented")
}
func (UnimplementedChainKitServer) mustEmbedUnimplementedChainKitServer() {}
// UnsafeChainKitServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ChainKitServer will
// result in compilation errors.
type UnsafeChainKitServer interface {
mustEmbedUnimplementedChainKitServer()
}
func RegisterChainKitServer(s grpc.ServiceRegistrar, srv ChainKitServer) {
s.RegisterService(&ChainKit_ServiceDesc, srv)
}
func _ChainKit_GetBlock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBlockRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChainKitServer).GetBlock(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/chainrpc.ChainKit/GetBlock",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChainKitServer).GetBlock(ctx, req.(*GetBlockRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ChainKit_GetBestBlock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBestBlockRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChainKitServer).GetBestBlock(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/chainrpc.ChainKit/GetBestBlock",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChainKitServer).GetBestBlock(ctx, req.(*GetBestBlockRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ChainKit_GetBlockHash_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBlockHashRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ChainKitServer).GetBlockHash(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/chainrpc.ChainKit/GetBlockHash",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ChainKitServer).GetBlockHash(ctx, req.(*GetBlockHashRequest))
}
return interceptor(ctx, in, info, handler)
}
// ChainKit_ServiceDesc is the grpc.ServiceDesc for ChainKit service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ChainKit_ServiceDesc = grpc.ServiceDesc{
ServiceName: "chainrpc.ChainKit",
HandlerType: (*ChainKitServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetBlock",
Handler: _ChainKit_GetBlock_Handler,
},
{
MethodName: "GetBestBlock",
Handler: _ChainKit_GetBestBlock_Handler,
},
{
MethodName: "GetBlockHash",
Handler: _ChainKit_GetBlockHash_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "chainrpc/chainkit.proto",
}

View File

@ -5,6 +5,7 @@ package chainrpc
import (
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/macaroons"
)
@ -32,4 +33,7 @@ type Config struct {
// notifier RPC server. The job of the chain notifier RPC server is
// simply to proxy valid requests to the active chain notifier instance.
ChainNotifier chainntnfs.ChainNotifier
// Chain provides access to the most up-to-date blockchain data.
Chain lnwallet.BlockChainIO
}

View File

@ -45,9 +45,14 @@ func createNewSubServer(configRegistry lnrpc.SubServerConfigDispatcher) (
case config.MacService != nil && config.NetworkDir == "":
return nil, nil, fmt.Errorf("NetworkDir must be set to create " +
"chainrpc")
case config.ChainNotifier == nil:
return nil, nil, fmt.Errorf("ChainNotifier must be set to " +
"create chainrpc")
case config.Chain == nil:
return nil, nil, fmt.Errorf("field Chain must be set to " +
"create chainrpc")
}
return New(config)

View File

@ -67,7 +67,7 @@ function generate() {
--plugin=protoc-gen-custom=$falafel\
--custom_out=. \
--custom_opt="$opts" \
"$(find . -name '*.proto')"
$(find . -name '*.proto')
popd
done
}

View File

@ -39,6 +39,7 @@ type HarnessRPC struct {
WatchtowerClient wtclientrpc.WatchtowerClientClient
State lnrpc.StateClient
ChainClient chainrpc.ChainNotifierClient
ChainKit chainrpc.ChainKitClient
Peer peersrpc.PeersClient
// Name is the HarnessNode's name.
@ -68,6 +69,7 @@ func NewHarnessRPC(ctxt context.Context, t *testing.T, c *grpc.ClientConn,
Signer: signrpc.NewSignerClient(c),
State: lnrpc.NewStateClient(c),
ChainClient: chainrpc.NewChainNotifierClient(c),
ChainKit: chainrpc.NewChainKitClient(c),
Peer: peersrpc.NewPeersClient(c),
Name: name,
}

View File

@ -367,6 +367,7 @@ type HarnessNode struct {
WatchtowerClient wtclientrpc.WatchtowerClientClient
StateClient lnrpc.StateClient
ChainClient chainrpc.ChainNotifierClient
ChainKit chainrpc.ChainKitClient
}
// RPCClients wraps a list of RPC clients into a single struct for easier
@ -385,6 +386,7 @@ type RPCClients struct {
WatchtowerClient wtclientrpc.WatchtowerClientClient
State lnrpc.StateClient
ChainClient chainrpc.ChainNotifierClient
ChainKit chainrpc.ChainKitClient
}
// Assert *HarnessNode implements the lnrpc.LightningClient interface.
@ -938,6 +940,7 @@ func (hn *HarnessNode) InitRPCClients(c *grpc.ClientConn) {
Signer: signrpc.NewSignerClient(c),
State: lnrpc.NewStateClient(c),
ChainClient: chainrpc.NewChainNotifierClient(c),
ChainKit: chainrpc.NewChainKitClient(c),
}
}
@ -960,6 +963,7 @@ func (hn *HarnessNode) initLightningClient() error {
hn.PeersClient = peersrpc.NewPeersClient(conn)
hn.StateClient = lnrpc.NewStateClient(conn)
hn.ChainClient = chainrpc.NewChainNotifierClient(conn)
hn.ChainKit = chainrpc.NewChainKitClient(conn)
// Wait until the server is fully started.
if err := hn.WaitUntilServerActive(); err != nil {

View File

@ -219,4 +219,8 @@ var allTestCasesTemp = []*lntemp.TestCase{
Name: "failing link",
TestFunc: testFailingChannel,
},
{
Name: "chain kit",
TestFunc: testChainKit,
},
}

View File

@ -12,7 +12,9 @@ import (
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/chainrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntemp"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lnwallet"
@ -20,6 +22,72 @@ import (
"github.com/stretchr/testify/require"
)
// testChainKit tests ChainKit RPC endpoints.
func testChainKit(ht *lntemp.HarnessTest) {
ctx := context.Background()
// Test functions registered as test cases spin up separate nodes during
// execution. By calling sub-test functions as seen below we avoid the
// need to start separate nodes.
testChainKitGetBlock(ctx, ht)
testChainKitGetBlockHash(ctx, ht)
}
// testChainKitGetBlock ensures that given a block hash, the RPC endpoint
// returns the correct target block.
func testChainKitGetBlock(ctx context.Context, ht *lntemp.HarnessTest) {
// Get best block hash.
bestBlockRes, err := ht.Alice.RPC.ChainKit.GetBestBlock(
ctx, &chainrpc.GetBestBlockRequest{},
)
require.NoError(ht, err)
var bestBlockHash chainhash.Hash
err = bestBlockHash.SetBytes(bestBlockRes.BlockHash)
require.NoError(ht, err)
// Retrieve the best block by hash.
getBlockRes, err := ht.Alice.RPC.ChainKit.GetBlock(
ctx, &chainrpc.GetBlockRequest{
BlockHash: bestBlockHash.CloneBytes(),
},
)
require.NoError(ht, err)
// Deserialize the block which was retrieved by hash.
msgBlock := &wire.MsgBlock{}
blockReader := bytes.NewReader(getBlockRes.RawBlock)
err = msgBlock.Deserialize(blockReader)
require.NoError(ht, err)
// Ensure best block hash is the same as retrieved block hash.
expected := bestBlockHash
actual := msgBlock.BlockHash()
require.Equal(ht, expected, actual)
}
// testChainKitGetBlockHash ensures that given a block height, the RPC endpoint
// returns the correct target block hash.
func testChainKitGetBlockHash(ctx context.Context, ht *lntemp.HarnessTest) {
// Get best block hash.
bestBlockRes, err := ht.Alice.RPC.ChainKit.GetBestBlock(
ctx, &chainrpc.GetBestBlockRequest{},
)
require.NoError(ht, err)
// Retrieve the block hash at best block height.
getBlockHashRes, err := ht.Alice.RPC.ChainKit.GetBlockHash(
ctx, &chainrpc.GetBlockHashRequest{
BlockHeight: int64(bestBlockRes.BlockHeight),
},
)
require.NoError(ht, err)
// Ensure best block hash is the same as retrieved block hash.
expected := bestBlockRes.BlockHash
actual := getBlockHashRes.BlockHash
require.Equal(ht, expected, actual)
}
// testCPFP ensures that the daemon can bump an unconfirmed transaction's fee
// rate by broadcasting a Child-Pays-For-Parent (CPFP) transaction.
//

View File

@ -217,6 +217,9 @@ func (s *subRPCServerConfigs) PopulateDependencies(cfg *Config,
subCfgValue.FieldByName("ChainNotifier").Set(
reflect.ValueOf(cc.ChainNotifier),
)
subCfgValue.FieldByName("Chain").Set(
reflect.ValueOf(cc.ChainIO),
)
case *invoicesrpc.Config:
subCfgValue := extractReflectValue(subCfg)