Skip to content

Commit 9db23ae

Browse files
committed
mod+itest: bump to latest lnd+tapd, add bandwidth test
1 parent d0e6a25 commit 9db23ae

File tree

2 files changed

+221
-0
lines changed

2 files changed

+221
-0
lines changed

itest/litd_custom_channels_test.go

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3320,3 +3320,220 @@ func runCustomChannelsHtlcForceClose(ctxb context.Context, t *harnessTest,
33203320
t.t, zaneTap, assetID, zaneExpectedBalance,
33213321
)
33223322
}
3323+
3324+
// testCustomChannelsForwardBandwidth is a test that runs through some Taproot
3325+
// Assets Channel liquidity edge cases, specifically related to forwarding HTLCs
3326+
// into channels with no available asset bandwidth.
3327+
func testCustomChannelsForwardBandwidth(ctxb context.Context,
3328+
net *NetworkHarness, t *harnessTest) {
3329+
3330+
lndArgs := slices.Clone(lndArgsTemplate)
3331+
litdArgs := slices.Clone(litdArgsTemplate)
3332+
3333+
// Explicitly set the proof courier as Zane (now has no other role
3334+
// other than proof shuffling), otherwise a hashmail courier will be
3335+
// used. For the funding transaction, we're just posting it and don't
3336+
// expect a true receiver.
3337+
zane, err := net.NewNode(
3338+
t.t, "Zane", lndArgs, false, true, litdArgs...,
3339+
)
3340+
require.NoError(t.t, err)
3341+
3342+
litdArgs = append(litdArgs, fmt.Sprintf(
3343+
"--taproot-assets.proofcourieraddr=%s://%s",
3344+
proof.UniverseRpcCourierType, zane.Cfg.LitAddr(),
3345+
))
3346+
3347+
// The topology we are going for looks like the following:
3348+
//
3349+
// Charlie --[assets]--> Dave --[sats]--> Erin --[assets]--> Fabia
3350+
// |
3351+
// |
3352+
// [assets]
3353+
// |
3354+
// v
3355+
// Yara
3356+
//
3357+
// With [assets] being a custom channel and [sats] being a normal, BTC
3358+
// only channel.
3359+
// All 5 nodes need to be full litd nodes running in integrated mode
3360+
// with tapd included. We also need specific flags to be enabled, so we
3361+
// create 5 completely new nodes, ignoring the two default nodes that
3362+
// are created by the harness.
3363+
charlie, err := net.NewNode(
3364+
t.t, "Charlie", lndArgs, false, true, litdArgs...,
3365+
)
3366+
require.NoError(t.t, err)
3367+
3368+
dave, err := net.NewNode(t.t, "Dave", lndArgs, false, true, litdArgs...)
3369+
require.NoError(t.t, err)
3370+
erin, err := net.NewNode(t.t, "Erin", lndArgs, false, true, litdArgs...)
3371+
require.NoError(t.t, err)
3372+
fabia, err := net.NewNode(
3373+
t.t, "Fabia", lndArgs, false, true, litdArgs...,
3374+
)
3375+
require.NoError(t.t, err)
3376+
yara, err := net.NewNode(
3377+
t.t, "Yara", lndArgs, false, true, litdArgs...,
3378+
)
3379+
require.NoError(t.t, err)
3380+
3381+
nodes := []*HarnessNode{charlie, dave, erin, fabia, yara}
3382+
connectAllNodes(t.t, net, nodes)
3383+
fundAllNodes(t.t, net, nodes)
3384+
3385+
// Create the normal channel between Dave and Erin.
3386+
t.Logf("Opening normal channel between Dave and Erin...")
3387+
channelOp := openChannelAndAssert(
3388+
t, net, dave, erin, lntest.OpenChannelParams{
3389+
Amt: 10_000_000,
3390+
SatPerVByte: 5,
3391+
},
3392+
)
3393+
defer closeChannelAndAssert(t, net, dave, channelOp, false)
3394+
3395+
// This is the only public channel, we need everyone to be aware of it.
3396+
assertChannelKnown(t.t, charlie, channelOp)
3397+
assertChannelKnown(t.t, fabia, channelOp)
3398+
3399+
universeTap := newTapClient(t.t, zane)
3400+
charlieTap := newTapClient(t.t, charlie)
3401+
daveTap := newTapClient(t.t, dave)
3402+
erinTap := newTapClient(t.t, erin)
3403+
fabiaTap := newTapClient(t.t, fabia)
3404+
yaraTap := newTapClient(t.t, yara)
3405+
3406+
// Mint an asset on Charlie and sync all nodes to Charlie as the
3407+
// universe.
3408+
mintedAssets := itest.MintAssetsConfirmBatch(
3409+
t.t, t.lndHarness.Miner.Client, charlieTap,
3410+
[]*mintrpc.MintAssetRequest{
3411+
{
3412+
Asset: itestAsset,
3413+
},
3414+
},
3415+
)
3416+
cents := mintedAssets[0]
3417+
assetID := cents.AssetGenesis.AssetId
3418+
3419+
t.Logf("Minted %d lightning cents, syncing universes...", cents.Amount)
3420+
syncUniverses(t.t, charlieTap, dave, erin, fabia, yara)
3421+
t.Logf("Universes synced between all nodes, distributing assets...")
3422+
3423+
const (
3424+
daveFundingAmount = uint64(400_000)
3425+
erinFundingAmount = uint64(200_000)
3426+
)
3427+
charlieFundingAmount := cents.Amount - uint64(2*400_000)
3428+
3429+
_, _, chanPointEF := createTestAssetNetwork(
3430+
t, net, charlieTap, daveTap, erinTap, fabiaTap, yaraTap,
3431+
universeTap, cents, 400_000, charlieFundingAmount,
3432+
daveFundingAmount, erinFundingAmount, 0,
3433+
)
3434+
3435+
// Before we start sending out payments, let's make sure each node can
3436+
// see the other one in the graph and has all required features.
3437+
require.NoError(t.t, t.lndHarness.AssertNodeKnown(charlie, dave))
3438+
require.NoError(t.t, t.lndHarness.AssertNodeKnown(dave, charlie))
3439+
require.NoError(t.t, t.lndHarness.AssertNodeKnown(dave, yara))
3440+
require.NoError(t.t, t.lndHarness.AssertNodeKnown(yara, dave))
3441+
require.NoError(t.t, t.lndHarness.AssertNodeKnown(erin, fabia))
3442+
require.NoError(t.t, t.lndHarness.AssertNodeKnown(fabia, erin))
3443+
require.NoError(t.t, t.lndHarness.AssertNodeKnown(charlie, erin))
3444+
3445+
logBalance(t.t, nodes, assetID, "initial")
3446+
3447+
// We now deplete the channel between Erin and Fabia by moving all
3448+
// assets to Fabia.
3449+
sendAssetKeySendPayment(
3450+
t.t, erin, fabia, erinFundingAmount, assetID,
3451+
fn.None[int64](), lnrpc.Payment_SUCCEEDED,
3452+
fn.None[lnrpc.PaymentFailureReason](),
3453+
)
3454+
logBalance(t.t, nodes, assetID, "after moving assets to Fabia")
3455+
3456+
// Test case 1: We cannot keysend more assets from Erin to Fabia.
3457+
sendAssetKeySendPayment(
3458+
t.t, erin, fabia, 1, assetID, fn.None[int64](),
3459+
lnrpc.Payment_FAILED, fn.Some(errNoBalance),
3460+
)
3461+
3462+
// Test case 2: We cannot pay an invoice from Charlie to Fabia.
3463+
invoiceResp := createAssetInvoice(t.t, erin, fabia, 123, assetID)
3464+
payInvoiceWithSatoshi(
3465+
t.t, charlie, invoiceResp, lnrpc.Payment_FAILED,
3466+
fn.Some(errNoRoute),
3467+
)
3468+
3469+
// Test case 3: We now create an asset buy order for a normal amount of
3470+
// assets. We then "fake" an invoice referencing that buy order that
3471+
// is for an amount that is too small to be paid with a single asset
3472+
// unit. This should be handled gracefully and not lead to a crash.
3473+
// Ideally such an invoice shouldn't be created in the first place, but
3474+
// we want to make sure that the system doesn't crash in this case.
3475+
numUnits := uint64(10)
3476+
buyOrderResp, err := fabiaTap.RfqClient.AddAssetBuyOrder(
3477+
ctxb, &rfqrpc.AddAssetBuyOrderRequest{
3478+
AssetSpecifier: &rfqrpc.AssetSpecifier{
3479+
Id: &rfqrpc.AssetSpecifier_AssetId{
3480+
AssetId: assetID,
3481+
},
3482+
},
3483+
AssetMaxAmt: numUnits,
3484+
Expiry: uint64(
3485+
time.Now().Add(time.Hour).Unix(),
3486+
),
3487+
PeerPubKey: erin.PubKey[:],
3488+
TimeoutSeconds: 10,
3489+
},
3490+
)
3491+
require.NoError(t.t, err)
3492+
3493+
quoteResp := buyOrderResp.Response
3494+
quote, ok := quoteResp.(*rfqrpc.AddAssetBuyOrderResponse_AcceptedQuote)
3495+
require.True(t.t, ok)
3496+
3497+
// We calculate the milli-satoshi amount one below the equivalent of a
3498+
// single asset unit.
3499+
rate, err := oraclerpc.UnmarshalFixedPoint(&oraclerpc.FixedPoint{
3500+
Coefficient: quote.AcceptedQuote.AskAssetRate.Coefficient,
3501+
Scale: quote.AcceptedQuote.AskAssetRate.Scale,
3502+
})
3503+
require.NoError(t.t, err)
3504+
3505+
oneUnit := rfqmath.NewBigIntFixedPoint(1, 0)
3506+
oneUnitMilliSat := rfqmath.UnitsToMilliSatoshi(oneUnit, *rate)
3507+
3508+
t.Logf("Got quote for %v asset units per BTC", rate)
3509+
msatPerUnit := float64(oneUnitMilliSat) / float64(1)
3510+
t.Logf("Got quote for %v asset units at %3f msat/unit from peer %s "+
3511+
"with SCID %d", numUnits, msatPerUnit, erin.PubKeyStr,
3512+
quote.AcceptedQuote.Scid)
3513+
3514+
// We now manually add the invoice in order to inject the above,
3515+
// manually generated, quote.
3516+
invoiceResp2, err := fabia.AddInvoice(ctxb, &lnrpc.Invoice{
3517+
Memo: "too small invoice",
3518+
ValueMsat: int64(oneUnitMilliSat - 1),
3519+
RouteHints: []*lnrpc.RouteHint{{
3520+
HopHints: []*lnrpc.HopHint{{
3521+
NodeId: erin.PubKeyStr,
3522+
ChanId: quote.AcceptedQuote.Scid,
3523+
}},
3524+
}},
3525+
})
3526+
require.NoError(t.t, err)
3527+
3528+
payInvoiceWithSatoshi(
3529+
t.t, dave, invoiceResp2, lnrpc.Payment_FAILED,
3530+
fn.Some(errNoRoute),
3531+
)
3532+
3533+
// Finally, we close the channel between Erin and Fabia to make sure
3534+
// everything is settled correctly.
3535+
closeAssetChannelAndAssert(
3536+
t, net, erin, fabia, chanPointEF, assetID, nil,
3537+
universeTap, noOpCoOpCloseBalanceCheck,
3538+
)
3539+
}

itest/litd_test_list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,8 @@ var allTestCases = []*testCase{
6868
name: "test custom channels fee",
6969
test: testCustomChannelsFee,
7070
},
71+
{
72+
name: "test custom channels forward bandwidth",
73+
test: testCustomChannelsForwardBandwidth,
74+
},
7175
}

0 commit comments

Comments
 (0)