From b88a6f6eb47c6911b4dba8bb33c77503349120a8 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Wed, 13 Dec 2023 15:23:04 +0100 Subject: [PATCH] itest: add test for local universe proof delivery --- itest/addrs_test.go | 82 ++++++++++++++++++++++++++++++++++++++ itest/send_test.go | 61 ++++++++++++++++++++++++++++ itest/test_list_on_test.go | 4 ++ 3 files changed, 147 insertions(+) diff --git a/itest/addrs_test.go b/itest/addrs_test.go index 657cafc64..b03ddfbc9 100644 --- a/itest/addrs_test.go +++ b/itest/addrs_test.go @@ -8,6 +8,7 @@ import ( tap "github.com/lightninglabs/taproot-assets" "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/internal/test" + "github.com/lightninglabs/taproot-assets/proof" "github.com/lightninglabs/taproot-assets/tappsbt" "github.com/lightninglabs/taproot-assets/taprpc" wrpc "github.com/lightninglabs/taproot-assets/taprpc/assetwalletrpc" @@ -512,6 +513,8 @@ func runMultiSendTest(ctxt context.Context, t *harnessTest, alice, require.NoError(t.t, err) } +// 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, genInfo *taprpc.GenesisInfo) *tapdevrpc.ImportProofResponse { @@ -543,6 +546,85 @@ func sendProof(t *harnessTest, src, dst *tapdHarness, scriptKey []byte, return importResp } +// sendProofUniRPC manually exports a proof from the given source node and +// imports it using the universe related InsertProof RPC on the destination +// node. +func sendProofUniRPC(t *harnessTest, src, dst *tapdHarness, scriptKey []byte, + genInfo *taprpc.GenesisInfo) *unirpc.AssetProofResponse { + + ctxb := context.Background() + + var proofResp *taprpc.ProofFile + waitErr := wait.NoError(func() error { + resp, err := src.ExportProof(ctxb, &taprpc.ExportProofRequest{ + AssetId: genInfo.AssetId, + ScriptKey: scriptKey, + }) + if err != nil { + return err + } + + proofResp = resp + return nil + }, defaultWaitTimeout) + require.NoError(t.t, waitErr) + + t.Logf("Importing proof %x using InsertProof", proofResp.RawProofFile) + + f := proof.File{} + err := f.Decode(bytes.NewReader(proofResp.RawProofFile)) + require.NoError(t.t, err) + + lastProof, err := f.LastProof() + require.NoError(t.t, err) + + var lastProofBytes bytes.Buffer + err = lastProof.Encode(&lastProofBytes) + require.NoError(t.t, err) + asset := lastProof.Asset + + proofType := universe.ProofTypeTransfer + if asset.IsGenesisAsset() { + proofType = universe.ProofTypeIssuance + } + + uniID := universe.Identifier{ + AssetID: asset.ID(), + ProofType: proofType, + } + if asset.GroupKey != nil { + uniID.GroupKey = &asset.GroupKey.GroupPubKey + } + + rpcUniID, err := tap.MarshalUniID(uniID) + require.NoError(t.t, err) + + outpoint := &unirpc.Outpoint{ + HashStr: lastProof.AnchorTx.TxHash().String(), + Index: int32(lastProof.InclusionProof.OutputIndex), + } + + importResp, err := dst.InsertProof(ctxb, &unirpc.AssetProof{ + Key: &unirpc.UniverseKey{ + Id: rpcUniID, + LeafKey: &unirpc.AssetKey{ + Outpoint: &unirpc.AssetKey_Op{ + Op: outpoint, + }, + ScriptKey: &unirpc.AssetKey_ScriptKeyBytes{ + ScriptKeyBytes: scriptKey, + }, + }, + }, + AssetLeaf: &unirpc.AssetLeaf{ + Proof: lastProofBytes.Bytes(), + }, + }) + require.NoError(t.t, err) + + return importResp +} + // sendAssetsToAddr spends the given input asset and sends the amount specified // in the address to the Taproot output derived from the address. func sendAssetsToAddr(t *harnessTest, sender *tapdHarness, diff --git a/itest/send_test.go b/itest/send_test.go index c7ab48f26..e23ef80eb 100644 --- a/itest/send_test.go +++ b/itest/send_test.go @@ -1370,6 +1370,67 @@ func testSendMultipleCoins(t *harnessTest) { AssertNonInteractiveRecvComplete(t.t, secondTapd, 5) } +// testSendNoCourierUniverseImport tests that we can send assets to a node that +// has no courier, and then manually transfer the proof to the receiving using +// the universe proof import RPC method. +func testSendNoCourierUniverseImport(t *harnessTest) { + ctxb := context.Background() + + // First, we'll make a normal assets with enough units. + rpcAssets := MintAssetsConfirmBatch( + t.t, t.lndHarness.Miner.Client, t.tapd, + []*mintrpc.MintAssetRequest{simpleAssets[0]}, + ) + + firstAsset := rpcAssets[0] + genInfo := firstAsset.AssetGenesis + + // Now that we have the asset created, we'll make a new node that'll + // serve as the node which'll receive the assets. We turn off the proof + // courier by supplying a dummy implementation. + secondTapd := setupTapdHarness( + t.t, t, t.lndHarness.Bob, t.universeServer, + func(params *tapdHarnessParams) { + params.proofCourier = &proof.MockProofCourier{} + }, + ) + defer func() { + require.NoError(t.t, secondTapd.stop(!*noDelete)) + }() + + // Next, we'll attempt to transfer some amount of assets[0] to the + // receiving node. + numUnitsSend := uint64(1200) + + // Get a new address (which accepts the first asset) from the + // receiving node. + receiveAddr, err := secondTapd.NewAddr(ctxb, &taprpc.NewAddrRequest{ + AssetId: genInfo.AssetId, + Amt: numUnitsSend, + }) + require.NoError(t.t, err) + AssertAddrCreated(t.t, secondTapd, firstAsset, receiveAddr) + + // Send the assets to the receiving node. + sendResp := sendAssetsToAddr(t, t.tapd, receiveAddr) + + // Assert that the outbound transfer was confirmed. + expectedAmtAfterSend := firstAsset.Amount - numUnitsSend + ConfirmAndAssertOutboundTransfer( + t.t, t.lndHarness.Miner.Client, t.tapd, sendResp, + genInfo.AssetId, + []uint64{expectedAmtAfterSend, numUnitsSend}, 0, 1, + ) + + // Since we disabled proof couriers, we need to manually transfer the + // proof from the sender to the receiver now. We use the universe RPC + // InsertProof method to do this. + sendProofUniRPC(t, t.tapd, secondTapd, receiveAddr.ScriptKey, genInfo) + + // And now, the transfer should be completed on the receiver side too. + AssertNonInteractiveRecvComplete(t.t, secondTapd, 1) +} + // addProofTestVectorFromFile adds a proof test vector by extracting it from the // proof file found at the given asset ID and script key. func addProofTestVectorFromFile(t *testing.T, testName string, diff --git a/itest/test_list_on_test.go b/itest/test_list_on_test.go index a7a9d52d1..47fe2f18d 100644 --- a/itest/test_list_on_test.go +++ b/itest/test_list_on_test.go @@ -76,6 +76,10 @@ var testCases = []*testCase{ test: testOfflineReceiverEventuallyReceives, proofCourierType: proof.HashmailCourierType, }, + { + name: "addr send no proof courier with local universe import", + test: testSendNoCourierUniverseImport, + }, { name: "basic send passive asset", test: testBasicSendPassiveAsset,