Skip to content

Commit 592dea0

Browse files
authored
Merge pull request #1674 from lightninglabs/wip/supplycommit/add-verifier
supplyverifier: add push syncer and universe server verification
2 parents dc5a65a + 21c412d commit 592dea0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+7542
-1394
lines changed

cmd/commands/universe.go

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,21 +1638,6 @@ var fetchSupplyCommitCmd = cli.Command{
16381638
Usage: "the group key of the asset group to fetch",
16391639
Required: true,
16401640
},
1641-
&cli.StringSliceFlag{
1642-
Name: "issuance_leaf_keys",
1643-
Usage: "a list of issuance leaf keys to fetch " +
1644-
"inclusion proofs for",
1645-
},
1646-
&cli.StringSliceFlag{
1647-
Name: "burn_leaf_keys",
1648-
Usage: "a list of burn leaf keys to fetch inclusion " +
1649-
"proofs for",
1650-
},
1651-
&cli.StringSliceFlag{
1652-
Name: "ignore_leaf_keys",
1653-
Usage: "a list of ignore leaf keys to fetch " +
1654-
"inclusion proofs for",
1655-
},
16561641
},
16571642
Action: fetchSupplyCommit,
16581643
}
@@ -1668,26 +1653,6 @@ func fetchSupplyCommit(ctx *cli.Context) error {
16681653
},
16691654
}
16701655

1671-
issuanceKeys, err := parseHexStrings(
1672-
ctx.StringSlice("issuance_leaf_keys"),
1673-
)
1674-
if err != nil {
1675-
return fmt.Errorf("invalid issuance_leaf_keys: %w", err)
1676-
}
1677-
req.IssuanceLeafKeys = issuanceKeys
1678-
1679-
burnKeys, err := parseHexStrings(ctx.StringSlice("burn_leaf_keys"))
1680-
if err != nil {
1681-
return fmt.Errorf("invalid burn_leaf_keys: %w", err)
1682-
}
1683-
req.BurnLeafKeys = burnKeys
1684-
1685-
ignoreKeys, err := parseHexStrings(ctx.StringSlice("ignore_leaf_keys"))
1686-
if err != nil {
1687-
return fmt.Errorf("invalid ignore_leaf_keys: %w", err)
1688-
}
1689-
req.IgnoreLeafKeys = ignoreKeys
1690-
16911656
resp, err := client.FetchSupplyCommit(cliCtx, req)
16921657
if err != nil {
16931658
return err
@@ -1719,6 +1684,21 @@ var fetchSupplyLeavesCmd = cli.Command{
17191684
Usage: "the end of the block height range",
17201685
Required: true,
17211686
},
1687+
&cli.StringSliceFlag{
1688+
Name: "issuance_leaf_keys",
1689+
Usage: "a list of issuance leaf keys to fetch " +
1690+
"inclusion proofs for",
1691+
},
1692+
&cli.StringSliceFlag{
1693+
Name: "burn_leaf_keys",
1694+
Usage: "a list of burn leaf keys to fetch inclusion " +
1695+
"proofs for",
1696+
},
1697+
&cli.StringSliceFlag{
1698+
Name: "ignore_leaf_keys",
1699+
Usage: "a list of ignore leaf keys to fetch " +
1700+
"inclusion proofs for",
1701+
},
17221702
},
17231703
Action: fetchSupplyLeaves,
17241704
}
@@ -1736,6 +1716,26 @@ func fetchSupplyLeaves(ctx *cli.Context) error {
17361716
BlockHeightEnd: uint32(ctx.Uint64("block_height_end")),
17371717
}
17381718

1719+
issuanceKeys, err := parseHexStrings(
1720+
ctx.StringSlice("issuance_leaf_keys"),
1721+
)
1722+
if err != nil {
1723+
return fmt.Errorf("invalid issuance_leaf_keys: %w", err)
1724+
}
1725+
req.IssuanceLeafKeys = issuanceKeys
1726+
1727+
burnKeys, err := parseHexStrings(ctx.StringSlice("burn_leaf_keys"))
1728+
if err != nil {
1729+
return fmt.Errorf("invalid burn_leaf_keys: %w", err)
1730+
}
1731+
req.BurnLeafKeys = burnKeys
1732+
1733+
ignoreKeys, err := parseHexStrings(ctx.StringSlice("ignore_leaf_keys"))
1734+
if err != nil {
1735+
return fmt.Errorf("invalid ignore_leaf_keys: %w", err)
1736+
}
1737+
req.IgnoreLeafKeys = ignoreKeys
1738+
17391739
resp, err := client.FetchSupplyLeaves(cliCtx, req)
17401740
if err != nil {
17411741
return err

config.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/lightninglabs/taproot-assets/tapgarden"
2020
"github.com/lightninglabs/taproot-assets/universe"
2121
"github.com/lightninglabs/taproot-assets/universe/supplycommit"
22+
"github.com/lightninglabs/taproot-assets/universe/supplyverifier"
2223
"github.com/lightningnetwork/lnd"
2324
"github.com/lightningnetwork/lnd/build"
2425
"github.com/lightningnetwork/lnd/signal"
@@ -195,10 +196,15 @@ type Config struct {
195196
// SupplyCommitManager is a service that is used to manage supply
196197
// commitments for assets. Supply commitments are issuer published
197198
// attestations of the total supply of an asset.
198-
SupplyCommitManager *supplycommit.MultiStateMachineManager
199+
SupplyCommitManager *supplycommit.Manager
199200

200201
IgnoreChecker *tapdb.CachingIgnoreChecker
201202

203+
// SupplyVerifyManager is a service that is used to verify supply
204+
// commitments for assets. Supply commitments are issuer published
205+
// attestations of the total supply of an asset.
206+
SupplyVerifyManager *supplyverifier.Manager
207+
202208
UniverseArchive *universe.Archive
203209

204210
UniverseSyncer universe.Syncer

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
- https://github.com/lightninglabs/taproot-assets/pull/1587
7272
- https://github.com/lightninglabs/taproot-assets/pull/1716
7373
- https://github.com/lightninglabs/taproot-assets/pull/1675
74+
- https://github.com/lightninglabs/taproot-assets/pull/1674
7475

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

fn/func.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,29 @@ func MapErr[I, O any, S []I](s S, f func(I) (O, error)) ([]O, error) {
9393
return output, nil
9494
}
9595

96+
// MapErrWithPtr applies the given fallible mapping function to each element of
97+
// the given slice and generates a new slice. This is identical to MapErr, but
98+
// can be used when the callback returns a pointer, and returns early if any
99+
// single mapping fails.
100+
func MapErrWithPtr[I, O any, S []I](s S, f func(I) (*O, error)) ([]O, error) {
101+
output := make([]O, len(s))
102+
for i, x := range s {
103+
outPtr, err := f(x)
104+
if err != nil {
105+
return nil, err
106+
}
107+
108+
if outPtr == nil {
109+
return nil, fmt.Errorf("nil pointer returned for "+
110+
"item %d", i)
111+
}
112+
113+
output[i] = *outPtr
114+
}
115+
116+
return output, nil
117+
}
118+
96119
// FlatMapErr applies the given mapping function to each element of the given
97120
// slice, concatenates the results into a new slice, and returns an error if
98121
// the mapping function fails.

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,

0 commit comments

Comments
 (0)