Merge pull request #8390 from carlaKC/7883-experimental-endorsement

Add Experimental Endorsement Signalling
This commit is contained in:
Elle authored and GitHub committed 2024-11-26 09:43:22 +02:00
commit fbeab726e1
20 files changed
+380 -40

No files matched your search

+4
View File
@@ -706,4 +706,8 @@ var allTestCases = []*lntest.TestCase{
Name: "debuglevel show",
TestFunc: testDebuglevelShow,
},
{
Name: "experimental endorsement",
TestFunc: testExperimentalEndorsement,
},
}
+124
View File
@@ -0,0 +1,124 @@
package itest
import (
"math"
"github.com/btcsuite/btcd/btcutil"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntest"
"github.com/lightningnetwork/lnd/lntest/rpc"
"github.com/lightningnetwork/lnd/lntest/wait"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"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)
}
// testEndorsement sets up a 5 hop network and tests propagation of
// experimental endorsement signals.
func testEndorsement(ht *lntest.HarnessTest, aliceEndorse bool) {
alice, bob := ht.Alice, ht.Bob
carol := ht.NewNode(
"carol", []string{"--protocol.no-experimental-endorsement"},
)
dave := ht.NewNode("dave", nil)
eve := ht.NewNode("eve", nil)
ht.EnsureConnected(alice, bob)
ht.EnsureConnected(bob, carol)
ht.EnsureConnected(carol, dave)
ht.EnsureConnected(dave, eve)
ht.FundCoins(btcutil.SatoshiPerBitcoin, carol)
ht.FundCoins(btcutil.SatoshiPerBitcoin, dave)
// Open and wait for channels.
const chanAmt = btcutil.Amount(300000)
p := lntest.OpenChannelParams{Amt: chanAmt}
reqs := []*lntest.OpenChannelRequest{
{Local: alice, Remote: bob, Param: p},
{Local: bob, Remote: carol, Param: p},
{Local: carol, Remote: dave, Param: p},
{Local: dave, Remote: eve, Param: p},
}
resp := ht.OpenMultiChannelsAsync(reqs)
cpAB, cpBC, cpCD, cpDE := resp[0], resp[1], resp[2], resp[3]
// Make sure Alice is aware of Bob=>Carol=>Dave=>Eve channels.
ht.AssertChannelInGraph(alice, cpBC)
ht.AssertChannelInGraph(alice, cpCD)
ht.AssertChannelInGraph(alice, cpDE)
bobIntercept, cancelBob := bob.RPC.HtlcInterceptor()
defer cancelBob()
carolIntercept, cancelCarol := carol.RPC.HtlcInterceptor()
defer cancelCarol()
daveIntercept, cancelDave := dave.RPC.HtlcInterceptor()
defer cancelDave()
req := &lnrpc.Invoice{ValueMsat: 1000}
addResponse := eve.RPC.AddInvoice(req)
invoice := eve.RPC.LookupInvoice(addResponse.RHash)
sendReq := &routerrpc.SendPaymentRequest{
PaymentRequest: invoice.PaymentRequest,
TimeoutSeconds: int32(wait.PaymentTimeout.Seconds()),
FeeLimitMsat: math.MaxInt64,
}
expectedValue := []byte{lnwire.ExperimentalUnendorsed}
if aliceEndorse {
expectedValue = []byte{lnwire.ExperimentalEndorsed}
t := uint64(lnwire.ExperimentalEndorsementType)
sendReq.FirstHopCustomRecords = map[uint64][]byte{
t: expectedValue,
}
}
_ = alice.RPC.SendPayment(sendReq)
// Validate that our signal (positive or zero) propagates until carol
// and then is dropped because she has disabled the feature.
validateEndorsedAndResume(ht, bobIntercept, true, expectedValue)
validateEndorsedAndResume(ht, carolIntercept, true, expectedValue)
validateEndorsedAndResume(ht, daveIntercept, false, nil)
var preimage lntypes.Preimage
copy(preimage[:], invoice.RPreimage)
ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED)
ht.CloseChannel(alice, cpAB)
ht.CloseChannel(bob, cpBC)
ht.CloseChannel(carol, cpCD)
ht.CloseChannel(dave, cpDE)
}
func validateEndorsedAndResume(ht *lntest.HarnessTest,
interceptor rpc.InterceptorClient, hasEndorsement bool,
expectedValue []byte) {
packet := ht.ReceiveHtlcInterceptor(interceptor)
var expectedRecords map[uint64][]byte
if hasEndorsement {
u64Type := uint64(lnwire.ExperimentalEndorsementType)
expectedRecords = map[uint64][]byte{
u64Type: expectedValue,
}
}
require.Equal(ht, expectedRecords, packet.InWireCustomRecords)
err := interceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{
IncomingCircuitKey: packet.IncomingCircuitKey,
Action: routerrpc.ResolveHoldForwardAction_RESUME,
})
require.NoError(ht, err)
}
+21 -18
View File
@@ -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{
@@ -530,9 +527,10 @@ func testForwardInterceptorWireRecords(ht *lntest.HarnessTest) {
require.NoError(ht, err, "failed to send request")
// Assert that the Alice -> Bob custom records in update_add_htlc are
// not propagated on the Bob -> Carol link.
// not propagated on the Bob -> Carol link, just an endorsement signal.
packet = ht.ReceiveHtlcInterceptor(carolInterceptor)
require.Len(ht, packet.InWireCustomRecords, 0)
require.Equal(ht, lntest.CustomRecordsWithUnendorsed(nil),
packet.InWireCustomRecords)
// We're going to tell Carol to forward 5k sats less to Dave. We need to
// set custom records on the HTLC as well, to make sure the HTLC isn't
@@ -568,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 "+
@@ -642,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
@@ -680,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,
@@ -689,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,
@@ -703,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 "+
+8 -4
View File
@@ -102,9 +102,12 @@ func testInvoiceHtlcModifierBasic(ht *lntest.HarnessTest) {
require.EqualValues(
ht, tc.sendAmountMsat, modifierRequest.ExitHtlcAmt,
)
// Expect custom records plus endorsement signal.
require.Equal(
ht, tc.lastHopCustomRecords,
modifierRequest.ExitHtlcWireCustomRecords,
ht, lntest.CustomRecordsWithUnendorsed(
tc.lastHopCustomRecords,
), modifierRequest.ExitHtlcWireCustomRecords,
)
// For all other packets we resolve according to the test case.
@@ -140,8 +143,9 @@ func testInvoiceHtlcModifierBasic(ht *lntest.HarnessTest) {
require.Len(ht, updatedInvoice.Htlcs, 1)
require.Equal(
ht, tc.lastHopCustomRecords,
updatedInvoice.Htlcs[0].CustomRecords,
ht, lntest.CustomRecordsWithUnendorsed(
tc.lastHopCustomRecords,
), updatedInvoice.Htlcs[0].CustomRecords,
)
// Make sure the custom channel data contains the encoded