Skip to content

Commit 6c1916d

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. (temp) build: bump tapd This commit bumps tapd to the this commit: lightninglabs/taproot-assets@31d333c This commit should be dropped before merging in the main branch.
1 parent 27e6713 commit 6c1916d

File tree

5 files changed

+238
-24
lines changed

5 files changed

+238
-24
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ replace github.com/lightninglabs/lightning-terminal/autopilotserverrpc => ./auto
227227
// taproot-assets dependency to function properly.
228228
replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display
229229

230+
replace github.com/lightninglabs/taproot-assets => github.com/lightninglabs/taproot-assets v0.4.2-0.20241016192705-31d333cce24b
231+
230232
go 1.22.3
231233

232234
toolchain go1.22.4

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,8 +1175,8 @@ github.com/lightninglabs/pool/auctioneerrpc v1.1.2 h1:Dbg+9Z9jXnhimR27EN37foc4aB
11751175
github.com/lightninglabs/pool/auctioneerrpc v1.1.2/go.mod h1:1wKDzN2zEP8srOi0B9iySlEsPdoPhw6oo3Vbm1v4Mhw=
11761176
github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display h1:pRdza2wleRN1L2fJXd6ZoQ9ZegVFTAb2bOQfruJPKcY=
11771177
github.com/lightninglabs/protobuf-go-hex-display v1.30.0-hex-display/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
1178-
github.com/lightninglabs/taproot-assets v0.4.2-0.20240923062224-3b92c82bb332 h1:AVh0Ks5erEqC3RDY6gsycbf9dcYXv308j/kxi47WPyM=
1179-
github.com/lightninglabs/taproot-assets v0.4.2-0.20240923062224-3b92c82bb332/go.mod h1:B6wbs1rSTBTJwTilsKt7p/WravtKqRvJI0ICDwvcdNQ=
1178+
github.com/lightninglabs/taproot-assets v0.4.2-0.20241016192705-31d333cce24b h1:J6FwOW3bB4BwdD54FEk0CtnFsL7UVWLu1Js7ghRQnL4=
1179+
github.com/lightninglabs/taproot-assets v0.4.2-0.20241016192705-31d333cce24b/go.mod h1:B6wbs1rSTBTJwTilsKt7p/WravtKqRvJI0ICDwvcdNQ=
11801180
github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f h1:Pua7+5TcFEJXIIZ1I2YAUapmbcttmLj4TTi786bIi3s=
11811181
github.com/lightningnetwork/lightning-onion v1.2.1-0.20230823005744-06182b1d7d2f/go.mod h1:c0kvRShutpj3l6B9WtTsNTBUtjSmjZXbJd9ZBRQOSKI=
11821182
github.com/lightningnetwork/lnd v0.18.0-beta.rc4.0.20240919091721-70580403898e h1:Weu9TWNEIpC4XLbcUoSFK3Pv2aUSwn7NlYZKdsm8wUU=

itest/assets_test.go

Lines changed: 10 additions & 9 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

