Skip to content

Commit 450bb48

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 a3c79c2 commit 450bb48

File tree

6 files changed

+402
-56
lines changed

6 files changed

+402
-56
lines changed

Diff for: 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
@@ -1988,7 +1996,7 @@ func AssertGenesisOutput(t *testing.T, output *taprpc.ManagedUtxo,
19881996
require.Equal(t, expectedMerkleRoot[:], output.MerkleRoot)
19891997
}
19901998

1991-
func AssertAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,
1999+
func AssertMintedAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,
19922000
simpleAssets, issuableAssets []*taprpc.Asset, includeLeased bool) {
19932001

19942002
t.Helper()
@@ -1999,12 +2007,9 @@ func AssertAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,
19992007

20002008
// First, we'll ensure that we're able to get the balances of all the
20012009
// assets grouped by their asset IDs.
2002-
balanceReq := &taprpc.ListBalancesRequest_AssetId{
2003-
AssetId: true,
2004-
}
20052010
assetIDBalances, err := client.ListBalances(
20062011
ctxt, &taprpc.ListBalancesRequest{
2007-
GroupBy: balanceReq,
2012+
GroupBy: groupBalancesByAssetID,
20082013
IncludeLeased: includeLeased,
20092014
},
20102015
)
@@ -2045,20 +2050,17 @@ func AssertAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,
20452050
require.NoError(t, err)
20462051

20472052
var totalAssetListBalance uint64
2048-
for _, asset := range assetList.Assets {
2049-
totalAssetListBalance += asset.Amount
2053+
for _, a := range assetList.Assets {
2054+
totalAssetListBalance += a.Amount
20502055
}
20512056

20522057
require.Equal(t, totalBalance, totalAssetListBalance)
20532058

20542059
// We'll also ensure that we're able to get the balance by key group
20552060
// for all the assets that have one specified.
2056-
groupBalanceReq := &taprpc.ListBalancesRequest_GroupKey{
2057-
GroupKey: true,
2058-
}
20592061
assetGroupBalances, err := client.ListBalances(
20602062
ctxt, &taprpc.ListBalancesRequest{
2061-
GroupBy: groupBalanceReq,
2063+
GroupBy: groupBalancesByGroupKey,
20622064
},
20632065
)
20642066
require.NoError(t, err)
@@ -2067,19 +2069,274 @@ func AssertAssetBalances(t *testing.T, client taprpc.TaprootAssetsClient,
20672069
t, len(issuableAssets),
20682070
len(assetGroupBalances.AssetGroupBalances),
20692071
)
2072+
}
20702073

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

0 commit comments

Comments
 (0)