From 34329c684e7047c77799b88a4fcbb317c0bf6d18 Mon Sep 17 00:00:00 2001 From: elnosh Date: Wed, 12 Nov 2025 17:11:20 -0500 Subject: [PATCH 1/2] multi: rename experimental endorsement signal to accountable Renames the endorsement signal to accountable to match the latest proposal https://github.com/lightning/blips/pull/67 --- feature/default_sets.go | 2 +- feature/manager.go | 12 ++--- htlcswitch/link.go | 48 +++++++++--------- htlcswitch/link_test.go | 46 ++++++++--------- htlcswitch/test_utils.go | 42 ++++++++-------- itest/list_on_test.go | 4 +- ....go => lnd_experimental_accountability.go} | 50 +++++++++---------- itest/lnd_forward_interceptor_test.go | 14 +++--- itest/lnd_invoice_acceptor_test.go | 6 +-- lncfg/protocol.go | 12 ++--- lncfg/protocol_integration.go | 12 ++--- lnrpc/routerrpc/router_backend.go | 14 +++--- lnrpc/routerrpc/router_backend_test.go | 30 +++++------ lntest/utils.go | 19 +++---- lnwire/features.go | 18 ++++--- lnwire/update_add_htlc.go | 29 +++++------ peer/brontide.go | 44 ++++++++-------- routing/route/route.go | 2 +- rpcserver.go | 8 ++- sample-lnd.conf | 4 +- server.go | 44 ++++++++-------- 21 files changed, 231 insertions(+), 229 deletions(-) rename itest/{lnd_experimental_endorsement.go => lnd_experimental_accountability.go} (64%) diff --git a/feature/default_sets.go b/feature/default_sets.go index fcb53b6664e..5be5706f683 100644 --- a/feature/default_sets.go +++ b/feature/default_sets.go @@ -100,7 +100,7 @@ var defaultSetDesc = setDesc{ SetInit: {}, // I SetNodeAnn: {}, // N }, - lnwire.ExperimentalEndorsementOptional: { + lnwire.ExperimentalAccountabilityOptional: { SetNodeAnn: {}, // N }, lnwire.RbfCoopCloseOptionalStaging: { diff --git a/feature/manager.go b/feature/manager.go index 862880f3b22..baef44019d1 100644 --- a/feature/manager.go +++ b/feature/manager.go @@ -69,9 +69,9 @@ type Config struct { // NoTaprootOverlay unsets the taproot overlay channel feature bits. NoTaprootOverlay bool - // NoExperimentalEndorsement unsets any bits that signal support for - // forwarding experimental endorsement. - NoExperimentalEndorsement bool + // NoExperimentalAccountability unsets any bits that signal support for + // forwarding experimental accountability. + NoExperimentalAccountability bool // NoRbfCoopClose unsets any bits that signal support for using RBF for // coop close. @@ -213,9 +213,9 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) { raw.Unset(lnwire.SimpleTaprootOverlayChansOptional) raw.Unset(lnwire.SimpleTaprootOverlayChansRequired) } - if cfg.NoExperimentalEndorsement { - raw.Unset(lnwire.ExperimentalEndorsementOptional) - raw.Unset(lnwire.ExperimentalEndorsementRequired) + if cfg.NoExperimentalAccountability { + raw.Unset(lnwire.ExperimentalAccountabilityOptional) + raw.Unset(lnwire.ExperimentalAccountabilityRequired) } if cfg.NoRbfCoopClose { raw.Unset(lnwire.RbfCoopCloseOptionalStaging) diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 4c81964cc24..93bbabb78c8 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -290,9 +290,9 @@ type ChannelLinkConfig struct { // restrict the flow of HTLCs and fee updates. MaxFeeExposure lnwire.MilliSatoshi - // ShouldFwdExpEndorsement is a closure that indicates whether the link - // should forward experimental endorsement signals. - ShouldFwdExpEndorsement func() bool + // ShouldFwdExpAccountability is a closure that indicates whether the + // link should forward experimental accountability signals. + ShouldFwdExpAccountability func() bool // AuxTrafficShaper is an optional auxiliary traffic shaper that can be // used to manage the bandwidth of the link. @@ -3163,11 +3163,11 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg) { continue } - endorseValue := l.experimentalEndorsement( + accountableValue := l.experimentalAccountability( record.CustomSet(add.CustomRecords), ) - endorseType := uint64( - lnwire.ExperimentalEndorsementType, + accountableType := uint64( + lnwire.ExperimentalAccountableType, ) switch fwdPkg.State { @@ -3191,9 +3191,9 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg) { BlindingPoint: fwdInfo.NextBlinding, } - endorseValue.WhenSome(func(e byte) { + accountableValue.WhenSome(func(e byte) { custRecords := map[uint64][]byte{ - endorseType: {e}, + accountableType: {e}, } outgoingAdd.CustomRecords = custRecords @@ -3249,9 +3249,9 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg) { BlindingPoint: fwdInfo.NextBlinding, } - endorseValue.WhenSome(func(e byte) { + accountableValue.WhenSome(func(e byte) { addMsg.CustomRecords = map[uint64][]byte{ - endorseType: {e}, + accountableType: {e}, } }) @@ -3340,44 +3340,44 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg) { l.forwardBatch(reforward, switchPackets...) } -// experimentalEndorsement returns the value to set for our outgoing -// experimental endorsement field, and a boolean indicating whether it should -// be populated on the outgoing htlc. -func (l *channelLink) experimentalEndorsement( +// experimentalAccountability returns the value to set for our outgoing +// experimental accountable field. It only considers the accountability bit, +// other custom records present are not considered for forwarding. +func (l *channelLink) experimentalAccountability( customUpdateAdd record.CustomSet) fn.Option[byte] { // Only relay experimental signal if we are within the experiment // period. - if !l.cfg.ShouldFwdExpEndorsement() { + if !l.cfg.ShouldFwdExpAccountability() { return fn.None[byte]() } // If we don't have any custom records or the experimental field is // not set, just forward a zero value. if len(customUpdateAdd) == 0 { - return fn.Some[byte](lnwire.ExperimentalUnendorsed) + return fn.Some[byte](lnwire.ExperimentalUnaccountable) } - t := uint64(lnwire.ExperimentalEndorsementType) + t := uint64(lnwire.ExperimentalAccountableType) value, set := customUpdateAdd[t] if !set { - return fn.Some[byte](lnwire.ExperimentalUnendorsed) + return fn.Some[byte](lnwire.ExperimentalUnaccountable) } // We expect at least one byte for this field, consider it invalid if // it has no data and just forward a zero value. if len(value) == 0 { - return fn.Some[byte](lnwire.ExperimentalUnendorsed) + return fn.Some[byte](lnwire.ExperimentalUnaccountable) } - // Only forward endorsed if the incoming link is endorsed. - if value[0] == lnwire.ExperimentalEndorsed { - return fn.Some[byte](lnwire.ExperimentalEndorsed) + // Only forward accountable if the incoming link is accountable. + if value[0] == lnwire.ExperimentalAccountable { + return fn.Some[byte](lnwire.ExperimentalAccountable) } - // Forward as unendorsed otherwise, including cases where we've + // Forward as unaccountable otherwise, including cases where we've // received an invalid value that uses more than 3 bits of information. - return fn.Some[byte](lnwire.ExperimentalUnendorsed) + return fn.Some[byte](lnwire.ExperimentalUnaccountable) } // processExitHop handles an htlc for which this link is the exit hop. It diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index 101a47b98af..e4e63d98203 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -2234,18 +2234,18 @@ func newSingleLinkTestHarness(t *testing.T, chanAmt, PendingCommitTicker: ticker.New(time.Minute), // Make the BatchSize and Min/MaxUpdateTimeout large enough // to not trigger commit updates automatically during tests. - BatchSize: 10000, - MinUpdateTimeout: 30 * time.Minute, - MaxUpdateTimeout: 40 * time.Minute, - MaxOutgoingCltvExpiry: DefaultMaxOutgoingCltvExpiry, - MaxFeeAllocation: DefaultMaxLinkFeeAllocation, - NotifyActiveLink: func(wire.OutPoint) {}, - NotifyActiveChannel: func(wire.OutPoint) {}, - NotifyInactiveChannel: func(wire.OutPoint) {}, - NotifyInactiveLinkEvent: func(wire.OutPoint) {}, - HtlcNotifier: aliceSwitch.cfg.HtlcNotifier, - GetAliases: getAliases, - ShouldFwdExpEndorsement: func() bool { return true }, + BatchSize: 10000, + MinUpdateTimeout: 30 * time.Minute, + MaxUpdateTimeout: 40 * time.Minute, + MaxOutgoingCltvExpiry: DefaultMaxOutgoingCltvExpiry, + MaxFeeAllocation: DefaultMaxLinkFeeAllocation, + NotifyActiveLink: func(wire.OutPoint) {}, + NotifyActiveChannel: func(wire.OutPoint) {}, + NotifyInactiveChannel: func(wire.OutPoint) {}, + NotifyInactiveLinkEvent: func(wire.OutPoint) {}, + HtlcNotifier: aliceSwitch.cfg.HtlcNotifier, + GetAliases: getAliases, + ShouldFwdExpAccountability: func() bool { return true }, } aliceLink := NewChannelLink(aliceCfg, aliceLc.channel) @@ -4924,17 +4924,17 @@ func (h *persistentLinkHarness) restartLink( MinUpdateTimeout: 30 * time.Minute, MaxUpdateTimeout: 40 * time.Minute, // Set any hodl flags requested for the new link. - HodlMask: hodl.MaskFromFlags(hodlFlags...), - MaxOutgoingCltvExpiry: DefaultMaxOutgoingCltvExpiry, - MaxFeeAllocation: DefaultMaxLinkFeeAllocation, - NotifyActiveLink: func(wire.OutPoint) {}, - NotifyActiveChannel: func(wire.OutPoint) {}, - NotifyInactiveChannel: func(wire.OutPoint) {}, - NotifyInactiveLinkEvent: func(wire.OutPoint) {}, - HtlcNotifier: h.hSwitch.cfg.HtlcNotifier, - SyncStates: syncStates, - GetAliases: getAliases, - ShouldFwdExpEndorsement: func() bool { return true }, + HodlMask: hodl.MaskFromFlags(hodlFlags...), + MaxOutgoingCltvExpiry: DefaultMaxOutgoingCltvExpiry, + MaxFeeAllocation: DefaultMaxLinkFeeAllocation, + NotifyActiveLink: func(wire.OutPoint) {}, + NotifyActiveChannel: func(wire.OutPoint) {}, + NotifyInactiveChannel: func(wire.OutPoint) {}, + NotifyInactiveLinkEvent: func(wire.OutPoint) {}, + HtlcNotifier: h.hSwitch.cfg.HtlcNotifier, + SyncStates: syncStates, + GetAliases: getAliases, + ShouldFwdExpAccountability: func() bool { return true }, } aliceLink := NewChannelLink(aliceCfg, aliceChannel) diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index bdb365d3c93..b74dbd0bbfc 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -1157,27 +1157,27 @@ func (h *hopNetwork) createChannelLink(server, peer *mockServer, UpdateContractSignals: func(*contractcourt.ContractSignals) error { return nil }, - NotifyContractUpdate: notifyContractUpdate, - ChainEvents: &contractcourt.ChainEventSubscription{}, - SyncStates: true, - BatchSize: 10, - BatchTicker: ticker.NewForce(testBatchTimeout), - FwdPkgGCTicker: ticker.NewForce(fwdPkgTimeout), - PendingCommitTicker: ticker.New(2 * time.Minute), - MinUpdateTimeout: minFeeUpdateTimeout, - MaxUpdateTimeout: maxFeeUpdateTimeout, - OnChannelFailure: func(lnwire.ChannelID, lnwire.ShortChannelID, LinkFailureError) {}, - OutgoingCltvRejectDelta: 3, - MaxOutgoingCltvExpiry: DefaultMaxOutgoingCltvExpiry, - MaxFeeAllocation: DefaultMaxLinkFeeAllocation, - MaxAnchorsCommitFeeRate: chainfee.SatPerKVByte(10 * 1000).FeePerKWeight(), - NotifyActiveLink: func(wire.OutPoint) {}, - NotifyActiveChannel: func(wire.OutPoint) {}, - NotifyInactiveChannel: func(wire.OutPoint) {}, - NotifyInactiveLinkEvent: func(wire.OutPoint) {}, - HtlcNotifier: server.htlcSwitch.cfg.HtlcNotifier, - GetAliases: getAliases, - ShouldFwdExpEndorsement: func() bool { return true }, + NotifyContractUpdate: notifyContractUpdate, + ChainEvents: &contractcourt.ChainEventSubscription{}, + SyncStates: true, + BatchSize: 10, + BatchTicker: ticker.NewForce(testBatchTimeout), + FwdPkgGCTicker: ticker.NewForce(fwdPkgTimeout), + PendingCommitTicker: ticker.New(2 * time.Minute), + MinUpdateTimeout: minFeeUpdateTimeout, + MaxUpdateTimeout: maxFeeUpdateTimeout, + OnChannelFailure: func(lnwire.ChannelID, lnwire.ShortChannelID, LinkFailureError) {}, + OutgoingCltvRejectDelta: 3, + MaxOutgoingCltvExpiry: DefaultMaxOutgoingCltvExpiry, + MaxFeeAllocation: DefaultMaxLinkFeeAllocation, + MaxAnchorsCommitFeeRate: chainfee.SatPerKVByte(10 * 1000).FeePerKWeight(), + NotifyActiveLink: func(wire.OutPoint) {}, + NotifyActiveChannel: func(wire.OutPoint) {}, + NotifyInactiveChannel: func(wire.OutPoint) {}, + NotifyInactiveLinkEvent: func(wire.OutPoint) {}, + HtlcNotifier: server.htlcSwitch.cfg.HtlcNotifier, + GetAliases: getAliases, + ShouldFwdExpAccountability: func() bool { return true }, }, channel, ) diff --git a/itest/list_on_test.go b/itest/list_on_test.go index f5961147d3a..02457d7d131 100644 --- a/itest/list_on_test.go +++ b/itest/list_on_test.go @@ -700,8 +700,8 @@ var allTestCases = []*lntest.TestCase{ TestFunc: testDebuglevelShow, }, { - Name: "experimental endorsement", - TestFunc: testExperimentalEndorsement, + Name: "experimental accountability", + TestFunc: testExperimentalAccountability, }, { Name: "quiescence", diff --git a/itest/lnd_experimental_endorsement.go b/itest/lnd_experimental_accountability.go similarity index 64% rename from itest/lnd_experimental_endorsement.go rename to itest/lnd_experimental_accountability.go index 67f5e30c04c..a636769aed1 100644 --- a/itest/lnd_experimental_endorsement.go +++ b/itest/lnd_experimental_accountability.go @@ -15,19 +15,19 @@ import ( "github.com/stretchr/testify/require" ) -// testExperimentalEndorsement tests setting of positive and negative -// experimental endorsement signals. -func testExperimentalEndorsement(ht *lntest.HarnessTest) { - testEndorsement(ht, true) - testEndorsement(ht, false) +// testExperimentalAccountability tests setting of positive and negative +// experimental accountable signals. +func testExperimentalAccountability(ht *lntest.HarnessTest) { + testAccountability(ht, true) + testAccountability(ht, false) } -// testEndorsement sets up a 5 hop network and tests propagation of -// experimental endorsement signals. -func testEndorsement(ht *lntest.HarnessTest, aliceEndorse bool) { +// testAccountability sets up a 5 hop network and tests propagation of +// experimental accountable signals. +func testAccountability(ht *lntest.HarnessTest, aliceAccountable bool) { cfg := node.CfgAnchor carolCfg := append( - []string{"--protocol.no-experimental-endorsement"}, cfg..., + []string{"--protocol.no-experimental-accountability"}, cfg..., ) cfgs := [][]string{cfg, cfg, carolCfg, cfg, cfg} @@ -58,17 +58,17 @@ func testEndorsement(ht *lntest.HarnessTest, aliceEndorse bool) { } var expectedValue []byte - hasEndorsement := lntest.ExperimentalEndorsementActive() + hasAccountability := lntest.ExperimentalAccountabilityActive() - if hasEndorsement { - if aliceEndorse { - expectedValue = []byte{lnwire.ExperimentalEndorsed} - t := uint64(lnwire.ExperimentalEndorsementType) + if hasAccountability { + if aliceAccountable { + expectedValue = []byte{lnwire.ExperimentalAccountable} + t := uint64(lnwire.ExperimentalAccountableType) sendReq.FirstHopCustomRecords = map[uint64][]byte{ t: expectedValue, } } else { - expectedValue = []byte{lnwire.ExperimentalUnendorsed} + expectedValue = []byte{lnwire.ExperimentalUnaccountable} } } @@ -76,29 +76,29 @@ func testEndorsement(ht *lntest.HarnessTest, aliceEndorse bool) { // Validate that our signal (positive or zero) propagates until carol // and then is dropped because she has disabled the feature. - // When the endorsement experiment is not active, no signal is sent. - validateEndorsedAndResume( - ht, bobIntercept, hasEndorsement, expectedValue, + // When the accountability experiment is not active, no signal is sent. + validateAccountableAndResume( + ht, bobIntercept, hasAccountability, expectedValue, ) - validateEndorsedAndResume( - ht, carolIntercept, hasEndorsement, expectedValue, + validateAccountableAndResume( + ht, carolIntercept, hasAccountability, expectedValue, ) - validateEndorsedAndResume(ht, daveIntercept, false, nil) + validateAccountableAndResume(ht, daveIntercept, false, nil) var preimage lntypes.Preimage copy(preimage[:], invoice.RPreimage) ht.AssertPaymentStatus(alice, preimage.Hash(), lnrpc.Payment_SUCCEEDED) } -func validateEndorsedAndResume(ht *lntest.HarnessTest, - interceptor rpc.InterceptorClient, hasEndorsement bool, +func validateAccountableAndResume(ht *lntest.HarnessTest, + interceptor rpc.InterceptorClient, hasAccountable bool, expectedValue []byte) { packet := ht.ReceiveHtlcInterceptor(interceptor) var expectedRecords map[uint64][]byte - if hasEndorsement { - u64Type := uint64(lnwire.ExperimentalEndorsementType) + if hasAccountable { + u64Type := uint64(lnwire.ExperimentalAccountableType) expectedRecords = map[uint64][]byte{ u64Type: expectedValue, } diff --git a/itest/lnd_forward_interceptor_test.go b/itest/lnd_forward_interceptor_test.go index 615f9f48bca..d45d65025e4 100644 --- a/itest/lnd_forward_interceptor_test.go +++ b/itest/lnd_forward_interceptor_test.go @@ -387,7 +387,7 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { // all intercepted packets. These packets are held to simulate a // pending payment. packet := ht.ReceiveHtlcInterceptor(bobInterceptor) - require.Equal(ht, lntest.CustomRecordsWithUnendorsed( + require.Equal(ht, lntest.CustomRecordsWithUnaccountable( customRecords, ), packet.InWireCustomRecords) @@ -433,21 +433,21 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { packet = ht.ReceiveHtlcInterceptor(bobInterceptor) // Check the expected number of custom records based on whether the - // endorsement experiment is still active. + // accountability experiment is still active. expectedLen := 1 - if lntest.ExperimentalEndorsementActive() { + if lntest.ExperimentalAccountabilityActive() { expectedLen = 2 } require.Len(ht, packet.InWireCustomRecords, expectedLen) - require.Equal(ht, lntest.CustomRecordsWithUnendorsed(customRecords), + require.Equal(ht, lntest.CustomRecordsWithUnaccountable(customRecords), packet.InWireCustomRecords) // And now we forward the payment at Carol, expecting only an - // endorsement signal in our incoming custom records (if the experiment + // accountability signal in our incoming custom records (if the experiment // is still active). packet = ht.ReceiveHtlcInterceptor(carolInterceptor) expectedCarolLen := 0 - if lntest.ExperimentalEndorsementActive() { + if lntest.ExperimentalAccountabilityActive() { expectedCarolLen = 1 } require.Len(ht, packet.InWireCustomRecords, expectedCarolLen) @@ -462,7 +462,7 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { alice, preimage.Hash(), lnrpc.Payment_SUCCEEDED, func(p *lnrpc.Payment) error { recordsEqual := reflect.DeepEqual( - lntest.CustomRecordsWithUnendorsed( + lntest.CustomRecordsWithUnaccountable( sendReq.FirstHopCustomRecords, ), p.FirstHopCustomRecords, ) diff --git a/itest/lnd_invoice_acceptor_test.go b/itest/lnd_invoice_acceptor_test.go index f7c617b250d..4d5e30cc1bb 100644 --- a/itest/lnd_invoice_acceptor_test.go +++ b/itest/lnd_invoice_acceptor_test.go @@ -102,9 +102,9 @@ func testInvoiceHtlcModifierBasic(ht *lntest.HarnessTest) { ht, tc.sendAmountMsat, modifierRequest.ExitHtlcAmt, ) - // Expect custom records plus endorsement signal. + // Expect custom records plus accountable signal. require.Equal( - ht, lntest.CustomRecordsWithUnendorsed( + ht, lntest.CustomRecordsWithUnaccountable( tc.lastHopCustomRecords, ), modifierRequest.ExitHtlcWireCustomRecords, ) @@ -152,7 +152,7 @@ func testInvoiceHtlcModifierBasic(ht *lntest.HarnessTest) { require.Len(ht, updatedInvoice.Htlcs, 1) require.Equal( - ht, lntest.CustomRecordsWithUnendorsed( + ht, lntest.CustomRecordsWithUnaccountable( tc.lastHopCustomRecords, ), updatedInvoice.Htlcs[0].CustomRecords, ) diff --git a/lncfg/protocol.go b/lncfg/protocol.go index 4d348b2154a..fbfe26411b6 100644 --- a/lncfg/protocol.go +++ b/lncfg/protocol.go @@ -71,8 +71,8 @@ type ProtocolOptions struct { // NoRouteBlindingOption disables forwarding of payments in blinded routes. NoRouteBlindingOption bool `long:"no-route-blinding" description:"do not forward payments that are a part of a blinded route"` - // NoExperimentalEndorsementOption disables experimental endorsement. - NoExperimentalEndorsementOption bool `long:"no-experimental-endorsement" description:"do not forward experimental endorsement signals"` + // NoExperimentalAccountabilityOption disables experimental accountability. + NoExperimentalAccountabilityOption bool `long:"no-experimental-accountability" description:"do not forward experimental accountability signals"` // CustomMessage allows the custom message APIs to handle messages with // the provided protocol numbers, which fall outside the custom message @@ -139,10 +139,10 @@ func (l *ProtocolOptions) NoRouteBlinding() bool { return l.NoRouteBlindingOption } -// NoExperimentalEndorsement returns true if experimental endorsement should -// be disabled. -func (l *ProtocolOptions) NoExperimentalEndorsement() bool { - return l.NoExperimentalEndorsementOption +// NoExpAccountability returns true if experimental accountability should be +// disabled. +func (l *ProtocolOptions) NoExpAccountability() bool { + return l.NoExperimentalAccountabilityOption } // NoQuiescence returns true if quiescence is disabled. diff --git a/lncfg/protocol_integration.go b/lncfg/protocol_integration.go index c68d6ffe63f..72a26ae8b03 100644 --- a/lncfg/protocol_integration.go +++ b/lncfg/protocol_integration.go @@ -74,8 +74,8 @@ type ProtocolOptions struct { // NoRouteBlindingOption disables forwarding of payments in blinded routes. NoRouteBlindingOption bool `long:"no-route-blinding" description:"do not forward payments that are a part of a blinded route"` - // NoExperimentalEndorsementOption disables experimental endorsement. - NoExperimentalEndorsementOption bool `long:"no-experimental-endorsement" description:"do not forward experimental endorsement signals"` + // NoExperimentalAccountabilityOption disables experimental accountability. + NoExperimentalAccountabilityOption bool `long:"no-experimental-accountability" description:"do not forward experimental accountability signals"` // NoQuiescenceOption disables quiescence for all channels. NoQuiescenceOption bool `long:"no-quiescence" description:"do not allow or advertise quiescence for any channel"` @@ -137,10 +137,10 @@ func (l *ProtocolOptions) NoRouteBlinding() bool { return l.NoRouteBlindingOption } -// NoExperimentalEndorsement returns true if experimental endorsement should -// be disabled. -func (l *ProtocolOptions) NoExperimentalEndorsement() bool { - return l.NoExperimentalEndorsementOption +// NoExpAccountability returns true if experimental accountability should be +// disabled. +func (l *ProtocolOptions) NoExpAccountability() bool { + return l.NoExperimentalAccountabilityOption } // NoQuiescence returns true if quiescence is disabled. diff --git a/lnrpc/routerrpc/router_backend.go b/lnrpc/routerrpc/router_backend.go index f8a3c568eb7..d8c8a17c410 100644 --- a/lnrpc/routerrpc/router_backend.go +++ b/lnrpc/routerrpc/router_backend.go @@ -122,9 +122,9 @@ type RouterBackend struct { // 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 + // ShouldSetExpAccountability returns a boolean indicating whether the + // experimental accountability bit should be set. + ShouldSetExpAccountability func() bool // Clock is the clock used to validate payment requests expiry. // It is useful for testing. @@ -947,19 +947,19 @@ func (r *RouterBackend) extractIntentFromSendRequest( } payIntent.FirstHopCustomRecords = firstHopRecords - // If the experimental endorsement signal is not already set, propagate + // If the experimental accountable signal is not already set, propagate // a zero value field if configured to set this signal. - if r.ShouldSetExpEndorsement() { + if r.ShouldSetExpAccountability() { if payIntent.FirstHopCustomRecords == nil { payIntent.FirstHopCustomRecords = make( map[uint64][]byte, ) } - t := uint64(lnwire.ExperimentalEndorsementType) + t := uint64(lnwire.ExperimentalAccountableType) if _, set := payIntent.FirstHopCustomRecords[t]; !set { payIntent.FirstHopCustomRecords[t] = []byte{ - lnwire.ExperimentalUnendorsed, + lnwire.ExperimentalUnaccountable, } } } diff --git a/lnrpc/routerrpc/router_backend_test.go b/lnrpc/routerrpc/router_backend_test.go index a1095a36c8a..373b9298394 100644 --- a/lnrpc/routerrpc/router_backend_test.go +++ b/lnrpc/routerrpc/router_backend_test.go @@ -677,7 +677,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Amount conflict, both sat and msat specified", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return true }, }, @@ -692,7 +692,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Both dest and payment_request provided", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, }, @@ -708,7 +708,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Both payment_hash and payment_request provided", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, }, @@ -725,7 +725,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { name: "Both final_cltv_delta and payment_request " + "provided", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, }, @@ -741,7 +741,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Invalid payment request length", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, ActiveNetParams: &chaincfg.RegressionNetParams, @@ -756,7 +756,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Expired invoice payment request", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, ActiveNetParams: &chaincfg.RegressionNetParams, @@ -772,7 +772,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Invoice missing payment address", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, ActiveNetParams: &chaincfg.RegressionNetParams, @@ -789,7 +789,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Invalid dest vertex length", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, }, @@ -803,7 +803,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Payment request with missing amount", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, }, @@ -817,7 +817,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Destination lacks AMP support", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, }, @@ -834,7 +834,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Invalid payment hash length", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, }, @@ -849,7 +849,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { { name: "Payment amount exceeds maximum possible amount", backend: &RouterBackend{ - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, }, @@ -868,7 +868,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { name: "Reject self-payments if not permitted", backend: &RouterBackend{ MaxTotalTimelock: 1000, - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, SelfNode: target, @@ -885,7 +885,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { name: "Required and optional feature bits set", backend: &RouterBackend{ MaxTotalTimelock: 1000, - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, }, @@ -906,7 +906,7 @@ func TestExtractIntentFromSendRequest(t *testing.T) { name: "Valid send req parameters, payment settled", backend: &RouterBackend{ MaxTotalTimelock: 1000, - ShouldSetExpEndorsement: func() bool { + ShouldSetExpAccountability: func() bool { return false }, }, diff --git a/lntest/utils.go b/lntest/utils.go index ab998ecf863..a2c3ea83932 100644 --- a/lntest/utils.go +++ b/lntest/utils.go @@ -285,12 +285,13 @@ func CalcStaticFeeBuffer(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount { return feeBuffer.ToSatoshis() } -// CustomRecordsWithUnendorsed copies the map of custom records and adds an -// endorsed signal (replacing in the case of conflict) for assertion in tests. -func CustomRecordsWithUnendorsed( +// CustomRecordsWithUnaccountable copies the map of custom records and adds an +// accountable signal (replacing in the case of conflict) for assertion in +// tests. +func CustomRecordsWithUnaccountable( originalRecords lnwire.CustomRecords) map[uint64][]byte { - if !ExperimentalEndorsementActive() { + if !ExperimentalAccountabilityActive() { // Return nil if there are no records, to match wire encoding. if len(originalRecords) == 0 { return nil @@ -300,16 +301,16 @@ func CustomRecordsWithUnendorsed( } return originalRecords.MergedCopy(map[uint64][]byte{ - uint64(lnwire.ExperimentalEndorsementType): { - lnwire.ExperimentalUnendorsed, + uint64(lnwire.ExperimentalAccountableType): { + lnwire.ExperimentalUnaccountable, }}, ) } -// ExperimentalEndorsementActive returns true if the experimental endorsement +// ExperimentalAccountabilityActive returns true if the experimental accountability // window is still open. -func ExperimentalEndorsementActive() bool { - return time.Now().Before(lnd.EndorsementExperimentEnd) +func ExperimentalAccountabilityActive() bool { + return time.Now().Before(lnd.AccountabilityExperimentEnd) } // LnrpcOutpointToStr returns a string representation of an lnrpc.OutPoint. diff --git a/lnwire/features.go b/lnwire/features.go index 107828ee20f..4e927e170be 100644 --- a/lnwire/features.go +++ b/lnwire/features.go @@ -289,13 +289,15 @@ const ( // being finalized. SimpleTaprootChannelsOptionalStaging = 181 - // ExperimentalEndorsementRequired is a required feature bit that - // indicates that the node will relay experimental endorsement signals. - ExperimentalEndorsementRequired FeatureBit = 260 + // ExperimentalAccountabilityRequired is a required feature bit that + // indicates that the node will relay experimental accountability + // signals. + ExperimentalAccountabilityRequired FeatureBit = 260 - // ExperimentalEndorsementOptional is an optional feature bit that - // indicates that the node will relay experimental endorsement signals. - ExperimentalEndorsementOptional FeatureBit = 261 + // ExperimentalAccountabilityOptional is an optional feature bit that + // indicates that the node will relay experimental accountability + // signals. + ExperimentalAccountabilityOptional FeatureBit = 261 // Bolt11BlindedPathsRequired is a required feature bit that indicates // that the node is able to understand the blinded path tagged field in @@ -385,8 +387,8 @@ var Features = map[FeatureBit]string{ SimpleTaprootChannelsOptionalStaging: "simple-taproot-chans-x", SimpleTaprootOverlayChansOptional: "taproot-overlay-chans", SimpleTaprootOverlayChansRequired: "taproot-overlay-chans", - ExperimentalEndorsementRequired: "endorsement-x", - ExperimentalEndorsementOptional: "endorsement-x", + ExperimentalAccountabilityRequired: "accountable-x", + ExperimentalAccountabilityOptional: "accountable-x", Bolt11BlindedPathsOptional: "bolt-11-blinded-paths", Bolt11BlindedPathsRequired: "bolt-11-blinded-paths", RbfCoopCloseOptional: "rbf-coop-close", diff --git a/lnwire/update_add_htlc.go b/lnwire/update_add_htlc.go index e627dbf4e68..38ceeec2149 100644 --- a/lnwire/update_add_htlc.go +++ b/lnwire/update_add_htlc.go @@ -16,20 +16,21 @@ const ( // entire packet. OnionPacketSize = 1366 - // ExperimentalEndorsementType is the TLV type used for a custom - // record that sets an experimental endorsement value. - ExperimentalEndorsementType tlv.Type = 106823 - - // ExperimentalUnendorsed is the value that the experimental endorsement - // field contains when a htlc is not endorsed. - ExperimentalUnendorsed = 0 - - // ExperimentalEndorsed is the value that the experimental endorsement - // field contains when a htlc is endorsed. We're using a single byte - // to represent our endorsement value, but limit the value to using - // the first three bits (max value = 00000111). Interpreted as a uint8 - // (an alias for byte in go), we can just define this constant as 7. - ExperimentalEndorsed = 7 + // ExperimentalAccountableType is the TLV type used for a custom + // record that sets an experimental accountable value. + ExperimentalAccountableType tlv.Type = 106823 + + // ExperimentalUnaccountable is the value that the experimental + // accountable field contains when a htlc is not accountable. + ExperimentalUnaccountable = 0 + + // ExperimentalAccountable is the value that the experimental + // accountable field contains when a htlc is accountable. We're using a + // single byte to represent our accountable value, but limit the value + // to using the first three bits (max value = 00000111). Interpreted as + // a uint8 (an alias for byte in go), we can just define this constant + // as 7. + ExperimentalAccountable = 7 ) type ( diff --git a/peer/brontide.go b/peer/brontide.go index 8d02ca6e539..73c5acda48c 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -468,9 +468,9 @@ type Config struct { // onion messages to subscribers. OnionMessageServer *subscribe.Server - // ShouldFwdExpEndorsement is a closure that indicates whether - // experimental endorsement signals should be set. - ShouldFwdExpEndorsement func() bool + // ShouldFwdExpAccountability is a closure that indicates whether + // experimental accountability signals should be set. + ShouldFwdExpAccountability func() bool // NoDisconnectOnPongFailure indicates whether the peer should *not* be // disconnected if a pong is not received in time or is mismatched. @@ -1460,25 +1460,25 @@ func (p *Brontide) addLink(chanPoint *wire.OutPoint, PendingCommitTicker: ticker.New( p.cfg.PendingCommitInterval, ), - BatchSize: p.cfg.ChannelCommitBatchSize, - UnsafeReplay: p.cfg.UnsafeReplay, - MinUpdateTimeout: htlcswitch.DefaultMinLinkFeeUpdateTimeout, - MaxUpdateTimeout: htlcswitch.DefaultMaxLinkFeeUpdateTimeout, - OutgoingCltvRejectDelta: p.cfg.OutgoingCltvRejectDelta, - TowerClient: p.cfg.TowerClient, - MaxOutgoingCltvExpiry: p.cfg.MaxOutgoingCltvExpiry, - MaxFeeAllocation: p.cfg.MaxChannelFeeAllocation, - MaxAnchorsCommitFeeRate: p.cfg.MaxAnchorsCommitFeeRate, - NotifyActiveLink: p.cfg.ChannelNotifier.NotifyActiveLinkEvent, - NotifyActiveChannel: p.cfg.ChannelNotifier.NotifyActiveChannelEvent, - NotifyInactiveChannel: p.cfg.ChannelNotifier.NotifyInactiveChannelEvent, - NotifyInactiveLinkEvent: p.cfg.ChannelNotifier.NotifyInactiveLinkEvent, - HtlcNotifier: p.cfg.HtlcNotifier, - GetAliases: p.cfg.GetAliases, - PreviouslySentShutdown: shutdownMsg, - DisallowRouteBlinding: p.cfg.DisallowRouteBlinding, - MaxFeeExposure: p.cfg.MaxFeeExposure, - ShouldFwdExpEndorsement: p.cfg.ShouldFwdExpEndorsement, + BatchSize: p.cfg.ChannelCommitBatchSize, + UnsafeReplay: p.cfg.UnsafeReplay, + MinUpdateTimeout: htlcswitch.DefaultMinLinkFeeUpdateTimeout, + MaxUpdateTimeout: htlcswitch.DefaultMaxLinkFeeUpdateTimeout, + OutgoingCltvRejectDelta: p.cfg.OutgoingCltvRejectDelta, + TowerClient: p.cfg.TowerClient, + MaxOutgoingCltvExpiry: p.cfg.MaxOutgoingCltvExpiry, + MaxFeeAllocation: p.cfg.MaxChannelFeeAllocation, + MaxAnchorsCommitFeeRate: p.cfg.MaxAnchorsCommitFeeRate, + NotifyActiveLink: p.cfg.ChannelNotifier.NotifyActiveLinkEvent, + NotifyActiveChannel: p.cfg.ChannelNotifier.NotifyActiveChannelEvent, + NotifyInactiveChannel: p.cfg.ChannelNotifier.NotifyInactiveChannelEvent, + NotifyInactiveLinkEvent: p.cfg.ChannelNotifier.NotifyInactiveLinkEvent, + HtlcNotifier: p.cfg.HtlcNotifier, + GetAliases: p.cfg.GetAliases, + PreviouslySentShutdown: shutdownMsg, + DisallowRouteBlinding: p.cfg.DisallowRouteBlinding, + MaxFeeExposure: p.cfg.MaxFeeExposure, + ShouldFwdExpAccountability: p.cfg.ShouldFwdExpAccountability, DisallowQuiescence: p.cfg.DisallowQuiescence || !p.remoteFeatures.HasFeature(lnwire.QuiescenceOptional), AuxTrafficShaper: p.cfg.AuxTrafficShaper, diff --git a/routing/route/route.go b/routing/route/route.go index 3b35ad62b25..1bb52badbdb 100644 --- a/routing/route/route.go +++ b/routing/route/route.go @@ -526,7 +526,7 @@ type Route struct { // FirstHopWireCustomRecords is a set of custom records that should be // included in the wire message sent to the first hop. This is for // example used in custom channels. Besides custom channels we use it - // also for the endorsement bit. This data will be sent to the first + // also for the accountable bit. This data will be sent to the first // hop in the UpdateAddHTLC message. // // NOTE: Since these records already represent TLV records, and we diff --git a/rpcserver.go b/rpcserver.go index 5d2c4d2667d..026b224fd98 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -695,8 +695,6 @@ func newRPCServer(cfg *Config, interceptorChain *rpcperms.InterceptorChain, // addDeps populates all dependencies needed by the RPC server, and any // of the sub-servers that it maintains. When this is done, the RPC server can // be started, and start accepting RPC calls. -// -//nolint:funlen func (r *rpcServer) addDeps(ctx context.Context, s *server, macService *macaroons.Service, subServerCgs *subRPCServerConfigs, atpl *autopilot.Manager, @@ -781,13 +779,13 @@ func (r *rpcServer) addDeps(ctx context.Context, s *server, return nil }, - ShouldSetExpEndorsement: func() bool { - if s.cfg.ProtocolOptions.NoExperimentalEndorsement() { + ShouldSetExpAccountability: func() bool { + if s.cfg.ProtocolOptions.NoExpAccountability() { return false } return clock.NewDefaultClock().Now().Before( - EndorsementExperimentEnd, + AccountabilityExperimentEnd, ) }, } diff --git a/sample-lnd.conf b/sample-lnd.conf index c9a2865b858..830d42ea151 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -1440,8 +1440,8 @@ ; Set to disable blinded route forwarding. ; protocol.no-route-blinding=false -; Set to disable experimental endorsement signaling. -; protocol.no-experimental-endorsement=false +; Set to disable experimental accountability signaling. +; protocol.no-experimental-accountability=false ; Set to enable support for RBF based coop close. ; protocol.rbf-coop-close=false diff --git a/server.go b/server.go index c3b724ed39d..ef8abbf817b 100644 --- a/server.go +++ b/server.go @@ -139,11 +139,11 @@ var ( // TODO(roasbeef): add command line param to modify. MaxFundingAmount = funding.MaxBtcFundingAmount - // EndorsementExperimentEnd is the time after which nodes should stop - // propagating experimental endorsement signals. + // AccountabilityExperimentEnd is the time after which nodes should stop + // propagating experimental accountable signals. // // Per blip04: January 1, 2026 12:00:00 AM UTC in unix seconds. - EndorsementExperimentEnd = time.Unix(1767225600, 0) + AccountabilityExperimentEnd = time.Unix(1767225600, 0) // ErrGossiperBan is one of the errors that can be returned when we // attempt to finalize a connection to a remote peer. @@ -641,22 +641,22 @@ func newServer(ctx context.Context, cfg *Config, listenAddrs []net.Addr, //nolint:ll featureMgr, err := feature.NewManager(feature.Config{ - NoTLVOnion: cfg.ProtocolOptions.LegacyOnion(), - NoStaticRemoteKey: cfg.ProtocolOptions.NoStaticRemoteKey(), - NoAnchors: cfg.ProtocolOptions.NoAnchorCommitments(), - NoWumbo: !cfg.ProtocolOptions.Wumbo(), - NoScriptEnforcementLease: cfg.ProtocolOptions.NoScriptEnforcementLease(), - NoKeysend: !cfg.AcceptKeySend, - NoOptionScidAlias: !cfg.ProtocolOptions.ScidAlias(), - NoZeroConf: !cfg.ProtocolOptions.ZeroConf(), - NoAnySegwit: cfg.ProtocolOptions.NoAnySegwit(), - CustomFeatures: cfg.ProtocolOptions.CustomFeatures(), - NoTaprootChans: !cfg.ProtocolOptions.TaprootChans, - NoTaprootOverlay: !cfg.ProtocolOptions.TaprootOverlayChans, - NoRouteBlinding: cfg.ProtocolOptions.NoRouteBlinding(), - NoExperimentalEndorsement: cfg.ProtocolOptions.NoExperimentalEndorsement(), - NoQuiescence: cfg.ProtocolOptions.NoQuiescence(), - NoRbfCoopClose: !cfg.ProtocolOptions.RbfCoopClose, + NoTLVOnion: cfg.ProtocolOptions.LegacyOnion(), + NoStaticRemoteKey: cfg.ProtocolOptions.NoStaticRemoteKey(), + NoAnchors: cfg.ProtocolOptions.NoAnchorCommitments(), + NoWumbo: !cfg.ProtocolOptions.Wumbo(), + NoScriptEnforcementLease: cfg.ProtocolOptions.NoScriptEnforcementLease(), + NoKeysend: !cfg.AcceptKeySend, + NoOptionScidAlias: !cfg.ProtocolOptions.ScidAlias(), + NoZeroConf: !cfg.ProtocolOptions.ZeroConf(), + NoAnySegwit: cfg.ProtocolOptions.NoAnySegwit(), + CustomFeatures: cfg.ProtocolOptions.CustomFeatures(), + NoTaprootChans: !cfg.ProtocolOptions.TaprootChans, + NoTaprootOverlay: !cfg.ProtocolOptions.TaprootOverlayChans, + NoRouteBlinding: cfg.ProtocolOptions.NoRouteBlinding(), + NoExperimentalAccountability: cfg.ProtocolOptions.NoExpAccountability(), + NoQuiescence: cfg.ProtocolOptions.NoQuiescence(), + NoRbfCoopClose: !cfg.ProtocolOptions.RbfCoopClose, }) if err != nil { return nil, err @@ -4443,13 +4443,13 @@ func (s *server) peerConnected(conn net.Conn, connReq *connmgr.ConnReq, AuxResolver: s.implCfg.AuxContractResolver, AuxTrafficShaper: s.implCfg.TrafficShaper, AuxChannelNegotiator: s.implCfg.AuxChannelNegotiator, - ShouldFwdExpEndorsement: func() bool { - if s.cfg.ProtocolOptions.NoExperimentalEndorsement() { + ShouldFwdExpAccountability: func() bool { + if s.cfg.ProtocolOptions.NoExpAccountability() { return false } return clock.NewDefaultClock().Now().Before( - EndorsementExperimentEnd, + AccountabilityExperimentEnd, ) }, NoDisconnectOnPongFailure: s.cfg.NoDisconnectOnPongFailure, From 6f49bea52b8ff6e4d2362582ce7c6462a7af6df0 Mon Sep 17 00:00:00 2001 From: elnosh Date: Thu, 13 Nov 2025 10:33:02 -0500 Subject: [PATCH 2/2] server: remove accountability signal experiment period In the previous iteration with endorsement signaling, the recommendation was for the sender to set it to 1 and that could have had privacy concerns when first deploying given that the default was to downgrade the signal to 0. In the latest proposal the recommended default for both sending and forwarding nodes is to set `accountable` to 0. As a result, the dates have been removed given that there are no privacy risks associated with relaying the signal with zero values. --- docs/release-notes/release-notes-0.21.0.md | 4 ++++ htlcswitch/link.go | 2 -- itest/lnd_experimental_accountability.go | 23 ++++++++-------------- itest/lnd_forward_interceptor_test.go | 17 +++------------- lntest/utils.go | 18 ----------------- rpcserver.go | 8 +------- server.go | 14 +------------ 7 files changed, 17 insertions(+), 69 deletions(-) diff --git a/docs/release-notes/release-notes-0.21.0.md b/docs/release-notes/release-notes-0.21.0.md index 4e032a340c5..71965798d60 100644 --- a/docs/release-notes/release-notes-0.21.0.md +++ b/docs/release-notes/release-notes-0.21.0.md @@ -75,6 +75,10 @@ This applies to both funders and fundees, with the ability to override the value during channel opening or acceptance. +* Rename [experimental endorsement signal](https://github.com/lightning/blips/blob/a833e7b49f224e1240b5d669e78fa950160f5a06/blip-0004.md) + to [accountable](https://github.com/lightningnetwork/lnd/pull/10367) to match + the latest [proposal](https://github.com/lightning/blips/pull/67). + ## RPC Updates ## lncli Updates diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 93bbabb78c8..4dbfa522373 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -3346,8 +3346,6 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg) { func (l *channelLink) experimentalAccountability( customUpdateAdd record.CustomSet) fn.Option[byte] { - // Only relay experimental signal if we are within the experiment - // period. if !l.cfg.ShouldFwdExpAccountability() { return fn.None[byte]() } diff --git a/itest/lnd_experimental_accountability.go b/itest/lnd_experimental_accountability.go index a636769aed1..30296e7cbcd 100644 --- a/itest/lnd_experimental_accountability.go +++ b/itest/lnd_experimental_accountability.go @@ -57,18 +57,12 @@ func testAccountability(ht *lntest.HarnessTest, aliceAccountable bool) { FeeLimitMsat: math.MaxInt64, } - var expectedValue []byte - hasAccountability := lntest.ExperimentalAccountabilityActive() - - if hasAccountability { - if aliceAccountable { - expectedValue = []byte{lnwire.ExperimentalAccountable} - t := uint64(lnwire.ExperimentalAccountableType) - sendReq.FirstHopCustomRecords = map[uint64][]byte{ - t: expectedValue, - } - } else { - expectedValue = []byte{lnwire.ExperimentalUnaccountable} + expectedValue := []byte{lnwire.ExperimentalUnaccountable} + if aliceAccountable { + expectedValue = []byte{lnwire.ExperimentalAccountable} + t := uint64(lnwire.ExperimentalAccountableType) + sendReq.FirstHopCustomRecords = map[uint64][]byte{ + t: expectedValue, } } @@ -76,12 +70,11 @@ func testAccountability(ht *lntest.HarnessTest, aliceAccountable bool) { // Validate that our signal (positive or zero) propagates until carol // and then is dropped because she has disabled the feature. - // When the accountability experiment is not active, no signal is sent. validateAccountableAndResume( - ht, bobIntercept, hasAccountability, expectedValue, + ht, bobIntercept, true, expectedValue, ) validateAccountableAndResume( - ht, carolIntercept, hasAccountability, expectedValue, + ht, carolIntercept, true, expectedValue, ) validateAccountableAndResume(ht, daveIntercept, false, nil) diff --git a/itest/lnd_forward_interceptor_test.go b/itest/lnd_forward_interceptor_test.go index d45d65025e4..f68042db57a 100644 --- a/itest/lnd_forward_interceptor_test.go +++ b/itest/lnd_forward_interceptor_test.go @@ -432,25 +432,14 @@ func testForwardInterceptorRestart(ht *lntest.HarnessTest) { // We should get another notification about the held HTLC. packet = ht.ReceiveHtlcInterceptor(bobInterceptor) - // Check the expected number of custom records based on whether the - // accountability experiment is still active. - expectedLen := 1 - if lntest.ExperimentalAccountabilityActive() { - expectedLen = 2 - } - require.Len(ht, packet.InWireCustomRecords, expectedLen) + require.Len(ht, packet.InWireCustomRecords, 2) require.Equal(ht, lntest.CustomRecordsWithUnaccountable(customRecords), packet.InWireCustomRecords) // And now we forward the payment at Carol, expecting only an - // accountability signal in our incoming custom records (if the experiment - // is still active). + // accountability signal in our incoming custom records. packet = ht.ReceiveHtlcInterceptor(carolInterceptor) - expectedCarolLen := 0 - if lntest.ExperimentalAccountabilityActive() { - expectedCarolLen = 1 - } - require.Len(ht, packet.InWireCustomRecords, expectedCarolLen) + require.Len(ht, packet.InWireCustomRecords, 1) err = carolInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{ IncomingCircuitKey: packet.IncomingCircuitKey, Action: actionResume, diff --git a/lntest/utils.go b/lntest/utils.go index a2c3ea83932..99943985565 100644 --- a/lntest/utils.go +++ b/lntest/utils.go @@ -7,11 +7,9 @@ import ( "os" "strconv" "strings" - "time" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/wire" - "github.com/lightningnetwork/lnd" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntest/wait" @@ -290,16 +288,6 @@ func CalcStaticFeeBuffer(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount { // tests. func CustomRecordsWithUnaccountable( originalRecords lnwire.CustomRecords) map[uint64][]byte { - - if !ExperimentalAccountabilityActive() { - // Return nil if there are no records, to match wire encoding. - if len(originalRecords) == 0 { - return nil - } - - return originalRecords.Copy() - } - return originalRecords.MergedCopy(map[uint64][]byte{ uint64(lnwire.ExperimentalAccountableType): { lnwire.ExperimentalUnaccountable, @@ -307,12 +295,6 @@ func CustomRecordsWithUnaccountable( ) } -// ExperimentalAccountabilityActive returns true if the experimental accountability -// window is still open. -func ExperimentalAccountabilityActive() bool { - return time.Now().Before(lnd.AccountabilityExperimentEnd) -} - // LnrpcOutpointToStr returns a string representation of an lnrpc.OutPoint. func LnrpcOutpointToStr(outpoint *lnrpc.OutPoint) string { return fmt.Sprintf("%s:%d", outpoint.TxidStr, outpoint.OutputIndex) diff --git a/rpcserver.go b/rpcserver.go index 026b224fd98..29efd150e28 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -780,13 +780,7 @@ func (r *rpcServer) addDeps(ctx context.Context, s *server, return nil }, ShouldSetExpAccountability: func() bool { - if s.cfg.ProtocolOptions.NoExpAccountability() { - return false - } - - return clock.NewDefaultClock().Now().Before( - AccountabilityExperimentEnd, - ) + return !s.cfg.ProtocolOptions.NoExpAccountability() }, } diff --git a/server.go b/server.go index ef8abbf817b..3f7b3e8265b 100644 --- a/server.go +++ b/server.go @@ -139,12 +139,6 @@ var ( // TODO(roasbeef): add command line param to modify. MaxFundingAmount = funding.MaxBtcFundingAmount - // AccountabilityExperimentEnd is the time after which nodes should stop - // propagating experimental accountable signals. - // - // Per blip04: January 1, 2026 12:00:00 AM UTC in unix seconds. - AccountabilityExperimentEnd = time.Unix(1767225600, 0) - // ErrGossiperBan is one of the errors that can be returned when we // attempt to finalize a connection to a remote peer. ErrGossiperBan = errors.New("gossiper has banned remote's key") @@ -4444,13 +4438,7 @@ func (s *server) peerConnected(conn net.Conn, connReq *connmgr.ConnReq, AuxTrafficShaper: s.implCfg.TrafficShaper, AuxChannelNegotiator: s.implCfg.AuxChannelNegotiator, ShouldFwdExpAccountability: func() bool { - if s.cfg.ProtocolOptions.NoExpAccountability() { - return false - } - - return clock.NewDefaultClock().Now().Before( - AccountabilityExperimentEnd, - ) + return !s.cfg.ProtocolOptions.NoExpAccountability() }, NoDisconnectOnPongFailure: s.cfg.NoDisconnectOnPongFailure, }