Skip to content

Commit

Permalink
WIP: get previous asset snapshot inorder to validate current proof
Browse files Browse the repository at this point in the history
  • Loading branch information
ffranr committed Sep 6, 2023
1 parent e5bcc06 commit fc55f2c
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 4 deletions.
36 changes: 36 additions & 0 deletions asset/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,42 @@ func (a *Asset) IsUnSpendable() bool {
a.Amount == 0
}

// IsSplitCommitWitness returns true if the witness is a split-commitment
// witness.
func IsSplitCommitWitness(witness Witness) bool {
return witness.PrevID != nil && len(witness.TxWitness) == 0 &&
witness.SplitCommitment != nil
}

// PrimaryPrevID returns the primary prev ID of an asset. This is the prev ID of
// the first witness, unless the first witness is a split-commitment witness,
// in which case it is the prev ID of the first witness of the root asset.
func (a *Asset) PrimaryPrevID() *PrevID {
if len(a.PrevWitnesses) == 0 {
return nil
}

// The primary prev ID is stored on the root asset if this asset is a
// split output. We determine whether this asset is a split output by
// inspecting the first previous witness.
primaryWitness := a.PrevWitnesses[0]
isSplitOutput := IsSplitCommitWitness(primaryWitness)

// If this is a split output, then we need to look up the first PrevID
// in the split root asset.
if isSplitOutput {
rootAsset := primaryWitness.SplitCommitment.RootAsset
if len(rootAsset.PrevWitnesses) == 0 {
return nil
}
return rootAsset.PrevWitnesses[0].PrevID
}

// This asset is not a split output, so we can just return the PrevID
// found in the first witness.
return primaryWitness.PrevID
}

// Copy returns a deep copy of an Asset.
func (a *Asset) Copy() *Asset {
assetCopy := *a
Expand Down
2 changes: 1 addition & 1 deletion itest/send_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func testBasicSendUnidirectional(t *harnessTest) {

const (
numUnits = 10
numSends = 2
numSends = 1
)

// Subscribe to receive assent send events from primary tapd node.
Expand Down
8 changes: 8 additions & 0 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2745,6 +2745,10 @@ func (r *rpcServer) QueryProof(ctx context.Context,
// not be fully specified
proof := proofs[0]

rpcsLog.Infof("[QueryProof]: returning proof at "+
"(universeID=%x, leafKey=%x)", universeID.String(),
leafKey.UniverseKey())

return r.marshalIssuanceProof(ctx, req, proof)
}

Expand Down Expand Up @@ -2804,6 +2808,10 @@ func (r *rpcServer) InsertProof(ctx context.Context,
return nil, err
}

rpcsLog.Infof("[InsertProof]: inserted proof at "+
"(universeID=%x, leafKey=%x)", universeID.String(),
leafKey.UniverseKey())

return r.marshalIssuanceProof(ctx, req.Key, newUniverseState)
}

Expand Down
78 changes: 75 additions & 3 deletions universe/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (
"fmt"
"sync"

"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/davecgh/go-spew/spew"
"github.com/lightninglabs/taproot-assets/asset"
"github.com/lightninglabs/taproot-assets/proof"
)

Expand Down Expand Up @@ -184,11 +186,21 @@ func (a *MintingArchive) RegisterIssuance(ctx context.Context, id Identifier,
// Otherwise, this is a new proof, so we'll first perform validation of
// the minting leaf to ensure it's a valid issuance proof.
//
// The proofs we insert are just the state transition, so we'll encode
// it as a file first as that's what the expected wants.
//
// TODO(roasbeef): add option to skip proof verification?
assetSnapshot, err := newProof.Verify(ctx, nil, a.cfg.HeaderVerifier)

// Before we can validate a non-issuance proof we need to fetch the
// previous asset snapshot (which is the proof verification result for
// the previous/parent proof in the proof file).
prevAssetSnapshot, err := a.getPrevAssetSnapshot(ctx, id, newProof)
if err != nil {
return nil, fmt.Errorf("unable to fetch previous asset "+
"snapshot: %w", err)
}

assetSnapshot, err := newProof.Verify(
ctx, prevAssetSnapshot, a.cfg.HeaderVerifier,
)
if err != nil {
return nil, fmt.Errorf("unable to verify proof: %v", err)
}
Expand Down Expand Up @@ -245,6 +257,66 @@ func (a *MintingArchive) RegisterIssuance(ctx context.Context, id Identifier,
return issuanceProof, nil
}

func (a *MintingArchive) getPrevAssetSnapshot(ctx context.Context,
uniID Identifier, newProof proof.Proof) (*proof.AssetSnapshot, error) {

// If this is a genesis proof, then there is no previous asset (and
// therefore no previous asset snapshot).
if newProof.Asset.HasGenesisWitness() {
return nil, nil
}

// Query for proof associated with the previous asset.
prevID := newProof.Asset.PrimaryPrevID()

// Parse script key for previous asset.
prevScriptKeyBytes := prevID.ScriptKey
prevScriptKeyPubKey, err := btcec.ParsePubKey(
prevScriptKeyBytes[:],
)
if err != nil {
return nil, fmt.Errorf("unable to parse previous "+
"script key: %v", err)
}
prevScriptKey := asset.NewScriptKey(prevScriptKeyPubKey)

prevBaseKey := BaseKey{
MintingOutpoint: prevID.OutPoint,
ScriptKey: &prevScriptKey,
}

prevProofs, err := a.cfg.Multiverse.FetchIssuanceProof(
ctx, uniID, prevBaseKey,
)
if err != nil {
return nil, fmt.Errorf("unable to fetch previous "+
"proof: %v", err)
}
prevProofFileBytes := prevProofs[0].Leaf.GenesisProof

// Parse proof file bytes.
var prevProofFile proof.File
if err := prevProofFile.Decode(
bytes.NewReader(prevProofFileBytes),
); err != nil {
return nil, err
}

prevProof, err := prevProofFile.LastProof()
if err != nil {
return nil, err
}

// Construct minimal asset snapshot for previous asset.
// This is a minimal the proof verification result for the
// previous (input) asset. We know that it was already verified
// as it was present in the multiverse/universe archive.
return &proof.AssetSnapshot{
Asset: &prevProof.Asset,
OutPoint: prevID.OutPoint,
}, nil
}

// FetchIssuanceProof attempts to fetch an issuance proof for the target base
// leaf based on the universe identifier (assetID/groupKey).
func (a *MintingArchive) FetchIssuanceProof(ctx context.Context, id Identifier,
Expand Down

0 comments on commit fc55f2c

Please sign in to comment.