|
6 | 6 | "slices" |
7 | 7 | "time" |
8 | 8 |
|
| 9 | + "github.com/btcsuite/btcd/btcec/v2/schnorr" |
9 | 10 | "github.com/btcsuite/btcd/btcutil" |
10 | 11 | "github.com/btcsuite/btcd/chaincfg/chainhash" |
11 | 12 | "github.com/lightninglabs/taproot-assets/itest" |
@@ -1894,3 +1895,200 @@ func testCustomChannelsLiquidityEdgeCases(_ context.Context, |
1894 | 1895 |
|
1895 | 1896 | logBalance(t.t, nodes, assetID, "after giant asset payment") |
1896 | 1897 | } |
| 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 := tapchannel.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 | + assertAssetBalance(t.t, charlieTap, assetID, cents.Amount) |
| 1997 | + |
| 1998 | + // There should only be a single asset piece for Charlie, the one in the |
| 1999 | + // channel. |
| 2000 | + assertNumAssetOutputs(t.t, charlieTap, assetID, 1) |
| 2001 | + |
| 2002 | + // The script key should now not be local anymore, since he funded a |
| 2003 | + // channel with it. Charlie does still know the script key though. |
| 2004 | + scriptKeyLocal = false |
| 2005 | + scriptKeyKnown = true |
| 2006 | + scriptKeyHasScriptPath = true |
| 2007 | + assertAssetExists( |
| 2008 | + t.t, charlieTap, assetID, charlieBalance, |
| 2009 | + fundingScriptKey, scriptKeyLocal, scriptKeyKnown, |
| 2010 | + scriptKeyHasScriptPath, |
| 2011 | + ) |
| 2012 | + |
| 2013 | + // Assert that the proofs for both channels has been uploaded to the |
| 2014 | + // designated Universe server. |
| 2015 | + assertUniverseProofExists( |
| 2016 | + t.t, universeTap, assetID, groupKey, fundingScriptTreeBytes, |
| 2017 | + fmt.Sprintf("%v:%v", fundRespCD.Txid, fundRespCD.OutputIndex), |
| 2018 | + ) |
| 2019 | + |
| 2020 | + // Make sure the channel shows the correct asset information. |
| 2021 | + assertAssetChan( |
| 2022 | + t.t, charlieTap.node, daveTap.node, charlieBalance, assetID, |
| 2023 | + ) |
| 2024 | + |
| 2025 | + logBalance(t.t, nodes, assetID, "initial") |
| 2026 | + |
| 2027 | + // Normal case. |
| 2028 | + // Send 500 assets from Charlie to Dave. |
| 2029 | + sendAssetKeySendPayment( |
| 2030 | + t.t, charlie, dave, 500, assetID, |
| 2031 | + fn.None[int64](), lnrpc.Payment_SUCCEEDED, |
| 2032 | + fn.None[lnrpc.PaymentFailureReason](), |
| 2033 | + ) |
| 2034 | + |
| 2035 | + logBalance(t.t, nodes, assetID, "after 500 assets") |
| 2036 | + |
| 2037 | + // Charlie should have a single balance output with the full balance. |
| 2038 | + // TODO: THIS ASSUMPTION SHOULD BE CHANGED AFTER TAPD STOPS INCLUDING |
| 2039 | + // NON-LOCAL BALANCES IN LISTBALANCES CALLS. |
| 2040 | + assertAssetBalance(t.t, charlieTap, assetID, charlieBalance) |
| 2041 | + assertAssetBalance(t.t, daveTap, assetID, 0) |
| 2042 | + |
| 2043 | + // Send 10k sats from Charlie to Dave. Dave needs the sats to be able to |
| 2044 | + // send assets. |
| 2045 | + sendKeySendPayment(t.t, charlie, dave, 10000) |
| 2046 | + |
| 2047 | + // Now Dave tries to send 250 assets. |
| 2048 | + sendAssetKeySendPayment( |
| 2049 | + t.t, dave, charlie, 250, assetID, |
| 2050 | + fn.None[int64](), lnrpc.Payment_SUCCEEDED, |
| 2051 | + fn.None[lnrpc.PaymentFailureReason](), |
| 2052 | + ) |
| 2053 | + |
| 2054 | + logBalance(t.t, nodes, assetID, "after 250 sats backwards") |
| 2055 | + |
| 2056 | + // Charlie should have a single balance output with the full balance. |
| 2057 | + // TODO: THIS ASSUMPTION SHOULD BE CHANGED AFTER TAPD STOPS INCLUDING |
| 2058 | + // NON-LOCAL BALANCES IN LISTBALANCES CALLS. |
| 2059 | + assertAssetBalance(t.t, charlieTap, assetID, charlieBalance) |
| 2060 | + assertAssetBalance(t.t, daveTap, assetID, 0) |
| 2061 | + |
| 2062 | + // We will now close the channel. |
| 2063 | + t.Logf("Close the channel between Charlie and Dave...") |
| 2064 | + charlieChanPoint := &lnrpc.ChannelPoint{ |
| 2065 | + OutputIndex: uint32(fundRespCD.OutputIndex), |
| 2066 | + FundingTxid: &lnrpc.ChannelPoint_FundingTxidStr{ |
| 2067 | + FundingTxidStr: fundRespCD.Txid, |
| 2068 | + }, |
| 2069 | + } |
| 2070 | + |
| 2071 | + closeChannelAndAssert(t, net, charlie, charlieChanPoint, false) |
| 2072 | + |
| 2073 | + // Charlie should have a single balance output with the balance 250 less |
| 2074 | + // than the total amount minted. |
| 2075 | + assertAssetBalance(t.t, charlieTap, assetID, charlieBalance-250) |
| 2076 | + assertAssetBalance(t.t, daveTap, assetID, 250) |
| 2077 | + |
| 2078 | + // The script key should now be local to both Charlie and Dave, since |
| 2079 | + // the channel was closed. |
| 2080 | + scriptKeyLocal = true |
| 2081 | + scriptKeyKnown = true |
| 2082 | + scriptKeyHasScriptPath = false |
| 2083 | + assertAssetExists( |
| 2084 | + t.t, charlieTap, assetID, charlieBalance-250, |
| 2085 | + nil, scriptKeyLocal, scriptKeyKnown, scriptKeyHasScriptPath, |
| 2086 | + ) |
| 2087 | + assertAssetExists( |
| 2088 | + t.t, daveTap, assetID, 250, |
| 2089 | + nil, scriptKeyLocal, scriptKeyKnown, scriptKeyHasScriptPath, |
| 2090 | + ) |
| 2091 | + |
| 2092 | + assertNumAssetOutputs(t.t, charlieTap, assetID, 1) |
| 2093 | + assertNumAssetOutputs(t.t, daveTap, assetID, 1) |
| 2094 | +} |
0 commit comments