Skip to content

Commit 881ecaf

Browse files
committed
multi: add new CopySpendTemplate function
`CopySpendTemplate` is similar to `Copy` but sheds some fields that don't need to be carried along when making a copy of an input to spend. This includes the split commitment root, and time lock information.
1 parent 0302f74 commit 881ecaf

File tree

5 files changed

+52
-27
lines changed

5 files changed

+52
-27
lines changed

asset/asset.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,6 +1831,26 @@ func (a *Asset) Copy() *Asset {
18311831
return &assetCopy
18321832
}
18331833

1834+
// CopySpendTemplate is similar to Copy, but should be used when wanting to
1835+
// spend an input asset in a new transaction. Compared to Copy, this method
1836+
// also blanks out some other fields that shouldn't always be carried along for
1837+
// a dependent spend.
1838+
func (a *Asset) CopySpendTemplate() *Asset {
1839+
assetCopy := a.Copy()
1840+
1841+
// We nil out the split commitment root, as we don't need to carry that
1842+
// into the next spend.
1843+
assetCopy.SplitCommitmentRoot = nil
1844+
1845+
// We'll also make sure to clear out the lock time and relative lock
1846+
// time from the input. The input at this point is already valid, so we
1847+
// don't need to inherit the time lock encumbrance.
1848+
assetCopy.RelativeLockTime = 0
1849+
assetCopy.LockTime = 0
1850+
1851+
return assetCopy
1852+
}
1853+
18341854
// DeepEqual returns true if this asset is equal with the given asset.
18351855
func (a *Asset) DeepEqual(o *Asset) bool {
18361856
return a.deepEqual(false, o)

asset/asset_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,3 +1194,25 @@ func TestNewAssetWithCustomVersion(t *testing.T) {
11941194

11951195
require.Equal(t, int(assetCustomVersion.Version), newVersion)
11961196
}
1197+
1198+
// TestCopySpendTemplate tests that the spend template is copied correctly.
1199+
func TestCopySpendTemplate(t *testing.T) {
1200+
newAsset := RandAsset(t, Normal)
1201+
newAsset.SplitCommitmentRoot = mssmt.NewComputedNode(hashBytes1, 1337)
1202+
newAsset.RelativeLockTime = 1
1203+
newAsset.LockTime = 2
1204+
1205+
// The template should have the relevant set of fields blanked.
1206+
spendTemplate := newAsset.CopySpendTemplate()
1207+
require.Zero(t, spendTemplate.SplitCommitmentRoot)
1208+
require.Zero(t, spendTemplate.RelativeLockTime)
1209+
require.Zero(t, spendTemplate.LockTime)
1210+
1211+
// If blank these fields of the OG asset, then things should be
1212+
// identical.
1213+
newAsset.SplitCommitmentRoot = nil
1214+
newAsset.RelativeLockTime = 0
1215+
newAsset.LockTime = 0
1216+
1217+
require.True(t, newAsset.DeepEqual(spendTemplate))
1218+
}

commitment/split.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func NewSplitCommitment(ctx context.Context, inputs []SplitCommitmentInput,
194194
remainingAmount := totalInputAmount
195195
rootIdx := len(locators) - 1
196196
addAssetSplit := func(locator *SplitLocator) error {
197-
assetSplit := inputs[0].Asset.Copy()
197+
assetSplit := inputs[0].Asset.CopySpendTemplate()
198198
assetSplit.Amount = locator.Amount
199199
assetSplit.Version = locator.AssetVersion
200200

@@ -208,13 +208,6 @@ func NewSplitCommitment(ctx context.Context, inputs []SplitCommitmentInput,
208208
TxWitness: nil,
209209
SplitCommitment: nil,
210210
}}
211-
assetSplit.SplitCommitmentRoot = nil
212-
213-
// We'll also make sure to clear out the lock time and relative
214-
// lock time from the input. The input at this point is already
215-
// valid, so we don't need to inherit the time lock encumbrance.
216-
assetSplit.RelativeLockTime = 0
217-
assetSplit.LockTime = 0
218211

219212
splitAssets[*locator] = &SplitAsset{
220213
Asset: *assetSplit,

proof/verifier.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -375,21 +375,20 @@ func CreateOwnershipProofAsset(ownedAsset *asset.Asset,
375375
),
376376
}
377377

378-
outputAsset := ownedAsset.Copy()
379-
outputAsset.ScriptKey = address.GenChallengeNUMS(challengeBytes)
380-
outputAsset.PrevWitnesses = []asset.Witness{{
381-
PrevID: &prevId,
382-
}}
383-
384378
// The ownership proof needs to be a 1-in-1-out transaction. So it will
385379
// definitely not have a split commitment. Keeping the split commitment
386380
// of the copied owned asset would lead to an issue with the
387381
// non-inflation check we have in the VM that takes the split commitment
388382
// root sum as the expected total output amount. We also clear any time
389383
// locks, as they don't apply to the ownership proof.
390-
outputAsset.SplitCommitmentRoot = nil
391-
outputAsset.LockTime = 0
392-
outputAsset.RelativeLockTime = 0
384+
//
385+
// This is handled by CopySpendTemplate.
386+
outputAsset := ownedAsset.CopySpendTemplate()
387+
388+
outputAsset.ScriptKey = address.GenChallengeNUMS(challengeBytes)
389+
outputAsset.PrevWitnesses = []asset.Witness{{
390+
PrevID: &prevId,
391+
}}
393392

394393
return prevId, outputAsset
395394
}

tapfreighter/wallet.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -309,16 +309,7 @@ func createPassivePacket(params *address.ChainParams, passiveAsset *asset.Asset,
309309
}
310310

311311
// Specify virtual output.
312-
outputAsset := passiveAsset.Copy()
313-
314-
// Clear the split commitment root, as we'll be transferring the whole
315-
// asset.
316-
outputAsset.SplitCommitmentRoot = nil
317-
318-
// If this was previously a time locked asset, it's now a simple asset.
319-
// So we need to clear out the time locks as well.
320-
outputAsset.LockTime = 0
321-
outputAsset.RelativeLockTime = 0
312+
outputAsset := passiveAsset.CopySpendTemplate()
322313

323314
// Clear the output asset witness data. We'll be creating a new witness.
324315
outputAsset.PrevWitnesses = []asset.Witness{{

0 commit comments

Comments
 (0)