Skip to content

Commit 21cc5ba

Browse files
committed
tapgarden+tapdb: MintingBatch.GenesisPacket to FundedMintAnchorPsbt type
Update the MintingBatch.GenesisPacket field to use the FundedMintAnchorPsbt type to include pre-commitment output information.
1 parent 524e6bd commit 21cc5ba

File tree

8 files changed

+116
-80
lines changed

8 files changed

+116
-80
lines changed

tapdb/asset_minting.go

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,11 @@ type PendingAssetStore interface {
239239
// FetchAssetMetaForAsset fetches the asset meta for a given asset.
240240
FetchAssetMetaForAsset(ctx context.Context,
241241
assetID []byte) (sqlc.FetchAssetMetaForAssetRow, error)
242+
243+
// FetchMintAnchorUniCommitment fetches the mint anchor uni commitment
244+
// for a given batch.
245+
FetchMintAnchorUniCommitment(ctx context.Context,
246+
batchID int32) (sqlc.MintAnchorUniCommitment, error)
242247
}
243248

244249
var (
@@ -1164,11 +1169,59 @@ func marshalMintingBatch(ctx context.Context, q PendingAssetStore,
11641169
if err != nil {
11651170
return nil, err
11661171
}
1167-
batch.GenesisPacket = &tapsend.FundedPsbt{
1168-
Pkt: genesisPkt,
1169-
ChangeOutputIndex: extractSqlInt32[int32](
1170-
dbBatch.ChangeOutputIndex,
1171-
),
1172+
1173+
if !dbBatch.AssetsOutputIndex.Valid {
1174+
return nil, fmt.Errorf("missing asset anchor output " +
1175+
"index")
1176+
}
1177+
assetAnchorOutIdx := dbBatch.AssetsOutputIndex.Int32
1178+
1179+
// If the batch has universe commitments, we will retrieve
1180+
// the pre-commitment output index from the database.
1181+
var preCommitOut fn.Option[tapgarden.PreCommitmentOutput]
1182+
if dbBatch.UniverseCommitments {
1183+
res, err := q.FetchMintAnchorUniCommitment(
1184+
ctx, int32(dbBatch.BatchID),
1185+
)
1186+
if err != nil {
1187+
return nil, fmt.Errorf("unable to fetch mint "+
1188+
"anchor uni commitment: %w", err)
1189+
}
1190+
1191+
// Parse the internal key from the database.
1192+
internalKey, err := btcec.ParsePubKey(
1193+
res.TaprootInternalKey,
1194+
)
1195+
if err != nil {
1196+
return nil, fmt.Errorf("error parsing "+
1197+
"taproot internal key: %w", err)
1198+
}
1199+
1200+
// Parse the group public key from the database.
1201+
groupPubKey, err := btcec.ParsePubKey(res.GroupKey)
1202+
if err != nil {
1203+
return nil, fmt.Errorf("error parsing "+
1204+
"group public key: %w", err)
1205+
}
1206+
1207+
preCommitOut = fn.Some(
1208+
tapgarden.PreCommitmentOutput{
1209+
OutIdx: uint32(res.TxOutputIndex),
1210+
InternalKey: *internalKey,
1211+
GroupPubKey: *groupPubKey,
1212+
},
1213+
)
1214+
}
1215+
1216+
batch.GenesisPacket = &tapgarden.FundedMintAnchorPsbt{
1217+
FundedPsbt: tapsend.FundedPsbt{
1218+
Pkt: genesisPkt,
1219+
ChangeOutputIndex: extractSqlInt32[int32](
1220+
dbBatch.ChangeOutputIndex,
1221+
),
1222+
},
1223+
AssetAnchorOutIdx: uint32(assetAnchorOutIdx),
1224+
PreCommitmentOutput: preCommitOut,
11721225
}
11731226
}
11741227

@@ -1283,7 +1336,8 @@ func encodeOutpoint(outPoint wire.OutPoint) ([]byte, error) {
12831336
// CommitBatchTx updates the genesis transaction of a batch based on the batch
12841337
// key.
12851338
func (a *AssetMintingStore) CommitBatchTx(ctx context.Context,
1286-
batchKey *btcec.PublicKey, genesisPacket *tapsend.FundedPsbt) error {
1339+
batchKey *btcec.PublicKey,
1340+
genesisPacket tapgarden.FundedMintAnchorPsbt) error {
12871341

12881342
genesisOutpoint := genesisPacket.Pkt.UnsignedTx.TxIn[0].PreviousOutPoint
12891343
rawBatchKey := batchKey.SerializeCompressed()
@@ -1417,7 +1471,8 @@ func fetchSeedlingGroups(ctx context.Context, q PendingAssetStore,
14171471
// binds the genesis transaction (which will create the set of assets in the
14181472
// batch) to the batch itself.
14191473
func (a *AssetMintingStore) AddSproutsToBatch(ctx context.Context,
1420-
batchKey *btcec.PublicKey, genesisPacket *tapsend.FundedPsbt,
1474+
batchKey *btcec.PublicKey,
1475+
genesisPacket *tapgarden.FundedMintAnchorPsbt,
14211476
assetRoot *commitment.TapCommitment) error {
14221477

14231478
// Before we open the DB transaction below, we'll fetch the set of

tapdb/asset_minting_test.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ func assertBatchEqual(t *testing.T, a, b *tapgarden.MintingBatch) {
8888
require.Equal(t, a.TapSibling(), b.TapSibling())
8989
require.Equal(t, a.BatchKey, b.BatchKey)
9090
require.Equal(t, a.Seedlings, b.Seedlings)
91-
assertPsbtEqual(t, a.GenesisPacket, b.GenesisPacket)
91+
assertPsbtEqual(
92+
t, &a.GenesisPacket.FundedPsbt, &b.GenesisPacket.FundedPsbt,
93+
)
9294
require.Equal(t, a.RootAssetCommitment, b.RootAssetCommitment)
9395
}
9496

@@ -842,7 +844,10 @@ func TestAddSproutsToBatch(t *testing.T) {
842844
// state.
843845
assertSeedlingBatchLen(t, mintingBatches, 1, 0)
844846
assertBatchState(t, mintingBatches[0], tapgarden.BatchStateCommitted)
845-
assertPsbtEqual(t, genesisPacket, mintingBatches[0].GenesisPacket)
847+
assertPsbtEqual(
848+
t, &genesisPacket.FundedPsbt,
849+
&mintingBatches[0].GenesisPacket.FundedPsbt,
850+
)
846851
assertAssetsEqual(t, assetRoot, mintingBatches[0].RootAssetCommitment)
847852

848853
// We also expect that for each of the assets we created above, we're
@@ -930,7 +935,7 @@ func addRandAssets(t *testing.T, ctx context.Context,
930935
batchKey: batchKey,
931936
groupKey: &group.GroupKey.GroupPubKey,
932937
groupGenAmt: genAmt,
933-
genesisPkt: genesisPacket,
938+
genesisPkt: &genesisPacket.FundedPsbt,
934939
assetRoot: assetRoot,
935940
merkleRoot: merkleRoot[:],
936941
scriptRoot: scriptRoot[:],
@@ -981,7 +986,8 @@ func TestCommitBatchChainActions(t *testing.T) {
981986
t, mintingBatches[0], tapgarden.BatchStateBroadcast,
982987
)
983988
assertPsbtEqual(
984-
t, randAssetCtx.genesisPkt, mintingBatches[0].GenesisPacket,
989+
t, randAssetCtx.genesisPkt,
990+
&mintingBatches[0].GenesisPacket.FundedPsbt,
985991
)
986992
assertBatchSibling(t, mintingBatches[0], randAssetCtx.tapSiblingHash)
987993

@@ -1486,7 +1492,10 @@ func TestGroupAnchors(t *testing.T) {
14861492
// state.
14871493
assertSeedlingBatchLen(t, mintingBatches, 1, 0)
14881494
assertBatchState(t, mintingBatches[0], tapgarden.BatchStateCommitted)
1489-
assertPsbtEqual(t, genesisPacket, mintingBatches[0].GenesisPacket)
1495+
assertPsbtEqual(
1496+
t, &genesisPacket.FundedPsbt,
1497+
&mintingBatches[0].GenesisPacket.FundedPsbt,
1498+
)
14901499
assertAssetsEqual(t, assetRoot, mintingBatches[0].RootAssetCommitment)
14911500

14921501
// Check that the number of group anchors and members matches the batch

tapgarden/batch.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"github.com/lightninglabs/taproot-assets/fn"
1515
"github.com/lightninglabs/taproot-assets/proof"
1616
"github.com/lightninglabs/taproot-assets/tapscript"
17-
"github.com/lightninglabs/taproot-assets/tapsend"
1817
"github.com/lightningnetwork/lnd/keychain"
1918
)
2019

@@ -51,7 +50,7 @@ type MintingBatch struct {
5150
// GenesisPacket is the funded genesis packet that may or may not be
5251
// fully signed. When broadcast, this will create all assets stored
5352
// within this batch.
54-
GenesisPacket *tapsend.FundedPsbt
53+
GenesisPacket *FundedMintAnchorPsbt
5554

5655
// RootAssetCommitment is the root Taproot Asset commitment for all the
5756
// assets contained in this batch.

tapgarden/caretaker.go

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -412,24 +412,6 @@ func (b *BatchCaretaker) assetCultivator() {
412412
}
413413
}
414414

415-
// extractAnchorOutputIndex extracts the anchor output index from a funded
416-
// genesis packet.
417-
func extractAnchorOutputIndex(genesisPkt *tapsend.FundedPsbt) (uint32, error) {
418-
if len(genesisPkt.Pkt.UnsignedTx.TxOut) != 2 {
419-
return 0, fmt.Errorf("funded genesis packet has unexpected "+
420-
"number of outputs, expected 2 (txout_len=%d)",
421-
len(genesisPkt.Pkt.UnsignedTx.TxOut))
422-
}
423-
424-
anchorOutputIndex := uint32(0)
425-
426-
if genesisPkt.ChangeOutputIndex == 0 {
427-
anchorOutputIndex = 1
428-
}
429-
430-
return anchorOutputIndex, nil
431-
}
432-
433415
// extractGenesisOutpoint extracts the genesis point (the first input from the
434416
// genesis transaction).
435417
func extractGenesisOutpoint(tx *wire.MsgTx) wire.OutPoint {
@@ -612,18 +594,12 @@ func (b *BatchCaretaker) stateStep(currentState BatchState) (BatchState, error)
612594
return 0, fmt.Errorf("unable to deserialize genesis "+
613595
"PSBT: %w", err)
614596
}
615-
changeOutputIndex := b.cfg.Batch.GenesisPacket.ChangeOutputIndex
616-
617-
// If the change output is first, then our commitment is second,
618-
// and vice versa.
619-
// TODO(jhb): return the anchor index instead of change? or both
620-
// so this works for N outputs
621-
b.anchorOutputIndex, err = extractAnchorOutputIndex(
622-
b.cfg.Batch.GenesisPacket,
623-
)
624-
if err != nil {
625-
return 0, err
626-
}
597+
598+
// Unpack output indexes.
599+
genesisPacket := b.cfg.Batch.GenesisPacket
600+
601+
changeOutputIndex := genesisPacket.ChangeOutputIndex
602+
b.anchorOutputIndex = genesisPacket.AssetAnchorOutIdx
627603

628604
genesisPoint := extractGenesisOutpoint(genesisTxPkt.UnsignedTx)
629605

@@ -671,10 +647,15 @@ func (b *BatchCaretaker) stateStep(currentState BatchState) (BatchState, error)
671647
log.Infof("BatchCaretaker(%x): committing sprouts to disk",
672648
b.batchKey[:])
673649

674-
fundedGenesisPsbt := tapsend.FundedPsbt{
675-
Pkt: genesisTxPkt,
676-
ChangeOutputIndex: changeOutputIndex,
650+
fundedGenesisPsbt := FundedMintAnchorPsbt{
651+
FundedPsbt: tapsend.FundedPsbt{
652+
Pkt: genesisTxPkt,
653+
ChangeOutputIndex: changeOutputIndex,
654+
},
655+
AssetAnchorOutIdx: b.anchorOutputIndex,
656+
PreCommitmentOutput: genesisPacket.PreCommitmentOutput,
677657
}
658+
678659
// With all our commitments created, we'll commit them to disk,
679660
// replacing the existing seedlings we had created for each of
680661
// these assets.
@@ -801,8 +782,9 @@ func (b *BatchCaretaker) stateStep(currentState BatchState) (BatchState, error)
801782

802783
err = b.cfg.Log.CommitSignedGenesisTx(
803784
ctx, b.cfg.Batch.BatchKey.PubKey,
804-
b.cfg.Batch.GenesisPacket, b.anchorOutputIndex,
805-
merkleRoot, tapCommitmentRoot[:], siblingBytes,
785+
&b.cfg.Batch.GenesisPacket.FundedPsbt,
786+
b.anchorOutputIndex, merkleRoot, tapCommitmentRoot[:],
787+
siblingBytes,
806788
)
807789
if err != nil {
808790
return 0, fmt.Errorf("unable to commit genesis "+

tapgarden/interface.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ type MintingStore interface {
234234
// NOTE: The BatchState should transition to BatchStateCommitted upon a
235235
// successful call.
236236
AddSproutsToBatch(ctx context.Context, batchKey *btcec.PublicKey,
237-
genesisPacket *tapsend.FundedPsbt,
237+
genesisPacket *FundedMintAnchorPsbt,
238238
assets *commitment.TapCommitment) error
239239

240240
// CommitSignedGenesisTx adds a fully signed genesis transaction to the
@@ -288,7 +288,7 @@ type MintingStore interface {
288288
// CommitBatchTx adds a funded transaction to the batch, which also sets
289289
// the genesis point for the batch.
290290
CommitBatchTx(ctx context.Context, batchKey *btcec.PublicKey,
291-
genesisTx *tapsend.FundedPsbt) error
291+
genesisTx FundedMintAnchorPsbt) error
292292
}
293293

294294
// ChainBridge is our bridge to the target chain. It's used to get confirmation

tapgarden/mock.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,12 @@ func RandSeedlingMintingBatch(t testing.TB, numSeedlings int) *MintingBatch {
6666
Seedlings: RandSeedlings(t, numSeedlings),
6767
HeightHint: test.RandInt[uint32](),
6868
CreationTime: time.Now(),
69-
GenesisPacket: &tapsend.FundedPsbt{
70-
Pkt: &genesisTx,
71-
ChangeOutputIndex: 1,
69+
GenesisPacket: &FundedMintAnchorPsbt{
70+
FundedPsbt: tapsend.FundedPsbt{
71+
Pkt: &genesisTx,
72+
ChangeOutputIndex: 1,
73+
},
74+
AssetAnchorOutIdx: 0,
7275
},
7376
}
7477
}

tapgarden/planter.go

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,12 +1323,13 @@ func filterFinalizedBatches(batches []*MintingBatch) ([]*MintingBatch,
13231323
func fetchFinalizedBatch(ctx context.Context, batchStore MintingStore,
13241324
archiver proof.Archiver, batch *MintingBatch) (*MintingBatch, error) {
13251325

1326+
if batch.GenesisPacket == nil {
1327+
return nil, fmt.Errorf("batch is missing anchor tx packet")
1328+
}
1329+
13261330
// Collect genesis TX information from the batch to build the proof
13271331
// locators.
1328-
anchorOutputIndex, err := extractAnchorOutputIndex(batch.GenesisPacket)
1329-
if err != nil {
1330-
return nil, err
1331-
}
1332+
anchorOutputIndex := batch.GenesisPacket.AssetAnchorOutIdx
13321333

13331334
signedTx, err := psbt.Extract(batch.GenesisPacket.Pkt)
13341335
if err != nil {
@@ -1565,12 +1566,7 @@ func newVerboseBatch(currentBatch *MintingBatch,
15651566

15661567
// Before we can build the group key requests for each seedling, we must
15671568
// fetch the genesis point and anchor index for the batch.
1568-
anchorOutputIndex, err := extractAnchorOutputIndex(
1569-
currentBatch.GenesisPacket,
1570-
)
1571-
if err != nil {
1572-
return nil, err
1573-
}
1569+
anchorOutputIndex := currentBatch.GenesisPacket.AssetAnchorOutIdx
15741570

15751571
genesisPoint := extractGenesisOutpoint(
15761572
currentBatch.GenesisPacket.Pkt.UnsignedTx,
@@ -2019,10 +2015,7 @@ func (c *ChainPlanter) fundBatch(ctx context.Context, params FundParams,
20192015
"batch: %x %w", batchKey[:], err)
20202016
}
20212017

2022-
// TODO(ffranr): In a future commit, we will replace the
2023-
// GenesisPacket field type so as to carry along the
2024-
// pre-commitment output info.
2025-
batch.GenesisPacket = &mintAnchorTx.FundedPsbt
2018+
batch.GenesisPacket = &mintAnchorTx
20262019

20272020
return nil
20282021
}
@@ -2070,7 +2063,7 @@ func (c *ChainPlanter) fundBatch(ctx context.Context, params FundParams,
20702063
}
20712064

20722065
err = c.cfg.Log.CommitBatchTx(
2073-
ctx, workingBatch.BatchKey.PubKey, workingBatch.GenesisPacket,
2066+
ctx, workingBatch.BatchKey.PubKey, *workingBatch.GenesisPacket,
20742067
)
20752068
if err != nil {
20762069
return err
@@ -2151,12 +2144,7 @@ func (c *ChainPlanter) sealBatch(ctx context.Context, params SealParams,
21512144

21522145
// Before we can build the group key requests for each seedling, we must
21532146
// fetch the genesis point and anchor index for the batch.
2154-
anchorOutputIndex, err := extractAnchorOutputIndex(
2155-
workingBatch.GenesisPacket,
2156-
)
2157-
if err != nil {
2158-
return nil, err
2159-
}
2147+
anchorOutputIndex := workingBatch.GenesisPacket.AssetAnchorOutIdx
21602148

21612149
genesisPoint := extractGenesisOutpoint(
21622150
workingBatch.GenesisPacket.Pkt.UnsignedTx,

tapgarden/planter_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,14 +1148,14 @@ func testBasicAssetCreation(t *mintingTestHarness) {
11481148
// Now that the planter is back up, a single caretaker should have been
11491149
// launched as well. The batch should already be funded.
11501150
batch := t.fetchSingleBatch(nil)
1151-
t.assertBatchGenesisTx(batch.GenesisPacket)
1151+
t.assertBatchGenesisTx(&batch.GenesisPacket.FundedPsbt)
11521152
t.assertNumCaretakersActive(1)
11531153

11541154
// We'll now force yet another restart to ensure correctness of the
11551155
// state machine. We expect the PSBT packet to still be funded.
11561156
t.refreshChainPlanter()
11571157
batch = t.fetchSingleBatch(nil)
1158-
t.assertBatchGenesisTx(batch.GenesisPacket)
1158+
t.assertBatchGenesisTx(&batch.GenesisPacket.FundedPsbt)
11591159

11601160
// Now that the batch has been ticked, and the caretaker started, there
11611161
// should no longer be a pending batch.
@@ -1251,7 +1251,7 @@ func testMintingTicker(t *mintingTestHarness) {
12511251
// that the batch is already funded.
12521252
t.assertBatchProgressing()
12531253
currentBatch := t.fetchLastBatch()
1254-
t.assertBatchGenesisTx(currentBatch.GenesisPacket)
1254+
t.assertBatchGenesisTx(&currentBatch.GenesisPacket.FundedPsbt)
12551255

12561256
// Now that the batch has been ticked, and the caretaker started, there
12571257
// should no longer be a pending batch.
@@ -1352,7 +1352,7 @@ func testMintingCancelFinalize(t *mintingTestHarness) {
13521352

13531353
t.assertBatchProgressing()
13541354
thirdBatch = t.fetchLastBatch()
1355-
t.assertBatchGenesisTx(thirdBatch.GenesisPacket)
1355+
t.assertBatchGenesisTx(&thirdBatch.GenesisPacket.FundedPsbt)
13561356

13571357
// Now that the batch has been ticked, and the caretaker started, there
13581358
// should no longer be a pending batch.
@@ -1761,7 +1761,7 @@ func testFundSealBeforeFinalize(t *mintingTestHarness) {
17611761
fundedEmptyBatch := fundedBatches[0]
17621762
require.Len(t, fundedEmptyBatch.Seedlings, 0)
17631763
require.NotNil(t, fundedEmptyBatch.GenesisPacket)
1764-
t.assertBatchGenesisTx(fundedEmptyBatch.GenesisPacket)
1764+
t.assertBatchGenesisTx(&fundedEmptyBatch.GenesisPacket.FundedPsbt)
17651765
require.Equal(t, defaultTapHash[:], fundedEmptyBatch.TapSibling())
17661766
require.True(t, fundedEmptyBatch.State() == tapgarden.BatchStatePending)
17671767

0 commit comments

Comments
 (0)