mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
Merge pull request #1198 from jtobin/capacity-check
itest: add channel capacity assertions
This commit is contained in:
commit
8d601c6e45
2 changed files with 150 additions and 0 deletions
|
|
@ -3,6 +3,7 @@ package itest
|
|||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
|
|
@ -35,6 +36,7 @@ import (
|
|||
"github.com/lightningnetwork/lnd/lntest"
|
||||
"github.com/lightningnetwork/lnd/lntest/node"
|
||||
"github.com/lightningnetwork/lnd/lntest/port"
|
||||
"github.com/lightningnetwork/lnd/lntest/wait"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
|
|
@ -5486,3 +5488,146 @@ func testCustomChannelsMultiChannelPathfinding(ctx context.Context,
|
|||
t.t, alice, bob, invoiceResp.PaymentRequest, assetIDPences,
|
||||
)
|
||||
}
|
||||
|
||||
// testCustomChannelsPassiveAssets tests that passive assets (assets
|
||||
// in the same input commitment but not used for channel funding) are
|
||||
// not included in the funding assets sent to the responder
|
||||
func testCustomChannelsPassiveAssets(ctx context.Context, net *NetworkHarness,
|
||||
t *harnessTest) {
|
||||
|
||||
lndArgs := slices.Clone(lndArgsTemplate)
|
||||
litdArgs := slices.Clone(litdArgsTemplate)
|
||||
|
||||
charliePort := port.NextAvailablePort()
|
||||
litdArgs = append(litdArgs, fmt.Sprintf(
|
||||
"--taproot-assets.proofcourieraddr=%s://%s",
|
||||
proof.UniverseRpcCourierType,
|
||||
fmt.Sprintf(node.ListenerFormat, charliePort),
|
||||
))
|
||||
|
||||
charlie, err := net.NewNodeWithPort(
|
||||
t.t, "Charlie", lndArgs, false, true, charliePort, litdArgs...,
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
dave, err := net.NewNode(t.t, "Dave", lndArgs, false, true, litdArgs...)
|
||||
require.NoError(t.t, err)
|
||||
|
||||
nodes := []*HarnessNode{charlie, dave}
|
||||
connectAllNodes(t.t, net, nodes)
|
||||
fundAllNodes(t.t, net, nodes)
|
||||
|
||||
charlieTap := newTapClient(t.t, charlie)
|
||||
daveTap := newTapClient(t.t, dave)
|
||||
|
||||
// Mint two assets in the same batch with the same group key. This puts
|
||||
// them in the same anchor UTXO/commitment.
|
||||
assetA := &mintrpc.MintAsset{
|
||||
AssetType: taprpc.AssetType_NORMAL,
|
||||
Name: "asset-a-for-channel",
|
||||
AssetMeta: dummyMetaData,
|
||||
Amount: 100_000,
|
||||
NewGroupedAsset: true,
|
||||
}
|
||||
assetB := &mintrpc.MintAsset{
|
||||
AssetType: taprpc.AssetType_NORMAL,
|
||||
Name: "asset-b-passive",
|
||||
AssetMeta: dummyMetaData,
|
||||
Amount: 50_000,
|
||||
GroupedAsset: true,
|
||||
GroupAnchor: "asset-a-for-channel",
|
||||
}
|
||||
mintedAssets := itest.MintAssetsConfirmBatch(
|
||||
t.t, t.lndHarness.Miner.Client, charlieTap,
|
||||
[]*mintrpc.MintAssetRequest{
|
||||
{Asset: assetA},
|
||||
{Asset: assetB},
|
||||
},
|
||||
)
|
||||
require.Len(t.t, mintedAssets, 2)
|
||||
|
||||
mintedA := mintedAssets[0]
|
||||
mintedB := mintedAssets[1]
|
||||
assetIDA := mintedA.AssetGenesis.AssetId
|
||||
|
||||
// Both assets should have the same group key.
|
||||
require.NotNil(t.t, mintedA.AssetGroup)
|
||||
require.NotNil(t.t, mintedB.AssetGroup)
|
||||
groupKey := mintedA.AssetGroup.TweakedGroupKey
|
||||
require.Equal(t.t, groupKey, mintedB.AssetGroup.TweakedGroupKey)
|
||||
|
||||
// Check if both assets share the same anchor outpoint (i.e. UTXO).
|
||||
outpointA := mintedA.ChainAnchor.AnchorOutpoint
|
||||
outpointB := mintedB.ChainAnchor.AnchorOutpoint
|
||||
t.Logf("Asset A anchor outpoint: %s", outpointA)
|
||||
t.Logf("Asset B anchor outpoint: %s", outpointB)
|
||||
require.Equal(t.t, outpointA, outpointB,
|
||||
"assets must be in same UTXO for passive asset test")
|
||||
|
||||
syncUniverses(t.t, charlieTap, dave)
|
||||
mineBlocks(t, net, 1, 0)
|
||||
|
||||
// Fund a channel using the group key. We request 75,000 units which
|
||||
// forces Asset A (100,000) to be selected since Asset B (50,000) is
|
||||
// insufficient. Asset B should become passive and not appear in Dave's
|
||||
// view of the channel.
|
||||
const fundingAmount = 75_000
|
||||
fundResp, err := charlieTap.FundChannel(
|
||||
ctx, &tchrpc.FundChannelRequest{
|
||||
AssetAmount: fundingAmount,
|
||||
GroupKey: groupKey,
|
||||
PeerPubkey: daveTap.node.PubKey[:],
|
||||
FeeRateSatPerVbyte: 5,
|
||||
PushSat: DefaultPushSat,
|
||||
},
|
||||
)
|
||||
require.NoError(t.t, err)
|
||||
|
||||
mineBlocks(t, net, 6, 1)
|
||||
|
||||
// Assert Dave (responder) only sees Asset A in the channel, not the
|
||||
// passive Asset B. Use wait.NoError to handle the race condition where
|
||||
// the channel may not be immediately visible after mining.
|
||||
var chanData *rfqmsg.JsonAssetChannel
|
||||
err = wait.NoError(func() error {
|
||||
var chanErr error
|
||||
chanData, chanErr = getChannelCustomData(dave, charlie)
|
||||
if chanErr != nil {
|
||||
return chanErr
|
||||
}
|
||||
|
||||
// There should be exactly one funding asset (Asset A).
|
||||
if len(chanData.FundingAssets) != 1 {
|
||||
return fmt.Errorf("expected 1 funding asset, got %d",
|
||||
len(chanData.FundingAssets))
|
||||
}
|
||||
|
||||
// Verify it's Asset A, not Asset B.
|
||||
fundingAssetID := chanData.FundingAssets[0].AssetGenesis.AssetID
|
||||
if hex.EncodeToString(assetIDA) != fundingAssetID {
|
||||
return fmt.Errorf("funding asset should be Asset A, "+
|
||||
"got %s", fundingAssetID)
|
||||
}
|
||||
|
||||
// Verify capacity matches funding amount, not inflated by
|
||||
// Asset B.
|
||||
if chanData.Capacity != uint64(fundingAmount) {
|
||||
return fmt.Errorf("capacity should be %d, not "+
|
||||
"inflated by passive assets, got %d",
|
||||
fundingAmount, chanData.Capacity)
|
||||
}
|
||||
|
||||
return nil
|
||||
}, defaultTimeout)
|
||||
require.NoError(t.t, err)
|
||||
|
||||
chanPoint := &lnrpc.ChannelPoint{
|
||||
OutputIndex: uint32(fundResp.OutputIndex),
|
||||
FundingTxid: &lnrpc.ChannelPoint_FundingTxidStr{
|
||||
FundingTxidStr: fundResp.Txid,
|
||||
},
|
||||
}
|
||||
closeAssetChannelAndAssert(
|
||||
t, net, charlie, dave, chanPoint, [][]byte{assetIDA}, nil,
|
||||
charlieTap, noOpCoOpCloseBalanceCheck,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,11 @@ var allTestCases = []*testCase{
|
|||
test: testCustomChannelsSingleAssetMultiInput,
|
||||
noAliceBob: true,
|
||||
},
|
||||
{
|
||||
name: "custom channels passive assets",
|
||||
test: testCustomChannelsPassiveAssets,
|
||||
noAliceBob: true,
|
||||
},
|
||||
{
|
||||
name: "custom channels oracle pricing",
|
||||
test: testCustomChannelsOraclePricing,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue