Skip to content

RPC: Add Ignore Tree Endpoints #1554

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

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

ffranr
Copy link
Contributor

@ffranr ffranr commented May 21, 2025

Closes #1534


Sharing early to get early feedback on naming and architecture. Still missing itests and query RPC endpoint.

This PR will not include the verifier, I will add that in a separate PR.

This PR adds RPC endpoints to populate and query from ignore trees.

ffranr added 5 commits May 20, 2025 20:02
This new field will be used to interact with ignore trees from the RPC
server.
Add a new column to the asset_seedlings table to store a reference to
the universe commitment delegation key. The delegation public key is
included in the asset metadata. It can be used to query the
internal_keys table to retrieve full key information, including key
family and key index.
Adds a method to generate a Schnorr signature over the TLV serialization
of an IgnoreTuple.
Introduce a new RPC endpoint to add an asset outpoint to the asset's
ignore tree. This allows asset issuers to explicitly exclude certain
asset outpoints.
@ffranr ffranr requested a review from guggero May 21, 2025 15:02
@ffranr ffranr self-assigned this May 21, 2025
@ffranr ffranr changed the title RPC: add ignore tree RPC endpoints RPC: Add Ignore Tree Endpoints May 21, 2025
@coveralls
Copy link

Pull Request Test Coverage Report for Build 15165694648

Details

  • 27 of 360 (7.5%) changed or added relevant lines in 7 files are covered.
  • 49 unchanged lines in 9 files lost coverage.
  • Overall coverage decreased (-0.2%) to 36.973%

Changes Missing Coverage Covered Lines Changed/Added Lines %
universe/archive.go 0 7 0.0%
asset/asset.go 0 24 0.0%
tapdb/asset_minting.go 24 49 48.98%
universe/ignore_records.go 0 54 0.0%
rpcutils/marshal.go 0 105 0.0%
rpcserver.go 0 118 0.0%
Files with Coverage Reduction New Missed Lines %
commitment/tap.go 2 72.05%
tappsbt/create.go 2 26.74%
asset/asset.go 3 44.45%
tapchannel/aux_leaf_signer.go 3 43.43%
asset/mock.go 4 64.71%
tapdb/universe.go 4 80.4%
tapgarden/caretaker.go 7 68.21%
address/address.go 8 67.47%
address/mock.go 16 86.93%
Totals Coverage Status
Change from base Build 15160950886: -0.2%
Covered Lines: 26994
Relevant Lines: 73010

💛 - Coveralls

@@ -24,6 +25,10 @@ type ArchiveConfig struct {
// if the identifier has never been seen before.
NewBaseTree func(id Identifier) StorageBackend

// IgnoreTreeArchive is an archive of all known ignore trees across all
// assets.
IgnoreTreeArchive IgnoreTreeArchive
Copy link
Member

Choose a reason for hiding this comment

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

FWIW, the I envisioned things originally is that you almost never serve the ignore tree by itself. It's always accompanied with two additional layers of inclusion proofs: first into the mains supply tree, and then the block header proof into the blockchain.

//
// NOTE: Ignore proofs are not included in the multiverse, as they are purely
// off-chain. Only issuance and transfer proofs are included in the multiverse.
func (a *Archive) UpsertIgnoreTuples(ctx context.Context,
Copy link
Member

Choose a reason for hiding this comment

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

In the context of the greater system, we wouldn't want to insert ignore tuples directly into the tree. We want to make sure that we're always serving information that's consistent with the latest commitment on chain. Hence the way we stage updates as state transitions in #1508.


// GenSig generates a Schnorr signature over the IgnoreTuple using the
// provided SignerClient and key locator.
func (i *IgnoreTuple) GenSig(ctx context.Context, signer lndclient.SignerClient,
Copy link
Member

Choose a reason for hiding this comment

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

What about instead having a method that accepts the same params, but returns a SIgnedIgnoreTuple?

@@ -569,6 +606,10 @@ func (id PrevID) Hash() [sha256.Size]byte {
return *(*[sha256.Size]byte)(h.Sum(nil))
}

// OutPoint is a type alias for an asset outpoint. It links the anchor outpoint
// to the asset it secures.
type OutPoint = PrevID
Copy link
Member

Choose a reason for hiding this comment

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

PrevOut?

Copy link
Member

Choose a reason for hiding this comment

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

Or AnchorPoint (to be used as asset.AnchorPoint which reads nicely IMO) to not confuse it with a purely on-chain wire.OutPoint?

// Upsert a signed ignore tuple into the ignore tree archive and
// get back the authenticated ignore tuples.
signedIgnore := universe.NewSignedIgnoreTuple(ignoreTuple, ignoreSig)
authIgnoreTuples, err := r.cfg.UniverseArchive.UpsertIgnoreTuples(
Copy link
Member

Choose a reason for hiding this comment

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

Rather than insert directly into the DB, we should call into the supply commit state machine:

// NewIgnoreEvent signals that a caller wishes to update the ignore portion of
// the supply tree with a new outpoint + script key combo.
type NewIgnoreEvent struct {
universe.SignedIgnoreTuple
}

Copy link
Member

@guggero guggero left a comment

Choose a reason for hiding this comment

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

Looks pretty good, did a quick first pass.

@@ -569,6 +606,10 @@ func (id PrevID) Hash() [sha256.Size]byte {
return *(*[sha256.Size]byte)(h.Sum(nil))
}

// OutPoint is a type alias for an asset outpoint. It links the anchor outpoint
// to the asset it secures.
type OutPoint = PrevID
Copy link
Member

Choose a reason for hiding this comment

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

Or AnchorPoint (to be used as asset.AnchorPoint which reads nicely IMO) to not confuse it with a purely on-chain wire.OutPoint?


// The 32-byte asset ID encoded as a hex string. Use this field when
// interacting via REST.
string asset_id_str = 2;
Copy link
Member

Choose a reason for hiding this comment

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

What's the reason for not just using the raw bytes for an asset ID? We don't have the same problem here as we have with TXIDs that the content is reversed in the bytes vs. the human-readable string version.
And if a response has a oneof type, which one will be set?

oneof script_key {
// The script key in raw byte form. Use this field when interacting
// via gRPC.
bytes script_key_bytes = 4;
Copy link
Member

Choose a reason for hiding this comment

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

Same question here: Why do we need both forms? On the CLI it should look the same. But in an itest I'd never easily know which field would actually be set by the RPC server (without looking up the code or calling the RPC).

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

Successfully merging this pull request may close these issues.

Add IgnoreAsset RPC endpoint
4 participants