@@ -460,6 +460,20 @@ type vPktsWithInput struct {
460460 tapSigDesc lfn.Option [cmsg.TapscriptSigDesc ]
461461}
462462
463+ // isPresigned returns true if the vPktsWithInput is presigned. This will be the
464+ // for an HTLC spent directly from our local commitment transaction.
465+ func (v vPktsWithInput ) isPresigned () bool {
466+ witType := v .btcInput .WitnessType ()
467+ switch witType {
468+ case input .TaprootHtlcAcceptedLocalSuccess :
469+ return true
470+ case input .TaprootHtlcLocalOfferedTimeout :
471+ return true
472+ default :
473+ return false
474+ }
475+ }
476+
463477// sweepVpkts contains the set of vPkts needed for sweeping an output. Most
464478// outputs will only have the first level specified. The second level is needed
465479// for HTLC outputs on our local commitment transaction.
@@ -501,6 +515,27 @@ func (s sweepVpkts) allPkts() []*tappsbt.VPacket {
501515 return append (s .firstLevelPkts (), s .secondLevelPkts ()... )
502516}
503517
518+ // allVpktsWithInput returns a slice of all vPktsWithInput.
519+ func (s sweepVpkts ) allVpktsWithInput () []vPktsWithInput {
520+ return append (s .firstLevel , s .secondLevel ... )
521+ }
522+
523+ // directSpendPkts returns the slice of all vPkts that are a direct spend from
524+ // the commitment transaction. This excludes vPkts that are the pre-signed 2nd
525+ // level transaction variant.
526+ func (s sweepVpkts ) directSpendPkts () []* tappsbt.VPacket {
527+ directSpends := lfn .Filter (func (vi vPktsWithInput ) bool {
528+ return ! vi .isPresigned ()
529+ }, s .allVpktsWithInput ())
530+ directPkts := fn .FlatMap (
531+ directSpends , func (v vPktsWithInput ) []* tappsbt.VPacket {
532+ return v .vPkts
533+ },
534+ )
535+
536+ return directPkts
537+ }
538+
504539// createAndSignSweepVpackets creates vPackets that sweep the funds from the
505540// channel to the wallet, and then signs them as well.
506541func (a * AuxSweeper ) createAndSignSweepVpackets (
@@ -1177,6 +1212,7 @@ func deriveCommitKeys(req lnwallet.ResolutionReq) (*asset.ScriptKey,
11771212// importCommitScriptKeys imports the script keys for the commitment outputs
11781213// into the local addr book.
11791214func (a * AuxSweeper ) importCommitScriptKeys (req lnwallet.ResolutionReq ) error {
1215+
11801216 // Generate the local and remote script key, so we can properly import
11811217 // into the addr book, like we did above.
11821218 localCommitScriptKey , remoteCommitScriptKey , err := deriveCommitKeys (
@@ -1815,44 +1851,68 @@ func (a *AuxSweeper) resolveContract(
18151851 return lfn.Err [tlv.Blob ](err )
18161852 }
18171853
1818- // We can't yet make the second level proof as we don't know exactly
1819- // what the final txid of the sweep transaction will be. So we'll use a
1820- // blank proof in place.
1821- //
1822- // TODO(roasbeef): need to set internal key? already known
1823- var proof proof.Proof
1824-
1825- // We'll make a place holder for the second level output based on the
1826- // assetID+value tuple.
1827- secondLevelInputs := []* cmsg.AssetOutput {cmsg .NewAssetOutput (
1828- assetOutputs [0 ].AssetID .Val , assetOutputs [0 ].Amount .Val , proof ,
1829- )}
1830-
1831- // Unlike the first level packets, we can't yet sign the second level
1832- // packets yet, as we don't know what the sweeping transaction will look
1833- // like. So we'll just create them.
1834- secondLevelPkts , err := lfn .MapOption (
1835- func (desc tapscriptSweepDesc ) lfn.Result [[]* tappsbt.VPacket ] {
1836- return a .createSweepVpackets (
1837- secondLevelInputs , lfn .Ok (desc ), req ,
1838- )
1839- },
1840- )(tapSweepDesc .secondLevel ).UnwrapOr (
1841- lfn.Ok [[]* tappsbt.VPacket ](nil ),
1842- ).Unpack ()
1843- if err != nil {
1844- return lfn.Err [tlv.Blob ](err )
1845- }
1854+ var (
1855+ secondLevelPkts []* tappsbt.VPacket
1856+ secondLevelSigDesc lfn.Option [cmsg.TapscriptSigDesc ]
1857+ )
18461858
1847- // With the vPackets fully generated and signed above, we'll serialize
1848- // it into a resolution blob to return.
1849- secondLevelSigDesc := lfn .MapOption (
1850- func (d tapscriptSweepDesc ) cmsg.TapscriptSigDesc {
1851- return cmsg .NewTapscriptSigDesc (
1852- d .scriptTree .TapTweak (), d .ctrlBlockBytes ,
1853- )
1854- },
1855- )(tapSweepDesc .secondLevel )
1859+ // We'll only need a set of second level packets if we're sweeping a set
1860+ // of HTLC outputs on the local party's commitment transaction.
1861+ if needsSecondLevel {
1862+ log .Infof ("Creating+signing 2nd level vPkts" )
1863+
1864+ // We'll make a place holder for the second level output based
1865+ // on the assetID+value tuple.
1866+ secondLevelInputs := []* cmsg.AssetOutput {cmsg .NewAssetOutput (
1867+ assetOutputs [0 ].AssetID .Val ,
1868+ assetOutputs [0 ].Amount .Val , assetOutputs [0 ].Proof .Val ,
1869+ )}
1870+
1871+ // Unlike the first level packets, we can't yet sign the second
1872+ // level packets yet, as we don't know what the sweeping
1873+ // transaction will look like. So we'll just create them.
1874+ secondLevelPkts , err = lfn .MapOption (
1875+ func (desc tapscriptSweepDesc ) lfn.Result [[]* tappsbt.VPacket ] {
1876+ return a .createSweepVpackets (
1877+ secondLevelInputs , lfn .Ok (desc ), req ,
1878+ )
1879+ },
1880+ )(tapSweepDesc .secondLevel ).UnwrapOr (
1881+ lfn.Ok [[]* tappsbt.VPacket ](nil ),
1882+ ).Unpack ()
1883+ if err != nil {
1884+ return lfn .Errf [tlv.Blob ]("unable to make " +
1885+ "second level pkts: %w" , err )
1886+ }
1887+
1888+ // We'll update some of the details of the 2nd level pkt based
1889+ // on the first lvl packet created above (as we don't yet have
1890+ // the full proof for the first lvl packet above).
1891+ for pktIdx , vPkt := range secondLevelPkts {
1892+ prevAsset := firstLevelPkts [pktIdx ].Outputs [0 ].Asset
1893+
1894+ for inputIdx , vIn := range vPkt .Inputs {
1895+ //nolint:lll
1896+ prevScriptKey := prevAsset .ScriptKey
1897+ vIn .PrevID .ScriptKey = asset .ToSerialized (
1898+ prevScriptKey .PubKey ,
1899+ )
1900+
1901+ vPkt .SetInputAsset (inputIdx , prevAsset )
1902+ }
1903+ }
1904+
1905+ // With the vPackets fully generated and signed above, we'll
1906+ // serialize it into a resolution blob to return.
1907+ secondLevelSigDesc = lfn .MapOption (
1908+ func (d tapscriptSweepDesc ) cmsg.TapscriptSigDesc {
1909+ return cmsg .NewTapscriptSigDesc (
1910+ d .scriptTree .TapTweak (),
1911+ d .ctrlBlockBytes ,
1912+ )
1913+ },
1914+ )(tapSweepDesc .secondLevel )
1915+ }
18561916
18571917 res := cmsg .NewContractResolution (
18581918 firstLevelPkts , secondLevelPkts , secondLevelSigDesc ,
0 commit comments