Skip to content

Commit de58c89

Browse files
committed
itest: add new balance assertions to multiple tests
We add a new AssetBalances function that makes sure that the output from all the following RPCs is aligned: - ListAssets - ListBalances (both grouped by asset ID or group key) - ListUtxos
1 parent dfe3fbf commit de58c89

File tree

6 files changed

+402
-56
lines changed

6 files changed

+402
-56
lines changed

itest/assertions.go

+278-21
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ var (
5252
AllTypes: true,
5353
},
5454
}
55+
56+
groupBalancesByAssetID = &taprpc.ListBalancesRequest_AssetId{
57+
AssetId: true,
58+
}
59+
60+
groupBalancesByGroupKey = &taprpc.ListBalancesRequest_GroupKey{
61+
GroupKey: true,
62+
}
5563
)
5664

5765
// tapClient is an interface that covers all currently available RPC interfaces
@@ -2010,7 +2018,7 @@ func AssertGenesisOutput(t *testing.T, output *taprpc.ManagedUtxo,
20102018
require.Equal(t, expectedMerkleRoot[:], output.MerkleRoot)
20112019
}
20122020

2013-
func AssertAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,
2021+
func AssertMintedAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,
20142022
simpleAssets, issuableAssets []*taprpc.Asset, includeLeased bool) {
20152023

20162024
t.Helper()
@@ -2021,12 +2029,9 @@ func AssertAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,
20212029

20222030
// First, we'll ensure that we're able to get the balances of all the
20232031
// assets grouped by their asset IDs.
2024-
balanceReq := &taprpc.ListBalancesRequest_AssetId{
2025-
AssetId: true,
2026-
}
20272032
assetIDBalances, err := client.ListBalances(
20282033
ctxt, &taprpc.ListBalancesRequest{
2029-
GroupBy: balanceReq,
2034+
GroupBy: groupBalancesByAssetID,
20302035
IncludeLeased: includeLeased,
20312036
},
20322037
)
@@ -2067,20 +2072,17 @@ func AssertAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,
20672072
require.NoError(t, err)
20682073

20692074
var totalAssetListBalance uint64
2070-
for _, asset := range assetList.Assets {
2071-
totalAssetListBalance += asset.Amount
2075+
for _, a := range assetList.Assets {
2076+
totalAssetListBalance += a.Amount
20722077
}
20732078

20742079
require.Equal(t, totalBalance, totalAssetListBalance)
20752080

20762081
// We'll also ensure that we're able to get the balance by key group
20772082
// for all the assets that have one specified.
2078-
groupBalanceReq := &taprpc.ListBalancesRequest_GroupKey{
2079-
GroupKey: true,
2080-
}
20812083
assetGroupBalances, err := client.ListBalances(
20822084
ctxt, &taprpc.ListBalancesRequest{
2083-
GroupBy: groupBalanceReq,
2085+
GroupBy: groupBalancesByGroupKey,
20842086
},
20852087
)
20862088
require.NoError(t, err)
@@ -2089,19 +2091,274 @@ func AssertAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,
20892091
t, len(issuableAssets),
20902092
len(assetGroupBalances.AssetGroupBalances),
20912093
)
2094+
}
20922095

