Skip to content

Commit 4ffe39f

Browse files
authored
Merge pull request #1716 from lightninglabs/ignore-checker
proof: implement and hook up ignore checker
2 parents 8ff0ae9 + 6a9ab2c commit 4ffe39f

37 files changed

+1442
-355
lines changed

asset/asset.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,12 @@ func (id PrevID) Hash() [sha256.Size]byte {
772772
return *(*[sha256.Size]byte)(h.Sum(nil))
773773
}
774774

775+
// String returns a human-readable description of the PrevID.
776+
func (id PrevID) String() string {
777+
return fmt.Sprintf("PrevID(outpoint=%s, id=%s, script_key=%x)",
778+
id.OutPoint.String(), id.ID.String(), id.ScriptKey[:])
779+
}
780+
775781
// AnchorPoint is a type alias for an asset anchor outpoint. It relates the
776782
// on-chain anchor outpoint (txid:vout) to the corresponding committed asset.
777783
type AnchorPoint = PrevID

config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ type Config struct {
197197
// attestations of the total supply of an asset.
198198
SupplyCommitManager *supplycommit.MultiStateMachineManager
199199

200+
IgnoreChecker *tapdb.CachingIgnoreChecker
201+
200202
UniverseArchive *universe.Archive
201203

202204
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
@@ -52,6 +52,7 @@
5252
- https://github.com/lightninglabs/taproot-assets/pull/1655
5353
- https://github.com/lightninglabs/taproot-assets/pull/1554
5454
- https://github.com/lightninglabs/taproot-assets/pull/1587
55+
- https://github.com/lightninglabs/taproot-assets/pull/1716
5556

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

itest/supply_commit_test.go

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,10 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
196196
// Determine the transfer output owned by the secondary node.
197197
// This is the output that we will ignore.
198198
transferOutput := sendResp.RpcResp.Transfer.Outputs[0]
199+
changeOutput := sendResp.RpcResp.Transfer.Outputs[1]
199200
if sendResp.RpcResp.Transfer.Outputs[1].Amount == sendAssetAmount {
200201
transferOutput = sendResp.RpcResp.Transfer.Outputs[1]
202+
changeOutput = sendResp.RpcResp.Transfer.Outputs[0]
201203
}
202204

203205
// Get block height at the time of the ignore request.
@@ -217,6 +219,21 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
217219
require.NotNil(t.t, respIgnore)
218220
require.EqualValues(t.t, sendAssetAmount, respIgnore.Leaf.RootSum)
219221

222+
// We also ignore our change output, so we can later verify that the
223+
// proof verifier correctly denies spending the change output.
224+
ignoreReq2 := &unirpc.IgnoreAssetOutPointRequest{
225+
AssetOutPoint: &taprpc.AssetOutPoint{
226+
AnchorOutPoint: changeOutput.Anchor.Outpoint,
227+
AssetId: rpcAsset.AssetGenesis.AssetId,
228+
ScriptKey: changeOutput.ScriptKey,
229+
},
230+
Amount: sendChangeAmount,
231+
}
232+
respIgnore2, err := t.tapd.IgnoreAssetOutPoint(ctxb, ignoreReq2)
233+
require.NoError(t.t, err)
234+
require.NotNil(t.t, respIgnore2)
235+
require.EqualValues(t.t, sendChangeAmount, respIgnore2.Leaf.RootSum)
236+
220237
// Assert that the mempool is empty.
221238
mempool := t.lndHarness.Miner().GetRawMempool()
222239
require.Empty(t.t, mempool)
@@ -232,6 +249,7 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
232249
},
233250
IgnoreLeafKeys: [][]byte{
234251
respIgnore.LeafKey,
252+
respIgnore2.LeafKey,
235253
},
236254
},
237255
)
@@ -256,6 +274,7 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
256274
minedBlocks := MineBlocks(t.t, t.lndHarness.Miner().Client, 1, 1)
257275

258276
t.Log("Fetch updated supply commitment")
277+
259278
// Ensure that the supply commitment reflects the ignored asset
260279
// outpoint owned by the secondary node.
261280
var fetchResp *unirpc.FetchSupplyCommitResponse
@@ -268,6 +287,7 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
268287
},
269288
IgnoreLeafKeys: [][]byte{
270289
respIgnore.LeafKey,
290+
respIgnore2.LeafKey,
271291
},
272292
},
273293
)
@@ -283,7 +303,7 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
283303
// Once the ignore tree includes the ignored asset outpoint, we
284304
// know that the supply commitment has been updated.
285305
return fetchResp.IgnoreSubtreeRoot.RootNode.RootSum ==
286-
int64(sendAssetAmount)
306+
int64(sendAssetAmount+sendChangeAmount)
287307
}, defaultWaitTimeout, time.Second)
288308

