Skip to content

Commit 57984a4

Browse files
committed
Merge pull request #1418 from lightninglabs/unit-tests-mint-pre-commit
Refactor `fundGenesisPsbt` and enhance test helpers for coverage
2 parents 8f6b510 + 10b3fb4 commit 57984a4

File tree

5 files changed

+251
-128
lines changed

5 files changed

+251
-128
lines changed

tapdb/asset_minting_test.go

Lines changed: 85 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"crypto/sha256"
77
"database/sql"
8+
"fmt"
89
"math/rand"
910
"os"
1011
"testing"
@@ -503,7 +504,9 @@ func TestCommitMintingBatchSeedlings(t *testing.T) {
503504
// First, we'll write a new minting batch to disk, including an
504505
// internal key and a set of seedlings. One random seedling will
505506
// be a reissuance into a specific group.
506-
mintingBatch := tapgarden.RandSeedlingMintingBatch(t, numSeedlings)
507+
mintingBatch := tapgarden.RandMintingBatch(
508+
t, tapgarden.WithTotalSeedlings(numSeedlings),
509+
)
507510
_, randGroup, _ := addRandGroupToBatch(
508511
t, assetStore, ctx, mintingBatch.Seedlings,
509512
)
@@ -604,7 +607,9 @@ func TestCommitMintingBatchSeedlings(t *testing.T) {
604607

605608
// Insert another normal batch into the database. We should get this
606609
// batch back if we query for the set of non-final batches.
607-
mintingBatch = tapgarden.RandSeedlingMintingBatch(t, numSeedlings)
610+
mintingBatch = tapgarden.RandMintingBatch(
611+
t, tapgarden.WithTotalSeedlings(numSeedlings),
612+
)
608613
err = assetStore.CommitMintingBatch(ctx, mintingBatch)
609614
require.NoError(t, err)
610615
mintingBatches = noError1(t, assetStore.FetchNonFinalBatches, ctx)
@@ -851,7 +856,9 @@ func TestAddSproutsToBatch(t *testing.T) {
851856

852857
// First, we'll create a new batch, then add some sample seedlings.
853858
// One random seedling will be a reissuance into a specific group.
854-
mintingBatch := tapgarden.RandSeedlingMintingBatch(t, numSeedlings)
859+
mintingBatch := tapgarden.RandMintingBatch(
860+
t, tapgarden.WithTotalSeedlings(numSeedlings),
861+
)
855862
_, seedlingGroups, _ := addRandGroupToBatch(
856863
t, assetStore, ctx, mintingBatch.Seedlings,
857864
)
@@ -949,7 +956,9 @@ type randAssetCtx struct {
949956
func addRandAssets(t *testing.T, ctx context.Context,
950957
assetStore *AssetMintingStore, numAssets int) randAssetCtx {
951958

952-
mintingBatch := tapgarden.RandSeedlingMintingBatch(t, numAssets)
959+
mintingBatch := tapgarden.RandMintingBatch(
960+
t, tapgarden.WithTotalSeedlings(numAssets),
961+
)
953962
genAmt, seedlingGroups, group := addRandGroupToBatch(
954963
t, assetStore, ctx, mintingBatch.Seedlings,
955964
)
@@ -1463,7 +1472,9 @@ func TestGroupAnchors(t *testing.T) {
14631472
// internal key and a set of seedlings. One random seedling will
14641473
// be a reissuance into a specific group. Two other seedlings will form
14651474
// a multi-asset group.
1466-
mintingBatch := tapgarden.RandSeedlingMintingBatch(t, numSeedlings)
1475+
mintingBatch := tapgarden.RandMintingBatch(
1476+
t, tapgarden.WithTotalSeedlings(numSeedlings),
1477+
)
14671478
_, seedlingGroups, _ := addRandGroupToBatch(
14681479
t, assetStore, ctx, mintingBatch.Seedlings,
14691480
)
@@ -1839,7 +1850,7 @@ func TestTapscriptTreeManager(t *testing.T) {
18391850
// storeMintSupplyPreCommit stores a mint anchor supply pre-commitment in the
18401851
// DB.
18411852
func storeMintSupplyPreCommit(t *testing.T, assetStore AssetMintingStore,
1842-
batchKey []byte, txOutputIndex int32,
1853+
batchKey []byte, txOutputIndex uint32,
18431854
taprootInternalKey keychain.KeyDescriptor, groupKey []byte,
18441855
outpoint wire.OutPoint) {
18451856

@@ -1863,7 +1874,7 @@ func storeMintSupplyPreCommit(t *testing.T, assetStore AssetMintingStore,
18631874
_, err = q.UpsertMintSupplyPreCommit(
18641875
ctx, UpsertBatchPreCommitParams{
18651876
BatchKey: batchKey,
1866-
TxOutputIndex: txOutputIndex,
1877+
TxOutputIndex: int32(txOutputIndex),
18671878
TaprootInternalKeyID: internalKeyID,
18681879
GroupKey: groupKey,
18691880
Outpoint: opBytes,
@@ -1880,7 +1891,7 @@ func storeMintSupplyPreCommit(t *testing.T, assetStore AssetMintingStore,
18801891
// supply pre-commitment from the DB and asserts that it matches the expected
18811892
// values.
18821893
func assertMintSupplyPreCommit(t *testing.T, assetStore AssetMintingStore,
1883-
batchKey []byte, txOutputIndex int32,
1894+
batchKey []byte, txOutputIndex uint32,
18841895
preCommitInternalKey keychain.KeyDescriptor, groupPubKeyBytes []byte,
18851896
outpoint wire.OutPoint) {
18861897

@@ -1906,7 +1917,7 @@ func assertMintSupplyPreCommit(t *testing.T, assetStore AssetMintingStore,
19061917
// Ensure the mint anchor commitment matches the one we inserted.
19071918
require.NotNil(t, preCommit)
19081919
require.Equal(t, batchKey, preCommit.BatchKey)
1909-
require.Equal(t, txOutputIndex, preCommit.TxOutputIndex)
1920+
require.EqualValues(t, txOutputIndex, preCommit.TxOutputIndex)
19101921

19111922
rawInternalKey := preCommitInternalKey.PubKey.SerializeCompressed()
19121923
require.Equal(
@@ -1927,6 +1938,39 @@ func assertMintSupplyPreCommit(t *testing.T, assetStore AssetMintingStore,
19271938
require.Equal(t, opBytes, preCommit.Outpoint)
19281939
}
19291940

1941+
// storeSeedlingGroupGenesis stores the group genesis and an initial asset
1942+
// associated with the given seedling in the DB. This is necessary before we can
1943+
// commit a minting batch that contains the seedling.
1944+
func storeSeedlingGroupGenesis(t *testing.T, ctx context.Context,
1945+
assetStore *AssetMintingStore, seedling tapgarden.Seedling) {
1946+
1947+
genesis := seedling.GroupInfo.Genesis
1948+
groupKey := seedling.GroupInfo.GroupKey
1949+
initialAsset := asset.RandAssetWithValues(
1950+
t, *genesis, groupKey, asset.RandScriptKey(t),
1951+
)
1952+
1953+
upsertAsset := func(q PendingAssetStore) error {
1954+
_, err := maybeUpsertAssetMeta(ctx, q, genesis, nil)
1955+
require.NoError(t, err)
1956+
1957+
// Insert a random managed UTXO.
1958+
utxoID := addRandomManagedUTXO(t, ctx, q, initialAsset)
1959+
1960+
_, _, err = upsertAssetsWithGenesis(
1961+
ctx, q, genesis.FirstPrevOut,
1962+
[]*asset.Asset{initialAsset},
1963+
[]sql.NullInt64{sqlInt64(utxoID)},
1964+
)
1965+
require.NoError(t, err)
1966+
return nil
1967+
}
1968+
1969+
var writeTxOpts AssetStoreTxOptions
1970+
err := assetStore.db.ExecTx(ctx, &writeTxOpts, upsertAsset)
1971+
require.NoError(t, err)
1972+
}
1973+
19301974
// TestUpsertMintSupplyPreCommit tests the UpsertMintSupplyPreCommit and
19311975
// FetchSupplyPreCommits SQL queries. In particular, it tests that upsert works
19321976
// correctly.
@@ -1937,13 +1981,21 @@ func TestUpsertMintSupplyPreCommit(t *testing.T) {
19371981
assetStore, _, _ := newAssetStore(t)
19381982

19391983
// Create a new batch with one asset group seedling.
1940-
mintingBatch := tapgarden.RandSeedlingMintingBatch(t, 1)
1941-
mintingBatch.SupplyCommitments = true
1942-
1943-
_, _, group := addRandGroupToBatch(
1944-
t, assetStore, ctx, mintingBatch.Seedlings,
1984+
mintingBatch := tapgarden.RandMintingBatch(
1985+
t, tapgarden.WithTotalGroups([]int{1}),
1986+
tapgarden.WithUniverseCommitments(true),
19451987
)
19461988

1989+
// Store group genesis associated with seedling. This is necessary
1990+
// before we can commit the batch.
1991+
require.Len(t, mintingBatch.Seedlings, 1)
1992+
var seedling tapgarden.Seedling
1993+
for _, s := range mintingBatch.Seedlings {
1994+
seedling = *s
1995+
break
1996+
}
1997+
storeSeedlingGroupGenesis(t, ctx, assetStore, seedling)
1998+
19471999
// Commit batch.
19482000
require.NoError(t, assetStore.CommitMintingBatch(ctx, mintingBatch))
19492001

@@ -1962,45 +2014,47 @@ func TestUpsertMintSupplyPreCommit(t *testing.T) {
19622014
)
19632015

19642016
// Define pre-commit outpoint for the batch mint anchor tx.
1965-
txOutputIndex := int32(2)
1966-
txidStr := mintingBatch.GenesisPacket.FundedPsbt.Pkt.UnsignedTx.TxID()
2017+
genesisPkt := mintingBatch.GenesisPacket
2018+
require.NotNil(t, genesisPkt)
2019+
2020+
preCommitOut, err := genesisPkt.PreCommitmentOutput.UnwrapOrErr(
2021+
fmt.Errorf("no pre-commitment output"),
2022+
)
2023+
require.NoError(t, err)
19672024

2025+
txidStr := genesisPkt.FundedPsbt.Pkt.UnsignedTx.TxID()
19682026
txid, err := chainhash.NewHashFromStr(txidStr)
19692027
require.NoError(t, err)
19702028

19712029
preCommitOutpoint := wire.OutPoint{
19722030
Hash: *txid,
1973-
Index: uint32(txOutputIndex),
2031+
Index: preCommitOut.OutIdx,
19742032
}
19752033

19762034
// Serialize keys into bytes for easier handling.
1977-
preCommitInternalKey, _ := test.RandKeyDesc(t)
1978-
1979-
groupPubKeyBytes := schnorr.SerializePubKey(&group.GroupPubKey)
1980-
1981-
// Upsert a mint anchor commitment for the batch.
1982-
storeMintSupplyPreCommit(
1983-
t, *assetStore, batchKey, txOutputIndex,
1984-
preCommitInternalKey, groupPubKeyBytes, preCommitOutpoint,
2035+
preCommitGroupKey, err := preCommitOut.GroupPubKey.UnwrapOrErr(
2036+
fmt.Errorf("no group key"),
19852037
)
2038+
require.NoError(t, err)
2039+
groupPubKeyBytes := schnorr.SerializePubKey(&preCommitGroupKey)
19862040

19872041
// Retrieve and inspect the mint anchor commitment we just inserted.
19882042
assertMintSupplyPreCommit(
1989-
t, *assetStore, batchKey, txOutputIndex,
1990-
preCommitInternalKey, groupPubKeyBytes, preCommitOutpoint,
2043+
t, *assetStore, batchKey, preCommitOut.OutIdx,
2044+
preCommitOut.InternalKey, groupPubKeyBytes, preCommitOutpoint,
19912045
)
19922046

19932047
// Upsert-ing a new taproot internal key for the same pre-commit
19942048
// outpoint should overwrite the existing one.
19952049
internalKey2, _ := test.RandKeyDesc(t)
19962050

19972051
storeMintSupplyPreCommit(
1998-
t, *assetStore, batchKey, txOutputIndex, internalKey2,
2052+
t, *assetStore, batchKey, preCommitOut.OutIdx, internalKey2,
19992053
groupPubKeyBytes, preCommitOutpoint,
20002054
)
20012055

20022056
assertMintSupplyPreCommit(
2003-
t, *assetStore, batchKey, txOutputIndex, internalKey2,
2057+
t, *assetStore, batchKey, preCommitOut.OutIdx, internalKey2,
20042058
groupPubKeyBytes, preCommitOutpoint,
20052059
)
20062060

@@ -2010,12 +2064,12 @@ func TestUpsertMintSupplyPreCommit(t *testing.T) {
20102064
groupPubKey2Bytes := schnorr.SerializePubKey(groupPubKey2)
20112065

20122066
storeMintSupplyPreCommit(
2013-
t, *assetStore, batchKey, txOutputIndex, internalKey2,
2067+
t, *assetStore, batchKey, preCommitOut.OutIdx, internalKey2,
20142068
groupPubKey2Bytes, preCommitOutpoint,
20152069
)
20162070

20172071
assertMintSupplyPreCommit(
2018-
t, *assetStore, batchKey, txOutputIndex, internalKey2,
2072+
t, *assetStore, batchKey, preCommitOut.OutIdx, internalKey2,
20192073
groupPubKey2Bytes, preCommitOutpoint,
20202074
)
20212075
}

tapgarden/batch_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,13 @@ func TestValidateUniCommitment(t *testing.T) {
110110
// Ensures that a group anchor candidate seedling
111111
// with universe commitments can be added to an empty
112112
// batch.
113-
name: "empty batch; candidate seedling is group " +
114-
"anchor; is valid",
113+
name: "empty unfunded batch; candidate seedling is " +
114+
"group anchor; is valid",
115115

116116
candidateSeedling: RandGroupAnchorSeedling(
117117
t, "some-anchor-name", true,
118118
),
119-
batch: RandMintingBatch(t),
119+
batch: RandMintingBatch(t, WithSkipFunding()),
120120
expectErr: false,
121121
},
122122
}

tapgarden/mock.go

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/btcsuite/btcd/wire"
2323
"github.com/btcsuite/btcwallet/waddrmgr"
2424
"github.com/lightninglabs/lndclient"
25+
"github.com/lightninglabs/taproot-assets/address"
2526
"github.com/lightninglabs/taproot-assets/asset"
2627
"github.com/lightninglabs/taproot-assets/fn"
2728
"github.com/lightninglabs/taproot-assets/internal/test"
@@ -163,6 +164,9 @@ type MintBatchOptions struct {
163164
// universeCommitments specifies whether to generate universe
164165
// commitments for the asset groups in this minting batch.
165166
universeCommitments bool
167+
168+
// skipFunding specifies whether to skip funding the genesis PSBT.
169+
skipFunding bool
166170
}
167171

168172
// MintBatchOption is a functional option for creating a new minting batch.
@@ -198,6 +202,13 @@ func WithUniverseCommitments(enabled bool) MintBatchOption {
198202
}
199203
}
200204

205+
// WithSkipFunding specifies whether to skip funding the genesis PSBT.
206+
func WithSkipFunding() MintBatchOption {
207+
return func(options *MintBatchOptions) {
208+
options.skipFunding = true
209+
}
210+
}
211+
201212
// RandMintingBatch creates a new minting batch with only random seedlings
202213
// populated for testing.
203214
func RandMintingBatch(t testing.TB, opts ...MintBatchOption) *MintingBatch {
@@ -259,6 +270,32 @@ func RandMintingBatch(t testing.TB, opts ...MintBatchOption) *MintingBatch {
259270
// requested amount. This check might help debug flakes in tests.
260271
require.Equal(t, options.totalSeedlings, len(batch.Seedlings))
261272

273+
// Return early if funding is to be skipped.
274+
if options.skipFunding {
275+
return batch
276+
}
277+
278+
walletFundPsbt := func(ctx context.Context,
279+
anchorPkt psbt.Packet) (tapsend.FundedPsbt, error) {
280+
281+
changeOutputIdx := FundGenesisTx(
282+
&anchorPkt, chainfee.FeePerKwFloor,
283+
)
284+
285+
return tapsend.FundedPsbt{
286+
Pkt: &anchorPkt,
287+
ChangeOutputIndex: int32(changeOutputIdx),
288+
}, nil
289+
}
290+
291+
// Fund genesis packet.
292+
ctx := context.Background()
293+
fundedPsbt, err := fundGenesisPsbt(
294+
ctx, address.TestNet3Tap, batch, walletFundPsbt,
295+
)
296+
require.NoError(t, err)
297+
batch.GenesisPacket = &fundedPsbt
298+
262299
return batch
263300
}
264301

@@ -286,29 +323,6 @@ func RandSeedlings(t testing.TB, numSeedlings int) map[string]*Seedling {
286323
return seedlings
287324
}
288325

289-
// RandSeedlingMintingBatch creates a new minting batch with only random
290-
// seedlings populated for testing.
291-
//
292-
// TODO(ffranr): Replace this function with RandMintingBatch. Note also function
293-
// addRandGroupToBatch.
294-
func RandSeedlingMintingBatch(t testing.TB, numSeedlings int) *MintingBatch {
295-
genesisTx := NewGenesisTx(t, chainfee.FeePerKwFloor)
296-
BatchKey, _ := test.RandKeyDesc(t)
297-
return &MintingBatch{
298-
BatchKey: BatchKey,
299-
Seedlings: RandSeedlings(t, numSeedlings),
300-
HeightHint: test.RandInt[uint32](),
301-
CreationTime: time.Now(),
302-
GenesisPacket: &FundedMintAnchorPsbt{
303-
FundedPsbt: tapsend.FundedPsbt{
304-
Pkt: &genesisTx,
305-
ChangeOutputIndex: 1,
306-
},
307-
AssetAnchorOutIdx: 0,
308-
},
309-
}
310-
}
311-
312326
type MockWalletAnchor struct {
313327
FundPsbtSignal chan *tapsend.FundedPsbt
314328
SignPsbtSignal chan struct{}
@@ -345,8 +359,9 @@ func NewGenesisTx(t testing.TB, feeRate chainfee.SatPerKWeight) psbt.Packet {
345359
return *genesisPkt
346360
}
347361

348-
// FundGenesisTx add a genesis input and change output to a 1-output TX.
349-
func FundGenesisTx(packet *psbt.Packet, feeRate chainfee.SatPerKWeight) {
362+
// FundGenesisTx add a genesis input and change output to a 1-output TX and
363+
// returns the index of the change output.
364+
func FundGenesisTx(packet *psbt.Packet, feeRate chainfee.SatPerKWeight) uint32 {
350365
const anchorBalance = int64(100000)
351366

352367
// Take the PSBT packet and add an additional input and output to
@@ -382,7 +397,10 @@ func FundGenesisTx(packet *psbt.Packet, feeRate chainfee.SatPerKWeight) {
382397
[][]byte{tapsend.GenesisDummyScript}, packet.UnsignedTx.TxOut,
383398
feeRate,
384399
)
385-
packet.UnsignedTx.TxOut[1].Value -= int64(fee)
400+
changeOutputIdx := len(packet.UnsignedTx.TxOut) - 1
401+
packet.UnsignedTx.TxOut[changeOutputIdx].Value -= int64(fee)
402+
403+
return uint32(changeOutputIdx)
386404
}
387405

388406
// FundPsbt funds a PSBT.

0 commit comments

Comments
 (0)