Skip to content

proof: implement and hook up ignore checker #1716

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open

Conversation

guggero
Copy link
Member

@guggero guggero commented Aug 8, 2025

Fixes #1684.

Implements and hooks up a caching ignore tree checker.

@coveralls
Copy link

coveralls commented Aug 8, 2025

Pull Request Test Coverage Report for Build 16940968541

Details

  • 404 of 536 (75.37%) changed or added relevant lines in 25 files are covered.
  • 40 unchanged lines in 12 files lost coverage.
  • Overall coverage increased (+8.1%) to 56.7%

Changes Missing Coverage Covered Lines Changed/Added Lines %
tapfreighter/wallet.go 14 16 87.5%
server.go 0 8 0.0%
tapchannel/aux_closer.go 0 8 0.0%
tapchannel/aux_funding_controller.go 0 8 0.0%
tapdb/multiverse.go 0 10 0.0%
proof/verifier.go 53 64 82.81%
tapchannel/aux_sweeper.go 0 11 0.0%
tapdb/supply_ignore_checker.go 149 166 89.76%
tapdb/supply_tree.go 77 100 77.0%
monitoring/db_collector.go 0 34 0.0%
Files with Coverage Reduction New Missed Lines %
proof/verifier.go 1 86.82%
fn/iter.go 2 62.07%
monitoring/db_collector.go 2 0.0%
tapdb/mssmt.go 2 90.45%
tapdb/multiverse.go 2 79.79%
tapdb/supply_tree.go 2 63.77%
itest/multisig.go 3 97.91%
universe/archive.go 3 79.81%
mssmt/compacted_tree.go 4 79.49%
tapdb/universe.go 4 81.11%
Totals Coverage Status
Change from base Build 16913585335: 8.1%
Covered Lines: 60786
Relevant Lines: 107206

💛 - Coveralls

guggero added 11 commits August 13, 2025 14:26
To better support the actual implementation of the ignore checker, we
add a context and also allow returning an error through the use of a
fn.Result return type.
To allow a proof to be validated at least partially, we extract all the
steps (1 through 7) into its own method, called VerifyProofIntegrity.
These steps are all verification steps that can be executed without
needing access to the previous asset snapshot (the inputs being spent),
which aren't available in some situations.
This refactor allows us to make sure a proof is structurally sound (e.g.
all Taproot/Tapscript inclusion/exclusion proofs are valid) and the
proof isn't being ignored.
To make sure ignored assets can't be sent out in the first place, we add
the better proof integrity check that includes the ignore check to the
asset wallet.
To make sure we don't always hit the DB when we encounter a new asset
point that is _not_ ignored, we add an LRU cache that tracks asset
points that are currently _not_ ignored.
The cache will be invalidated by the supply verifier that watches the
chain for new supply commitment updates and is aware of new potential
ignore tuples.
This commit makes the negative lookup LRU cache size configurable by the
user.
With this commit we hook up the different caches we have in the
multiverse store and the supply ignore checker to the Prometheus metrics
collector.
To make sure we don't have old entries in our negative lookup cache, we
invalidate the ignore checker's LRU cache as soon as we have written a
new supply update to disk.
@guggero guggero marked this pull request as ready for review August 13, 2025 14:54
@guggero
Copy link
Member Author

guggero commented Aug 13, 2025

Added the negative LRU cache, hooked up the cache stats to our Prometheus metrics and implemented the cache invalidation.

@guggero guggero requested review from Roasbeef and ffranr August 13, 2025 14:55
@levmi levmi moved this from 🏗 In progress to 👀 In review in Taproot-Assets Project Board Aug 14, 2025
// FetchSupplyLeavesByType fetches all supply leaves for a given asset specifier
// and a specific supply sub-tree.
func (s *SupplyTreeStore) FetchSupplyLeavesByType(ctx context.Context,
spec asset.Specifier, tree supplycommit.SupplySubTree, startHeight,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tree -> treeType ?

@@ -45,7 +45,7 @@ type IgnoreChecker interface {
// IsIgnored returns true if the given prevID is known to be invalid. A
// prevID is used here, but the check should be tested against a proof
// result, or produced output.
IsIgnored(prevID AssetPoint) bool
IsIgnored(ctx context.Context, prevID AssetPoint) lfn.Result[bool]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

// String returns a human-readable description of the PrevID.
func (id PrevID) String() string {
return fmt.Sprintf("PrevID(outpoint=%s, id=%s, script_key=%x)",
id.OutPoint.String(), id.ID.String(), id.ScriptKey.CopyBytes())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CopyBytes() as an alternative to just slicing into the underlying byte slice?

// IgnoreCheckerCfg is a configuration struct for the CachingIgnoreChecker.
type IgnoreCheckerCfg struct {
// GroupQuery is used to query asset groups by their asset ID.
GroupQuery assetGroupQuery
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, if the config struct itself is publicly exported, then shouldn't the interfaces exported also be?

// group (or 0 if we haven't encountered this group yet).
specifier := asset.NewSpecifierFromGroupKey(*groupPubKey)
bestHeight := c.bestHeightLookup[groupKey]
leaves, err := c.cfg.Store.FetchSupplyLeavesByType(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One alternative here would be doing a more precise query just that that particular ignore point. On the other ahdn wit hthis approach, we do the broad look up once, then just cache it from there on.

Store: supplyTreeStore,
})

var ignoreCheckerIface proof.IgnoreChecker = ignoreChecker
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative to adding an explicit type param to the lfn.Some call below?

return nil, fmt.Errorf("input proof is nil")
}

_, err := assetProof.VerifyProofIntegrity(ctx, vCtx)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to do additional verification here as well.

withError("is ignored"),
)

// TODO(ffranr): The above only tests that the node that issued the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can make an issue for this 👍

@@ -3,8 +3,10 @@ package tapdb
import (
"context"
"errors"
"fmt"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re the commit message: do we need a supply verifier to invalidate it? Couldn't we just invalidate it selectively when/if an asset in that group is ignored?

// We know our tree has been updated, so we need to make sure
// the negative lookup cache of the ignore checker is flushed
// and the new ignore leaves are loaded from disk.
env.IgnoreCheckerCache.InvalidateCache()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't we just selectively invalidate the cache for this particular group key?

Even before that, we can check to see if this batch adds any new ignored assets, only invalidating if so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 👀 In review
Development

Successfully merging this pull request may close these issues.

multi: implement IgnoreChecker for Supply Commitment System
3 participants