@@ -85,7 +85,7 @@ func createTestAssetNetwork(t *harnessTest, net *NetworkHarness, charlieTap,
8585

8686
t.Logf("Sending %v asset units to Dave...", assetSendAmount)
8787

88-
// Send the assets to Erin.
88+
// Send the assets to Dave.
8989
itest.AssertAddrCreated(t.t, daveTap, mintedAsset, daveAddr)
9090
sendResp, err := charlieTap.SendAsset(ctxb, &taprpc.SendAssetRequest{
9191
TapAddrs: []string{daveAddr.Encoded},
@@ -184,14 +184,15 @@ func createTestAssetNetwork(t *harnessTest, net *NetworkHarness, charlieTap,
184184

185185
// We'll be tracking the expected asset balances throughout the test, so
186186
// we can assert it after each action.
187-
charlieAssetBalance := charlieFundingAmount
188-
daveAssetBalance := assetSendAmount
189-
erinAssetBalance := assetSendAmount
187+
charlieAssetBalance := mintedAsset.Amount - 2*assetSendAmount -
188+
charlieFundingAmount
189+
daveAssetBalance := assetSendAmount - daveFundingAmount
190+
erinAssetBalance := assetSendAmount - erinFundingAmount
190191

191192
// After opening the channels, the asset balance of the funding nodes
192-
// shouldn't have been decreased, since the asset with the funding
193-
// output was imported into the asset DB and should count toward the
194-
// balance.
193+
// should have been decreased with the funding amount. The asset with
194+
// the funding output was imported into the asset DB but are kept out of
195+
// the balance reporting by tapd.
195196
assertAssetBalance(t.t, charlieTap, assetID, charlieAssetBalance)
196197
assertAssetBalance(t.t, daveTap, assetID, daveAssetBalance)
197198
assertAssetBalance(t.t, erinTap, assetID, erinAssetBalance)

itest/litd_custom_channels_test.go

Lines changed: 220 additions & 13 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

@@ -1224,13 +1225,15 @@ func testCustomChannelsForceClose(_ context.Context, net *NetworkHarness,
12241225
t.Logf("Channel funding transfer: %v",
12251226
toProtoJSON(t.t, assetFundingTransfer))
12261227

1227-
// Charlie's balance should reflect that the funding asset was added to
1228-
// the DB.
1229-
assertAssetBalance(t.t, charlieTap, assetID, itestAsset.Amount)
1228+
// Charlie's balance should reflect that the funding asset is now
1229+
// excluded from balance reporting by tapd.
1230+
assertAssetBalance(
1231+
t.t, charlieTap, assetID, itestAsset.Amount-fundingAmount,
1232+
)
12301233

12311234
// Make sure that Charlie properly uploaded funding proof to the
12321235
// Universe server.
1233-
fundingScriptTree := tapchannel.NewFundingScriptTree()
1236+
fundingScriptTree := tapscript.NewFundingScriptTree()
12341237
fundingScriptKey := fundingScriptTree.TaprootKey
12351238
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
12361239
assertUniverseProofExists(
@@ -1562,13 +1565,15 @@ func testCustomChannelsBreach(_ context.Context, net *NetworkHarness,
15621565
t.Logf("Channel funding transfer: %v",
15631566
toProtoJSON(t.t, assetFundingTransfer))
15641567

1565-
// Charlie's balance should reflect that the funding asset was added to
1566-
// the DB.
1567-
assertAssetBalance(t.t, charlieTap, assetID, itestAsset.Amount)
1568+
// Charlie's balance should reflect that the funding asset is now
1569+
// excluded from balance reporting by tapd.
1570+
assertAssetBalance(
1571+
t.t, charlieTap, assetID, itestAsset.Amount-fundingAmount,
1572+
)
15681573

15691574
// Make sure that Charlie properly uploaded funding proof to the
15701575
// Universe server.
1571-
fundingScriptTree := tapchannel.NewFundingScriptTree()
1576+
fundingScriptTree := tapscript.NewFundingScriptTree()
15721577
fundingScriptKey := fundingScriptTree.TaprootKey
15731578
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
15741579
assertUniverseProofExists(
@@ -1748,7 +1753,7 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,
17481753
if cents.AssetGroup != nil {
17491754
groupKey = cents.AssetGroup.TweakedGroupKey
17501755
}
1751-
fundingScriptTree := tapchannel.NewFundingScriptTree()
1756+
fundingScriptTree := tapscript.NewFundingScriptTree()
17521757
fundingScriptKey := fundingScriptTree.TaprootKey
17531758
fundingScriptTreeBytes := fundingScriptKey.SerializeCompressed()
17541759

@@ -1779,7 +1784,10 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,
17791784
// Let's confirm the channel.
17801785
mineBlocks(t, net, 6, 1)
17811786

1782-
assertAssetBalance(t.t, charlieTap, assetID, cents.Amount)
1787+
// Charlie used the entire amount of the asset to fund the channel, so
1788+
// tapd will report 0 balance. Tapd excludes the funding output from the
1789+
// balance.
1790+
assertAssetBalance(t.t, charlieTap, assetID, 0)
17831791

17841792
// There should only be a single asset piece for Charlie, the one in the
17851793
// channel.
@@ -1894,3 +1902,202 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context,
18941902

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

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)