2093-
for _, balance := range assetGroupBalances.AssetBalances {
2094-
for _, rpcAsset := range issuableAssets {
2095-
if balance.AssetGenesis.Name == rpcAsset.AssetGenesis.Name {
2096-
require.Equal(
2097-
t, balance.Balance, rpcAsset.Amount,
2098-
)
2099-
require.Equal(
2100-
t, balance.AssetGenesis,
2101-
rpcAsset.AssetGenesis,
2102-
)
2096+
type balanceConfig struct {
2097+
assetID []byte
2098+
groupKey []byte
2099+
groupedAssetBalance uint64
2100+
numAssetUtxos uint32
2101+
numAnchorUtxos uint32
2102+
includeLeased bool
2103+
allScriptKeyTypes bool
2104+
scriptKeyType *asset.ScriptKeyType
2105+
}
2106+
2107+
type BalanceOption func(*balanceConfig)
2108+
2109+
func WithAssetID(assetID []byte) BalanceOption {
2110+
return func(c *balanceConfig) {
2111+
c.assetID = assetID
2112+
}
2113+
}
2114+
2115+
func WithGroupKey(groupKey []byte) BalanceOption {
2116+
return func(c *balanceConfig) {
2117+
c.groupKey = groupKey
2118+
}
2119+
}
2120+
2121+
func WithGroupedAssetBalance(groupedAssetBalance uint64) BalanceOption {
2122+
return func(c *balanceConfig) {
2123+
c.groupedAssetBalance = groupedAssetBalance
2124+
}
2125+
}
2126+
2127+
func WithNumUtxos(numAssetUtxos uint32) BalanceOption {
2128+
return func(c *balanceConfig) {
2129+
c.numAssetUtxos = numAssetUtxos
2130+
}
2131+
}
2132+
2133+
func WithNumAnchorUtxos(numAnchorUtxos uint32) BalanceOption {
2134+
return func(c *balanceConfig) {
2135+
c.numAnchorUtxos = numAnchorUtxos
2136+
}
2137+
}
2138+
2139+
func WithIncludeLeased() BalanceOption {
2140+
return func(c *balanceConfig) {
2141+
c.includeLeased = true
2142+
}
2143+
}
2144+
2145+
func WithAllScriptKeyTypes() BalanceOption {
2146+
return func(c *balanceConfig) {
2147+
c.allScriptKeyTypes = true
2148+
}
2149+
}
2150+
2151+
func WithScriptKeyType(scriptKeyType asset.ScriptKeyType) BalanceOption {
2152+
return func(c *balanceConfig) {
2153+
c.scriptKeyType = &scriptKeyType
2154+
}
2155+
}
2156+
2157+
func AssertBalances(t *testing.T, client taprpc.TaprootAssetsClient,
2158+
balance uint64, opts ...BalanceOption) {
2159+
2160+
t.Helper()
2161+
2162+
config := &balanceConfig{}
2163+
for _, opt := range opts {
2164+
opt(config)
2165+
}
2166+
2167+
var rpcTypeQuery *taprpc.ScriptKeyTypeQuery
2168+
switch {
2169+
case config.allScriptKeyTypes:
2170+
rpcTypeQuery = &taprpc.ScriptKeyTypeQuery{
2171+
Type: &taprpc.ScriptKeyTypeQuery_AllTypes{
2172+
AllTypes: true,
2173+
},
2174+
}
2175+
2176+
case config.scriptKeyType != nil:
2177+
rpcTypeQuery = &taprpc.ScriptKeyTypeQuery{
2178+
Type: &taprpc.ScriptKeyTypeQuery_ExplicitType{
2179+
ExplicitType: taprpc.MarshalScriptKeyType(
2180+
*config.scriptKeyType,
2181+
),
2182+
},
2183+
}
2184+
}
2185+
2186+
balanceSum := func(resp *taprpc.ListBalancesResponse,
2187+
group bool) uint64 {
2188+
2189+
var totalBalance uint64
2190+
2191+
if group {
2192+
for _, currentBalance := range resp.AssetGroupBalances {
2193+
totalBalance += currentBalance.Balance
2194+
}
2195+
} else {
2196+
for _, currentBalance := range resp.AssetBalances {
2197+
totalBalance += currentBalance.Balance
2198+
}
2199+
}
2200+
2201+
return totalBalance
2202+
}
2203+
2204+
ctxb := context.Background()
2205+
ctxt, cancel := context.WithTimeout(ctxb, defaultWaitTimeout)
2206+
defer cancel()
2207+
2208+
// First, we'll ensure that we're able to get the balances of all the
2209+
// assets grouped by their asset IDs.
2210+
assetIDBalances, err := client.ListBalances(
2211+
ctxt, &taprpc.ListBalancesRequest{
2212+
GroupBy: groupBalancesByAssetID,
2213+
IncludeLeased: config.includeLeased,
2214+
ScriptKeyType: rpcTypeQuery,
2215+
AssetFilter: config.assetID,
2216+
GroupKeyFilter: config.groupKey,
2217+
},
2218+
)
2219+
require.NoError(t, err)
2220+
2221+
// Spent assets (burns/tombstones) are never included in the balance,
2222+
// even if we specifically query for their type. So we skip the balance
2223+
// check in that case.
2224+
checkBalance := config.scriptKeyType == nil ||
2225+
(*config.scriptKeyType != asset.ScriptKeyBurn &&
2226+
*config.scriptKeyType != asset.ScriptKeyTombstone)
2227+
if checkBalance {
2228+
require.Equal(
2229+
t, balance, balanceSum(assetIDBalances, false),
2230+
"asset balance, wanted %d, got: %v", balance,
2231+
toJSON(t, assetIDBalances),
2232+
)
2233+
}
2234+
2235+
// Next, we do the same but grouped by group keys (if requested, since
2236+
// this only returns the balances for actually grouped assets).
2237+
if config.groupedAssetBalance > 0 {
2238+
assetGroupBalances, err := client.ListBalances(
2239+
ctxt, &taprpc.ListBalancesRequest{
2240+
GroupBy: groupBalancesByGroupKey,
2241+
IncludeLeased: config.includeLeased,
2242+
ScriptKeyType: rpcTypeQuery,
2243+
AssetFilter: config.assetID,
2244+
GroupKeyFilter: config.groupKey,
2245+
},
2246+
)
2247+
require.NoError(t, err)
2248+
2249+
// Spent assets (burns/tombstones) are never included in the
2250+
// balance, even if we specifically query for their type. So we
2251+
// skip the balance check in that case.
2252+
if checkBalance {
2253+
require.Equalf(
2254+
t, config.groupedAssetBalance,
2255+
balanceSum(assetGroupBalances, true),
2256+
"grouped balance, wanted %d, got: %v", balance,
2257+
toJSON(t, assetGroupBalances),
2258+
)
2259+
}
2260+
}
2261+
2262+
// Finally, we assert that the sum of all assets queried with the given
2263+
// query parameters matches the expected balance.
2264+
assetList, err := client.ListAssets(ctxt, &taprpc.ListAssetRequest{
2265+
IncludeLeased: config.includeLeased,
2266+
ScriptKeyType: rpcTypeQuery,
2267+
})
2268+
require.NoError(t, err)
2269+
2270+
var (
2271+
totalBalance uint64
2272+
numUtxos uint32
2273+
)
2274+
for _, a := range assetList.Assets {
2275+
if len(config.assetID) > 0 {
2276+
if !bytes.Equal(
2277+
a.AssetGenesis.AssetId, config.assetID,
2278+
) {
2279+
2280+
continue
2281+
}
2282+
}
2283+
2284+
if len(config.groupKey) > 0 {
2285+
if !bytes.Equal(
2286+
a.AssetGroup.TweakedGroupKey, config.groupKey,
2287+
) {
2288+
2289+
continue
21032290
}
21042291
}
2292+
2293+
totalBalance += a.Amount
2294+
numUtxos++
2295+
}
2296+
require.Equalf(
2297+
t, balance, totalBalance, "ListAssets balance, wanted %d, "+
2298+
"got: %v", balance, toJSON(t, assetList),
2299+
)
2300+
2301+
// The number of UTXOs means asset outputs in this case. We check the
2302+
// BTC-level UTXOs below as well, but that's just to make sure the
2303+
// output of that RPC lists the same assets.
2304+
if config.numAssetUtxos > 0 {
2305+
require.Equal(
2306+
t, config.numAssetUtxos, numUtxos, "ListAssets num "+
2307+
"asset utxos",
2308+
)
2309+
}
2310+
2311+
utxoList, err := client.ListUtxos(ctxt, &taprpc.ListUtxosRequest{
2312+
IncludeLeased: config.includeLeased,
2313+
ScriptKeyType: rpcTypeQuery,
2314+
})
2315+
require.NoError(t, err)
2316+
2317+
// Make sure the ListUtxos call returns the same number of (asset) UTXOs
2318+
// as the ListAssets call.
2319+
var numAnchorUtxos uint32
2320+
totalBalance = 0
2321+
numUtxos = 0
2322+
for _, btcUtxo := range utxoList.ManagedUtxos {
2323+
numAnchorUtxos++
2324+
for _, assetUtxo := range btcUtxo.Assets {
2325+
if len(config.assetID) > 0 {
2326+
if !bytes.Equal(
2327+
assetUtxo.AssetGenesis.AssetId,
2328+
config.assetID,
2329+
) {
2330+
2331+
continue
2332+
}
2333+
}
2334+
2335+
if len(config.groupKey) > 0 {
2336+
if !bytes.Equal(
2337+
btcUtxo.TaprootAssetRoot,
2338+
config.groupKey,
2339+
) {
2340+
2341+
continue
2342+
}
2343+
}
2344+
2345+
totalBalance += assetUtxo.Amount
2346+
numUtxos++
2347+
}
2348+
}
2349+
require.Equal(t, balance, totalBalance, "ListUtxos balance")
2350+
2351+
if config.numAnchorUtxos > 0 {
2352+
require.Equal(
2353+
t, config.numAnchorUtxos, numAnchorUtxos, "num anchor "+
2354+
"utxos",
2355+
)
2356+
}
2357+
if config.numAssetUtxos > 0 {
2358+
require.Equal(
2359+
t, config.numAssetUtxos, numUtxos, "ListUtxos num "+
2360+
"asset utxos",
2361+
)
21052362
}
21062363
}
21072364

0 commit comments

Comments
 (0)