diff --git a/asset/asset.go b/asset/asset.go index 7051f33c1..f423657c5 100644 --- a/asset/asset.go +++ b/asset/asset.go @@ -1192,8 +1192,13 @@ func (a *Asset) Copy() *Asset { if a.ScriptKey.TweakedScriptKey != nil { assetCopy.ScriptKey.TweakedScriptKey = &TweakedScriptKey{} assetCopy.ScriptKey.RawKey = a.ScriptKey.RawKey - assetCopy.ScriptKey.Tweak = make([]byte, len(a.ScriptKey.Tweak)) - copy(assetCopy.ScriptKey.Tweak, a.ScriptKey.Tweak) + + if len(a.ScriptKey.Tweak) > 0 { + assetCopy.ScriptKey.Tweak = make( + []byte, len(a.ScriptKey.Tweak), + ) + copy(assetCopy.ScriptKey.Tweak, a.ScriptKey.Tweak) + } } if a.GroupKey != nil { diff --git a/asset/mock.go b/asset/mock.go index b99489eb4..8772d5842 100644 --- a/asset/mock.go +++ b/asset/mock.go @@ -358,7 +358,7 @@ func RandAssetWithValues(t testing.TB, genesis Genesis, groupKey *GroupKey, t.Helper() - units := test.RandInt[uint64]() + 1 + units := test.RandInt[uint32]() + 1 switch genesis.Type { case Normal: @@ -376,7 +376,7 @@ func RandAssetWithValues(t testing.TB, genesis Genesis, groupKey *GroupKey, } a, err := New( - genesis, units, 0, 0, scriptKey, groupKey, + genesis, uint64(units), 0, 0, scriptKey, groupKey, WithAssetVersion(assetVersion), ) require.NoError(t, err) diff --git a/commitment/asset.go b/commitment/asset.go index 22965ea2d..510e35444 100644 --- a/commitment/asset.go +++ b/commitment/asset.go @@ -8,7 +8,7 @@ import ( "errors" "fmt" - "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/btcec/v2" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/mssmt" @@ -61,11 +61,11 @@ type AssetCommitment struct { // Version is the max version of the assets committed. Version asset.Version - // AssetID is the common identifier for all assets found within the + // TapKey is the common identifier for all assets found within the // AssetCommitment. This can either be an asset.ID, which every // committed asset must match, or the hash of an asset.GroupKey which // every committed asset must match if their asset.ID differs. - AssetID [32]byte + TapKey [32]byte // AssetType is the type of asset(s) committed to within the tree. AssetType asset.Type @@ -98,7 +98,7 @@ func parseCommon(assets ...*asset.Asset) (*AssetCommitment, error) { assetType asset.Type tapCommitmentKey [32]byte maxVersion = asset.Version(0) - assetGenesis = assets[0].Genesis.ID() + firstAssetID = assets[0].Genesis.ID() assetGroupKey = assets[0].GroupKey assetsMap = make(CommittedAssets, len(assets)) ) @@ -125,7 +125,7 @@ func parseCommon(assets ...*asset.Asset) (*AssetCommitment, error) { return nil, ErrAssetGroupKeyMismatch case assetGroupKey == nil: - if assetGenesis != newAsset.Genesis.ID() { + if firstAssetID != newAsset.Genesis.ID() { return nil, ErrAssetGenesisMismatch } } @@ -151,22 +151,20 @@ func parseCommon(assets ...*asset.Asset) (*AssetCommitment, error) { assetsMap[key] = newAsset } - // The assetID here is what will be used to place this asset commitment + var groupPubKey *btcec.PublicKey + if assetGroupKey != nil { + groupPubKey = &assetGroupKey.GroupPubKey + } + + // The tapKey here is what will be used to place this asset commitment // into the top-level Taproot Asset commitment. For assets without a // group key, then this will be the normal asset ID. Otherwise, this'll // be the sha256 of the group key. - var assetID [32]byte - if assetGroupKey == nil { - assetID = assetGenesis - } else { - assetID = sha256.Sum256( - schnorr.SerializePubKey(&assetGroupKey.GroupPubKey), - ) - } + tapKey := asset.TapCommitmentKey(firstAssetID, groupPubKey) return &AssetCommitment{ Version: maxVersion, - AssetID: assetID, + TapKey: tapKey, AssetType: assetType, assets: assetsMap, }, nil @@ -221,7 +219,7 @@ func (c *AssetCommitment) Upsert(newAsset *asset.Asset) error { // The given Asset must have an ID that matches the AssetCommitment ID. // The AssetCommitment ID is either a hash of the groupKey, or the ID // of all the assets in the AssetCommitment. - if newAsset.TapCommitmentKey() != c.AssetID { + if newAsset.TapCommitmentKey() != c.TapKey { if newAsset.GroupKey != nil { return ErrAssetGroupKeyMismatch } @@ -269,7 +267,7 @@ func (c *AssetCommitment) Delete(oldAsset *asset.Asset) error { // The given Asset must have an ID that matches the AssetCommitment ID. // The AssetCommitment ID is either a hash of the groupKey, or the ID // of all the assets in the AssetCommitment. - if oldAsset.TapCommitmentKey() != c.AssetID { + if oldAsset.TapCommitmentKey() != c.TapKey { if oldAsset.GroupKey != nil { return ErrAssetGroupKeyMismatch } @@ -322,7 +320,7 @@ func (c *AssetCommitment) Root() [sha256.Size]byte { right := c.TreeRoot.Right.NodeHash() h := sha256.New() - _, _ = h.Write(c.AssetID[:]) + _, _ = h.Write(c.TapKey[:]) _, _ = h.Write(left[:]) _, _ = h.Write(right[:]) _ = binary.Write(h, binary.BigEndian, c.TreeRoot.NodeSum()) @@ -332,7 +330,7 @@ func (c *AssetCommitment) Root() [sha256.Size]byte { // TapCommitmentKey computes the insertion key for this specific asset // commitment to include in the Taproot Asset commitment MS-SMT. func (c *AssetCommitment) TapCommitmentKey() [32]byte { - return c.AssetID + return c.TapKey } // TapCommitmentLeaf computes the leaf node for this specific asset commitment @@ -390,7 +388,7 @@ func (c *AssetCommitment) Copy() (*AssetCommitment, error) { treeRoot := c.TreeRoot.Copy().(*mssmt.BranchNode) return &AssetCommitment{ Version: c.Version, - AssetID: c.AssetID, + TapKey: c.TapKey, TreeRoot: treeRoot, }, nil } diff --git a/commitment/commitment_test.go b/commitment/commitment_test.go index 0280a03e9..53da735bc 100644 --- a/commitment/commitment_test.go +++ b/commitment/commitment_test.go @@ -1082,6 +1082,12 @@ func TestUpdateTapCommitment(t *testing.T) { groupKey1 := asset.RandGroupKey(t, genesis1, protoAsset1) groupKey2 := asset.RandGroupKey(t, genesis2, protoAsset2) + // We also create a thirds asset which is in the same group as the first + // one, to ensure that we can properly create Taproot Asset commitments + // from asset commitments of the same group. + genesis3 := asset.RandGenesis(t, asset.Normal) + asset3 := randAsset(t, genesis3, groupKey1) + asset1 := protoAsset1.Copy() asset1.GroupKey = groupKey1 @@ -1097,10 +1103,45 @@ func TestUpdateTapCommitment(t *testing.T) { require.NoError(t, err) commitmentKey2 := assetCommitment2.TapCommitmentKey() + assetCommitment3, err := NewAssetCommitment(asset3) + require.NoError(t, err) + commitmentKey3 := assetCommitment3.TapCommitmentKey() + + // When creating a Taproot Asset commitment from all three assets, we + // expect two commitments to be created, one for each group. + cp1, err := assetCommitment1.Copy() + require.NoError(t, err) + cp2, err := assetCommitment2.Copy() + require.NoError(t, err) + cp3, err := assetCommitment3.Copy() + require.NoError(t, err) + commitment, err := NewTapCommitment(cp1, cp2, cp3) + require.NoError(t, err) + require.Len(t, commitment.Commitments(), 2) + require.Len(t, commitment.CommittedAssets(), 3) + + require.Equal(t, commitmentKey1, commitmentKey3) + + // Make sure we can still generate proper proofs for all assets. + p1, _, err := commitment.Proof( + commitmentKey1, asset1.AssetCommitmentKey(), + ) + require.NoError(t, err) + require.True(t, p1.DeepEqual(asset1)) + p2, _, err := commitment.Proof( + commitmentKey2, asset2.AssetCommitmentKey(), + ) + require.NoError(t, err) + require.True(t, p2.DeepEqual(asset2)) + p3, _, err := commitment.Proof( + commitmentKey3, asset3.AssetCommitmentKey(), + ) + require.NoError(t, err) + require.True(t, p3.DeepEqual(asset3)) // Mint a new Taproot Asset commitment with only the first // assetCommitment. - commitment, err := NewTapCommitment(assetCommitment1) + commitment, err = NewTapCommitment(assetCommitment1) require.NoError(t, err) copyOfCommitment, err := NewTapCommitment(assetCommitment1) @@ -1201,7 +1242,7 @@ func TestAssetCommitmentDeepCopy(t *testing.T) { require.NoError(t, err) require.Equal(t, assetCommitment.Version, assetCommitmentCopy.Version) - require.Equal(t, assetCommitment.AssetID, assetCommitmentCopy.AssetID) + require.Equal(t, assetCommitment.TapKey, assetCommitmentCopy.TapKey) require.True( t, mssmt.IsEqualNode( assetCommitment.TreeRoot, assetCommitmentCopy.TreeRoot, diff --git a/commitment/encoding.go b/commitment/encoding.go index ae5e4d1f8..6e9fbae64 100644 --- a/commitment/encoding.go +++ b/commitment/encoding.go @@ -12,7 +12,7 @@ func AssetProofEncoder(w io.Writer, val any, buf *[8]byte) error { if t, ok := val.(**AssetProof); ok { records := []tlv.Record{ AssetProofVersionRecord(&(*t).Version), - AssetProofAssetIDRecord(&(*t).AssetID), + AssetProofAssetIDRecord(&(*t).TapKey), AssetProofRecord(&(*t).Proof), } stream, err := tlv.NewStream(records...) @@ -39,7 +39,7 @@ func AssetProofDecoder(r io.Reader, val any, buf *[8]byte, l uint64) error { var proof AssetProof records := []tlv.Record{ AssetProofVersionRecord(&proof.Version), - AssetProofAssetIDRecord(&proof.AssetID), + AssetProofAssetIDRecord(&proof.TapKey), AssetProofRecord(&proof.Proof), } stream, err := tlv.NewStream(records...) diff --git a/commitment/mock.go b/commitment/mock.go index cbfd1b87d..b214e92b5 100644 --- a/commitment/mock.go +++ b/commitment/mock.go @@ -83,7 +83,7 @@ func NewTestFromProof(t testing.TB, p *Proof) *TestProof { tp.AssetProof = &TestAssetProof{ Proof: mssmt.HexProof(t, &p.AssetProof.Proof), Version: uint8(p.AssetProof.Version), - AssetID: hex.EncodeToString(p.AssetProof.AssetID[:]), + TapKey: hex.EncodeToString(p.AssetProof.TapKey[:]), } } @@ -111,9 +111,9 @@ func (tp *TestProof) ToProof(t testing.TB) *Proof { Proof: mssmt.ParseProof(t, tp.AssetProof.Proof), Version: asset.Version(tp.AssetProof.Version), } - assetID, err := hex.DecodeString(tp.AssetProof.AssetID) + assetID, err := hex.DecodeString(tp.AssetProof.TapKey) require.NoError(t, err) - copy(p.AssetProof.AssetID[:], assetID) + copy(p.AssetProof.TapKey[:], assetID) } return p @@ -122,7 +122,7 @@ func (tp *TestProof) ToProof(t testing.TB) *Proof { type TestAssetProof struct { Proof string `json:"proof"` Version uint8 `json:"version"` - AssetID string `json:"asset_id"` + TapKey string `json:"tap_key"` } type TestTaprootAssetProof struct { diff --git a/commitment/proof.go b/commitment/proof.go index 8932c08fb..3f12d94d0 100644 --- a/commitment/proof.go +++ b/commitment/proof.go @@ -24,11 +24,11 @@ type AssetProof struct { // Version is the max version of the assets committed. Version asset.Version - // AssetID is the common identifier for all assets found within the + // TapKey is the common identifier for all assets found within the // AssetCommitment. This can either be an asset.ID, which every // committed asset must match, otherwise an asset.GroupKey which every // committed asset must match. - AssetID [32]byte + TapKey [32]byte } // TaprootAssetProof is the proof used along with an asset commitment leaf to @@ -117,7 +117,7 @@ func (p Proof) DeriveByAssetInclusion(asset *asset.Asset) (*TapCommitment, ) assetCommitment := &AssetCommitment{ Version: p.AssetProof.Version, - AssetID: p.AssetProof.AssetID, + TapKey: p.AssetProof.TapKey, TreeRoot: assetProofRoot, } @@ -158,7 +158,7 @@ func (p Proof) DeriveByAssetExclusion(assetCommitmentKey [32]byte) ( ) assetCommitment := &AssetCommitment{ Version: p.AssetProof.Version, - AssetID: p.AssetProof.AssetID, + TapKey: p.AssetProof.TapKey, TreeRoot: assetProofRoot, } diff --git a/commitment/tap.go b/commitment/tap.go index d37e55424..ffdca10e8 100644 --- a/commitment/tap.go +++ b/commitment/tap.go @@ -78,18 +78,33 @@ type TapCommitment struct { // NewTapCommitment creates a new Taproot Asset commitment for the given asset // commitments capable of computing merkle proofs. -func NewTapCommitment(assets ...*AssetCommitment) (*TapCommitment, error) { +func NewTapCommitment(newCommitments ...*AssetCommitment) (*TapCommitment, + error) { + maxVersion := asset.V0 tree := mssmt.NewCompactedTree(mssmt.NewDefaultStore()) - assetCommitments := make(AssetCommitments, len(assets)) - for _, asset := range assets { - asset := asset + assetCommitments := make(AssetCommitments, len(newCommitments)) + for idx := range newCommitments { + assetCommitment := newCommitments[idx] - if asset.Version > maxVersion { - maxVersion = asset.Version + if assetCommitment.Version > maxVersion { + maxVersion = assetCommitment.Version } - key := asset.TapCommitmentKey() - leaf := asset.TapCommitmentLeaf() + key := assetCommitment.TapCommitmentKey() + + // Do we already have an asset commitment for this key? If so, + // we need to merge them together. + existingCommitment, ok := assetCommitments[key] + if ok { + err := existingCommitment.Merge(assetCommitment) + if err != nil { + return nil, err + } + + assetCommitment = existingCommitment + } + + leaf := assetCommitment.TapCommitmentLeaf() // TODO(bhandras): thread the context through. _, err := tree.Insert(context.TODO(), key, leaf) @@ -97,7 +112,7 @@ func NewTapCommitment(assets ...*AssetCommitment) (*TapCommitment, error) { return nil, err } - assetCommitments[key] = asset + assetCommitments[key] = assetCommitment } root, err := tree.Root(context.Background()) @@ -365,7 +380,7 @@ func (c *TapCommitment) Proof(tapCommitmentKey, proof.AssetProof = &AssetProof{ Proof: *assetProof, Version: assetCommitment.Version, - AssetID: assetCommitment.AssetID, + TapKey: assetCommitment.TapKey, } return a, proof, nil @@ -437,18 +452,14 @@ func (c *TapCommitment) Merge(other *TapCommitment) error { // Otherwise, we'll need to merge the other asset commitments into // this commitment. - for key, otherCommitment := range other.assetCommitments { - existingCommitment, ok := c.assetCommitments[key] + for key := range other.assetCommitments { + otherCommitment := other.assetCommitments[key] // If we already have an asset commitment for this key, then we // merge the two asset trees together. + existingCommitment, ok := c.assetCommitments[key] if ok { - commitmentCopy, err := otherCommitment.Copy() - if err != nil { - return fmt.Errorf("error copying asset "+ - "commitment: %w", err) - } - err = existingCommitment.Merge(commitmentCopy) + err := existingCommitment.Merge(otherCommitment) if err != nil { return fmt.Errorf("error merging asset "+ "commitment: %w", err) @@ -459,12 +470,7 @@ func (c *TapCommitment) Merge(other *TapCommitment) error { // With either the new or merged asset commitment obtained, we // can now (re-)insert it into the Taproot Asset commitment. - existingCommitmentCopy, err := existingCommitment.Copy() - if err != nil { - return fmt.Errorf("error copying asset commitment: "+ - "%w", err) - } - if err := c.Upsert(existingCommitmentCopy); err != nil { + if err := c.Upsert(existingCommitment); err != nil { return fmt.Errorf("error upserting other commitment: "+ "%w", err) } diff --git a/itest/multi_asset_group_test.go b/itest/multi_asset_group_test.go index 601e8e14d..6c4f43836 100644 --- a/itest/multi_asset_group_test.go +++ b/itest/multi_asset_group_test.go @@ -1,9 +1,11 @@ package itest import ( + "bytes" "context" "encoding/hex" - "strconv" + "fmt" + "testing" "github.com/lightninglabs/taproot-assets/fn" "github.com/lightninglabs/taproot-assets/taprpc" @@ -190,14 +192,14 @@ func createMultiAssetGroup(anchor *mintrpc.MintAssetRequest, groupRequests := []*mintrpc.MintAssetRequest{CopyRequest(anchor)} anchorAmount := anchor.Asset.Amount anchorName := anchor.Asset.Name - nameModifier := "-tranche-" groupSum := uint64(0) - for i := uint64(1); i < numAssets+1; i++ { + for i := uint64(1); i <= numAssets; i++ { assetReq := CopyRequest(anchor) assetReq.EnableEmission = false assetReq.Asset.GroupAnchor = anchorName - reqName := anchorName + nameModifier + strconv.FormatUint(i, 10) - assetReq.Asset.Name = reqName + assetReq.Asset.Name = fmt.Sprintf( + "%s-tranche-%d", anchorName, i, + ) if assetReq.Asset.AssetType == taprpc.AssetType_NORMAL { reqAmount := anchorAmount / (2 * i) @@ -270,3 +272,144 @@ func testMintMultiAssetGroupErrors(t *harnessTest) { validAnchor.Asset.Amount AssertBalanceByGroup(t.t, t.tapd, groupKeyHex, expectedGroupBalance) } + +// testMultiAssetGroupSend tests that we can randomly send assets from a group +// of collectibles one after another from one node to the other. +func testMultiAssetGroupSend(t *harnessTest) { + // We use a hashmail proof courier for this test, which takes a bit + // longer to send proofs. So we use a longer timeout. + ctxb := context.Background() + ctxt, cancel := context.WithTimeout(ctxb, defaultWaitTimeout*3) + defer cancel() + + // First, we'll build a batch to mint. + issuableAsset := CopyRequest(simpleAssets[1]) + issuableAsset.EnableEmission = true + + collectibleGroupMembers := 50 + collectibleGroup, collectibleGroupSum := createMultiAssetGroup( + issuableAsset, uint64(collectibleGroupMembers), + ) + + // The minted batch should contain 51 assets total, and the daemon + // should now be aware of one asset group. + mintedBatch := MintAssetsConfirmBatch( + t.t, t.lndHarness.Miner.Client, t.tapd, collectibleGroup, + ) + require.Len(t.t, mintedBatch, collectibleGroupMembers+1) + + // Once the batch is minted, we can verify that all asset groups were + // created correctly. We begin by verifying the number of asset groups. + groupCount := 1 + AssertNumGroups(t.t, t.tapd, groupCount) + balancesResp, err := t.tapd.ListBalances( + ctxt, &taprpc.ListBalancesRequest{ + GroupBy: &taprpc.ListBalancesRequest_GroupKey{ + GroupKey: true, + }, + }, + ) + require.NoError(t.t, err) + + require.NotNil(t.t, mintedBatch[0].AssetGroup) + groupKeyStr := hex.EncodeToString( + mintedBatch[0].AssetGroup.TweakedGroupKey, + ) + + require.Contains(t.t, balancesResp.AssetGroupBalances, groupKeyStr) + require.EqualValues( + t.t, collectibleGroupSum, + balancesResp.AssetGroupBalances[groupKeyStr].Balance, + ) + + AssertGroupSizes(t.t, t.tapd, []string{groupKeyStr}, []int{ + collectibleGroupMembers + 1, + }) + + // We'll make a second node now that'll be the receiver of all the + // assets made above. + secondTapd := setupTapdHarness( + t.t, t, t.lndHarness.Bob, t.universeServer, + func(params *tapdHarnessParams) { + params.startupSyncNode = t.tapd + params.startupSyncNumAssets = groupCount + }, + ) + defer func() { + require.NoError(t.t, secondTapd.stop(!*noDelete)) + }() + + // Send 5 of the assets to Bob, and verify that they are received. + numUnits := issuableAsset.Asset.Amount + assetType := issuableAsset.Asset.AssetType + for i := 0; i < 5; i++ { + // Query the asset we'll be sending, so we can assert some + // things about it later. + sendAsset := assetIDWithBalance( + t.t, t.tapd, numUnits, assetType, + ) + genInfo := sendAsset.AssetGenesis + t.Logf("Attempt %d: Sending %d asset(s) with ID %x from "+ + "alice to bob", i+1, numUnits, genInfo.AssetId) + + addr, err := secondTapd.NewAddr(ctxt, &taprpc.NewAddrRequest{ + AssetId: genInfo.AssetId, + Amt: numUnits, + }) + require.NoError(t.t, err) + AssertAddrCreated(t.t, secondTapd, sendAsset, addr) + + sendResp := sendAssetsToAddr(t, t.tapd, addr) + + ConfirmAndAssertOutboundTransfer( + t.t, t.lndHarness.Miner.Client, t.tapd, + sendResp, genInfo.AssetId, + []uint64{0, numUnits}, i, i+1, + ) + + AssertNonInteractiveRecvComplete(t.t, secondTapd, i+1) + } +} + +// assetIDWithBalance returns the asset ID of an asset that has at least the +// given balance. If no such asset is found, nil is returned. +func assetIDWithBalance(t *testing.T, node *tapdHarness, + minBalance uint64, assetType taprpc.AssetType) *taprpc.Asset { + + ctxb := context.Background() + ctxt, cancel := context.WithTimeout(ctxb, defaultWaitTimeout) + defer cancel() + + balances, err := node.ListBalances(ctxt, &taprpc.ListBalancesRequest{ + GroupBy: &taprpc.ListBalancesRequest_AssetId{ + AssetId: true, + }, + }) + require.NoError(t, err) + + for assetIDHex, balance := range balances.AssetBalances { + if balance.Balance >= minBalance && + balance.AssetType == assetType { + + assetIDBytes, err := hex.DecodeString(assetIDHex) + require.NoError(t, err) + + assets, err := node.ListAssets( + ctxt, &taprpc.ListAssetRequest{}, + ) + require.NoError(t, err) + + for _, asset := range assets.Assets { + if bytes.Equal( + asset.AssetGenesis.AssetId, + assetIDBytes, + ) { + + return asset + } + } + } + } + + return nil +} diff --git a/itest/test_list_on_test.go b/itest/test_list_on_test.go index ecdc77bcc..78e435d22 100644 --- a/itest/test_list_on_test.go +++ b/itest/test_list_on_test.go @@ -96,6 +96,11 @@ var testCases = []*testCase{ name: "minting multi asset groups", test: testMintMultiAssetGroups, }, + { + name: "sending multi asset groups", + test: testMultiAssetGroupSend, + proofCourierType: proof.HashmailCourierType, + }, { name: "re-issuance amount overflow", test: testReIssuanceAmountOverflow, diff --git a/log.go b/log.go index aa82dcb23..27b5e2b3a 100644 --- a/log.go +++ b/log.go @@ -8,6 +8,7 @@ import ( "github.com/lightninglabs/taproot-assets/tapdb" "github.com/lightninglabs/taproot-assets/tapfreighter" "github.com/lightninglabs/taproot-assets/tapgarden" + "github.com/lightninglabs/taproot-assets/tapscript" "github.com/lightninglabs/taproot-assets/universe" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/signal" @@ -96,6 +97,9 @@ func SetupLoggers(root *build.RotatingLogWriter, interceptor signal.Interceptor) ) AddSubLogger(root, proof.Subsystem, interceptor, proof.UseLogger) AddSubLogger(root, tapdb.Subsystem, interceptor, tapdb.UseLogger) + AddSubLogger( + root, tapscript.Subsystem, interceptor, tapscript.UseLogger, + ) AddSubLogger(root, universe.Subsystem, interceptor, universe.UseLogger) AddSubLogger( root, commitment.Subsystem, interceptor, commitment.UseLogger, diff --git a/proof/proof_test.go b/proof/proof_test.go index 910ec43d7..671bedcb1 100644 --- a/proof/proof_test.go +++ b/proof/proof_test.go @@ -19,6 +19,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" + "github.com/davecgh/go-spew/spew" "github.com/lightninglabs/taproot-assets/asset" "github.com/lightninglabs/taproot-assets/commitment" "github.com/lightninglabs/taproot-assets/internal/test" @@ -731,6 +732,8 @@ func TestProofVerification(t *testing.T) { assetID := p.Asset.ID() t.Logf("Proof asset ID: %x", assetID[:]) + t.Logf("Proof anchor TX: %v", spew.Sdump(p.AnchorTx)) + inclusionTxOut := p.AnchorTx.TxOut[p.InclusionProof.OutputIndex] t.Logf("Proof inclusion tx out: %x", inclusionTxOut.PkScript) proofKey, proofTree, err := p.InclusionProof.DeriveByAssetInclusion( diff --git a/proof/testdata/proof_tlv_encoding_generated.json b/proof/testdata/proof_tlv_encoding_generated.json index 7fcbeeb15..d7759b982 100644 --- a/proof/testdata/proof_tlv_encoding_generated.json +++ b/proof/testdata/proof_tlv_encoding_generated.json @@ -55,7 +55,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "1624d9703a0fea948dd97385753c57c8225b9421af0ec87d4c92a4832a01b03c" + "tap_key": "1624d9703a0fea948dd97385753c57c8225b9421af0ec87d4c92a4832a01b03c" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -141,7 +141,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 1, - "asset_id": "4c3b9aff77396d1ff1d5470229b11164512a56d86db16be09c26b890512e349d" + "tap_key": "4c3b9aff77396d1ff1d5470229b11164512a56d86db16be09c26b890512e349d" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -227,7 +227,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "c2b2144031c7f0158c9b080b3d4f28533c8bd79f3371fa2d486305cb32d52919" + "tap_key": "c2b2144031c7f0158c9b080b3d4f28533c8bd79f3371fa2d486305cb32d52919" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -313,7 +313,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "ee82654f2c644ea7941327d5d842649c79588e663d67314a0b999d13471aafa0" + "tap_key": "ee82654f2c644ea7941327d5d842649c79588e663d67314a0b999d13471aafa0" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -399,7 +399,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "c4fd51257eced9f6bb3f5918545d257fa7a490b129189d0d8096117341b87425" + "tap_key": "c4fd51257eced9f6bb3f5918545d257fa7a490b129189d0d8096117341b87425" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -485,7 +485,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 1, - "asset_id": "cb74bf55f8cd601b17db37abc586a01b59533caa2e1ecd629f840a9d416423c6" + "tap_key": "cb74bf55f8cd601b17db37abc586a01b59533caa2e1ecd629f840a9d416423c6" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -571,7 +571,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "db7a3ba3a675af4724280dc944a6377cc68de6fb2c4c6c51b494e9ca23e22dd0" + "tap_key": "db7a3ba3a675af4724280dc944a6377cc68de6fb2c4c6c51b494e9ca23e22dd0" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -657,7 +657,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "f0b65d4efa4a0c2daec2372a807c817a3a4c2eab20fa90c6d36ab78366d98c5c" + "tap_key": "f0b65d4efa4a0c2daec2372a807c817a3a4c2eab20fa90c6d36ab78366d98c5c" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -743,7 +743,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "341dcde8656fe3a35d4c69986694f44934a74f7b76aabe111d39e6b1f579dbe3" + "tap_key": "341dcde8656fe3a35d4c69986694f44934a74f7b76aabe111d39e6b1f579dbe3" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -832,7 +832,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "90100b5f5edf4a3e49b48a91703912e695f4796fcd23e38bd362c3ef3775172f" + "tap_key": "90100b5f5edf4a3e49b48a91703912e695f4796fcd23e38bd362c3ef3775172f" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", diff --git a/proof/testdata/proof_tlv_encoding_regtest.json b/proof/testdata/proof_tlv_encoding_regtest.json index 6286ec7a8..5dec3fda5 100644 --- a/proof/testdata/proof_tlv_encoding_regtest.json +++ b/proof/testdata/proof_tlv_encoding_regtest.json @@ -55,7 +55,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0001475985869e2c0a018e7f4997cf646922438dfca3a3e571f72e6371db0f1e150500000000000007d0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7", @@ -153,7 +153,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0001b2433a697dcd01e0c5462c85cd53b3ef8662c1484216d4722d0c96851040a3bb00000000000007d0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7", @@ -173,7 +173,7 @@ "asset_proof": { "proof": "0001db29f471c91019c8acfe37b9486e7ca67b0440a0e427347cf83dfb75c6a52b1500000000000004b0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -289,7 +289,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -309,7 +309,7 @@ "asset_proof": { "proof": "00017367d3004d4eacd4e931e0a9df36a4a4161b94c5d05db5b47a4d014381ccb2e2000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0001b2433a697dcd01e0c5462c85cd53b3ef8662c1484216d4722d0c96851040a3bb00000000000007d0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7", @@ -339,7 +339,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0001b2433a697dcd01e0c5462c85cd53b3ef8662c1484216d4722d0c96851040a3bb00000000000007d0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7", @@ -447,7 +447,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -467,7 +467,7 @@ "asset_proof": { "proof": "00010a1b05a2e5107e4912babe314f825d0ce1588e0f0733d1d85804483de66fa0690000000000000258ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -497,7 +497,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -574,7 +574,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0001475985869e2c0a018e7f4997cf646922438dfca3a3e571f72e6371db0f1e150500000000000007d0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7", @@ -704,7 +704,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -724,7 +724,7 @@ "asset_proof": { "proof": "00017367d3004d4eacd4e931e0a9df36a4a4161b94c5d05db5b47a4d014381ccb2e2000000000000012cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0001b2433a697dcd01e0c5462c85cd53b3ef8662c1484216d4722d0c96851040a3bb00000000000007d0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7", @@ -754,7 +754,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0001b2433a697dcd01e0c5462c85cd53b3ef8662c1484216d4722d0c96851040a3bb00000000000007d0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7", @@ -862,7 +862,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -882,7 +882,7 @@ "asset_proof": { "proof": "00010a1b05a2e5107e4912babe314f825d0ce1588e0f0733d1d85804483de66fa0690000000000000258ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", @@ -912,7 +912,7 @@ "asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "version": 0, - "asset_id": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" + "tap_key": "a88ed3e42cfbf677223639c2f0e9339bceb795223cfa476b149c73f73560edad" }, "taproot_asset_proof": { "proof": "0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", diff --git a/tapcfg/config.go b/tapcfg/config.go index 62bdb5578..65e0f1a0c 100644 --- a/tapcfg/config.go +++ b/tapcfg/config.go @@ -455,6 +455,14 @@ func LoadConfig(interceptor signal.Interceptor) (*Config, btclog.Logger, error) return nil, nil, err } + // Parse, validate, and set debug log level(s). + err = build.ParseAndSetDebugLevels(cfg.DebugLevel, cfg.LogWriter) + if err != nil { + str := "error parsing debug level: %v" + cfgLogger.Warnf(str, err) + return nil, nil, fmt.Errorf(str, err) + } + // Warn about missing config file only after all other configuration is // done. This prevents the warning on help messages and invalid // options. Note this should go directly before the return. @@ -687,13 +695,6 @@ func ValidateConfig(cfg Config, cfgLogger btclog.Logger) (*Config, error) { os.Exit(0) } - // Parse, validate, and set debug log level(s). - err := build.ParseAndSetDebugLevels(cfg.DebugLevel, cfg.LogWriter) - if err != nil { - str := "error parsing debug level: %v" - return nil, &usageError{mkErr(str, err)} - } - // At least one RPCListener is required. So listen on localhost per // default. if len(cfg.RpcConf.RawRPCListeners) == 0 { @@ -713,6 +714,7 @@ func ValidateConfig(cfg Config, cfgLogger btclog.Logger) (*Config, error) { // Add default port to all RPC listener addresses if needed and remove // duplicate addresses. + var err error cfg.rpcListeners, err = lncfg.NormalizeAddresses( cfg.RpcConf.RawRPCListeners, strconv.Itoa(defaultRPCPort), cfg.net.ResolveTCPAddr, diff --git a/tapdb/asset_minting.go b/tapdb/asset_minting.go index 12690a27e..de20ea173 100644 --- a/tapdb/asset_minting.go +++ b/tapdb/asset_minting.go @@ -541,9 +541,9 @@ func fetchAssetSprouts(ctx context.Context, q PendingAssetStore, return nil, fmt.Errorf("unable to fetch batch assets: %w", err) } - // For each sprout, we'll create a new asset commitment which will be a - // leaf at the top-level Taproot Asset commitment. - assetCommitments := make([]*commitment.AssetCommitment, len(dbSprout)) + // We collect all the sprouts into fully grown assets, from which we'll + // then create asset and tap level commitments. + assetSprouts := make([]*asset.Asset, len(dbSprout)) for i, sprout := range dbSprout { // First, we'll decode the script key which very asset must // specify, and populate the key locator information @@ -649,18 +649,10 @@ func fetchAssetSprouts(ctx context.Context, q PendingAssetStore, // TODO(roasbeef): need to update the above to set the // witnesses of a valid asset - // Finally make a new asset commitment from this sprout and - // accumulate it along the rest of the assets. - assetCommitment, err := commitment.NewAssetCommitment( - assetSprout, - ) - if err != nil { - return nil, err - } - assetCommitments[i] = assetCommitment + assetSprouts[i] = assetSprout } - tapCommitment, err := commitment.NewTapCommitment(assetCommitments...) + tapCommitment, err := commitment.FromAssets(assetSprouts...) if err != nil { return nil, err } diff --git a/tapdb/asset_minting_test.go b/tapdb/asset_minting_test.go index 3da0c3142..d3486abc0 100644 --- a/tapdb/asset_minting_test.go +++ b/tapdb/asset_minting_test.go @@ -1092,11 +1092,9 @@ func TestGroupAnchors(t *testing.T) { orderedSeedlings := tapgarden.SortSeedlings(maps.Values(seedlings)) for _, seedlingName := range orderedSeedlings { seedling := seedlings[seedlingName] - require.NoError(t, - assetStore.AddSeedlingsToBatch( - ctx, batchKey, seedling, - ), "unable to write seedlings: %v", err, - ) + require.NoError(t, assetStore.AddSeedlingsToBatch( + ctx, batchKey, seedling, + )) } // If we read the batch from disk again, then we should have 20 total @@ -1109,10 +1107,9 @@ func TestGroupAnchors(t *testing.T) { badGrouped := seedlings[secondGrouped] badAnchorName := secondAnchor + secondGrouped badGrouped.GroupAnchor = &badAnchorName - require.ErrorContains(t, - assetStore.AddSeedlingsToBatch( - ctx, batchKey, badGrouped, - ), "no rows in result set", + require.ErrorContains( + t, assetStore.AddSeedlingsToBatch(ctx, batchKey, badGrouped), + "no rows in result set", ) seedlings[secondGrouped].GroupAnchor = &secondAnchor diff --git a/tapfreighter/chain_porter.go b/tapfreighter/chain_porter.go index 8583bff30..9c9cf1d0e 100644 --- a/tapfreighter/chain_porter.go +++ b/tapfreighter/chain_porter.go @@ -605,6 +605,18 @@ func (p *ChainPorter) transferReceiverProof(pkg *sendPackage) error { return nil } + unSpendable, err := out.ScriptKey.IsUnSpendable() + if err != nil { + return fmt.Errorf("error checking if script key is "+ + "unspendable: %w", err) + } + if unSpendable { + log.Debugf("Not transferring proof for un-spendable "+ + "output script key %x", + key.SerializeCompressed()) + return nil + } + // We just look for the full proof in the list of final proofs // by matching the content of the proof suffix. var receiverProof *proof.AnnotatedProof diff --git a/tapfreighter/wallet.go b/tapfreighter/wallet.go index 271cb849a..c05cd8607 100644 --- a/tapfreighter/wallet.go +++ b/tapfreighter/wallet.go @@ -766,6 +766,17 @@ func (f *AssetWallet) fundPacketWithInputs(ctx context.Context, } } + // We now also need to remove all tombstone or burns from our active + // commitments. + for idx := range inputCommitments { + inputCommitments[idx], err = pruneTombstonesAndBurns( + inputCommitments[idx], + ) + if err != nil { + return nil, err + } + } + // We expect some change back, or have passive assets to commit to, so // let's make sure we create a transfer output. var changeOut *tappsbt.VOutput @@ -1127,6 +1138,20 @@ func verifyInclusionProof(vIn *tappsbt.VInput) error { return nil } +// pruneTombstonesAndBurns removes all tombstones and burns from the active +// input commitment. +func pruneTombstonesAndBurns( + inputCommitment *commitment.TapCommitment) (*commitment.TapCommitment, + error) { + + committedAssets := inputCommitment.CommittedAssets() + committedAssets = fn.Filter(committedAssets, func(a *asset.Asset) bool { + return !a.IsUnSpendable() && !a.IsBurn() + }) + + return commitment.FromAssets(committedAssets...) +} + // removeActiveCommitments removes all active commitments from the given input // commitment and only returns a tree of passive commitments. func removeActiveCommitments(inputCommitment *commitment.TapCommitment, diff --git a/tappsbt/testdata/psbt_encoding_generated.json b/tappsbt/testdata/psbt_encoding_generated.json index eaf266ad7..7109eb660 100644 --- a/tappsbt/testdata/psbt_encoding_generated.json +++ b/tappsbt/testdata/psbt_encoding_generated.json @@ -169,7 +169,7 @@ "genesis_meta_hash": "1fb586b14323a6bc8f9e7df1d929333ff993933bea6f5b3af6de0374366c4719", "genesis_output_index": 3197016449, "genesis_type": 0, - "amount": 2873287401706343735, + "amount": 609209655, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -180,7 +180,7 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "9ca48fa123a923de60d62bd8f5122db894939bd2718d73e884d282644818cd2c8daae166b56a2051b93ec8f00bec736c0c8aa5cdba0c5030e6faa6ceb6673b60" + "189c0126f90da1ce11a0826fa3e81feda8e44d9916a52c660a12e093ca00795b130085141b7d23cb8d210351c00c61072757e707f5978d227ebc6093b6b448c7" ], "split_commitment": null } @@ -261,7 +261,7 @@ "genesis_meta_hash": "63afa467d49dec6a40e9a1d007f033c2823061bdd0eaa59f8e4da6430105220d", "genesis_output_index": 654045851, "genesis_type": 0, - "amount": 3724427934598140042, + "amount": 1094946954, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -272,7 +272,7 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "d950c3393d2e8f7180c4e56d6601ec7f3a9f1cf1fd59a79f52969f2570c592b30757f3201d64e3b959e4f99a3ada35f03ab6d7cb350798740c13331d46132333" + "e146db011035548ffd57d9b36b69834268212414ca5ae2a1e6f47b411eac70ade3b4f60f4668bf277ade3ed0e4d45ca13902de5904e52e4f6adba355df03a963" ], "split_commitment": null } @@ -291,7 +291,7 @@ "genesis_meta_hash": "63afa467d49dec6a40e9a1d007f033c2823061bdd0eaa59f8e4da6430105220d", "genesis_output_index": 654045851, "genesis_type": 0, - "amount": 3724427934598140042, + "amount": 1094946954, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -302,7 +302,7 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "d950c3393d2e8f7180c4e56d6601ec7f3a9f1cf1fd59a79f52969f2570c592b30757f3201d64e3b959e4f99a3ada35f03ab6d7cb350798740c13331d46132333" + "e146db011035548ffd57d9b36b69834268212414ca5ae2a1e6f47b411eac70ade3b4f60f4668bf277ade3ed0e4d45ca13902de5904e52e4f6adba355df03a963" ], "split_commitment": null } @@ -362,7 +362,7 @@ "genesis_meta_hash": "63afa467d49dec6a40e9a1d007f033c2823061bdd0eaa59f8e4da6430105220d", "genesis_output_index": 654045851, "genesis_type": 0, - "amount": 3724427934598140042, + "amount": 1094946954, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -373,7 +373,7 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "d950c3393d2e8f7180c4e56d6601ec7f3a9f1cf1fd59a79f52969f2570c592b30757f3201d64e3b959e4f99a3ada35f03ab6d7cb350798740c13331d46132333" + "e146db011035548ffd57d9b36b69834268212414ca5ae2a1e6f47b411eac70ade3b4f60f4668bf277ade3ed0e4d45ca13902de5904e52e4f6adba355df03a963" ], "split_commitment": null } @@ -396,7 +396,7 @@ "version": 0, "chain_params_hrp": "tapbc" }, - "expected": "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", + "expected": "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", "comment": "random packet" } ], diff --git a/tapscript/log.go b/tapscript/log.go new file mode 100644 index 000000000..30c43be20 --- /dev/null +++ b/tapscript/log.go @@ -0,0 +1,26 @@ +package tapscript + +import ( + "github.com/btcsuite/btclog" +) + +// Subsystem defines the logging code for this subsystem. +const Subsystem = "SEND" + +// log is a logger that is initialized with no output filters. This +// means the package will not perform any logging by default until the caller +// requests it. +var log = btclog.Disabled + +// DisableLog disables all library log output. Logging output is disabled +// by default until UseLogger is called. +func DisableLog() { + UseLogger(btclog.Disabled) +} + +// UseLogger uses a specified Logger to output package logging info. +// This should be used in preference to SetLogWriter if the caller is also +// using btclog. +func UseLogger(logger btclog.Logger) { + log = logger +} diff --git a/tapscript/send.go b/tapscript/send.go index 11f40e0b1..517338bca 100644 --- a/tapscript/send.go +++ b/tapscript/send.go @@ -732,12 +732,12 @@ func CreateOutputCommitments(inputTapCommitments tappsbt.InputCommitments, // Merge all input Taproot Asset commitments into a single commitment. // // TODO(ffranr): Use `fn.ForEach` and `inputTapCommitments[1:]`. - inputTapCommitment := inputTapCommitments[0] + firstCommitment := inputTapCommitments[0] for idx := range inputTapCommitments { if idx == 0 { continue } - err := inputTapCommitment.Merge(inputTapCommitments[idx]) + err := firstCommitment.Merge(inputTapCommitments[idx]) if err != nil { return nil, fmt.Errorf("failed to merge input Taproot "+ "Asset commitments: %w", err) @@ -753,13 +753,13 @@ func CreateOutputCommitments(inputTapCommitments tappsbt.InputCommitments, // Remove the spent Asset from the AssetCommitment of the sender. Fail // if the input AssetCommitment or Asset were not in the input // TapCommitment. - inputTapCommitmentCopy, err := inputTapCommitment.Copy() + inputTapCommitment, err := firstCommitment.Copy() if err != nil { return nil, err } - inputCommitments := inputTapCommitmentCopy.Commitments() - inputCommitment, ok := inputCommitments[assetsTapCommitmentKey] + assetCommitments := inputTapCommitment.Commitments() + assetCommitment, ok := assetCommitments[assetsTapCommitmentKey] if !ok { return nil, ErrMissingAssetCommitment } @@ -770,13 +770,13 @@ func CreateOutputCommitments(inputTapCommitments tappsbt.InputCommitments, // Just a sanity check that the asset we're spending really was // in the list of input assets. - _, ok = inputCommitment.Asset(inputAsset.AssetCommitmentKey()) + _, ok = assetCommitment.Asset(inputAsset.AssetCommitmentKey()) if !ok { return nil, ErrMissingInputAsset } // Remove all input assets from the asset commitment tree. - err := inputCommitment.Delete(inputAsset) + err := assetCommitment.Delete(inputAsset) if err != nil { return nil, err } @@ -798,7 +798,7 @@ func CreateOutputCommitments(inputTapCommitments tappsbt.InputCommitments, // The asset is present, just commit it to the input // asset commitment. case vOut.Asset != nil: - err := inputCommitment.Upsert(vOut.Asset) + err := assetCommitment.Upsert(vOut.Asset) if err != nil { return nil, err } @@ -820,22 +820,31 @@ func CreateOutputCommitments(inputTapCommitments tappsbt.InputCommitments, // the new spend details. If there is nothing contained // in the input commitment, it is removed from the // Taproot Asset tree automatically. - err = inputTapCommitmentCopy.Upsert(inputCommitment) + err = inputTapCommitment.Upsert(assetCommitment) if err != nil { return nil, err } + log.Tracef("Adding %d passive assets to output with %d "+ + "current assets", len(passiveAssets), + len(inputTapCommitment.CommittedAssets())) + // Anchor passive assets to this output, since it's the // split root (=change output). err = AnchorPassiveAssets( - passiveAssets, inputTapCommitmentCopy, + passiveAssets, inputTapCommitment, ) if err != nil { return nil, fmt.Errorf("unable to anchor "+ "passive assets: %w", err) } - outputCommitments[idx] = inputTapCommitmentCopy + root := inputTapCommitment.TapscriptRoot(nil) + log.Tracef("Output %d commitment: root=%x, "+ + "num_assets=%d", idx, root[:], + len(inputTapCommitment.CommittedAssets())) + + outputCommitments[idx] = inputTapCommitment continue } diff --git a/tapscript/send_test.go b/tapscript/send_test.go index 7d9b707c9..dc98c8a8c 100644 --- a/tapscript/send_test.go +++ b/tapscript/send_test.go @@ -2219,7 +2219,7 @@ func sendCommitment(t *testing.T, a *asset.Asset, sendAmt btcutil.Amount, return &commitment.AssetCommitment{ Version: a.Version, - AssetID: a.ID(), + TapKey: a.TapCommitmentKey(), TreeRoot: root, } } diff --git a/vm/testdata/vm_validation_generated.json b/vm/testdata/vm_validation_generated.json index 76584c28d..7b1235fb5 100644 --- a/vm/testdata/vm_validation_generated.json +++ b/vm/testdata/vm_validation_generated.json @@ -43,7 +43,7 @@ "genesis_meta_hash": "8afa3f85b8a62708caebbac880b5b89b93da53810164402104e648b6226a1b78", "genesis_output_index": 327692610, "genesis_type": 0, - "amount": 6933583034365165053, + "amount": 3087187453, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -54,7 +54,7 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "f628bda4ee5a82c1465810b64fc808cef2e1d191e96172b8b9e6535c9057feebf033bc5b2f503c87086218ff8bbd4f704d340b755f711f6cbd94383814340c54" + "be6027ac2d3cef07abb355fee5e8786bb7e0841c1c3461af7deeb82161f93fd8092e12f3c15160267d7445cfb65efb48f1ac74b2895fa2de2e5b4467d3c6963d" ], "split_commitment": null } @@ -149,7 +149,7 @@ "genesis_meta_hash": "23e196c9dfff7fbaff4ffe94f4589733e563e19d3045aad3e226488ac02cca42", "genesis_output_index": 164677904, "genesis_type": 0, - "amount": 13637201695855811026, + "amount": 2077694418, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -160,7 +160,7 @@ "script_key": "0290e890b331192e241b29d9ff916cdb85c53be4b3afee55028fa75307d8c86b41" }, "tx_witness": [ - "e91d45c0a83f5e57410201c19b3145413097d1764fa21c2d4494affe86b6c592cef0054a5dfdc8e0210c6615ce17525698de65f593c3049bd61859b9f520378e" + "68563c1630ff6b93a3749fbdc8bd10eee6778dd466f4c44d8101db824e276b22f1e6958abc790f47f9965356ea744e119225090084bb2faa645e2328e2362414" ], "split_commitment": null }, @@ -171,7 +171,7 @@ "script_key": "02a382379d9e1635e23369627a19c587e751e447f073dafc92bdcfb89630eccc6a" }, "tx_witness": [ - "06f89772b022ce52821ec2e204f15cdc6f2ca8e10413d1f6c7d5e73a12af7da6987c72527c6821830f3d83c325e6f1d48427db9972647fd25468cec8228239ed", + "edc2c4951995bc82659d090dc4f61f533f27b4e835a16e66cfbb5162c3c709eb331a6bf4ba3ea6c59a5206f8daa05d5b7754702e4e67b73efc6ccfe2467e0b02", "20a354a15678381931fb574954a609244fc0b601830cac80bf6774882bfcf2e610ad56b2", "c1a354a15678381931fb574954a609244fc0b601830cac80bf6774882bfcf2e610" ], @@ -200,7 +200,7 @@ "genesis_meta_hash": "23e196c9dfff7fbaff4ffe94f4589733e563e19d3045aad3e226488ac02cca42", "genesis_output_index": 164677904, "genesis_type": 0, - "amount": 8695401978176517618, + "amount": 1752217074, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -235,7 +235,7 @@ "genesis_meta_hash": "01c0ab7ac65e502d39b216cbc50e73a32eaf936401e2506bd8b82c30d346bc4b", "genesis_output_index": 231487098, "genesis_type": 0, - "amount": 4941799717679293408, + "amount": 325477344, "lock_time": 0, "relative_lock_time": 6, "prev_witnesses": [ diff --git a/vm/testdata/vm_validation_generated_error_cases.json b/vm/testdata/vm_validation_generated_error_cases.json index 29ad8838b..5065bcf04 100644 --- a/vm/testdata/vm_validation_generated_error_cases.json +++ b/vm/testdata/vm_validation_generated_error_cases.json @@ -307,7 +307,7 @@ "genesis_meta_hash": "cde5e60c5ead6fc7ae77ba1d259b188a4b21c86fbc23d728b45347eada650af2", "genesis_output_index": 2905736656, "genesis_type": 0, - "amount": 8262326810234485413, + "amount": 1312193189, "lock_time": 0, "relative_lock_time": 0, "prev_witnesses": [ @@ -318,7 +318,7 @@ "script_key": "000000000000000000000000000000000000000000000000000000000000000000" }, "tx_witness": [ - "78dd6640c34a21aafecf552e44a4d8b957d8070f6a30a3ef7db2f31b9619220b0d696430969ea2cd972dc863c9301ea3b858319a09678c87b2d9177f5568e635" + "6c53c1b89d7ad7a42c438dc62b9515e477620e759f698a09fa75adffe698a129dc3913ba1812397e45fc8178cb1533e40975df74cc68eb3c927240f078a45f4f" ], "split_commitment": null }