Skip to content

Commit df6ae3f

Browse files
authored
Merge pull request #1820 from lightninglabs/wip/supplyverify/late-mint-precommit-sync
Extract supply pre-commits from mint leaves during supply verifier sync
2 parents 21f385d + 0ff013d commit df6ae3f

File tree

14 files changed

+1460
-154
lines changed

14 files changed

+1460
-154
lines changed

docs/release-notes/release-notes-0.7.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
- https://github.com/lightninglabs/taproot-assets/pull/1797
7979
- https://github.com/lightninglabs/taproot-assets/pull/1823
8080
- https://github.com/lightninglabs/taproot-assets/pull/1822
81+
- https://github.com/lightninglabs/taproot-assets/pull/1820
8182

8283
- A new [address version 2 was introduced that supports grouped assets and
8384
custom (sender-defined)

itest/supply_commit_test.go

Lines changed: 97 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,18 +1042,21 @@ func testSupplyCommitMintBurn(t *harnessTest) {
10421042
// 5. Ignores the asset outpoint sent to the secondary node.
10431043
// 6. Publishes the second supply commitment and mines it.
10441044
// 7. Verifies the secondary node can fetch the updated supply commitment.
1045+
// 8. Primary node mints another asset into the group and publishes the
1046+
// third supply commitment.
1047+
// 9. Verifies the secondary node can fetch the third supply commitment.
10451048
func testSupplyVerifyPeerNode(t *harnessTest) {
10461049
ctxb := context.Background()
10471050

10481051
t.Log("Minting initial asset group with universe/supply " +
10491052
"commitments enabled")
10501053

10511054
// Create a mint request for a grouped asset with supply commitments.
1052-
mintReq := CopyRequest(issuableAssets[0])
1053-
mintReq.Asset.Amount = 5000
1055+
firstMintReq := CopyRequest(issuableAssets[0])
1056+
firstMintReq.Asset.Amount = 5000
10541057

10551058
rpcFirstAsset, _ := MintAssetWithSupplyCommit(
1056-
t, mintReq, fn.None[btcec.PublicKey](),
1059+
t, firstMintReq, fn.None[btcec.PublicKey](),
10571060
)
10581061

10591062
// Parse out the group key from the minted asset.
@@ -1077,7 +1080,7 @@ func testSupplyVerifyPeerNode(t *harnessTest) {
10771080
// Verify the issuance subtree root exists and has the correct amount.
10781081
require.NotNil(t.t, fetchResp.IssuanceSubtreeRoot)
10791082
require.Equal(
1080-
t.t, int64(mintReq.Asset.Amount),
1083+
t.t, int64(firstMintReq.Asset.Amount),
10811084
fetchResp.IssuanceSubtreeRoot.RootNode.RootSum,
10821085
)
10831086

@@ -1125,7 +1128,7 @@ func testSupplyVerifyPeerNode(t *harnessTest) {
11251128
)
11261129

11271130
require.Equal(
1128-
t.t, int64(mintReq.Asset.Amount),
1131+
t.t, int64(firstMintReq.Asset.Amount),
11291132
peerFetchResp.IssuanceSubtreeRoot.RootNode.RootSum,
11301133
)
11311134

@@ -1160,7 +1163,7 @@ func testSupplyVerifyPeerNode(t *harnessTest) {
11601163

11611164
t.Log("Verifying retrieval of second supply commitment from primary " +
11621165
"node")
1163-
fetchResp, _ = WaitForSupplyCommit(
1166+
fetchResp, supplyOutpoint = WaitForSupplyCommit(
11641167
t.t, ctxb, t.tapd, groupKeyBytes, fn.Some(supplyOutpoint),
11651168
func(resp *unirpc.FetchSupplyCommitResponse) bool {
11661169
ignoreRoot := resp.IgnoreSubtreeRoot
@@ -1265,4 +1268,92 @@ func testSupplyVerifyPeerNode(t *harnessTest) {
12651268
// Verify that the secondary node's supply commitment matches the
12661269
// primary's.
12671270
assertFetchCommitResponse(t, fetchResp, peerFetchResp2)
1271+
1272+
// Step 8: Primary node mints another asset into the group and publishes
1273+
// the third supply commitment.
1274+
t.Log("Minting second asset into the same asset group")
1275+
1276+
secondMintReq := &mintrpc.MintAssetRequest{
1277+
Asset: &mintrpc.MintAsset{
1278+
AssetType: taprpc.AssetType_NORMAL,
1279+
Name: "itestbuxx-supply-commit-tranche-2",
1280+
AssetMeta: &taprpc.AssetMeta{
1281+
Data: []byte("second tranche metadata"),
1282+
},
1283+
Amount: 2000,
1284+
AssetVersion: taprpc.AssetVersion_ASSET_VERSION_V1,
1285+
NewGroupedAsset: false,
1286+
GroupedAsset: true,
1287+
GroupKey: groupKeyBytes,
1288+
1289+
EnableSupplyCommitments: true,
1290+
},
1291+
}
1292+
1293+
MintAssetWithSupplyCommit(
1294+
t, secondMintReq, fn.None[btcec.PublicKey](),
1295+
)
1296+
1297+
t.Log("Updating supply commitment after second mint (creating third " +
1298+
"supply commitment)")
1299+
UpdateAndMineSupplyCommit(
1300+
t.t, ctxb, t.tapd, t.lndHarness.Miner().Client,
1301+
groupKeyBytes, 1,
1302+
)
1303+
1304+
// Wait for the third supply commitment to be available.
1305+
expectedTotalAfterSecondMint := int64(
1306+
firstMintReq.Asset.Amount + secondMintReq.Asset.Amount,
1307+
)
1308+
var thirdSupplyCommitResp *unirpc.FetchSupplyCommitResponse
1309+
thirdSupplyCommitResp, _ = WaitForSupplyCommit(
1310+
t.t, ctxb, t.tapd, groupKeyBytes, fn.Some(supplyOutpoint),
1311+
func(resp *unirpc.FetchSupplyCommitResponse) bool {
1312+
actualRootSum :=
1313+
resp.IssuanceSubtreeRoot.RootNode.RootSum
1314+
1315+
return resp.IssuanceSubtreeRoot != nil &&
1316+
actualRootSum == expectedTotalAfterSecondMint
1317+
},
1318+
)
1319+
1320+
// Step 9: Verify the secondary node can fetch the third supply
1321+
// commitment.
1322+
t.Log("Verifying secondary node can fetch third supply commitment")
1323+
1324+
// Verify the secondary node can fetch the third supply commitment.
1325+
peerFetchPred3 := func(resp *unirpc.FetchSupplyCommitResponse) error {
1326+
if resp.IssuanceSubtreeRoot == nil {
1327+
return fmt.Errorf("expected issuance subtree root")
1328+
}
1329+
1330+
// Check if the supply commitment includes the second mint.
1331+
if resp.IssuanceSubtreeRoot.RootNode.RootSum !=
1332+
expectedTotalAfterSecondMint {
1333+
1334+
return fmt.Errorf("expected RootSum %d, got %d",
1335+
expectedTotalAfterSecondMint,
1336+
resp.IssuanceSubtreeRoot.RootNode.RootSum)
1337+
}
1338+
1339+
return nil
1340+
}
1341+
1342+
// nolint: lll
1343+
req = unirpc.FetchSupplyCommitRequest{
1344+
GroupKey: &unirpc.FetchSupplyCommitRequest_GroupKeyBytes{
1345+
GroupKeyBytes: groupKeyBytes,
1346+
},
1347+
Locator: &unirpc.FetchSupplyCommitRequest_SpentCommitOutpoint{
1348+
SpentCommitOutpoint: thirdSupplyCommitResp.SpentCommitmentOutpoint,
1349+
},
1350+
}
1351+
1352+
peerFetchResp3 := rpcassert.FetchSupplyCommitRPC(
1353+
t.t, ctxb, secondTapd, peerFetchPred3, &req,
1354+
)
1355+
1356+
// Verify that the secondary node's third supply commitment matches the
1357+
// primary's.
1358+
assertFetchCommitResponse(t, thirdSupplyCommitResp, peerFetchResp3)
12681359
}

tapdb/supply_commit.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,12 @@ func (s *SupplyCommitMachine) InsertSupplyCommit(ctx context.Context,
11511151
"pre-commit outpoint: %w", err)
11521152
}
11531153

1154+
err = upsertSupplyPreCommit(ctx, db, preCommit)
1155+
if err != nil {
1156+
return fmt.Errorf("failed to upsert "+
1157+
"pre-commit: %w", err)
1158+
}
1159+
11541160
markParams := sqlc.MarkPreCommitSpentByOutpointParams{
11551161
SpentByCommitID: sqlInt64(newCommitmentID),
11561162
Outpoint: outpointBytes,

tapdb/universe.go

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
"github.com/lightninglabs/taproot-assets/proof"
1717
"github.com/lightninglabs/taproot-assets/tapdb/sqlc"
1818
"github.com/lightninglabs/taproot-assets/universe"
19-
"github.com/lightninglabs/taproot-assets/universe/supplyverifier"
19+
"github.com/lightninglabs/taproot-assets/universe/supplycommit"
2020
lfn "github.com/lightningnetwork/lnd/fn/v2"
2121
"github.com/lightningnetwork/lnd/keychain"
2222
)
@@ -611,52 +611,27 @@ func shouldInsertPreCommit(proofType universe.ProofType,
611611
return true
612612
}
613613

614-
// maybeUpsertSupplyPreCommit inserts a supply pre-commitment output if the
615-
// asset group supports supply commitments and this is an issuance proof.
616-
func maybeUpsertSupplyPreCommit(ctx context.Context, dbTx UpsertAssetStore,
617-
proofType universe.ProofType, issuanceProof proof.Proof,
618-
metaReveal *proof.MetaReveal) error {
614+
// upsertSupplyPreCommit upserts a supply pre-commitment into the database.
615+
func upsertSupplyPreCommit(ctx context.Context, dbTx UpsertAssetStore,
616+
preCommit supplycommit.PreCommitment) error {
619617

620-
if !shouldInsertPreCommit(proofType, issuanceProof, metaReveal) {
621-
return nil
622-
}
623-
624-
delegationKey, err := metaReveal.DelegationKey.UnwrapOrErr(
625-
errors.New("missing delegation key"),
626-
)
627-
if err != nil {
628-
return err
629-
}
630-
631-
preCommitOutput, err := supplyverifier.ExtractPreCommitOutput(
632-
issuanceProof, delegationKey,
633-
)
634-
if err != nil {
635-
return fmt.Errorf("unable to extract pre-commit "+
636-
"output: %w", err)
637-
}
618+
// Encode the group key, taproot internal key, and pre-commit outpoint.
619+
groupKeyBytes := schnorr.SerializePubKey(&preCommit.GroupPubKey)
620+
taprootInternalKeyBytes :=
621+
preCommit.InternalKey.PubKey.SerializeCompressed()
638622

639-
outPointBytes, err := encodeOutpoint(preCommitOutput.OutPoint())
623+
outPointBytes, err := encodeOutpoint(preCommit.OutPoint())
640624
if err != nil {
641625
return fmt.Errorf("unable to encode supply pre-commit "+
642626
"outpoint: %w", err)
643627
}
644628

645-
// Upsert the supply pre-commitment output.
646-
//
647-
// Encode the group key and taproot internal key.
648-
groupKeyBytes := schnorr.SerializePubKey(
649-
&issuanceProof.Asset.GroupKey.GroupPubKey,
650-
)
651-
taprootInternalKeyBytes :=
652-
preCommitOutput.InternalKey.PubKey.SerializeCompressed()
653-
654629
// Try to fetch an existing chain tx row from the database. We fetch
655630
// first instead of blindly upserting to avoid overwriting existing data
656631
// with null values.
657632
var chainTxDbID fn.Option[int64]
658633

659-
txIDBytes := fn.ByteSlice(issuanceProof.AnchorTx.TxHash())
634+
txIDBytes := fn.ByteSlice(preCommit.MintingTxn.TxHash())
660635
chainTxn, err := dbTx.FetchChainTx(ctx, txIDBytes)
661636
switch {
662637
case errors.Is(err, sql.ErrNoRows):
@@ -677,17 +652,15 @@ func maybeUpsertSupplyPreCommit(ctx context.Context, dbTx UpsertAssetStore,
677652
// If we didn't find an existing chain tx, then we'll insert a new
678653
// one now.
679654
if chainTxDbID.IsNone() {
680-
blockHash := issuanceProof.BlockHeader.BlockHash()
681-
txBytes, err := fn.Serialize(&issuanceProof.AnchorTx)
655+
txBytes, err := fn.Serialize(preCommit.MintingTxn)
682656
if err != nil {
683657
return fmt.Errorf("failed to serialize tx: %w", err)
684658
}
685659

686660
txDbID, err := dbTx.UpsertChainTx(ctx, ChainTxParams{
687661
Txid: txIDBytes,
688662
RawTx: txBytes,
689-
BlockHeight: sqlInt32(issuanceProof.BlockHeight),
690-
BlockHash: blockHash.CloneBytes(),
663+
BlockHeight: sqlInt32(preCommit.BlockHeight),
691664
})
692665
if err != nil {
693666
return fmt.Errorf("unable to upsert chain tx: %w", err)
@@ -718,6 +691,39 @@ func maybeUpsertSupplyPreCommit(ctx context.Context, dbTx UpsertAssetStore,
718691
return nil
719692
}
720693

694+
// maybeUpsertSupplyPreCommit inserts a supply pre-commitment output if the
695+
// asset group supports supply commitments and this is an issuance proof.
696+
func maybeUpsertSupplyPreCommit(ctx context.Context, dbTx UpsertAssetStore,
697+
proofType universe.ProofType, issuanceProof proof.Proof,
698+
metaReveal *proof.MetaReveal) error {
699+
700+
if !shouldInsertPreCommit(proofType, issuanceProof, metaReveal) {
701+
return nil
702+
}
703+
704+
delegationKey, err := metaReveal.DelegationKey.UnwrapOrErr(
705+
errors.New("missing delegation key"),
706+
)
707+
if err != nil {
708+
return err
709+
}
710+
711+
preCommit, err := supplycommit.NewPreCommitFromProof(
712+
issuanceProof, delegationKey,
713+
)
714+
if err != nil {
715+
return fmt.Errorf("unable to extract pre-commit "+
716+
"output: %w", err)
717+
}
718+
719+
err = upsertSupplyPreCommit(ctx, dbTx, preCommit)
720+
if err != nil {
721+
return fmt.Errorf("unable to upsert supply pre-commit: %w", err)
722+
}
723+
724+
return nil
725+
}
726+
721727
// UpsertProofLeaf inserts or updates a proof leaf within the universe tree,
722728
// stored at the base key. The metaReveal type is purely optional, and should be
723729
// specified if the genesis proof committed to a non-zero meta hash.

0 commit comments

Comments
 (0)