From 4bb5b0c27c729bd21c129a530b48d3324b6f69d1 Mon Sep 17 00:00:00 2001 From: Carla Kirk-Cohen Date: Thu, 31 Oct 2024 15:56:03 -0400 Subject: [PATCH] lnrpc: set a zero value endorsement signal on sender outgoing htlc Before we have sufficient signaling in the network to relay this signal, set a zero value experimental endorsement value on the sender's outgoing htlc. Once the network is relaying this signal and a flag day has been set, we'll be able to set a non-zero value here. --- itest/lnd_forward_interceptor_test.go | 34 ++++++++++++++------------- lnrpc/routerrpc/router_backend.go | 21 +++++++++++++++++ rpcserver.go | 6 +++++ 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/itest/lnd_forward_interceptor_test.go b/itest/lnd_forward_interceptor_test.go index b7ddf5814..0edf1e109 100644 --- a/itest/lnd_forward_interceptor_test.go +++ b/itest/lnd_forward_interceptor_test.go @@ -515,12 +515,9 @@ func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) { // all intercepted packets. These packets are held to simulate a // pending payment. packet := ht.ReceiveHtlcInterceptor(bobInterceptor) - - require.Len(ht, packet.InWireCustomRecords, 1) - - val, ok := packet.InWireCustomRecords[65537] - require.True(ht, ok, "expected custom record") - require.Equal(ht, []byte("test"), val) + require.Equal(ht, lntest.CustomRecordsWithUnendorsed( + customRecords, + ), packet.InWireCustomRecords) // Just resume the payment on Bob. err := bobInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{ @@ -569,7 +566,9 @@ func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) { func(p *lnrpc.Payment) error { recordsEqual := reflect.DeepEqual( p.FirstHopCustomRecords, - sendReq.FirstHopCustomRecords, + lntest.CustomRecordsWithUnendorsed( + customRecords, + ), ) if !recordsEqual { return fmt.Errorf("expected custom records to "+ @@ -643,9 +642,9 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { // all intercepted packets. These packets are held to simulate a // pending payment. packet := ht.ReceiveHtlcInterceptor(bobInterceptor) - - require.Len(ht, packet.InWireCustomRecords, 1) - require.Equal(ht, customRecords, packet.InWireCustomRecords) + require.Equal(ht, lntest.CustomRecordsWithUnendorsed( + customRecords, + ), packet.InWireCustomRecords) // We accept the payment at Bob and resume it, so it gets to Carol. // This means the HTLC should now be fully locked in on Alice's side and @@ -681,8 +680,9 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { // We should get another notification about the held HTLC. packet = ht.ReceiveHtlcInterceptor(bobInterceptor) - require.Len(ht, packet.InWireCustomRecords, 1) - require.Equal(ht, customRecords, packet.InWireCustomRecords) + require.Len(ht, packet.InWireCustomRecords, 2) + require.Equal(ht, lntest.CustomRecordsWithUnendorsed(customRecords), + packet.InWireCustomRecords) err = carolInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{ IncomingCircuitKey: packet.IncomingCircuitKey, @@ -690,9 +690,10 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { }) require.NoError(ht, err, "failed to send request") - // And now we forward the payment at Carol. + // And now we forward the payment at Carol, expecting only an + // endorsement signal in our incoming custom records. packet = ht.ReceiveHtlcInterceptor(carolInterceptor) - require.Len(ht, packet.InWireCustomRecords, 0) + require.Len(ht, packet.InWireCustomRecords, 1) err = carolInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{ IncomingCircuitKey: packet.IncomingCircuitKey, Action: actionResume, @@ -704,8 +705,9 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { alice, preimage, lnrpc.Payment_SUCCEEDED, func(p *lnrpc.Payment) error { recordsEqual := reflect.DeepEqual( - p.FirstHopCustomRecords, - sendReq.FirstHopCustomRecords, + lntest.CustomRecordsWithUnendorsed( + sendReq.FirstHopCustomRecords, + ), p.FirstHopCustomRecords, ) if !recordsEqual { return fmt.Errorf("expected custom records to "+ diff --git a/lnrpc/routerrpc/router_backend.go b/lnrpc/routerrpc/router_backend.go index f2d21750a..9421e991b 100644 --- a/lnrpc/routerrpc/router_backend.go +++ b/lnrpc/routerrpc/router_backend.go @@ -110,6 +110,10 @@ type RouterBackend struct { // ParseCustomChannelData is a function that can be used to parse custom // channel data from the first hop of a route. ParseCustomChannelData func(message proto.Message) error + + // ShouldSetExpEndorsement returns a boolean indicating whether the + // experimental endorsement bit should be set. + ShouldSetExpEndorsement func() bool } // MissionControl defines the mission control dependencies of routerrpc. @@ -891,6 +895,23 @@ func (r *RouterBackend) extractIntentFromSendRequest( } payIntent.FirstHopCustomRecords = firstHopRecords + // If the experimental endorsement signal is not already set, propagate + // a zero value field if configured to set this signal. + if r.ShouldSetExpEndorsement() { + if payIntent.FirstHopCustomRecords == nil { + payIntent.FirstHopCustomRecords = make( + map[uint64][]byte, + ) + } + + t := uint64(lnwire.ExperimentalEndorsementType) + if _, set := payIntent.FirstHopCustomRecords[t]; !set { + payIntent.FirstHopCustomRecords[t] = []byte{ + lnwire.ExperimentalUnendorsed, + } + } + } + payIntent.PayAttemptTimeout = time.Second * time.Duration(rpcPayReq.TimeoutSeconds) diff --git a/rpcserver.go b/rpcserver.go index 7e016e056..60433be24 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -44,6 +44,7 @@ import ( "github.com/lightningnetwork/lnd/channeldb/graphsession" "github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/channelnotifier" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/feature" @@ -758,6 +759,11 @@ func (r *rpcServer) addDeps(s *server, macService *macaroons.Service, return nil }, + ShouldSetExpEndorsement: func() bool { + return clock.NewDefaultClock().Now().Before( + EndorsementExperimentEnd, + ) + }, } genInvoiceFeatures := func() *lnwire.FeatureVector {