Skip to content

Commit d06206e

Browse files
committed
itest: add test for unknown odd TLV types
1 parent 3c424d4 commit d06206e

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

itest/addrs_test.go

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/btcsuite/btcd/btcec/v2/schnorr"
99
"github.com/btcsuite/btcd/wire"
1010
tap "github.com/lightninglabs/taproot-assets"
11+
"github.com/lightninglabs/taproot-assets/address"
1112
"github.com/lightninglabs/taproot-assets/asset"
1213
"github.com/lightninglabs/taproot-assets/commitment"
1314
"github.com/lightninglabs/taproot-assets/fn"
@@ -22,6 +23,7 @@ import (
2223
unirpc "github.com/lightninglabs/taproot-assets/taprpc/universerpc"
2324
"github.com/lightninglabs/taproot-assets/universe"
2425
"github.com/lightningnetwork/lnd/lntest/wait"
26+
"github.com/lightningnetwork/lnd/tlv"
2527
"github.com/stretchr/testify/require"
2628
)
2729

@@ -661,6 +663,179 @@ func runMultiSendTest(ctxt context.Context, t *harnessTest, alice,
661663
}
662664
}
663665

666+
// testUnknownTlvType tests that we can create an address with an unknown TLV
667+
// type and that assets can be sent to it. We then modify a proof similarly and
668+
// make sure it can be imported by a node correctly.
669+
func testUnknownTlvType(t *harnessTest) {
670+
// First, mint an asset, so we have one to create addresses for.
671+
rpcAssets := MintAssetsConfirmBatch(
672+
t.t, t.lndHarness.Miner.Client, t.tapd,
673+
[]*mintrpc.MintAssetRequest{
674+
simpleAssets[0], issuableAssets[0],
675+
},
676+
)
677+
mintedAsset := rpcAssets[0]
678+
genInfo := mintedAsset.AssetGenesis
679+
680+
ctxb := context.Background()
681+
ctxt, cancel := context.WithTimeout(ctxb, defaultWaitTimeout)
682+
defer cancel()
683+
684+
// We'll make a second node now that'll be the receiver of all the
685+
// assets made above.
686+
alice := t.tapd
687+
bob := setupTapdHarness(
688+
t.t, t, t.lndHarness.Bob, t.universeServer,
689+
)
690+
defer func() {
691+
require.NoError(t.t, bob.stop(!*noDelete))
692+
}()
693+
694+
// We now create an address for Bob and add some unknown TLV type to it.
695+
bobAddr, err := bob.NewAddr(ctxt, &taprpc.NewAddrRequest{
696+
AssetId: genInfo.AssetId,
697+
Amt: 123,
698+
})
699+
require.NoError(t.t, err)
700+
701+
decoded, err := address.DecodeAddress(
702+
bobAddr.Encoded, &address.RegressionNetTap,
703+
)
704+
require.NoError(t.t, err)
705+
706+
decoded.UnknownOddTypes = tlv.TypeMap{
707+
345: []byte("plz send assets"),
708+
}
709+
bobAddr.Encoded, err = decoded.EncodeAddress()
710+
require.NoError(t.t, err)
711+
712+
sendResp, sendEvents := sendAssetsToAddr(t, alice, bobAddr)
713+
sendRespJSON, err := formatProtoJSON(sendResp)
714+
require.NoError(t.t, err)
715+
t.Logf("Got response from sending assets: %v", sendRespJSON)
716+
717+
AssertAddrEvent(t.t, bob, bobAddr, 1, statusDetected)
718+
719+
// Mine a block to make sure the events are marked as confirmed.
720+
_ = MineBlocks(t.t, t.lndHarness.Miner.Client, 1, 1)
721+
722+
// Eventually the event should be marked as confirmed.
723+
AssertAddrEventByStatus(t.t, bob, statusConfirmed, 1)
724+
725+
// Make sure we have imported and finalized all proofs.
726+
AssertNonInteractiveRecvComplete(t.t, bob, 1)
727+
AssertSendEventsComplete(t.t, bobAddr.ScriptKey, sendEvents)
728+
729+
// We export the proof for the address so we can modify it.
730+
transferProof := exportProof(
731+
t, bob, sendResp, bobAddr.ScriptKey, genInfo,
732+
)
733+
734+
f, err := proof.DecodeFile(transferProof.RawProofFile)
735+
require.NoError(t.t, err)
736+
737+
lastProof, err := f.LastProof()
738+
require.NoError(t.t, err)
739+
740+
proofCustomTypes := tlv.TypeMap{
741+
123: []byte("got something to prove"),
742+
}
743+
lastProof.UnknownOddTypes = proofCustomTypes
744+
lastProof.InclusionProof.UnknownOddTypes = tlv.TypeMap{
745+
345: []byte("it's included"),
746+
}
747+
cp := lastProof.InclusionProof.CommitmentProof
748+
cp.UnknownOddTypes = tlv.TypeMap{
749+
567: []byte("it's committed"),
750+
}
751+
cp.TaprootAssetProof.UnknownOddTypes = tlv.TypeMap{
752+
789: []byte("there's assets in here..."),
753+
}
754+
cp.AssetProof.UnknownOddTypes = tlv.TypeMap{
755+
987: []byte("...and here"),
756+
}
757+
lastProof.ExclusionProofs[0].UnknownOddTypes = tlv.TypeMap{
758+
321: []byte("it's excluded"),
759+
}
760+
761+
// Let's re-encode the proof and import it to the new node.
762+
err = f.ReplaceLastProof(*lastProof)
763+
require.NoError(t.t, err)
764+
modifiedBlob, err := proof.EncodeFile(f)
765+
require.NoError(t.t, err)
766+
767+
// We make a new node to import the modified proof.
768+
charlie := setupTapdHarness(
769+
t.t, t, t.lndHarness.Bob, t.universeServer,
770+
)
771+
defer func() {
772+
require.NoError(t.t, charlie.stop(!*noDelete))
773+
}()
774+
775+
importProof(t, charlie, modifiedBlob, genInfo.GenesisPoint)
776+
777+
// When we export it again, it should have the same TLV types.
778+
transferProof2 := exportProof(
779+
t, charlie, sendResp, bobAddr.ScriptKey, genInfo,
780+
)
781+
f2, err := proof.DecodeFile(transferProof2.RawProofFile)
782+
require.NoError(t.t, err)
783+
784+
lastProof2, err := f2.LastProof()
785+
require.NoError(t.t, err)
786+
787+
// If the contents are identical to what we uploaded, we just need to
788+
// check a single value in the proof to be sure all the custom types are
789+
// there.
790+
require.Equal(t.t, modifiedBlob, transferProof2.RawProofFile)
791+
require.True(t.t, bytes.Contains(modifiedBlob, []byte("it's included")))
792+
require.True(
793+
t.t, bytes.Contains(modifiedBlob, []byte("it's committed")),
794+
)
795+
require.Equal(t.t, proofCustomTypes, lastProof2.UnknownOddTypes)
796+
797+
// The proof should also still be valid. Importing the proof validates
798+
// it, but we also want to do it explicitly.
799+
verifyResp, err := charlie.VerifyProof(ctxb, &taprpc.ProofFile{
800+
RawProofFile: modifiedBlob,
801+
GenesisPoint: genInfo.GenesisPoint,
802+
})
803+
require.NoError(t.t, err)
804+
require.True(t.t, verifyResp.Valid)
805+
806+
// The final test involves adding some extra data to the meta reveal of
807+
// a proof. That will invalidate the proof, as the commitments are for
808+
// a different meta. But the meta hash should be calculated differently,
809+
// showing that the extra data is considered for the meta hash
810+
// calculation.
811+
firstProof, err := f2.ProofAt(0)
812+
require.NoError(t.t, err)
813+
814+
require.NotNil(t.t, firstProof.MetaReveal)
815+
hashBeforeUpdate := firstProof.MetaReveal.MetaHash()
816+
817+
// Let's modify the meta hash with some extra data.
818+
firstProof.MetaReveal.UnknownOddTypes = tlv.TypeMap{
819+
123: []byte("extra data"),
820+
}
821+
hashAfterUpdate := firstProof.MetaReveal.MetaHash()
822+
823+
require.NotEqual(t.t, hashBeforeUpdate, hashAfterUpdate)
824+
825+
// We should not be able to verify the proof anymore.
826+
err = f2.ReplaceProofAt(0, *firstProof)
827+
require.NoError(t.t, err)
828+
modifiedBlob2, err := proof.EncodeFile(f2)
829+
require.NoError(t.t, err)
830+
831+
verifyResp, err = charlie.VerifyProof(ctxb, &taprpc.ProofFile{
832+
RawProofFile: modifiedBlob2,
833+
GenesisPoint: genInfo.GenesisPoint,
834+
})
835+
require.NoError(t.t, err)
836+
require.False(t.t, verifyResp.Valid)
837+
}
838+
664839
// sendProof manually exports a proof from the given source node and imports it
665840
// using the development only ImportProof RPC on the destination node.
666841
func sendProof(t *harnessTest, src, dst *tapdHarness,

itest/test_list_on_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ var testCases = []*testCase{
4545
name: "multi address",
4646
test: testMultiAddress,
4747
},
48+
{
49+
name: "unknown TLV type",
50+
test: testUnknownTlvType,
51+
},
4852
{
4953
name: "address syncer",
5054
test: testAddressAssetSyncer,

0 commit comments

Comments
 (0)