289309
// Verify that the supply commitment tree commits to the ignore subtree.
@@ -310,7 +330,7 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
310330

311331
// Unmarshal ignore tree leaf inclusion proof to verify that the
312332
// ignored asset outpoint is included in the ignore tree.
313-
require.Len(t.t, fetchResp.IgnoreLeafInclusionProofs, 1)
333+
require.Len(t.t, fetchResp.IgnoreLeafInclusionProofs, 2)
314334
inclusionProofBytes := fetchResp.IgnoreLeafInclusionProofs[0]
315335

316336
// Verify that the ignore tree root can be computed from the ignore leaf
@@ -408,11 +428,11 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
408428
require.NoError(t.t, err)
409429
require.NotNil(t.t, respLeaves)
410430

411-
require.Len(t.t, respLeaves.IgnoreLeaves, 1)
431+
require.Len(t.t, respLeaves.IgnoreLeaves, 2)
412432

413433
ignoreLeafEntry := respLeaves.IgnoreLeaves[0]
414434
require.EqualValues(
415-
t.t, 10, ignoreLeafEntry.LeafNode.RootSum,
435+
t.t, sendAssetAmount, ignoreLeafEntry.LeafNode.RootSum,
416436
)
417437
require.EqualValues(
418438
t.t, newIgnoreBlockHeight, ignoreLeafEntry.BlockHeight,
@@ -432,6 +452,11 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
432452
"asset script key mismatch in ignore leaf",
433453
)
434454

455+
ignoreLeafEntry2 := respLeaves.IgnoreLeaves[1]
456+
require.EqualValues(
457+
t.t, sendChangeAmount, ignoreLeafEntry2.LeafNode.RootSum,
458+
)
459+
435460
transferOutPoint, err := wire.NewOutPointFromString(
436461
transferOutput.Anchor.Outpoint,
437462
)
@@ -443,6 +468,27 @@ func testSupplyCommitIgnoreAsset(t *harnessTest) {
443468
t.t, transferOutPoint.Index,
444469
ignoreLeafEntry.LeafKey.Outpoint.Index,
445470
)
471+
472+
// We now add our change output to the ignore list as well, then try to
473+
// spend it.
474+
bobAddr, err := secondTapd.NewAddr(ctxb, &taprpc.NewAddrRequest{
475+
AssetId: rpcAsset.AssetGenesis.AssetId,
476+
Amt: sendChangeAmount / 2,
477+
})
478+
require.NoError(t.t, err)
479+
sendAsset(
480+
t, t.tapd, withReceiverAddresses(bobAddr),
481+
withError("is ignored"),
482+
)
483+
484+
// TODO(ffranr): The above only tests that the node that issued the
485+
// ignore request has it in its ignore tree and can then deny spending
486+
// it. What we should also test is that the secondary node can sync the
487+
// ignore tree and then also deny spending the ignored asset outpoint
488+
// they received from the primary node.
489+
// Another test case we should add is that a node that _does not_ sync
490+
// the ignore tree can _send_ an ignored asset, but a synced node will
491+
// deny accepting it (transfer will never complete).
446492
}
447493

448494
// AssertInclusionProof checks that the inclusion proof for a given leaf key

monitoring/config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ type PrometheusConfig struct {
4343
// asset minter.
4444
AssetMinter tapgarden.Planter
4545

46+
// CacheStats is a function that can be used to collect cache stats
47+
// from the daemon. This is used to export cache hits and misses for
48+
// various caches used in the daemon.
49+
CacheStats func(hits, misses map[string]int64)
50+
4651
// PerfHistograms indicates if the additional histogram information for
4752
// latency, and handling time of gRPC calls should be enabled. This
4853
// generates additional data, and consume more memory for the

monitoring/db_collector.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99
)
1010

