Skip to content

Commit

Permalink
mod+lightning: bump to custom channel data commit
Browse files Browse the repository at this point in the history
  • Loading branch information
guggero committed Jun 4, 2024
1 parent 02b699d commit 6b56ac8
Show file tree
Hide file tree
Showing 7 changed files with 342 additions and 20 deletions.
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ require (
github.com/btcsuite/btcd/btcutil/psbt v1.1.8
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f
github.com/btcsuite/btcwallet v0.16.10-0.20240404104514-b2f31f9045fb
github.com/btcsuite/btcwallet v0.16.10-0.20240410030101-6fe19a472a62
github.com/btcsuite/btcwallet/wtxmgr v1.5.3
github.com/lightningnetwork/lnd v0.18.0-beta
github.com/lightningnetwork/lnd v0.18.0-beta.rc3.0.20240604145823-53dbd1ee66d0
github.com/lightningnetwork/lnd/kvdb v1.4.8
github.com/stretchr/testify v1.9.0
google.golang.org/grpc v1.59.0
Expand Down Expand Up @@ -95,12 +95,12 @@ require (
github.com/lightninglabs/neutrino/cache v1.1.2 // indirect
github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f // indirect
github.com/lightningnetwork/lnd/clock v1.1.1 // indirect
github.com/lightningnetwork/lnd/fn v1.0.5 // indirect
github.com/lightningnetwork/lnd/fn v1.0.8 // indirect
github.com/lightningnetwork/lnd/healthcheck v1.2.4 // indirect
github.com/lightningnetwork/lnd/queue v1.1.1 // indirect
github.com/lightningnetwork/lnd/sqldb v1.0.2 // indirect
github.com/lightningnetwork/lnd/ticker v1.1.1 // indirect
github.com/lightningnetwork/lnd/tlv v1.2.3 // indirect
github.com/lightningnetwork/lnd/tlv v1.2.6 // indirect
github.com/lightningnetwork/lnd/tor v1.1.2 // indirect
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtyd
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=
github.com/btcsuite/btcwallet v0.16.10-0.20240404104514-b2f31f9045fb h1:qoIOlBPRZWtfpcbQlNFf67Wz8ZlXo+mxQc9Pnbm/iqU=
github.com/btcsuite/btcwallet v0.16.10-0.20240404104514-b2f31f9045fb/go.mod h1:2C3Q/MhYAKmk7F+Tey6LfKtKRTdQsrCf8AAAzzDPmH4=
github.com/btcsuite/btcwallet v0.16.10-0.20240410030101-6fe19a472a62 h1:MtcTVTcDbGdTJhfDc7LLikojyl0PYtSRNLwoRaLVbWI=
github.com/btcsuite/btcwallet v0.16.10-0.20240410030101-6fe19a472a62/go.mod h1:2C3Q/MhYAKmk7F+Tey6LfKtKRTdQsrCf8AAAzzDPmH4=
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4 h1:poyHFf7+5+RdxNp5r2T6IBRD7RyraUsYARYbp/7t4D8=
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4/go.mod h1:GETGDQuyq+VFfH1S/+/7slLM/9aNa4l7P4ejX6dJfb0=
github.com/btcsuite/btcwallet/wallet/txrules v1.2.1 h1:UZo7YRzdHbwhK7Rhv3PO9bXgTxiOH45edK5qdsdiatk=
Expand Down Expand Up @@ -429,12 +429,12 @@ github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display h1:pRdza2wl
github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f h1:Pua7+5TcFEJXIIZ1I2YAUapmbcttmLj4TTi786bIi3s=
github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI=
github.com/lightningnetwork/lnd v0.18.0-beta h1:3cH7npkUh156FI5kb6bZbiO+Fl3YD+Bu2UbFKoLZ4lo=
github.com/lightningnetwork/lnd v0.18.0-beta/go.mod h1:1SA9iv9rZddNAcfP38SN9lNSVT1zf5aqmukLUoomjDU=
github.com/lightningnetwork/lnd v0.18.0-beta.rc3.0.20240604145823-53dbd1ee66d0 h1:5AhC7M7KvlFMBmGSdedps2CrsAoB8+rXM3zQ78ovxpw=
github.com/lightningnetwork/lnd v0.18.0-beta.rc3.0.20240604145823-53dbd1ee66d0/go.mod h1:ZZ8c08GgxS6bbtPQv8hPZYB4m2SrhBQJa3N+JgnpR0o=
github.com/lightningnetwork/lnd/clock v1.1.1 h1:OfR3/zcJd2RhH0RU+zX/77c0ZiOnIMsDIBjgjWdZgA0=
github.com/lightningnetwork/lnd/clock v1.1.1/go.mod h1:mGnAhPyjYZQJmebS7aevElXKTFDuO+uNFFfMXK1W8xQ=
github.com/lightningnetwork/lnd/fn v1.0.5 h1:ffDgMSn83avw6rNzxhbt6w5/2oIrwQKTPGfyaLupZtE=
github.com/lightningnetwork/lnd/fn v1.0.5/go.mod h1:P027+0CyELd92H9gnReUkGGAqbFA1HwjHWdfaDFD51U=
github.com/lightningnetwork/lnd/fn v1.0.8 h1:gwzzcUyeDXVIm5S6KgJ9iCQ9wLQGf367k7O3bn/BEvs=
github.com/lightningnetwork/lnd/fn v1.0.8/go.mod h1:P027+0CyELd92H9gnReUkGGAqbFA1HwjHWdfaDFD51U=
github.com/lightningnetwork/lnd/healthcheck v1.2.4 h1:lLPLac+p/TllByxGSlkCwkJlkddqMP5UCoawCj3mgFQ=
github.com/lightningnetwork/lnd/healthcheck v1.2.4/go.mod h1:G7Tst2tVvWo7cx6mSBEToQC5L1XOGxzZTPB29g9Rv2I=
github.com/lightningnetwork/lnd/kvdb v1.4.8 h1:xH0a5Vi1yrcZ5BEeF2ba3vlKBRxrL9uYXlWTjOjbNTY=
Expand All @@ -445,8 +445,8 @@ github.com/lightningnetwork/lnd/sqldb v1.0.2 h1:PfuYzScYMD9/QonKo/QvgsbXfTnH5Dfl
github.com/lightningnetwork/lnd/sqldb v1.0.2/go.mod h1:V2Xl6JNWLTKE97WJnwfs0d0TYJdIQTqK8/3aAwkd3qI=
github.com/lightningnetwork/lnd/ticker v1.1.1 h1:J/b6N2hibFtC7JLV77ULQp++QLtCwT6ijJlbdiZFbSM=
github.com/lightningnetwork/lnd/ticker v1.1.1/go.mod h1:waPTRAAcwtu7Ji3+3k+u/xH5GHovTsCoSVpho0KDvdA=
github.com/lightningnetwork/lnd/tlv v1.2.3 h1:If5ibokA/UoCBGuCKaY6Vn2SJU0l9uAbehCnhTZjEP8=
github.com/lightningnetwork/lnd/tlv v1.2.3/go.mod h1:zDkmqxOczP6LaLTvSFDQ1SJUfHcQRCMKFj93dn3eMB8=
github.com/lightningnetwork/lnd/tlv v1.2.6 h1:icvQG2yDr6k3ZuZzfRdG3EJp6pHurcuh3R6dg0gv/Mw=
github.com/lightningnetwork/lnd/tlv v1.2.6/go.mod h1:/CmY4VbItpOldksocmGT4lxiJqRP9oLxwSZOda2kzNQ=
github.com/lightningnetwork/lnd/tor v1.1.2 h1:3zv9z/EivNFaMF89v3ciBjCS7kvCj4ZFG7XvD2Qq0/k=
github.com/lightningnetwork/lnd/tor v1.1.2/go.mod h1:j7T9uJ2NLMaHwE7GiBGnpYLn4f7NRoTM6qj+ul6/ycA=
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
Expand Down
179 changes: 179 additions & 0 deletions invoices_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,33 @@ import (
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"google.golang.org/grpc"
)

type InvoiceHtlcModifyRequest struct {
Invoice *lnrpc.Invoice

CircuitKey invpkg.CircuitKey

ExitHtlcAmt lnwire.MilliSatoshi

ExitHtlcExpiry uint32

CurrentHeight uint32

WireCustomRecords lnwire.CustomRecords
}

type InvoiceHtlcModifyResponse struct {
CircuitKey invpkg.CircuitKey

AmtPaid lnwire.MilliSatoshi
}

type InvoiceHtlcModifyHandler func(context.Context,
InvoiceHtlcModifyRequest) (*InvoiceHtlcModifyResponse, error)

// InvoicesClient exposes invoice functionality.
type InvoicesClient interface {
SubscribeSingleInvoice(ctx context.Context, hash lntypes.Hash) (
Expand All @@ -26,6 +50,14 @@ type InvoicesClient interface {

AddHoldInvoice(ctx context.Context, in *invoicesrpc.AddInvoiceData) (
string, error)

// HtlcModifier is a bidirectional streaming RPC that allows a client to
// intercept and modify the HTLCs that attempt to settle the given
// invoice. The server will send HTLCs of invoices to the client and the
// client can modify some aspects of the HTLC in order to pass the
// invoice acceptance tests.
HtlcModifier(ctx context.Context,
handler InvoiceHtlcModifyHandler) error
}

// InvoiceUpdate contains a state update for an invoice.
Expand All @@ -38,6 +70,8 @@ type invoicesClient struct {
client invoicesrpc.InvoicesClient
invoiceMac serializedMacaroon
timeout time.Duration
quitOnce sync.Once
quit chan struct{}
wg sync.WaitGroup
}

Expand All @@ -48,10 +82,15 @@ func newInvoicesClient(conn grpc.ClientConnInterface,
client: invoicesrpc.NewInvoicesClient(conn),
invoiceMac: invoiceMac,
timeout: timeout,
quit: make(chan struct{}),
}
}

func (s *invoicesClient) WaitForFinished() {
s.quitOnce.Do(func() {
close(s.quit)
})

s.wg.Wait()
}

Expand Down Expand Up @@ -184,3 +223,143 @@ func fromRPCInvoiceState(state lnrpc.Invoice_InvoiceState) (

return 0, errors.New("unknown state")
}

// HtlcModifier is a bidirectional streaming RPC that allows a client to
// intercept and modify the HTLCs that attempt to settle the given invoice. The
// server will send HTLCs of invoices to the client and the client can modify
// some aspects of the HTLC in order to pass the invoice acceptance tests.
func (s *invoicesClient) HtlcModifier(ctx context.Context,
handler InvoiceHtlcModifyHandler) error {

// Create a child context that will be canceled when this function
// exits. We use this context to be able to cancel goroutines when we
// exit on errors, because the parent context won't be canceled in that
// case.
ctx, cancel := context.WithCancel(ctx)
defer cancel()

stream, err := s.client.HtlcModifier(
s.invoiceMac.WithMacaroonAuth(ctx),
)
if err != nil {
return err
}

// Create an error channel that we'll send errors on if any of our
// goroutines fail. We buffer by 1 so that the goroutine doesn't depend
// on the stream being read, and select on context cancellation and
// quit channel so that we do not block in the case where we exit with
// multiple errors.
errChan := make(chan error, 1)

sendErr := func(err error) {
select {
case errChan <- err:
case <-ctx.Done():
case <-s.quit:
}
}

// Start a goroutine that consumes interception requests from lnd and
// sends them into our requests channel for handling. The requests
// channel is not buffered because we expect all requests to be handled
// until this function exits, at which point we expect our context to
// be canceled or quit channel to be closed.
requestChan := make(chan InvoiceHtlcModifyRequest)
s.wg.Add(1)
go func() {
defer s.wg.Done()

for {
// Do a quick check whether our client context has been
// canceled so that we can exit sooner if needed.
if ctx.Err() != nil {
return
}

req, err := stream.Recv()
if err != nil {
sendErr(err)
return
}

wireCustomRecords := req.ExitHtlcWireCustomRecords
interceptReq := InvoiceHtlcModifyRequest{
Invoice: req.Invoice,
CircuitKey: invpkg.CircuitKey{
ChanID: lnwire.NewShortChanIDFromInt(
req.ExitHtlcCircuitKey.ChanId,
),
HtlcID: req.ExitHtlcCircuitKey.HtlcId,
},
ExitHtlcAmt: lnwire.MilliSatoshi(
req.ExitHtlcAmt,
),
ExitHtlcExpiry: req.ExitHtlcExpiry,
CurrentHeight: req.CurrentHeight,
WireCustomRecords: wireCustomRecords,
}

// Try to send our interception request, failing on
// context cancel or router exit.
select {
case requestChan <- interceptReq:

case <-s.quit:
sendErr(ErrRouterShuttingDown)
return

case <-ctx.Done():
sendErr(ctx.Err())
return
}
}
}()

for {
select {
case request := <-requestChan:
// Handle requests in a goroutine so that the handler
// provided to this function can be blocking. If we
// get an error, send it into our error channel to
// shut down the interceptor.
s.wg.Add(1)
go func() {
defer s.wg.Done()

// Get a response from handler, this may block
// for a while.
resp, err := handler(ctx, request)
if err != nil {
sendErr(err)
return
}

key := resp.CircuitKey
rpcResp := &invoicesrpc.HtlcModifyResponse{
CircuitKey: &invoicesrpc.CircuitKey{
ChanId: key.ChanID.ToUint64(),
HtlcId: key.HtlcID,
},
AmtPaid: uint64(resp.AmtPaid),
}

if err := stream.Send(rpcResp); err != nil {
sendErr(err)
return
}
}()

// If one of our goroutines fails, exit with the error that
// occurred.
case err := <-errChan:
return err

case <-s.quit:
return ErrRouterShuttingDown

case <-ctx.Done():
return ctx.Err()
}
}
}
20 changes: 16 additions & 4 deletions lightning_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ type ChannelInfo struct {
// AliasScids contains a list of alias short channel identifiers that
// may be used for this channel. This array can be empty.
AliasScids []uint64

// CustomChannelData is an optional field that can be used to store
// data for custom channels.
CustomChannelData []byte
}

func (s *lightningClient) newChannelInfo(channel *lnrpc.Channel) (*ChannelInfo,
Expand Down Expand Up @@ -465,8 +469,9 @@ func (s *lightningClient) newChannelInfo(channel *lnrpc.Channel) (*ChannelInfo,
RemoteConstraints: newChannelConstraint(
channel.RemoteConstraints,
),
ZeroConf: channel.ZeroConf,
ZeroConfScid: channel.ZeroConfConfirmedScid,
ZeroConf: channel.ZeroConf,
ZeroConfScid: channel.ZeroConfConfirmedScid,
CustomChannelData: channel.CustomChannelData,
}

chanInfo.AliasScids = make([]uint64, len(channel.AliasScids))
Expand Down Expand Up @@ -834,6 +839,10 @@ type ChannelBalance struct {

// PendingBalance is the sum of all pending channel balances.
PendingBalance btcutil.Amount

// CustomChannelData is an optional field that can be used to store
// data for custom channels.
CustomChannelData []byte
}

// Node describes a node in the network.
Expand Down Expand Up @@ -3422,8 +3431,11 @@ func (s *lightningClient) ChannelBalance(ctx context.Context) (*ChannelBalance,
}

return &ChannelBalance{
Balance: btcutil.Amount(resp.Balance), // nolint:staticcheck
PendingBalance: btcutil.Amount(resp.PendingOpenBalance), // nolint:staticcheck
//nolint:staticcheck
Balance: btcutil.Amount(resp.Balance),
//nolint:staticcheck
PendingBalance: btcutil.Amount(resp.PendingOpenBalance),
CustomChannelData: resp.CustomChannelData,
}, nil
}

Expand Down
19 changes: 15 additions & 4 deletions lnd_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ type LndServicesConfig struct {
// calls to lnd. If this value is not set, it will default to 30
// seconds.
RPCTimeout time.Duration

// ChainSyncPollInterval is the interval in which we poll the GetInfo
// call to find out if lnd is fully synced to its chain backend.
ChainSyncPollInterval time.Duration
}

// DialerFunc is a function that is used as grpc.WithContextDialer().
Expand Down Expand Up @@ -285,7 +289,8 @@ func NewLndServices(cfg *LndServicesConfig) (*GrpcLndServices, error) {
readonlyMac = serializedMacaroon(cfg.CustomMacaroonHex)
} else {
readonlyMac, err = loadMacaroon(
macaroonDir, string(ReadOnlyServiceMac), cfg.CustomMacaroonPath,
macaroonDir, string(ReadOnlyServiceMac),
cfg.CustomMacaroonPath,
)
if err != nil {
return nil, err
Expand All @@ -297,6 +302,10 @@ func NewLndServices(cfg *LndServicesConfig) (*GrpcLndServices, error) {
timeout = cfg.RPCTimeout
}

if cfg.ChainSyncPollInterval == 0 {
cfg.ChainSyncPollInterval = chainSyncPollInterval
}

basicClient := lnrpc.NewLightningClient(conn)
stateClient := newStateClient(conn, readonlyMac)
versionerClient := newVersionerClient(conn, readonlyMac, timeout)
Expand Down Expand Up @@ -413,7 +422,9 @@ func NewLndServices(cfg *LndServicesConfig) (*GrpcLndServices, error) {
log.Infof("Waiting for lnd to be fully synced to its chain " +
"backend, this might take a while")

err := services.waitForChainSync(cfg.CallerCtx, timeout)
err := services.waitForChainSync(
cfg.CallerCtx, timeout, cfg.ChainSyncPollInterval,
)
if err != nil {
cleanup()
return nil, fmt.Errorf("error waiting for chain to "+
Expand Down Expand Up @@ -453,7 +464,7 @@ func (s *GrpcLndServices) Close() {
// synced to its chain backend. This could theoretically take hours if the
// initial block download is still in progress.
func (s *GrpcLndServices) waitForChainSync(ctx context.Context,
timeout time.Duration) error {
timeout, pollInterval time.Duration) error {

mainCtx := ctx
if mainCtx == nil {
Expand Down Expand Up @@ -488,7 +499,7 @@ func (s *GrpcLndServices) waitForChainSync(ctx context.Context,

select {
// If we're not yet done, let's now wait a few seconds.
case <-time.After(chainSyncPollInterval):
case <-time.After(pollInterval):

// If the user cancels the context, we should also
// abort the wait.
Expand Down
Loading

0 comments on commit 6b56ac8

Please sign in to comment.