From b93fee2f06120c9caed21fd648ea5bcbc922bb42 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 6 May 2024 11:11:36 +0200 Subject: [PATCH] rpcserver+config_builder: add AuxDataParser --- config_builder.go | 4 +++ rpcserver.go | 67 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/config_builder.go b/config_builder.go index a726c63b1..b675cacaa 100644 --- a/config_builder.go +++ b/config_builder.go @@ -178,6 +178,10 @@ type AuxComponents struct { // TrafficShaper is an optional traffic shaper that can be used to // control the outgoing channel of a payment. TrafficShaper fn.Option[routing.TlvTrafficShaper] + + // AuxDataParser is an optional data parser that can be used to parse + // auxiliary data for certain custom channel types. + AuxDataParser fn.Option[AuxDataParser] } // DefaultWalletImpl is the default implementation of our normal, btcwallet diff --git a/rpcserver.go b/rpcserver.go index 4c5d0189b..2c3d481a2 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -46,6 +46,7 @@ import ( "github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/feature" + "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/htlcswitch" "github.com/lightningnetwork/lnd/htlcswitch/hop" @@ -82,6 +83,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" "gopkg.in/macaroon-bakery.v2/bakery" ) @@ -567,6 +569,17 @@ func MainRPCServerPermissions() map[string][]bakery.Op { } } +// AuxDataParser is an interface that is used to parse auxiliary custom data +// within RPC messages. This is used to transform binary blobs to human-readable +// JSON representations. +type AuxDataParser interface { + // InlineParseCustomData replaces any custom data binary blob in the + // given RPC message with its corresponding JSON formatted data. This + // transforms the binary (likely TLV encoded) data to a human-readable + // JSON representation (still as byte slice). + InlineParseCustomData(msg proto.Message) error +} + // rpcServer is a gRPC, RPC front end to the lnd daemon. // TODO(roasbeef): pagination support for the list-style calls type rpcServer struct { @@ -3478,6 +3491,7 @@ func (r *rpcServer) ChannelBalance(ctx context.Context, unsettledRemoteBalance lnwire.MilliSatoshi pendingOpenLocalBalance lnwire.MilliSatoshi pendingOpenRemoteBalance lnwire.MilliSatoshi + customDataBuf bytes.Buffer ) openChannels, err := r.server.chanStateDB.FetchAllOpenChannels() @@ -3485,6 +3499,12 @@ func (r *rpcServer) ChannelBalance(ctx context.Context, return nil, err } + // Encode the number of open channels to the custom data buffer. + err = wire.WriteVarInt(&customDataBuf, 0, uint64(len(openChannels))) + if err != nil { + return nil, err + } + for _, channel := range openChannels { c := channel.LocalCommitment localBalance += c.LocalBalance @@ -3498,6 +3518,13 @@ func (r *rpcServer) ChannelBalance(ctx context.Context, unsettledRemoteBalance += htlc.Amt } } + + // Encode the custom data for this open channel. + openChanData := channel.LocalCommitment.CustomBlob.UnwrapOr(nil) + err = wire.WriteVarBytes(&customDataBuf, 0, openChanData) + if err != nil { + return nil, err + } } pendingChannels, err := r.server.chanStateDB.FetchPendingChannels() @@ -3505,10 +3532,23 @@ func (r *rpcServer) ChannelBalance(ctx context.Context, return nil, err } + // Encode the number of pending channels to the custom data buffer. + err = wire.WriteVarInt(&customDataBuf, 0, uint64(len(pendingChannels))) + if err != nil { + return nil, err + } + for _, channel := range pendingChannels { c := channel.LocalCommitment pendingOpenLocalBalance += c.LocalBalance pendingOpenRemoteBalance += c.RemoteBalance + + // Encode the custom data for this pending channel. + openChanData := channel.LocalCommitment.CustomBlob.UnwrapOr(nil) + err = wire.WriteVarBytes(&customDataBuf, 0, openChanData) + if err != nil { + return nil, err + } } rpcsLog.Debugf("[channelbalance] local_balance=%v remote_balance=%v "+ @@ -3518,7 +3558,7 @@ func (r *rpcServer) ChannelBalance(ctx context.Context, unsettledRemoteBalance, pendingOpenLocalBalance, pendingOpenRemoteBalance) - return &lnrpc.ChannelBalanceResponse{ + resp := &lnrpc.ChannelBalanceResponse{ LocalBalance: &lnrpc.Amount{ Sat: uint64(localBalance.ToSatoshis()), Msat: uint64(localBalance), @@ -3543,11 +3583,24 @@ func (r *rpcServer) ChannelBalance(ctx context.Context, Sat: uint64(pendingOpenRemoteBalance.ToSatoshis()), Msat: uint64(pendingOpenRemoteBalance), }, + CustomChannelData: customDataBuf.Bytes(), // Deprecated fields. Balance: int64(localBalance.ToSatoshis()), PendingOpenBalance: int64(pendingOpenLocalBalance.ToSatoshis()), - }, nil + } + + err = fn.MapOptionZ( + r.server.implCfg.AuxDataParser, + func(parser AuxDataParser) error { + return parser.InlineParseCustomData(resp) + }, + ) + if err != nil { + return nil, fmt.Errorf("error parsing custom data: %w", err) + } + + return resp, nil } type ( @@ -4303,6 +4356,16 @@ func (r *rpcServer) ListChannels(ctx context.Context, resp.Channels = append(resp.Channels, channel) } + err = fn.MapOptionZ( + r.server.implCfg.AuxDataParser, + func(parser AuxDataParser) error { + return parser.InlineParseCustomData(resp) + }, + ) + if err != nil { + return nil, fmt.Errorf("error parsing custom data: %w", err) + } + return resp, nil }