Merge pull request #10367 from elnosh/rename-endorsement-accountable

multi: rename experimental endorsement signal to accountable
This commit is contained in:
ziggieXXX authored and GitHub committed 2026-01-06 18:02:22 +01:00
commit 99d07fdb78
22 files changed
+222 -272

No files matched your search

@@ -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
+1 -1
View File
@@ -100,7 +100,7 @@ var defaultSetDesc = setDesc{
SetInit: {}, // I
SetNodeAnn: {}, // N
},
lnwire.ExperimentalEndorsementOptional: {
lnwire.ExperimentalAccountabilityOptional: {
SetNodeAnn: {}, // N
},
lnwire.RbfCoopCloseOptionalStaging: {
+6 -6
View File
@@ -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)
+24 -26
View File
@@ -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,42 @@ 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
+23 -23
View File
@@ -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)
+21 -21
View File
@@ -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,
)
+2 -2
View File
@@ -700,8 +700,8 @@ var allTestCases = []*lntest.TestCase{
TestFunc: testDebuglevelShow,
},
{
Name: "experimental endorsement",
TestFunc: testExperimentalEndorsement,
Name: "experimental accountability",
TestFunc: testExperimentalAccountability,
},
{
Name: "quiescence",
@@ -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}
@@ -57,18 +57,12 @@ func testEndorsement(ht *lntest.HarnessTest, aliceEndorse bool) {
FeeLimitMsat: math.MaxInt64,
}
var expectedValue []byte
hasEndorsement := lntest.ExperimentalEndorsementActive()
if hasEndorsement {
if aliceEndorse {
expectedValue = []byte{lnwire.ExperimentalEndorsed}
t := uint64(lnwire.ExperimentalEndorsementType)
sendReq.FirstHopCustomRecords = map[uint64][]byte{
t: expectedValue,
}
} else {
expectedValue = []byte{lnwire.ExperimentalUnendorsed}
expectedValue := []byte{lnwire.ExperimentalUnaccountable}
if aliceAccountable {
expectedValue = []byte{lnwire.ExperimentalAccountable}
t := uint64(lnwire.ExperimentalAccountableType)
sendReq.FirstHopCustomRecords = map[uint64][]byte{
t: expectedValue,
}
}
@@ -76,29 +70,28 @@ 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,
validateAccountableAndResume(
ht, bobIntercept, true, expectedValue,
)
validateEndorsedAndResume(
ht, carolIntercept, hasEndorsement, expectedValue,
validateAccountableAndResume(
ht, carolIntercept, true, 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,
}
+6 -17
View File
@@ -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)
@@ -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
// endorsement experiment is still active.
expectedLen := 1
if lntest.ExperimentalEndorsementActive() {
expectedLen = 2
}
require.Len(ht, packet.InWireCustomRecords, expectedLen)
require.Equal(ht, lntest.CustomRecordsWithUnendorsed(customRecords),
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
// endorsement 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.ExperimentalEndorsementActive() {
expectedCarolLen = 1
}
require.Len(ht, packet.InWireCustomRecords, expectedCarolLen)
require.Len(ht, packet.InWireCustomRecords, 1)
err = carolInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{
IncomingCircuitKey: packet.IncomingCircuitKey,
Action: actionResume,
@@ -462,7 +451,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,
)
+3 -3
View File
@@ -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,
)
+6 -6
View File
@@ -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.
+6 -6
View File
@@ -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.
+7 -7
View File
@@ -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,
}
}
}
+15 -15
View File
@@ -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
},
},
+6 -23
View File
@@ -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"
@@ -285,33 +283,18 @@ 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() {
// 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.ExperimentalEndorsementType): {
lnwire.ExperimentalUnendorsed,
uint64(lnwire.ExperimentalAccountableType): {
lnwire.ExperimentalUnaccountable,
}},
)
}
// ExperimentalEndorsementActive returns true if the experimental endorsement
// window is still open.
func ExperimentalEndorsementActive() bool {
return time.Now().Before(lnd.EndorsementExperimentEnd)
}
// LnrpcOutpointToStr returns a string representation of an lnrpc.OutPoint.
func LnrpcOutpointToStr(outpoint *lnrpc.OutPoint) string {
return fmt.Sprintf("%s:%d", outpoint.TxidStr, outpoint.OutputIndex)
+10 -8
View File
@@ -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",
+13 -12
View File
@@ -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
// ExperimentalAccountableType is the TLV type used for a custom
// record that sets an experimental accountable value.
ExperimentalAccountableType tlv.Type = 106823
// ExperimentalUnendorsed is the value that the experimental endorsement
// field contains when a htlc is not endorsed.
ExperimentalUnendorsed = 0
// ExperimentalUnaccountable is the value that the experimental
// accountable field contains when a htlc is not accountable.
ExperimentalUnaccountable = 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
// 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 (
+22 -22
View File
@@ -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,
+1 -1
View File
@@ -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
+2 -10
View File
@@ -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,14 +779,8 @@ func (r *rpcServer) addDeps(ctx context.Context, s *server,
return nil
},
ShouldSetExpEndorsement: func() bool {
if s.cfg.ProtocolOptions.NoExperimentalEndorsement() {
return false
}
return clock.NewDefaultClock().Now().Before(
EndorsementExperimentEnd,
)
ShouldSetExpAccountability: func() bool {
return !s.cfg.ProtocolOptions.NoExpAccountability()
},
}
+2 -2
View File
@@ -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
+18 -30
View File
@@ -139,12 +139,6 @@ 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.
//
// Per blip04: January 1, 2026 12:00:00 AM UTC in unix seconds.
EndorsementExperimentEnd = 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")
@@ -641,22 +635,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,14 +4437,8 @@ 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() {
return false
}
return clock.NewDefaultClock().Now().Before(
EndorsementExperimentEnd,
)
ShouldFwdExpAccountability: func() bool {
return !s.cfg.ProtocolOptions.NoExpAccountability()
},
NoDisconnectOnPongFailure: s.cfg.NoDisconnectOnPongFailure,
}