Skip to content

Commit

Permalink
Add multiverse RPC proof courier (#473)
Browse files Browse the repository at this point in the history
* tapfreighter: fix proof transition state doc

* rpc: move MarshalAsset function to new file taprpc/marshal.go

This refactor allows us to avoid an import cycle when the RPC proof
courier marshals an asset.

* taprpc: add marshal functions for universe RPC types

* proof: clarify doc for Proof.PrevOut

* asset: add asset method for retrieving PrevID which handles split commit

This commit adds a method to the Asset structure which returns the
asset's primary PrevID and takes account of the fact that the asset may
correspond to a split output.

* multi: add universe RPC proof courier

* tapgarden: add proof retrieval delay to custodian

* proof: remove roasbeef's TODO now that we have two different couriers

* rpc: add debug messages for InsertProof and QueryProof endpoints

* universe: allow registering non-issuance proofs in universe/multiverse

* universe: use previous asset snapshot when verifying transition proof

* itest: fix nits

* itest: add universe RPC harness and utilise for basic send
  • Loading branch information
ffranr authored Sep 19, 2023
1 parent 0c6cf23 commit 90b0ac3
Show file tree
Hide file tree
Showing 17 changed files with 662 additions and 119 deletions.
31 changes: 31 additions & 0 deletions asset/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,37 @@ func (a *Asset) IsBurn() bool {
return IsBurnKey(a.ScriptKey.PubKey, a.PrevWitnesses[0])
}

// 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.
// The first witness effectively corresponds to the asset's direct lineage.
func (a *Asset) PrimaryPrevID() (*PrevID, error) {
if len(a.PrevWitnesses) == 0 {
return nil, fmt.Errorf("asset missing previous witnesses")
}

// 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, fmt.Errorf("asset missing previous " +
"witnesses")
}
return rootAsset.PrevWitnesses[0].PrevID, nil
}

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

// Copy returns a deep copy of an Asset.
func (a *Asset) Copy() *Asset {
assetCopy := *a
Expand Down
3 changes: 2 additions & 1 deletion cmd/tapcli/universe.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

tap "github.com/lightninglabs/taproot-assets"
"github.com/lightninglabs/taproot-assets/proof"
"github.com/lightninglabs/taproot-assets/taprpc"
"github.com/lightninglabs/taproot-assets/taprpc/universerpc"
unirpc "github.com/lightninglabs/taproot-assets/taprpc/universerpc"
"github.com/lightningnetwork/lnd/lncfg"
Expand Down Expand Up @@ -417,7 +418,7 @@ func universeProofInsert(ctx *cli.Context) error {
if err != nil {
return err
}
rpcAsset, err := tap.MarshalAsset(
rpcAsset, err := taprpc.MarshalAsset(
ctxc, &assetProof.Asset, false, true, nil,
)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions itest/send_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import (
"github.com/stretchr/testify/require"
)

// testBasicSend tests that we can properly send assets back and forth between
// nodes.
// testBasicSendUnidirectional tests that we can properly send assets back and
// forth between nodes.
func testBasicSendUnidirectional(t *harnessTest) {
var (
ctxb = context.Background()
Expand Down
7 changes: 7 additions & 0 deletions itest/tapd_harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@ func newTapdHarness(t *testing.T, ht *harnessTest, cfg tapdConfig,
ReceiverAckTimeout: receiverAckTimeout,
BackoffCfg: backoffCfg,
}

case *UniverseRPCHarness:
finalCfg.DefaultProofCourierAddr = fmt.Sprintf(
"%s://%s", proof.UniverseRpcCourierType,
typedProofCourier.ListenAddr,
)

default:
finalCfg.DefaultProofCourierAddr = ""
finalCfg.HashMailCourier = nil
Expand Down
5 changes: 4 additions & 1 deletion itest/test_harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func (h *harnessTest) LogfTimestamped(format string, args ...interface{}) {
}

// shutdown stops both the mock universe and tapd server.
func (h *harnessTest) shutdown(t *testing.T) error {
func (h *harnessTest) shutdown(_ *testing.T) error {
h.universeServer.stop()

if h.proofCourier != nil {
Expand Down Expand Up @@ -284,6 +284,9 @@ func setupHarnesses(t *testing.T, ht *harnessTest,
port := nextAvailablePort()
apHarness := NewApertureHarness(ht.t, port)
proofCourier = &apHarness

case proof.UniverseRpcCourierType:
proofCourier = NewUniverseRPCHarness(t, ht, lndHarness.Bob)
}

// Start the proof courier harness if specified.
Expand Down
5 changes: 5 additions & 0 deletions itest/test_list_on_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ var testCases = []*testCase{
test: testBasicSendUnidirectional,
proofCourierType: proof.HashmailCourierType,
},
{
name: "basic send universerpc proof courier",
test: testBasicSendUnidirectional,
proofCourierType: proof.UniverseRpcCourierType,
},
{
name: "resume pending package send",
test: testResumePendingPackageSend,
Expand Down
51 changes: 51 additions & 0 deletions itest/universerpc_harness.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package itest

import (
"testing"

"github.com/lightninglabs/taproot-assets/proof"
"github.com/lightningnetwork/lnd/lntest/node"
"github.com/stretchr/testify/require"
)

// UniverseRPCHarness is an integration testing harness for the universe tap
// service.
type UniverseRPCHarness struct {
// service is the instance of the universe tap service.
service *tapdHarness

// ListenAddr is the address that the service is listening on.
ListenAddr string
}

// NewUniverseRPCHarness creates a new test harness for a universe tap service.
func NewUniverseRPCHarness(t *testing.T, ht *harnessTest,
lndHarness *node.HarnessNode) *UniverseRPCHarness {

service, err := newTapdHarness(
t, ht, tapdConfig{
NetParams: harnessNetParams,
LndNode: lndHarness,
}, nil, nil, nil,
)
require.NoError(t, err)

return &UniverseRPCHarness{
service: service,
ListenAddr: service.rpcHost(),
}
}

// Start starts the service.
func (h *UniverseRPCHarness) Start(_ chan error) error {
return h.service.start(false)
}

// Stop stops the service.
func (h *UniverseRPCHarness) Stop() error {
return h.service.stop(true)
}

// Ensure that NewUniverseRPCHarness implements the proof.CourierHarness
// interface.
var _ proof.CourierHarness = (*UniverseRPCHarness)(nil)
4 changes: 4 additions & 0 deletions proof/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ type Locator struct {
// ScriptKey specifies the script key of the asset to fetch/store. This
// field MUST be specified.
ScriptKey btcec.PublicKey

// OutPoint is the outpoint of the associated asset. This field is
// optional.
OutPoint *wire.OutPoint
}

// Hash returns a SHA256 hash of the bytes serialized locator.
Expand Down
Loading

0 comments on commit 90b0ac3

Please sign in to comment.