Skip to content

[2/2] proof: allow proof courier to short cut with local archive #730

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

Merged
merged 19 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions asset/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import (
"io"
"reflect"
"strings"
"time"
"unicode"
"unicode/utf8"

"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil/psbt"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lightninglabs/lndclient"
Expand Down Expand Up @@ -1621,3 +1623,53 @@ func ValidateAssetName(name string) error {

return nil
}

// ChainAsset is a wrapper around the base asset struct that includes
// information detailing where in the chain the asset is currently anchored.
type ChainAsset struct {
*Asset

// IsSpent indicates whether the above asset was previously spent.
IsSpent bool

// AnchorTx is the transaction that anchors this chain asset.
AnchorTx *wire.MsgTx

// AnchorBlockHash is the blockhash that mined the anchor tx.
AnchorBlockHash chainhash.Hash

// AnchorBlockHeight is the height of the block that mined the anchor
// tx.
AnchorBlockHeight uint32

// AnchorOutpoint is the outpoint that commits to the asset.
AnchorOutpoint wire.OutPoint

// AnchorInternalKey is the raw internal key that was used to create the
// anchor Taproot output key.
AnchorInternalKey *btcec.PublicKey

// AnchorMerkleRoot is the Taproot merkle root hash of the anchor output
// the asset was committed to. If there is no Tapscript sibling, this is
// equal to the Taproot Asset root commitment hash.
AnchorMerkleRoot []byte

// AnchorTapscriptSibling is the serialized preimage of a Tapscript
// sibling, if there was one. If this is empty, then the
// AnchorTapscriptSibling hash is equal to the Taproot root hash of the
// anchor output.
AnchorTapscriptSibling []byte

// AnchorLeaseOwner is the identity of the application that currently
// has a lease on this UTXO. If empty/nil, then the UTXO is not
// currently leased. A lease means that the UTXO is being
// reserved/locked to be spent in an upcoming transaction and that it
// should not be available for coin selection through any of the wallet
// RPCs.
AnchorLeaseOwner [32]byte

// AnchorLeaseExpiry is the expiry of the lease. If the expiry is nil or
// the time is in the past, then the lease is not valid and the UTXO is
// available for coin selection.
AnchorLeaseExpiry *time.Time
}
3 changes: 2 additions & 1 deletion cmd/tapcli/universe.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/hex"
"fmt"

"github.com/btcsuite/btcd/wire"
tap "github.com/lightninglabs/taproot-assets"
"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightninglabs/taproot-assets/proof"
Expand Down Expand Up @@ -456,7 +457,7 @@ func parseAssetKey(ctx *cli.Context) (*unirpc.AssetKey, error) {
return nil, fmt.Errorf("outpoint and script key must be set")
}

outpoint, err := tap.UnmarshalOutpoint(ctx.String(outpointName))
outpoint, err := wire.NewOutPointFromString(ctx.String(outpointName))
if err != nil {
return nil, err
}
Expand Down
21 changes: 20 additions & 1 deletion itest/addrs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"

"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/wire"
tap "github.com/lightninglabs/taproot-assets"
"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightninglabs/taproot-assets/internal/test"
Expand Down Expand Up @@ -515,16 +516,34 @@ func runMultiSendTest(ctxt context.Context, t *harnessTest, alice,

// sendProof manually exports a proof from the given source node and imports it
// using the development only ImportProof RPC on the destination node.
func sendProof(t *harnessTest, src, dst *tapdHarness, scriptKey []byte,
func sendProof(t *harnessTest, src, dst *tapdHarness,
sendResp *taprpc.SendAssetResponse, scriptKey []byte,
genInfo *taprpc.GenesisInfo) *tapdevrpc.ImportProofResponse {

ctxb := context.Background()

// We need to find the outpoint of the asset we sent to the address.
var outpoint *taprpc.OutPoint
for _, out := range sendResp.Transfer.Outputs {
if bytes.Equal(out.ScriptKey, scriptKey) {
wireOutPoint, err := wire.NewOutPointFromString(
out.Anchor.Outpoint,
)
require.NoError(t.t, err)

outpoint = &taprpc.OutPoint{
Txid: wireOutPoint.Hash[:],
OutputIndex: wireOutPoint.Index,
}
}
}

var proofResp *taprpc.ProofFile
waitErr := wait.NoError(func() error {
resp, err := src.ExportProof(ctxb, &taprpc.ExportProofRequest{
AssetId: genInfo.AssetId,
ScriptKey: scriptKey,
Outpoint: outpoint,
})
if err != nil {
return err
Expand Down
18 changes: 9 additions & 9 deletions itest/psbt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func testPsbtScriptHashLockSend(t *harnessTest) {
// This is an interactive/PSBT based transfer, so we do need to manually
// send the proof from the sender to the receiver because the proof
// courier address gets lost in the address->PSBT conversion.
_ = sendProof(t, bob, alice, aliceAddr.ScriptKey, genInfo)
_ = sendProof(t, bob, alice, sendResp, aliceAddr.ScriptKey, genInfo)
AssertNonInteractiveRecvComplete(t.t, alice, 1)

aliceAssets, err := alice.ListAssets(ctxb, &taprpc.ListAssetRequest{
Expand Down Expand Up @@ -258,7 +258,7 @@ func testPsbtScriptCheckSigSend(t *harnessTest) {
// This is an interactive/PSBT based transfer, so we do need to manually
// send the proof from the sender to the receiver because the proof
// courier address gets lost in the address->PSBT conversion.
_ = sendProof(t, bob, alice, aliceAddr.ScriptKey, genInfo)
_ = sendProof(t, bob, alice, sendResp, aliceAddr.ScriptKey, genInfo)
AssertNonInteractiveRecvComplete(t.t, alice, 1)

aliceAssets, err := alice.ListAssets(ctxb, &taprpc.ListAssetRequest{
Expand Down Expand Up @@ -434,7 +434,7 @@ func runPsbtInteractiveFullValueSendTest(ctxt context.Context, t *harnessTest,
// This is an interactive transfer, so we do need to manually
// send the proof from the sender to the receiver.
_ = sendProof(
t, sender, receiver,
t, sender, receiver, sendResp,
receiverScriptKey.PubKey.SerializeCompressed(), genInfo,
)

Expand Down Expand Up @@ -647,7 +647,7 @@ func runPsbtInteractiveSplitSendTest(ctxt context.Context, t *harnessTest,
// This is an interactive transfer, so we do need to manually
// send the proof from the sender to the receiver.
_ = sendProof(
t, sender, receiver,
t, sender, receiver, sendResp,
receiverScriptKey.PubKey.SerializeCompressed(), genInfo,
)

Expand Down Expand Up @@ -769,7 +769,7 @@ func testPsbtInteractiveTapscriptSibling(t *harnessTest) {
// This is an interactive transfer, so we do need to manually send the
// proof from the sender to the receiver.
_ = sendProof(
t, alice, bob,
t, alice, bob, sendResp,
receiverScriptKey.PubKey.SerializeCompressed(), genInfo,
)

Expand Down Expand Up @@ -916,11 +916,11 @@ func testPsbtMultiSend(t *harnessTest) {
// This is an interactive transfer, so we do need to manually send the
// proof from the sender to the receiver.
_ = sendProof(
t, sender, receiver,
t, sender, receiver, sendResp,
receiverScriptKey1.PubKey.SerializeCompressed(), genInfo,
)
_ = sendProof(
t, sender, receiver,
t, sender, receiver, sendResp,
receiverScriptKey2.PubKey.SerializeCompressed(), genInfo,
)

Expand Down Expand Up @@ -1158,7 +1158,7 @@ func testMultiInputPsbtSingleAssetID(t *harnessTest) {
// This is an interactive transfer. Therefore, we will manually transfer
// the proof from the sender to the receiver.
_ = sendProof(
t, secondaryTapd, primaryTapd,
t, secondaryTapd, primaryTapd, sendResp,
primaryNodeScriptKey.PubKey.SerializeCompressed(), genInfo,
)

Expand Down Expand Up @@ -1233,7 +1233,7 @@ func testMultiInputPsbtSingleAssetID(t *harnessTest) {
// This is an interactive transfer. Therefore, we will manually transfer
// the proof from the sender to the receiver.
_ = sendProof(
t, secondaryTapd, primaryTapd,
t, secondaryTapd, primaryTapd, sendResp,
primaryNodeScriptKey.PubKey.SerializeCompressed(), genInfo,
)

Expand Down
2 changes: 1 addition & 1 deletion itest/round_trip_send_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func testRoundTripSend(t *harnessTest) {
// recipient's output is the second one.
bobToAliceOutput := transferResp.Transfers[0].Outputs[1]
bobToAliceAnchor := bobToAliceOutput.Anchor
outpoint, err := ParseOutPoint(bobToAliceAnchor.Outpoint)
outpoint, err := wire.NewOutPointFromString(bobToAliceAnchor.Outpoint)
require.NoError(t.t, err)

internalKey, err := btcec.ParsePubKey(bobToAliceAnchor.InternalKey)
Expand Down
12 changes: 7 additions & 5 deletions itest/test_list_on_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ var testCases = []*testCase{
test: testReOrgMintAndSend,
},
{
name: "basic send unidirectional",
name: "basic send unidirectional hashmail courier",
test: testBasicSendUnidirectional,
proofCourierType: proof.HashmailCourierType,
},
Expand All @@ -54,7 +54,8 @@ var testCases = []*testCase{
test: testRestartReceiverCheckBalance,
},
{
name: "resume pending package send",
name: "resume pending package send hashmail " +
"courier",
test: testResumePendingPackageSend,
proofCourierType: proof.HashmailCourierType,
},
Expand All @@ -72,7 +73,8 @@ var testCases = []*testCase{
test: testReattemptFailedReceiveUniCourier,
},
{
name: "offline receiver eventually receives",
name: "offline receiver eventually receives " +
"hashmail courier",
test: testOfflineReceiverEventuallyReceives,
proofCourierType: proof.HashmailCourierType,
},
Expand All @@ -81,7 +83,7 @@ var testCases = []*testCase{
test: testSendNoCourierUniverseImport,
},
{
name: "basic send passive asset",
name: "basic send passive asset hashmail courier",
test: testBasicSendPassiveAsset,
proofCourierType: proof.HashmailCourierType,
},
Expand Down Expand Up @@ -123,7 +125,7 @@ var testCases = []*testCase{
test: testMintMultiAssetGroups,
},
{
name: "sending multi asset groups",
name: "sending multi asset groups hashmail courier",
test: testMultiAssetGroupSend,
proofCourierType: proof.HashmailCourierType,
},
Expand Down
5 changes: 3 additions & 2 deletions itest/universe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/wire"
tap "github.com/lightninglabs/taproot-assets"
"github.com/lightninglabs/taproot-assets/asset"
"github.com/lightninglabs/taproot-assets/fn"
Expand Down Expand Up @@ -150,7 +151,7 @@ func testUniverseSync(t *harnessTest) {
// query for that asset with the compressed script key.
firstAssetID := rpcSimpleAssets[0].AssetGenesis.AssetId
firstScriptKey := hex.EncodeToString(rpcSimpleAssets[0].ScriptKey)
firstOutpoint, err := tap.UnmarshalOutpoint(
firstOutpoint, err := wire.NewOutPointFromString(
rpcSimpleAssets[0].ChainAnchor.AnchorOutpoint,
)
require.NoError(t.t, err)
Expand Down Expand Up @@ -326,7 +327,7 @@ func testUniverseManualSync(t *harnessTest) {

// We should also be able to fetch an asset from Bob's Universe, and
// query for that asset with the compressed script key.
firstOutpoint, err := tap.UnmarshalOutpoint(
firstOutpoint, err := wire.NewOutPointFromString(
firstAsset.ChainAnchor.AnchorOutpoint,
)
require.NoError(t.t, err)
Expand Down
29 changes: 1 addition & 28 deletions itest/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package itest

import (
"context"
"fmt"
"strconv"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -48,34 +45,10 @@ func CopyRequests(
return copied
}

// ParseOutPoint
func ParseOutPoint(s string) (*wire.OutPoint, error) {
split := strings.Split(s, ":")
if len(split) != 2 {
return nil, fmt.Errorf("expecting outpoint to be in format " +
"of: txid:index")
}

index, err := strconv.ParseInt(split[1], 10, 32)
if err != nil {
return nil, fmt.Errorf("unable to decode output index: %v", err)
}

txid, err := chainhash.NewHashFromStr(split[0])
if err != nil {
return nil, fmt.Errorf("unable to parse hex string: %v", err)
}

return &wire.OutPoint{
Hash: *txid,
Index: uint32(index),
}, nil
}

// ParseGenInfo converts a taprpc.GenesisInfo into its asset.Genesis
// counterpart.
func ParseGenInfo(t *testing.T, genInfo *taprpc.GenesisInfo) *asset.Genesis {
genPoint, err := ParseOutPoint(genInfo.GenesisPoint)
genPoint, err := wire.NewOutPointFromString(genInfo.GenesisPoint)
require.NoError(t, err)

parsedGenesis := asset.Genesis{
Expand Down
Loading