Skip to content

Commit 264c189

Browse files
committed
itest: add test for consistent balance reporting
This commit adds an integration test to ensure consistent balance reporting across various scenarios. The test covers custom channel funding and list balance operations to verify that balance information is accurately reported between lnd's `ChannelBalance` and tapd's `ListBalance` RPCs, without accidental double reporting.
1 parent 97bf95f commit 264c189

File tree

3 files changed

+212
-8
lines changed

3 files changed

+212
-8
lines changed

itest/assets_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"github.com/lightninglabs/taproot-assets/proof"
2222
"github.com/lightninglabs/taproot-assets/rfq"
2323
"github.com/lightninglabs/taproot-assets/rfqmsg"
24-
"github.com/lightninglabs/taproot-assets/tapchannel"
2524
"github.com/lightninglabs/taproot-assets/tapfreighter"
2625
"github.com/lightninglabs/taproot-assets/taprpc"
2726
"github.com/lightninglabs/taproot-assets/taprpc/assetwalletrpc"
@@ -30,6 +29,7 @@ import (
3029
tchrpc "github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
3130
"github.com/lightninglabs/taproot-assets/taprpc/tapdevrpc"
3231
"github.com/lightninglabs/taproot-assets/taprpc/universerpc"
32+
"github.com/lightninglabs/taproot-assets/tapscript"
3333
"github.com/lightningnetwork/lnd/fn"
3434
"github.com/lightningnetwork/lnd/lnrpc"
3535
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
@@ -67,7 +67,7 @@ func createTestAssetNetwork(t *harnessTest, net *NetworkHarness, charlieTap,
6767
groupKey = mintedAsset.AssetGroup.TweakedGroupKey
6868
}
6969

70-
fundingScriptTree := tapchannel.NewFundingScriptTree()
70+
fundingScriptTree := tapscript.NewFundingScriptTree()
7171
fundingScriptKey := fundingScriptTree.TaprootKey
7272
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
7373

itest/litd_custom_channels_test.go

Lines changed: 206 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ import (
66
"slices"
77
"time"
88

9+
"github.com/btcsuite/btcd/btcec/v2/schnorr"
910
"github.com/btcsuite/btcd/btcutil"
1011
"github.com/btcsuite/btcd/chaincfg/chainhash"
1112
"github.com/lightninglabs/taproot-assets/itest"
1213
"github.com/lightninglabs/taproot-assets/proof"
13-
"github.com/lightninglabs/taproot-assets/tapchannel"
1414
"github.com/lightninglabs/taproot-assets/taprpc"
1515
"github.com/lightninglabs/taproot-assets/taprpc/mintrpc"
1616
tchrpc "github.com/lightninglabs/taproot-assets/taprpc/tapchannelrpc"
1717
"github.com/lightninglabs/taproot-assets/taprpc/universerpc"
18+
"github.com/lightninglabs/taproot-assets/tapscript"
1819
"github.com/lightningnetwork/lnd/fn"
1920
"github.com/lightningnetwork/lnd/lnrpc"
2021
"github.com/lightningnetwork/lnd/lntest"
@@ -353,7 +354,7 @@ func testCustomChannels(_ context.Context, net *NetworkHarness,
353354
)
354355
cents := mintedAssets[0]
355356
assetID := cents.AssetGenesis.AssetId
356-
fundingScriptTree := tapchannel.NewFundingScriptTree()
357+
fundingScriptTree := tapscript.NewFundingScriptTree()
357358
fundingScriptKey := fundingScriptTree.TaprootKey
358359
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
359360

@@ -812,7 +813,7 @@ func testCustomChannelsGroupedAsset(_ context.Context, net *NetworkHarness,
812813
cents := mintedAssets[0]
813814
assetID := cents.AssetGenesis.AssetId
814815
groupID := cents.GetAssetGroup().GetTweakedGroupKey()
815-
fundingScriptTree := tapchannel.NewFundingScriptTree()
816+
fundingScriptTree := tapscript.NewFundingScriptTree()
816817
fundingScriptKey := fundingScriptTree.TaprootKey
817818
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
818819

@@ -1230,7 +1231,7 @@ func testCustomChannelsForceClose(_ context.Context, net *NetworkHarness,
12301231

12311232
// Make sure that Charlie properly uploaded funding proof to the
12321233
// Universe server.
1233-
fundingScriptTree := tapchannel.NewFundingScriptTree()
1234+
fundingScriptTree := tapscript.NewFundingScriptTree()
12341235
fundingScriptKey := fundingScriptTree.TaprootKey
12351236
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
12361237
assertUniverseProofExists(
@@ -1568,7 +1569,7 @@ func testCustomChannelsBreach(_ context.Context, net *NetworkHarness,
15681569

15691570
// Make sure that Charlie properly uploaded funding proof to the
15701571
// Universe server.
1571-
fundingScriptTree := tapchannel.NewFundingScriptTree()
1572+
fundingScriptTree := tapscript.NewFundingScriptTree()
15721573
fundingScriptKey := fundingScriptTree.TaprootKey
15731574
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
15741575
assertUniverseProofExists(
@@ -1748,7 +1749,7 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,
17481749
if cents.AssetGroup != nil {
17491750
groupKey = cents.AssetGroup.TweakedGroupKey
17501751
}
1751-
fundingScriptTree := tapchannel.NewFundingScriptTree()
1752+
fundingScriptTree := tapscript.NewFundingScriptTree()
17521753
fundingScriptKey := fundingScriptTree.TaprootKey
17531754
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
17541755

@@ -1894,3 +1895,202 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,
18941895

18951896
logBalance(t.t, nodes, assetID, "after giant asset payment")
18961897
}
1898+
1899+
// testCustomChannelsBalanceConsistency is a test that test the balance .
1900+
func testCustomChannelsBalanceConsistency(_ context.Context,
1901+
net *NetworkHarness, t *harnessTest) {
1902+
1903+
ctxb := context.Background()
1904+
lndArgs := slices.Clone(lndArgsTemplate)
1905+
litdArgs := slices.Clone(litdArgsTemplate)
1906+
1907+
zane, err := net.NewNode(
1908+
t.t, "Zane", lndArgs, false, true, litdArgs...,
1909+
)
1910+
require.NoError(t.t, err)
1911+
1912+
litdArgs = append(litdArgs, fmt.Sprintf(
1913+
"--taproot-assets.proofcourieraddr=%s://%s",
1914+
proof.UniverseRpcCourierType, zane.Cfg.LitAddr(),
1915+
))
1916+
1917+
charlie, err := net.NewNode(
1918+
t.t, "Charlie", lndArgs, false, true, litdArgs...,
1919+
)
1920+
require.NoError(t.t, err)
1921+
dave, err := net.NewNode(t.t, "Dave", lndArgs, false, true, litdArgs...)
1922+
require.NoError(t.t, err)
1923+
1924+
nodes := []*HarnessNode{charlie, dave}
1925+
connectAllNodes(t.t, net, nodes)
1926+
fundAllNodes(t.t, net, nodes)
1927+
1928+
charlieTap := newTapClient(t.t, charlie)
1929+
daveTap := newTapClient(t.t, dave)
1930+
universeTap := newTapClient(t.t, zane)
1931+
1932+
// Mint an asset on Charlie and sync Dave to Charlie as the universe.
1933+
mintedAssets := itest.MintAssetsConfirmBatch(
1934+
t.t, t.lndHarness.Miner.Client, charlieTap,
1935+
[]*mintrpc.MintAssetRequest{
1936+
{
1937+
Asset: itestAsset,
1938+
},
1939+
},
1940+
)
1941+
cents := mintedAssets[0]
1942+
assetID := cents.AssetGenesis.AssetId
1943+
var groupKey []byte
1944+
if cents.AssetGroup != nil {
1945+
groupKey = cents.AssetGroup.TweakedGroupKey
1946+
}
1947+
1948+
t.Logf("Minted %d lightning cents, syncing universes...", cents.Amount)
1949+
syncUniverses(t.t, charlieTap, dave)
1950+
t.Logf("Universes synced between all nodes, distributing assets...")
1951+
1952+
charlieBalance := cents.Amount
1953+
1954+
// Charlie should have a single balance output with the full balance.
1955+
assertAssetBalance(t.t, charlieTap, assetID, cents.Amount)
1956+
1957+
// The script key should be local to charlie, and the script key should
1958+
// be known. It is after all the asset he just minted himself.
1959+
scriptKeyLocal := true
1960+
scriptKeyKnown := false
1961+
scriptKeyHasScriptPath := false
1962+
1963+
scriptKey, err := schnorr.ParsePubKey(cents.ScriptKey[1:])
1964+
require.NoError(t.t, err)
1965+
assertAssetExists(
1966+
t.t, charlieTap, assetID, charlieBalance,
1967+
scriptKey, scriptKeyLocal, scriptKeyKnown,
1968+
scriptKeyHasScriptPath,
1969+
)
1970+
1971+
fundingScriptTree := tapscript.NewFundingScriptTree()
1972+
fundingScriptKey := fundingScriptTree.TaprootKey
1973+
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
1974+
1975+
fundRespCD, err := charlieTap.FundChannel(
1976+
ctxb, &tchrpc.FundChannelRequest{
1977+
AssetAmount: charlieBalance,
1978+
AssetId: assetID,
1979+
PeerPubkey: daveTap.node.PubKey[:],
1980+
FeeRateSatPerVbyte: 5,
1981+
PushSat: 0,
1982+
},
1983+
)
1984+
require.NoError(t.t, err)
1985+
t.Logf("Funded channel between Charlie and Dave: %v", fundRespCD)
1986+
1987+
// Make sure the pending channel shows up in the list and has the
1988+
// custom records set as JSON.
1989+
assertPendingChannels(
1990+
t.t, charlieTap.node, assetID, 1, charlieBalance, 0,
1991+
)
1992+
1993+
// Let's confirm the channel.
1994+
mineBlocks(t, net, 6, 1)
1995+
1996+
// Tapd should not report any balance for Charlie, since the asset is
1997+
// used in a funding transaction. It should also not report any balance
1998+
// for Dave. All those balances are reported through channel balances.
1999+
assertAssetBalance(t.t, charlieTap, assetID, 0)
2000+
assertAssetBalance(t.t, daveTap, assetID, 0)
2001+
2002+
// There should only be a single asset piece for Charlie, the one in the
2003+
// channel.
2004+
assertNumAssetOutputs(t.t, charlieTap, assetID, 1)
2005+
2006+
// The script key should now not be local anymore, since he funded a
2007+
// channel with it. Charlie does still know the script key though.
2008+
scriptKeyLocal = false
2009+
scriptKeyKnown = true
2010+
scriptKeyHasScriptPath = true
2011+
assertAssetExists(
2012+
t.t, charlieTap, assetID, charlieBalance,
2013+
fundingScriptKey, scriptKeyLocal, scriptKeyKnown,
2014+
scriptKeyHasScriptPath,
2015+
)
2016+
2017+
// Assert that the proofs for both channels has been uploaded to the
2018+
// designated Universe server.
2019+
assertUniverseProofExists(
2020+
t.t, universeTap, assetID, groupKey, fundingScriptTreeBytes,
2021+
fmt.Sprintf("%v:%v", fundRespCD.Txid, fundRespCD.OutputIndex),
2022+
)
2023+
2024+
// Make sure the channel shows the correct asset information.
2025+
assertAssetChan(
2026+
t.t, charlieTap.node, daveTap.node, charlieBalance, assetID,
2027+
)
2028+
2029+
logBalance(t.t, nodes, assetID, "initial")
2030+
2031+
// Normal case.
2032+
// Send 500 assets from Charlie to Dave.
2033+
sendAssetKeySendPayment(
2034+
t.t, charlie, dave, 500, assetID,
2035+
fn.None[int64](), lnrpc.Payment_SUCCEEDED,
2036+
fn.None[lnrpc.PaymentFailureReason](),
2037+
)
2038+
2039+
logBalance(t.t, nodes, assetID, "after 500 assets")
2040+
2041+
// Tapd stould still not report balances for Charlie and Dave, since
2042+
// they are still locked up in the funding transaction.
2043+
assertAssetBalance(t.t, charlieTap, assetID, 0)
2044+
assertAssetBalance(t.t, daveTap, assetID, 0)
2045+
2046+
// Send 10k sats from Charlie to Dave. Dave needs the sats to be able to
2047+
// send assets.
2048+
sendKeySendPayment(t.t, charlie, dave, 10000)
2049+
2050+
// Now Dave tries to send 250 assets.
2051+
sendAssetKeySendPayment(
2052+
t.t, dave, charlie, 250, assetID,
2053+
fn.None[int64](), lnrpc.Payment_SUCCEEDED,
2054+
fn.None[lnrpc.PaymentFailureReason](),
2055+
)
2056+
2057+
logBalance(t.t, nodes, assetID, "after 250 sats backwards")
2058+
2059+
// Tapd stould still not report balances for Charlie and Dave, since
2060+
// they are still locked up in the funding transaction.
2061+
assertAssetBalance(t.t, charlieTap, assetID, 0)
2062+
assertAssetBalance(t.t, daveTap, assetID, 0)
2063+
2064+
// We will now close the channel.
2065+
t.Logf("Close the channel between Charlie and Dave...")
2066+
charlieChanPoint := &lnrpc.ChannelPoint{
2067+
OutputIndex: uint32(fundRespCD.OutputIndex),
2068+
FundingTxid: &lnrpc.ChannelPoint_FundingTxidStr{
2069+
FundingTxidStr: fundRespCD.Txid,
2070+
},
2071+
}
2072+
2073+
closeChannelAndAssert(t, net, charlie, charlieChanPoint, false)
2074+
2075+
// Charlie should have a single balance output with the balance 250 less
2076+
// than the total amount minted.
2077+
assertAssetBalance(t.t, charlieTap, assetID, charlieBalance-250)
2078+
assertAssetBalance(t.t, daveTap, assetID, 250)
2079+
2080+
// The script key should now be local to both Charlie and Dave, since
2081+
// the channel was closed.
2082+
scriptKeyLocal = true
2083+
scriptKeyKnown = true
2084+
scriptKeyHasScriptPath = false
2085+
assertAssetExists(
2086+
t.t, charlieTap, assetID, charlieBalance-250,
2087+
nil, scriptKeyLocal, scriptKeyKnown, scriptKeyHasScriptPath,
2088+
)
2089+
assertAssetExists(
2090+
t.t, daveTap, assetID, 250,
2091+
nil, scriptKeyLocal, scriptKeyKnown, scriptKeyHasScriptPath,
2092+
)
2093+
2094+
assertNumAssetOutputs(t.t, charlieTap, assetID, 1)
2095+
assertNumAssetOutputs(t.t, daveTap, assetID, 1)
2096+
}

itest/litd_test_list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,8 @@ var allTestCases = []*testCase{
4444
name: "test custom channels liquidity",
4545
test: testCustomChannelsLiquidityEdgeCases,
4646
},
47+
{
48+
name: "test custom channels balance consistency",
49+
test: testCustomChannelsBalanceConsistency,
50+
},
4751
}

0 commit comments

Comments
 (0)