Skip to content

Commit c7054bc

Browse files
committed
universerpc: add locator and update response in FetchSupplyCommit RPC
Add `locator` field to the FetchSupplyCommit RPC request to specify which supply commit to retrieve. Supported options include: the first supply commit, the supply commit committed to at a given outpoint, and the supply commit that spends a given outpoint. Also update the response message for this endpoint. The response now includes all leaves new to the specified supply commit, as well as the outpoint that the fetched supply commit spends. Also add total outstanding asset amount helper field.
1 parent 945e3c7 commit c7054bc

File tree

7 files changed

+878
-607
lines changed

7 files changed

+878
-607
lines changed

itest/assertions.go

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2786,8 +2786,9 @@ func UpdateAndMineSupplyCommit(t *testing.T, ctx context.Context,
27862786
// it when the specified condition is met.
27872787
func WaitForSupplyCommit(t *testing.T, ctx context.Context,
27882788
tapd unirpc.UniverseClient, groupKeyBytes []byte,
2789+
spentCommitOutpoint fn.Option[wire.OutPoint],
27892790
condition func(*unirpc.FetchSupplyCommitResponse) bool,
2790-
) *unirpc.FetchSupplyCommitResponse {
2791+
) (*unirpc.FetchSupplyCommitResponse, wire.OutPoint) {
27912792

27922793
groupKeyReq := &unirpc.FetchSupplyCommitRequest_GroupKeyBytes{
27932794
GroupKeyBytes: groupKeyBytes,
@@ -2796,18 +2797,50 @@ func WaitForSupplyCommit(t *testing.T, ctx context.Context,
27962797
var fetchResp *unirpc.FetchSupplyCommitResponse
27972798
var err error
27982799

2799-
require.Eventually(t, func() bool {
2800-
fetchResp, err = tapd.FetchSupplyCommit(
2801-
ctx, &unirpc.FetchSupplyCommitRequest{
2802-
GroupKey: groupKeyReq,
2800+
// By default, we start the fetch from the very first commitment.
2801+
// If a spent outpoint is given, we start from there.
2802+
req := &unirpc.FetchSupplyCommitRequest{
2803+
GroupKey: groupKeyReq,
2804+
Locator: &unirpc.FetchSupplyCommitRequest_VeryFirst{
2805+
VeryFirst: true,
2806+
},
2807+
}
2808+
2809+
// nolint: lll
2810+
spentCommitOutpoint.WhenSome(func(outPoint wire.OutPoint) {
2811+
req = &unirpc.FetchSupplyCommitRequest{
2812+
GroupKey: groupKeyReq,
2813+
Locator: &unirpc.FetchSupplyCommitRequest_SpentCommitOutpoint{
2814+
SpentCommitOutpoint: &taprpc.OutPoint{
2815+
Txid: outPoint.Hash[:],
2816+
OutputIndex: outPoint.Index,
2817+
},
28032818
},
2804-
)
2819+
}
2820+
})
2821+
2822+
require.Eventually(t, func() bool {
2823+
fetchResp, err = tapd.FetchSupplyCommit(ctx, req)
28052824
if err != nil {
28062825
return false
28072826
}
28082827

28092828
return fetchResp != nil && condition(fetchResp)
28102829
}, defaultWaitTimeout, time.Second)
28112830

2812-
return fetchResp
2831+
// Return the supply commit outpoint used to fetch the next supply
2832+
// commitment. The next commitment is retrieved by referencing the
2833+
// outpoint of the previously spent commitment.
2834+
require.NotNil(t, fetchResp)
2835+
2836+
var msgTx wire.MsgTx
2837+
err = msgTx.Deserialize(bytes.NewReader(fetchResp.ChainData.Txn))
2838+
require.NoError(t, err)
2839+
2840+
supplyCommitOutpoint := wire.OutPoint{
2841+
Hash: msgTx.TxHash(),
2842+
Index: fetchResp.ChainData.TxOutIdx,
2843+
}
2844+
2845+
return fetchResp, supplyCommitOutpoint
28132846
}

itest/supply_commit_mint_burn_test.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/btcsuite/btcd/btcec/v2"
88
"github.com/btcsuite/btcd/chaincfg/chainhash"
9+
"github.com/btcsuite/btcd/wire"
910
taprootassets "github.com/lightninglabs/taproot-assets"
1011
"github.com/lightninglabs/taproot-assets/fn"
1112
"github.com/lightninglabs/taproot-assets/taprpc"
@@ -48,18 +49,19 @@ func testSupplyCommitMintBurn(t *harnessTest) {
4849
// Update the on-chain supply commitment for the asset group.
4950
//
5051
// TODO(roasbeef): still rely on the time based ticker here?
51-
t.Log("Updating and mining supply commitment for asset group")
52+
t.Log("Create first supply commitment tx for asset group")
5253
UpdateAndMineSupplyCommit(
5354
t.t, ctxb, t.tapd, t.lndHarness.Miner().Client,
5455
groupKeyBytes, 1,
5556
)
5657

5758
// Fetch the latest supply commitment for the asset group.
58-
t.Log("Fetching supply commitment to verify mint leaves")
59-
fetchResp := WaitForSupplyCommit(
60-
t.t, ctxb, t.tapd, groupKeyBytes,
59+
t.Log("Fetching first supply commitment to verify mint leaves")
60+
fetchResp, supplyOutpoint := WaitForSupplyCommit(
61+
t.t, ctxb, t.tapd, groupKeyBytes, fn.None[wire.OutPoint](),
6162
func(resp *unirpc.FetchSupplyCommitResponse) bool {
62-
return resp.BlockHeight > 0 && len(resp.BlockHash) > 0
63+
return resp.ChainData.BlockHeight > 0 &&
64+
len(resp.ChainData.BlockHash) > 0
6365
},
6466
)
6567

@@ -72,7 +74,7 @@ func testSupplyCommitMintBurn(t *harnessTest) {
7274

7375
// Verify the issuance leaf inclusion in the supply tree.
7476
AssertSubtreeInclusionProof(
75-
t, fetchResp.SupplyCommitmentRoot.RootHash,
77+
t, fetchResp.ChainData.SupplyRootHash,
7678
fetchResp.IssuanceSubtreeRoot,
7779
)
7880

@@ -106,8 +108,6 @@ func testSupplyCommitMintBurn(t *harnessTest) {
106108
)
107109

108110
t.Log("Updating supply commitment after second mint")
109-
110-
// Update and mine the supply commitment after second mint.
111111
UpdateAndMineSupplyCommit(
112112
t.t, ctxb, t.tapd, t.lndHarness.Miner().Client,
113113
groupKeyBytes, 1,
@@ -119,8 +119,8 @@ func testSupplyCommitMintBurn(t *harnessTest) {
119119
expectedTotal := int64(
120120
mintReq.Asset.Amount + secondMintReq.Asset.Amount,
121121
)
122-
fetchResp = WaitForSupplyCommit(
123-
t.t, ctxb, t.tapd, groupKeyBytes,
122+
fetchResp, supplyOutpoint = WaitForSupplyCommit(
123+
t.t, ctxb, t.tapd, groupKeyBytes, fn.Some(supplyOutpoint),
124124
func(resp *unirpc.FetchSupplyCommitResponse) bool {
125125
return resp.IssuanceSubtreeRoot != nil &&
126126
resp.IssuanceSubtreeRoot.RootNode.RootSum == expectedTotal //nolint:lll
@@ -175,7 +175,8 @@ func testSupplyCommitMintBurn(t *harnessTest) {
175175
t.Log("Verifying supply tree includes burn leaves")
176176

177177
// Fetch and verify the supply tree now includes burn leaves.
178-
fetchResp = WaitForSupplyCommit(t.t, ctxb, t.tapd, groupKeyBytes,
178+
fetchResp, _ = WaitForSupplyCommit(
179+
t.t, ctxb, t.tapd, groupKeyBytes, fn.Some(supplyOutpoint),
179180
func(resp *unirpc.FetchSupplyCommitResponse) bool {
180181
return resp.BurnSubtreeRoot != nil &&
181182
resp.BurnSubtreeRoot.RootNode.RootSum == int64(burnAmt) //nolint:lll
@@ -184,7 +185,7 @@ func testSupplyCommitMintBurn(t *harnessTest) {
184185

185186
// Verify the burn subtree inclusion in the supply tree.
186187
AssertSubtreeInclusionProof(
187-
t, fetchResp.SupplyCommitmentRoot.RootHash,
188+
t, fetchResp.ChainData.SupplyRootHash,
188189
fetchResp.BurnSubtreeRoot,
189190
)
190191

@@ -234,16 +235,16 @@ func testSupplyCommitMintBurn(t *harnessTest) {
234235
block := finalMinedBlocks[0]
235236
blockHash, _ := t.lndHarness.Miner().GetBestBlock()
236237

237-
fetchBlockHash, err := chainhash.NewHash(fetchResp.BlockHash)
238+
fetchBlockHash, err := chainhash.NewHash(fetchResp.ChainData.BlockHash)
238239
require.NoError(t.t, err)
239240
require.True(t.t, fetchBlockHash.IsEqual(blockHash))
240241

241242
// Re-compute the supply commitment root hash from the latest fetch,
242243
// then use that to derive the expected commitment output.
243244
supplyCommitRootHash := fn.ToArray[[32]byte](
244-
fetchResp.SupplyCommitmentRoot.RootHash,
245+
fetchResp.ChainData.SupplyRootHash,
245246
)
246-
internalKey, err := btcec.ParsePubKey(fetchResp.AnchorTxOutInternalKey)
247+
internalKey, err := btcec.ParsePubKey(fetchResp.ChainData.InternalKey)
247248
require.NoError(t.t, err)
248249
expectedTxOut, _, err := supplycommit.RootCommitTxOut(
249250
internalKey, nil, supplyCommitRootHash,

itest/supply_commit_test.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,13 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
247247
GroupKey: &unirpc.FetchSupplyCommitRequest_GroupKeyBytes{
248248
GroupKeyBytes: groupKeyBytes,
249249
},
250+
Locator: &unirpc.FetchSupplyCommitRequest_VeryFirst{
251+
VeryFirst: true,
252+
},
250253
},
251254
)
252255
require.Nil(t.t, fetchRespNil)
253-
require.ErrorContains(t.t, err, "supply commitment not found for "+
254-
"asset group with key")
256+
require.ErrorContains(t.t, err, "commitment not found")
255257

256258
t.Log("Update on-chain supply commitment for asset group")
257259

@@ -281,26 +283,35 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
281283
GroupKey: &unirpc.FetchSupplyCommitRequest_GroupKeyBytes{
282284
GroupKeyBytes: groupKeyBytes,
283285
},
286+
Locator: &unirpc.FetchSupplyCommitRequest_VeryFirst{
287+
VeryFirst: true,
288+
},
284289
},
285290
)
286291
require.NoError(t.t, err)
287292

288293
// If the fetch response has no block height or hash,
289294
// it means that the supply commitment transaction has not
290295
// been mined yet, so we should retry.
291-
if fetchResp.BlockHeight == 0 || len(fetchResp.BlockHash) == 0 {
296+
if fetchResp.ChainData.BlockHeight == 0 ||
297+
len(fetchResp.ChainData.BlockHash) == 0 {
298+
292299
return false
293300
}
294301

295302
// Once the ignore tree includes the ignored asset outpoint, we
296303
// know that the supply commitment has been updated.
304+
if fetchResp.IgnoreSubtreeRoot == nil {
305+
return false
306+
}
307+
297308
return fetchResp.IgnoreSubtreeRoot.RootNode.RootSum ==
298309
int64(sendAssetAmount+sendChangeAmount)
299310
}, defaultWaitTimeout, time.Second)
300311

301312
// Verify that the supply commitment tree commits to the ignore subtree.
302313
supplyCommitRootHash := fn.ToArray[[32]byte](
303-
fetchResp.SupplyCommitmentRoot.RootHash,
314+
fetchResp.ChainData.SupplyRootHash,
304315
)
305316

306317
// Formulate the ignore leaf node as it should appear in the supply
@@ -369,18 +380,18 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
369380

370381
// Ensure that the block hash and height matches the values in the fetch
371382
// response.
372-
fetchBlockHash, err := chainhash.NewHash(fetchResp.BlockHash)
383+
fetchBlockHash, err := chainhash.NewHash(fetchResp.ChainData.BlockHash)
373384
require.NoError(t.t, err)
374385
require.True(t.t, fetchBlockHash.IsEqual(blockHash))
375386

376-
require.EqualValues(t.t, blockHeight, fetchResp.BlockHeight)
387+
require.EqualValues(t.t, blockHeight, fetchResp.ChainData.BlockHeight)
377388

378389
// We expect two transactions in the block:
379390
// 1. The supply commitment transaction.
380391
// 2. The coinbase transaction.
381392
require.Len(t.t, block.Transactions, 2)
382393

383-
internalKey, err := btcec.ParsePubKey(fetchResp.AnchorTxOutInternalKey)
394+
internalKey, err := btcec.ParsePubKey(fetchResp.ChainData.InternalKey)
384395
require.NoError(t.t, err)
385396

386397
expectedTxOut, _, err := supplycommit.RootCommitTxOut(
@@ -415,7 +426,9 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
415426
}
416427

417428
require.True(t.t, foundCommitTxOut)
418-
require.EqualValues(t.t, actualBlockTxIndex, fetchResp.BlockTxIndex)
429+
require.EqualValues(
430+
t.t, actualBlockTxIndex, fetchResp.ChainData.TxIndex,
431+
)
419432

420433
// If we try to ignore the same asset outpoint using the secondary
421434
// node, it should fail because the secondary node does not have access

0 commit comments

Comments
 (0)