mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-27 18:46:18 +02:00
itest: enhance mission control namespace itest
In this commit, we enhance the itess to exercise the new query+reset+import namespace features. This also rounds out the test as well to make sure that the mc payment portion works properly.
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package itest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
@@ -11,79 +14,187 @@ import (
|
||||
// testMissionControlNamespace tests that payments can use different mission
|
||||
// control namespaces to maintain separate routing histories.
|
||||
func testMissionControlNamespace(ht *lntest.HarnessTest) {
|
||||
// Create a simple two-node network.
|
||||
const chanAmt = btcutil.Amount(1_000_000)
|
||||
|
||||
// Create two nodes. Alice gets funded.
|
||||
|
||||
// We'll create a simple two node network for this tesat.
|
||||
alice := ht.NewNodeWithCoins("Alice", nil)
|
||||
bob := ht.NewNode("Bob", nil)
|
||||
|
||||
// Connect nodes.
|
||||
ht.EnsureConnected(alice, bob)
|
||||
|
||||
// Open channel: Alice -> Bob.
|
||||
chanPoint := ht.OpenChannel(
|
||||
alice, bob, lntest.OpenChannelParams{
|
||||
Amt: chanAmt,
|
||||
},
|
||||
)
|
||||
|
||||
// Wait for channel to be seen by both nodes.
|
||||
ht.AssertChannelInGraph(alice, chanPoint)
|
||||
ht.AssertChannelInGraph(bob, chanPoint)
|
||||
|
||||
// Create an invoice from Bob.
|
||||
// Create an invoice for Bob that we'll pay below.
|
||||
const paymentAmt = 10_000
|
||||
invoice := bob.RPC.AddInvoice(&lnrpc.Invoice{
|
||||
Value: paymentAmt,
|
||||
Memo: "test payment default namespace",
|
||||
})
|
||||
|
||||
// Reset mission control to ensure clean state.
|
||||
alice.RPC.ResetMissionControl()
|
||||
// Reset mission control for the default namespace to ensure clean
|
||||
// state.
|
||||
_, err := alice.RPC.Router.ResetMissionControl(
|
||||
ht.Context(), &routerrpc.ResetMissionControlRequest{
|
||||
MissionControlNamespace: "",
|
||||
},
|
||||
)
|
||||
require.NoError(ht.T, err, "failed to reset default mission control")
|
||||
|
||||
// Send a payment using the default namespace.
|
||||
req := &routerrpc.SendPaymentRequest{
|
||||
PaymentRequest: invoice.PaymentRequest,
|
||||
TimeoutSeconds: 60,
|
||||
MissionControlNamespace: "", // default namespace
|
||||
}
|
||||
ht.SendPaymentAssertSettled(alice, req)
|
||||
ht.Run("send_payment_with_namespaces", func(t *testing.T) {
|
||||
// Send a payment using the default namespace.
|
||||
reqDefault := &routerrpc.SendPaymentRequest{
|
||||
PaymentRequest: invoice.PaymentRequest,
|
||||
TimeoutSeconds: 60,
|
||||
MissionControlNamespace: "",
|
||||
}
|
||||
ht.SendPaymentAssertSettled(alice, reqDefault)
|
||||
|
||||
// Create another invoice.
|
||||
invoice2 := bob.RPC.AddInvoice(&lnrpc.Invoice{
|
||||
Value: paymentAmt,
|
||||
Memo: "test payment custom namespace",
|
||||
// Make another payment with Bob but use our custom namespace
|
||||
// this time instead.
|
||||
invoice2 := bob.RPC.AddInvoice(&lnrpc.Invoice{
|
||||
Value: paymentAmt,
|
||||
Memo: "test payment custom namespace",
|
||||
})
|
||||
customNs := "custom-namespace-send"
|
||||
reqCustom := &routerrpc.SendPaymentRequest{
|
||||
PaymentRequest: invoice2.PaymentRequest,
|
||||
TimeoutSeconds: 60,
|
||||
MissionControlNamespace: customNs,
|
||||
}
|
||||
payment := ht.SendPaymentAssertSettled(alice, reqCustom)
|
||||
require.Equal(t, lnrpc.Payment_SUCCEEDED, payment.Status,
|
||||
"payment with custom namespace should succeed")
|
||||
|
||||
// If we query for the default mc, then we should find that the
|
||||
// records are populated.
|
||||
mcReqDefault := &routerrpc.QueryMissionControlRequest{
|
||||
MissionControlNamespace: "",
|
||||
}
|
||||
defaultMC, err := alice.RPC.Router.QueryMissionControl(
|
||||
ht.Context(), mcReqDefault,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, defaultMC.Pairs,
|
||||
"default namespace should have recorded channel usage")
|
||||
|
||||
// Similarly, we should find that the custom namespace also has
|
||||
// entries.
|
||||
mcReqCustom := &routerrpc.QueryMissionControlRequest{
|
||||
MissionControlNamespace: customNs,
|
||||
}
|
||||
customMC, err := alice.RPC.Router.QueryMissionControl(
|
||||
ht.Context(), mcReqCustom,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, customMC.Pairs,
|
||||
"custom namespace should have recorded channel usage")
|
||||
|
||||
require.True(t, len(defaultMC.Pairs) > 0, "Default MC empty")
|
||||
require.True(t, len(customMC.Pairs) > 0, "Custom MC empty")
|
||||
})
|
||||
|
||||
// Send a payment using a custom namespace.
|
||||
customReq := &routerrpc.SendPaymentRequest{
|
||||
PaymentRequest: invoice2.PaymentRequest,
|
||||
TimeoutSeconds: 60,
|
||||
MissionControlNamespace: "custom-namespace",
|
||||
}
|
||||
payment := ht.SendPaymentAssertSettled(alice, customReq)
|
||||
require.Equal(ht.T, lnrpc.Payment_SUCCEEDED, payment.Status,
|
||||
"payment with custom namespace should succeed")
|
||||
ht.Run("reset_mission_control_with_namespace", func(t *testing.T) {
|
||||
customNsReset := "namespace-to-reset"
|
||||
|
||||
// Query mission control to verify the default namespace has recorded
|
||||
// the payment attempt.
|
||||
mcReq := &routerrpc.QueryMissionControlRequest{}
|
||||
defaultMC, err := alice.RPC.Router.QueryMissionControl(
|
||||
ht.Context(), mcReq,
|
||||
)
|
||||
require.NoError(ht.T, err)
|
||||
|
||||
// The default namespace should have recorded at least one pair.
|
||||
require.NotEmpty(ht.T, defaultMC.Pairs,
|
||||
"default namespace should have recorded channel usage")
|
||||
|
||||
// The test passes if we have any pairs recorded, which proves
|
||||
// mission control is working with the default namespace.
|
||||
// The custom namespace payment also succeeded, demonstrating
|
||||
// namespace isolation.
|
||||
// Send a payment to populate this new custom namespace.
|
||||
invReset := bob.RPC.AddInvoice(&lnrpc.Invoice{Value: 100})
|
||||
reqPopulate := &routerrpc.SendPaymentRequest{
|
||||
PaymentRequest: invReset.PaymentRequest,
|
||||
TimeoutSeconds: 60,
|
||||
MissionControlNamespace: customNsReset,
|
||||
}
|
||||
ht.SendPaymentAssertSettled(alice, reqPopulate)
|
||||
|
||||
// Note: Currently there's no way to query a specific namespace's
|
||||
// mission control state via RPC, but the fact that both payments
|
||||
// succeeded proves the namespace isolation is working correctly.
|
||||
}
|
||||
// Query the namespace, we should find now that it has some
|
||||
// entries populated.
|
||||
mcBeforeReset, err := alice.RPC.Router.QueryMissionControl(
|
||||
ht.Context(), &routerrpc.QueryMissionControlRequest{
|
||||
MissionControlNamespace: customNsReset,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(
|
||||
t, mcBeforeReset.Pairs, "MC should be populated "+
|
||||
"before reset",
|
||||
)
|
||||
|
||||
// Now, we'll reset the ns, then check below that it's actually
|
||||
// empty.
|
||||
_, errReset := alice.RPC.Router.ResetMissionControl(
|
||||
ht.Context(), &routerrpc.ResetMissionControlRequest{
|
||||
MissionControlNamespace: customNsReset,
|
||||
},
|
||||
)
|
||||
require.NoError(t, errReset)
|
||||
|
||||
// Query again to confirm it's empty.
|
||||
mcAfterReset, err := alice.RPC.Router.QueryMissionControl(
|
||||
ht.Context(), &routerrpc.QueryMissionControlRequest{
|
||||
MissionControlNamespace: customNsReset,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.Empty(
|
||||
t, mcAfterReset.Pairs, "MC should be empty after reset",
|
||||
)
|
||||
|
||||
// Now we'll test isolation: the default namespace shouldn't
|
||||
// have been affected.
|
||||
defaultMC, err := alice.RPC.Router.QueryMissionControl(
|
||||
ht.Context(), &routerrpc.QueryMissionControlRequest{
|
||||
MissionControlNamespace: "",
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(
|
||||
t, defaultMC.Pairs, "Default MC should not be empty",
|
||||
)
|
||||
})
|
||||
|
||||
ht.Run("ximport_mission_control_with_namespace", func(t *testing.T) {
|
||||
customNs := "namespace-to-import"
|
||||
|
||||
// We'll make some fake data to import as weights.
|
||||
importData := &routerrpc.XImportMissionControlRequest{ //nolint:ll
|
||||
MissionControlNamespace: customNs,
|
||||
Pairs: []*routerrpc.PairHistory{
|
||||
{
|
||||
NodeFrom: alice.PubKey[:],
|
||||
NodeTo: bob.PubKey[:],
|
||||
History: &routerrpc.PairData{
|
||||
FailTime: time.Now().Unix() - 1000,
|
||||
FailAmtMsat: 5000,
|
||||
SuccessTime: time.Now().Unix(),
|
||||
SuccessAmtMsat: 10000,
|
||||
},
|
||||
},
|
||||
},
|
||||
Force: true,
|
||||
}
|
||||
|
||||
_, err := alice.RPC.Router.XImportMissionControl(
|
||||
ht.Context(), importData,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// That data that we created above should be found now.
|
||||
mcAfterImport, err := alice.RPC.Router.QueryMissionControl(
|
||||
ht.Context(), &routerrpc.QueryMissionControlRequest{
|
||||
MissionControlNamespace: customNs,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(
|
||||
t, mcAfterImport.Pairs, "MC should have imported data",
|
||||
)
|
||||
require.Equal(
|
||||
t, int64(10000),
|
||||
mcAfterImport.Pairs[0].History.SuccessAmtMsat,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user