Skip to content

Commit 183fac5

Browse files
committed
tapchannel: import script keys of all HTLC outputs, as known
If we don't import these script keys, spends will fail later as we didn't credit the balance, so we can't spend them.
1 parent b79b8eb commit 183fac5

File tree

1 file changed

+83
-34
lines changed

1 file changed

+83
-34
lines changed

tapchannel/aux_sweeper.go

Lines changed: 83 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,42 @@ func (a *AuxSweeper) importCommitScriptKeys(req lnwallet.ResolutionReq) error {
12511251
return nil
12521252
}
12531253

1254+
// importOutputScriptKey imports the output script key that this scriptDesc can
1255+
// spend into the local addr book.
1256+
func (a *AuxSweeper) importOutputScriptKeys(desc tapscriptSweepDescs) error {
1257+
ctxb := context.Background()
1258+
1259+
importScriptKey := func(desc tapscriptSweepDesc) error {
1260+
scriptTree := desc.scriptTree.Tree()
1261+
1262+
outputKey := asset.NewScriptKey(scriptTree.TaprootKey).PubKey
1263+
scriptKey := asset.ScriptKey{
1264+
PubKey: outputKey,
1265+
TweakedScriptKey: &asset.TweakedScriptKey{
1266+
RawKey: keychain.KeyDescriptor{
1267+
PubKey: scriptTree.InternalKey,
1268+
},
1269+
Tweak: scriptTree.TapscriptRoot,
1270+
},
1271+
}
1272+
1273+
log.Debugf("Importing script_keys=%v", spew.Sdump(scriptKey))
1274+
1275+
return a.cfg.AddrBook.InsertScriptKey(ctxb, scriptKey, true)
1276+
}
1277+
1278+
if err := importScriptKey(desc.firstLevel); err != nil {
1279+
return err
1280+
}
1281+
1282+
return lfn.MapOptionZ(
1283+
desc.secondLevel,
1284+
func(secondary tapscriptSweepDesc) error {
1285+
return importScriptKey(secondary)
1286+
},
1287+
)
1288+
}
1289+
12541290
// importOutputProofs imports the output proofs into the pending asset funding
12551291
// into our local database. This preps us to be able to detect force closes.
12561292
func importOutputProofs(scid lnwire.ShortChannelID,
@@ -1619,34 +1655,10 @@ func (a *AuxSweeper) resolveContract(
16191655
return lfn.Err[returnType](err)
16201656
}
16211657

1622-
// To be able to construct all the proofs we need to spend later, we'll
1623-
// make sure that this commitment transaction exists in our database.
1624-
// If not, then we'll complete the proof, register the script keys, and
1625-
// ship the pre-signed commitment transaction.
1626-
ctx := context.Background()
1627-
commitParcel, err := a.cfg.TxSender.QueryParcels(
1628-
ctx, fn.Some(req.CommitTx.TxHash()), false,
1629-
)
1630-
if err != nil {
1631-
return lfn.Err[returnType](err)
1632-
}
1633-
if len(commitParcel) == 0 {
1634-
log.Infof("First time seeing commit_txid=%v, importing",
1635-
req.CommitTx.TxHash())
1636-
1637-
err := a.importCommitTx(req, commitState, fundingInfo)
1638-
if err != nil {
1639-
return lfn.Errf[returnType]("unable to import "+
1640-
"commitment txn: %w", err)
1641-
}
1642-
} else {
1643-
log.Infof("Commitment commit_txid=%v already imported, "+
1644-
"skipping", req.CommitTx.TxHash())
1645-
}
1646-
16471658
var (
1648-
sweepDesc lfn.Result[tapscriptSweepDescs]
1649-
assetOutputs []*cmsg.AssetOutput
1659+
sweepDesc lfn.Result[tapscriptSweepDescs]
1660+
assetOutputs []*cmsg.AssetOutput
1661+
needsSecondLevel bool
16501662
)
16511663

16521664
switch req.Type {
@@ -1755,6 +1767,8 @@ func (a *AuxSweeper) resolveContract(
17551767
// desc.
17561768
sweepDesc = localHtlcTimeoutSweepDesc(req)
17571769

1770+
needsSecondLevel = true
1771+
17581772
// In this case, we've broadcast a commitment, with an incoming HTLC
17591773
// that we can sweep. We'll annotate the sweepDesc with the information
17601774
// needed to sweep both this output, as well as the second level
@@ -1769,26 +1783,61 @@ func (a *AuxSweeper) resolveContract(
17691783
// desc.
17701784
sweepDesc = localHtlcSucessSweepDesc(req)
17711785

1786+
needsSecondLevel = true
1787+
17721788
default:
17731789
return lfn.Errf[returnType]("unknown resolution type: %v",
17741790
req.Type)
17751791
// TODO(roasbeef): need to do HTLC revocation casesj:w
17761792
}
17771793

1794+
tapSweepDesc, err := sweepDesc.Unpack()
1795+
if err != nil {
1796+
return lfn.Err[tlv.Blob](err)
1797+
}
1798+
1799+
// Now that we know what output we're sweeping, before we proceed, we'll
1800+
// import the relevant script key to disk. This way, we'll properly
1801+
// recognize spends of it.
1802+
if err := a.importOutputScriptKeys(tapSweepDesc); err != nil {
1803+
return lfn.Errf[tlv.Blob]("unable to import output script "+
1804+
"key: %w", err)
1805+
}
1806+
1807+
// To be able to construct all the proofs we need to spend later, we'll
1808+
// make sure that this commitment transaction exists in our database. If
1809+
// not, then we'll complete the proof, register the script keys, and
1810+
// ship the pre-signed commitment transaction.
1811+
ctx := context.Background()
1812+
commitParcel, err := a.cfg.TxSender.QueryParcels(
1813+
ctx, fn.Some(req.CommitTx.TxHash()), false,
1814+
)
1815+
if err != nil {
1816+
return lfn.Err[returnType](err)
1817+
}
1818+
if len(commitParcel) == 0 {
1819+
log.Infof("First time seeing commit_txid=%v, importing",
1820+
req.CommitTx.TxHash())
1821+
1822+
err := a.importCommitTx(req, commitState, fundingInfo)
1823+
if err != nil {
1824+
return lfn.Errf[returnType]("unable to import "+
1825+
"commitment txn: %w", err)
1826+
}
1827+
} else {
1828+
log.Infof("Commitment commit_txid=%v already imported, "+
1829+
"skipping", req.CommitTx.TxHash())
1830+
}
1831+
17781832
// The input proofs above were made originally using the fake commit tx
17791833
// as an anchor. We now know the real commit tx, so we'll swap that in
17801834
// to ensure the outpoints used below are correct.
17811835
for _, assetOut := range assetOutputs {
17821836
assetOut.Proof.Val.AnchorTx = *req.CommitTx
17831837
}
17841838

1785-
log.Infof("Sweeping %v asset outputs: %v", len(assetOutputs),
1786-
limitSpewer.Sdump(assetOutputs))
1787-
1788-
tapSweepDesc, err := sweepDesc.Unpack()
1789-
if err != nil {
1790-
return lfn.Err[tlv.Blob](err)
1791-
}
1839+
log.Infof("Sweeping %v asset outputs (second_level=%v): %v",
1840+
len(assetOutputs), needsSecondLevel, spew.Sdump(assetOutputs))
17921841

17931842
// With the sweep desc constructed above, we'll create vPackets for each
17941843
// of the local assets, then sign them all.

0 commit comments

Comments
 (0)