mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-23 06:35:07 +01:00
itest: add itest for field modification HTLC interception response
Implement an integration test where an HTLC is intercepted and the interception response modifies fields in the resultant p2p message.
This commit is contained in:
parent
bd5de434ab
commit
8025296bc1
2 changed files with 139 additions and 0 deletions
|
@ -422,6 +422,10 @@ var allTestCases = []*lntest.TestCase{
|
|||
Name: "forward interceptor",
|
||||
TestFunc: testForwardInterceptorBasic,
|
||||
},
|
||||
{
|
||||
Name: "forward interceptor modified htlc",
|
||||
TestFunc: testForwardInterceptorModifiedHtlc,
|
||||
},
|
||||
{
|
||||
Name: "zero conf channel open",
|
||||
TestFunc: testZeroConfChannelOpen,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package itest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -344,6 +345,140 @@ func testForwardInterceptorBasic(ht *lntest.HarnessTest) {
|
|||
ht.CloseChannel(bob, cpBC)
|
||||
}
|
||||
|
||||
// testForwardInterceptorModifiedHtlc tests that the interceptor can modify the
|
||||
// amount and custom records of an intercepted HTLC and resume it.
|
||||
func testForwardInterceptorModifiedHtlc(ht *lntest.HarnessTest) {
|
||||
// Initialize the test context with 3 connected nodes.
|
||||
ts := newInterceptorTestScenario(ht)
|
||||
|
||||
alice, bob, carol := ts.alice, ts.bob, ts.carol
|
||||
|
||||
// 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},
|
||||
}
|
||||
resp := ht.OpenMultiChannelsAsync(reqs)
|
||||
cpAB, cpBC := resp[0], resp[1]
|
||||
|
||||
// Make sure Alice is aware of channel Bob=>Carol.
|
||||
ht.AssertTopologyChannelOpen(alice, cpBC)
|
||||
|
||||
// Connect an interceptor to Bob's node.
|
||||
bobInterceptor, cancelBobInterceptor := bob.RPC.HtlcInterceptor()
|
||||
|
||||
// Prepare the test cases.
|
||||
invoiceValueAmtMsat := int64(1000)
|
||||
req := &lnrpc.Invoice{ValueMsat: invoiceValueAmtMsat}
|
||||
addResponse := carol.RPC.AddInvoice(req)
|
||||
invoice := carol.RPC.LookupInvoice(addResponse.RHash)
|
||||
tc := &interceptorTestCase{
|
||||
amountMsat: invoiceValueAmtMsat,
|
||||
invoice: invoice,
|
||||
payAddr: invoice.PaymentAddr,
|
||||
}
|
||||
|
||||
// We initiate a payment from Alice.
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
// Signal that all the payments have been sent.
|
||||
defer close(done)
|
||||
|
||||
ts.sendPaymentAndAssertAction(tc)
|
||||
}()
|
||||
|
||||
// We start the htlc interceptor with a simple implementation that saves
|
||||
// all intercepted packets. These packets are held to simulate a
|
||||
// pending payment.
|
||||
packet := ht.ReceiveHtlcInterceptor(bobInterceptor)
|
||||
|
||||
// Resume the intercepted HTLC with a modified amount and custom
|
||||
// records.
|
||||
if packet.CustomRecords == nil {
|
||||
packet.CustomRecords = make(map[uint64][]byte)
|
||||
}
|
||||
customRecords := packet.CustomRecords
|
||||
|
||||
// Add custom records entry.
|
||||
crKey := uint64(65537)
|
||||
crValue := []byte("custom-records-test-value")
|
||||
customRecords[crKey] = crValue
|
||||
|
||||
action := routerrpc.ResolveHoldForwardAction_RESUME_MODIFIED
|
||||
newOutgoingAmountMsat := packet.OutgoingAmountMsat + 4000
|
||||
|
||||
err := bobInterceptor.Send(&routerrpc.ForwardHtlcInterceptResponse{
|
||||
IncomingCircuitKey: packet.IncomingCircuitKey,
|
||||
OutgoingAmountMsat: newOutgoingAmountMsat,
|
||||
CustomRecords: customRecords,
|
||||
Action: action,
|
||||
})
|
||||
require.NoError(ht, err, "failed to send request")
|
||||
|
||||
// Check that the modified UpdateAddHTLC message fields were reported in
|
||||
// Carol's log.
|
||||
targetLogPrefixStr := "Received UpdateAddHTLC("
|
||||
targetOutgoingAmountMsatStr := fmt.Sprintf(
|
||||
"amt=%d", newOutgoingAmountMsat,
|
||||
)
|
||||
|
||||
// Formulate custom records target log string.
|
||||
var asciiValues []string
|
||||
for _, b := range crValue {
|
||||
asciiValues = append(asciiValues, fmt.Sprintf("%d", b))
|
||||
}
|
||||
|
||||
targetCustomRecordsStr := fmt.Sprintf(
|
||||
"%d:[%s]", crKey, strings.Join(asciiValues, " "),
|
||||
)
|
||||
|
||||
// logEntryCheck is a helper function that checks if the log entry
|
||||
// contains the expected strings.
|
||||
logEntryCheck := func(logEntry string) bool {
|
||||
return strings.Contains(logEntry, targetLogPrefixStr) &&
|
||||
strings.Contains(logEntry, targetCustomRecordsStr) &&
|
||||
strings.Contains(logEntry, targetOutgoingAmountMsatStr)
|
||||
}
|
||||
|
||||
// Wait for the log entry to appear in Carol's log.
|
||||
require.Eventually(ht, func() bool {
|
||||
ctx := context.Background()
|
||||
dbgInfo, err := carol.RPC.LN.GetDebugInfo(
|
||||
ctx, &lnrpc.GetDebugInfoRequest{},
|
||||
)
|
||||
require.NoError(ht, err, "failed to get Carol node debug info")
|
||||
|
||||
for _, logEntry := range dbgInfo.Log {
|
||||
if logEntryCheck(logEntry) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}, defaultTimeout, time.Second)
|
||||
|
||||
// Cancel the context, which will disconnect Bob's interceptor.
|
||||
cancelBobInterceptor()
|
||||
|
||||
// Make sure all goroutines are finished.
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(defaultTimeout):
|
||||
require.Fail(ht, "timeout waiting for sending payment")
|
||||
}
|
||||
|
||||
// Assert that the payment was successful.
|
||||
var preimage lntypes.Preimage
|
||||
copy(preimage[:], invoice.RPreimage)
|
||||
ht.AssertPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED)
|
||||
|
||||
// Finally, close channels.
|
||||
ht.CloseChannel(alice, cpAB)
|
||||
ht.CloseChannel(bob, cpBC)
|
||||
}
|
||||
|
||||
// interceptorTestScenario is a helper struct to hold the test context and
|
||||
// provide the needed functionality.
|
||||
type interceptorTestScenario struct {
|
||||
|
|
Loading…
Add table
Reference in a new issue