1111
const (
12-
dbSizeMetric = "total_db_size"
12+
dbSizeMetric = "total_db_size"
13+
dbCacheHitsMetric = "db_cache_hits_total"
14+
dbCacheMissesMetric = "db_cache_misses_total"
1315

1416
assetProofSizesHistogram = "asset_proofs_sizes"
1517
)
@@ -24,6 +26,8 @@ type dbCollector struct {
2426

2527
dbSize prometheus.Gauge
2628
proofSizesHistogram prometheus.Histogram
29+
dbCacheHits *prometheus.CounterVec
30+
dbCacheMisses *prometheus.CounterVec
2731
}
2832

2933
func newDbCollector(cfg *PrometheusConfig,
@@ -47,6 +51,21 @@ func newDbCollector(cfg *PrometheusConfig,
4751
},
4852
),
4953
proofSizesHistogram: newProofSizesHistogram(),
54+
dbCacheHits: prometheus.NewCounterVec(
55+
prometheus.CounterOpts{
56+
Name: dbCacheHitsMetric,
57+
Help: "Total number of cache hits",
58+
},
59+
[]string{"cache_name"},
60+
),
61+
62+
dbCacheMisses: prometheus.NewCounterVec(
63+
prometheus.CounterOpts{
64+
Name: dbCacheMissesMetric,
65+
Help: "Total number of cache misses",
66+
},
67+
[]string{"cache_name"},
68+
),
5069
}, nil
5170
}
5271

@@ -75,6 +94,8 @@ func (a *dbCollector) Describe(ch chan<- *prometheus.Desc) {
7594

7695
a.dbSize.Describe(ch)
7796
a.proofSizesHistogram.Describe(ch)
97+
a.dbCacheHits.Describe(ch)
98+
a.dbCacheMisses.Describe(ch)
7899
}
79100

80101
// Collect is called by the Prometheus registry when collecting metrics.
@@ -117,4 +138,23 @@ func (a *dbCollector) Collect(ch chan<- prometheus.Metric) {
117138

118139
a.proofSizesHistogram.Collect(ch)
119140
a.dbSize.Collect(ch)
141+
142+
// If we don't have a cache stats function, then we skip the cache
143+
// stats collection.
144+
if a.cfg.CacheStats == nil {
145+
return
146+
}
147+
148+
// Fetch all db cache hits and misses.
149+
var (
150+
cacheHits = make(map[string]int64)
151+
cacheMisses = make(map[string]int64)
152+
)
153+
a.cfg.CacheStats(cacheHits, cacheMisses)
154+
for cacheName, hits := range cacheHits {
155+
a.dbCacheHits.WithLabelValues(cacheName).Add(float64(hits))
156+
}
157+
for cacheName, misses := range cacheMisses {
158+
a.dbCacheMisses.WithLabelValues(cacheName).Add(float64(misses))
159+
}
120160
}

proof/mock.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/lightninglabs/taproot-assets/internal/test"
2525
mboxrpc "github.com/lightninglabs/taproot-assets/taprpc/authmailboxrpc"
2626
"github.com/lightninglabs/taproot-assets/taprpc/universerpc"
27+
lfn "github.com/lightningnetwork/lnd/fn/v2"
2728
"github.com/lightningnetwork/lnd/keychain"
2829
"github.com/lightningnetwork/lnd/lnutils"
2930
"github.com/lightningnetwork/lnd/lnwire"
@@ -1080,8 +1081,10 @@ func newMockIgnoreChecker(ignoreAll bool,
10801081
}
10811082
}
10821083

1083-
func (m *mockIgnoreChecker) IsIgnored(assetPoint AssetPoint) bool {
1084-
return m.ignoreAll || m.ignoredAssetPoints.Contains(assetPoint)
1084+
func (m *mockIgnoreChecker) IsIgnored(_ context.Context,
1085+
assetPoint AssetPoint) lfn.Result[bool] {
1086+
1087+
return lfn.Ok(m.ignoreAll || m.ignoredAssetPoints.Contains(assetPoint))
10851088
}
10861089

10871090
// MockUniverseServer is a mock implementation of the UniverseServer

proof/proof_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,8 @@ func TestProofVerification(t *testing.T) {
996996

997997
// Verifying the inclusion and exclusion proofs can also be done without
998998
// the previous proof.
999-
_, err = p.VerifyProofs()
999+
vCtx := MockVerifierCtx
1000+
_, err = p.VerifyProofIntegrity(context.Background(), vCtx)
10001001
require.NoError(t, err)
10011002

10021003
// Ensure that verification of a proof of unknown version fails.

0 commit comments

Comments
 (0)