Skip to content

Commit

Permalink
multi: add new CopySpendTemplate function
Browse files Browse the repository at this point in the history
`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.
  • Loading branch information
Roasbeef committed Aug 24, 2024
1 parent 0302f74 commit 881ecaf
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 27 deletions.
20 changes: 20 additions & 0 deletions asset/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -1831,6 +1831,26 @@ func (a *Asset) Copy() *Asset {
return &assetCopy
}

// CopySpendTemplate is similar to Copy, but should be used when wanting to
// spend an input asset in a new transaction. Compared to Copy, this method
// also blanks out some other fields that shouldn't always be carried along for
// a dependent spend.
func (a *Asset) CopySpendTemplate() *Asset {
assetCopy := a.Copy()

// We nil out the split commitment root, as we don't need to carry that
// into the next spend.
assetCopy.SplitCommitmentRoot = nil

// We'll also make sure to clear out the lock time and relative lock
// time from the input. The input at this point is already valid, so we
// don't need to inherit the time lock encumbrance.
assetCopy.RelativeLockTime = 0
assetCopy.LockTime = 0

return assetCopy
}

// DeepEqual returns true if this asset is equal with the given asset.
func (a *Asset) DeepEqual(o *Asset) bool {
return a.deepEqual(false, o)
Expand Down
22 changes: 22 additions & 0 deletions asset/asset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1194,3 +1194,25 @@ func TestNewAssetWithCustomVersion(t *testing.T) {

require.Equal(t, int(assetCustomVersion.Version), newVersion)
}

// TestCopySpendTemplate tests that the spend template is copied correctly.
func TestCopySpendTemplate(t *testing.T) {
newAsset := RandAsset(t, Normal)
newAsset.SplitCommitmentRoot = mssmt.NewComputedNode(hashBytes1, 1337)
newAsset.RelativeLockTime = 1
newAsset.LockTime = 2

// The template should have the relevant set of fields blanked.
spendTemplate := newAsset.CopySpendTemplate()
require.Zero(t, spendTemplate.SplitCommitmentRoot)
require.Zero(t, spendTemplate.RelativeLockTime)
require.Zero(t, spendTemplate.LockTime)

// If blank these fields of the OG asset, then things should be
// identical.
newAsset.SplitCommitmentRoot = nil
newAsset.RelativeLockTime = 0
newAsset.LockTime = 0

require.True(t, newAsset.DeepEqual(spendTemplate))
}
9 changes: 1 addition & 8 deletions commitment/split.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func NewSplitCommitment(ctx context.Context, inputs []SplitCommitmentInput,
remainingAmount := totalInputAmount
rootIdx := len(locators) - 1
addAssetSplit := func(locator *SplitLocator) error {
assetSplit := inputs[0].Asset.Copy()
assetSplit := inputs[0].Asset.CopySpendTemplate()
assetSplit.Amount = locator.Amount
assetSplit.Version = locator.AssetVersion

Expand All @@ -208,13 +208,6 @@ func NewSplitCommitment(ctx context.Context, inputs []SplitCommitmentInput,
TxWitness: nil,
SplitCommitment: nil,
}}
assetSplit.SplitCommitmentRoot = nil

// We'll also make sure to clear out the lock time and relative
// lock time from the input. The input at this point is already
// valid, so we don't need to inherit the time lock encumbrance.
assetSplit.RelativeLockTime = 0
assetSplit.LockTime = 0

splitAssets[*locator] = &SplitAsset{
Asset: *assetSplit,
Expand Down
17 changes: 8 additions & 9 deletions proof/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,21 +375,20 @@ func CreateOwnershipProofAsset(ownedAsset *asset.Asset,
),
}

outputAsset := ownedAsset.Copy()
outputAsset.ScriptKey = address.GenChallengeNUMS(challengeBytes)
outputAsset.PrevWitnesses = []asset.Witness{{
PrevID: &prevId,
}}

// The ownership proof needs to be a 1-in-1-out transaction. So it will
// definitely not have a split commitment. Keeping the split commitment
// of the copied owned asset would lead to an issue with the
// non-inflation check we have in the VM that takes the split commitment
// root sum as the expected total output amount. We also clear any time
// locks, as they don't apply to the ownership proof.
outputAsset.SplitCommitmentRoot = nil
outputAsset.LockTime = 0
outputAsset.RelativeLockTime = 0
//
// This is handled by CopySpendTemplate.
outputAsset := ownedAsset.CopySpendTemplate()

outputAsset.ScriptKey = address.GenChallengeNUMS(challengeBytes)
outputAsset.PrevWitnesses = []asset.Witness{{
PrevID: &prevId,
}}

return prevId, outputAsset
}
Expand Down
11 changes: 1 addition & 10 deletions tapfreighter/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,16 +309,7 @@ func createPassivePacket(params *address.ChainParams, passiveAsset *asset.Asset,
}

// Specify virtual output.
outputAsset := passiveAsset.Copy()

// Clear the split commitment root, as we'll be transferring the whole
// asset.
outputAsset.SplitCommitmentRoot = nil

// If this was previously a time locked asset, it's now a simple asset.
// So we need to clear out the time locks as well.
outputAsset.LockTime = 0
outputAsset.RelativeLockTime = 0
outputAsset := passiveAsset.CopySpendTemplate()

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

0 comments on commit 881ecaf

Please sign in to comment.