Skip to content

Commit 317559c

Browse files
Roasbeefguggero
authored andcommitted
multi: copied assets shouldn't inherit locktime from inputs
In this commit, we fix an existing bug related to lock times and split commitments. Before this commit, if an input had a relative lock time, then when we went to make the new split assets, we would _copy_ that value into the split. This isn't correct as the input is valid/confirmed, so we don't need to copy over the lock time information. The prior behavior would cause certain classes of spends to fail, as we would be validating a new root asset that has no lock time, but the root asset split inserted into the split commitment would be carrying the old lock time. When verifying the split, we would set the lock times of the split to that of the new asset: https://github.com/lightninglabs/taproot-assets/blob/e893dee87e9d8f0de53b8ee9e2527add80df6491/vm/vm.go#L305-L307. As we copied over the lock time from the input, we would now effectively invalid the split commitment. Fixes #1099
1 parent 8eb6c53 commit 317559c

File tree

4 files changed

+57
-1
lines changed

4 files changed

+57
-1
lines changed

commitment/commitment_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,43 @@ func TestSplitCommitment(t *testing.T) {
656656
},
657657
err: nil,
658658
},
659+
{
660+
name: "single input split commitment lock time input",
661+
f: func() (*asset.Asset, *SplitLocator,
662+
[]*SplitLocator) {
663+
664+
input := randAsset(
665+
t, genesisNormal, groupKeyNormal,
666+
)
667+
input.Amount = 3
668+
input.RelativeLockTime = 1
669+
input.LockTime = 1
670+
671+
root := &SplitLocator{
672+
OutputIndex: 0,
673+
AssetID: genesisNormal.ID(),
674+
ScriptKey: asset.ToSerialized(
675+
input.ScriptKey.PubKey,
676+
),
677+
Amount: 1,
678+
}
679+
external := []*SplitLocator{{
680+
OutputIndex: 1,
681+
AssetID: genesisNormal.ID(),
682+
ScriptKey: asset.RandSerializedKey(t),
683+
Amount: 1,
684+
}, {
685+
686+
OutputIndex: 2,
687+
AssetID: genesisNormal.ID(),
688+
ScriptKey: asset.RandSerializedKey(t),
689+
Amount: 1,
690+
}}
691+
692+
return input, root, external
693+
},
694+
err: nil,
695+
},
659696
{
660697
name: "no external splits",
661698
f: func() (*asset.Asset, *SplitLocator, []*SplitLocator) {
@@ -871,6 +908,11 @@ func TestSplitCommitment(t *testing.T) {
871908
require.Contains(t, split.SplitAssets, *l)
872909
splitAsset := split.SplitAssets[*l]
873910

911+
// Make sure that the splits don't inherit lock
912+
// time information from the root asset.
913+
require.Zero(t, splitAsset.LockTime)
914+
require.Zero(t, splitAsset.RelativeLockTime)
915+
874916
// If this is a leaf split, then we need to
875917
// ensure that the prev ID is zero.
876918
if splitAsset.SplitCommitmentRoot == nil {

commitment/split.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ func NewSplitCommitment(ctx context.Context, inputs []SplitCommitmentInput,
210210
}}
211211
assetSplit.SplitCommitmentRoot = nil
212212

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
218+
213219
splitAssets[*locator] = &SplitAsset{
214220
Asset: *assetSplit,
215221
OutputIndex: locator.OutputIndex,

proof/verifier.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,8 +385,11 @@ func CreateOwnershipProofAsset(ownedAsset *asset.Asset,
385385
// definitely not have a split commitment. Keeping the split commitment
386386
// of the copied owned asset would lead to an issue with the
387387
// non-inflation check we have in the VM that takes the split commitment
388-
// root sum as the expected total output amount.
388+
// root sum as the expected total output amount. We also clear any time
389+
// locks, as they don't apply to the ownership proof.
389390
outputAsset.SplitCommitmentRoot = nil
391+
outputAsset.LockTime = 0
392+
outputAsset.RelativeLockTime = 0
390393

391394
return prevId, outputAsset
392395
}

tapfreighter/wallet.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,11 @@ func createPassivePacket(params *address.ChainParams, passiveAsset *asset.Asset,
315315
// asset.
316316
outputAsset.SplitCommitmentRoot = nil
317317

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
322+
318323
// Clear the output asset witness data. We'll be creating a new witness.
319324
outputAsset.PrevWitnesses = []asset.Witness{{
320325
PrevID: &vInput.PrevID,

0 commit comments

Comments
 (0)