Skip to content

Commit 46d79f5

Browse files
committed
sweeptimelock: refactor as preparation for next feature
1 parent 2d1c83c commit 46d79f5

File tree

2 files changed

+93
-36
lines changed

2 files changed

+93
-36
lines changed

cmd/chantools/sweeptimelock.go

Lines changed: 76 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/guggero/chantools/dataformat"
1515
"github.com/guggero/chantools/lnd"
1616
"github.com/lightningnetwork/lnd/input"
17+
"github.com/lightningnetwork/lnd/keychain"
1718
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
1819
"github.com/spf13/cobra"
1920
)
@@ -104,28 +105,28 @@ func (c *sweepTimeLockCommand) Execute(_ *cobra.Command, _ []string) error {
104105
if c.FeeRate == 0 {
105106
c.FeeRate = defaultFeeSatPerVByte
106107
}
107-
return sweepTimeLock(
108+
return sweepTimeLockFromSummary(
108109
extendedKey, c.APIURL, entries, c.SweepAddr, c.MaxCsvLimit,
109110
c.Publish, c.FeeRate,
110111
)
111112
}
112113

113-
func sweepTimeLock(extendedKey *hdkeychain.ExtendedKey, apiURL string,
114+
type sweepTarget struct {
115+
channelPoint string
116+
txid chainhash.Hash
117+
index uint32
118+
lockScript []byte
119+
value int64
120+
commitPoint *btcec.PublicKey
121+
revocationBasePoint *btcec.PublicKey
122+
delayBasePointDesc *keychain.KeyDescriptor
123+
}
124+
125+
func sweepTimeLockFromSummary(extendedKey *hdkeychain.ExtendedKey, apiURL string,
114126
entries []*dataformat.SummaryEntry, sweepAddr string,
115127
maxCsvTimeout uint16, publish bool, feeRate uint16) error {
116128

117-
// Create signer and transaction template.
118-
signer := &lnd.Signer{
119-
ExtendedKey: extendedKey,
120-
ChainParams: chainParams,
121-
}
122-
api := &btc.ExplorerAPI{BaseURL: apiURL}
123-
124-
sweepTx := wire.NewMsgTx(2)
125-
totalOutputValue := int64(0)
126-
signDescs := make([]*input.SignDescriptor, 0)
127-
var estimator input.TxWeightEstimator
128-
129+
targets := make([]*sweepTarget, 0, len(entries))
129130
for _, entry := range entries {
130131
// Skip entries that can't be swept.
131132
if entry.ForceClose == nil ||
@@ -169,44 +170,84 @@ func sweepTimeLock(extendedKey *hdkeychain.ExtendedKey, apiURL string,
169170
}
170171
revBase, err := pubKeyFromHex(fc.RevocationBasePoint.PubKey)
171172
if err != nil {
172-
return fmt.Errorf("error parsing commit point: %v", err)
173+
return fmt.Errorf("error parsing revocation base "+
174+
"point: %v", err)
173175
}
174-
delayDesc := fc.DelayBasePoint.Desc()
175-
delayPrivKey, err := signer.FetchPrivKey(delayDesc)
176+
delayDesc, err := fc.DelayBasePoint.Desc()
176177
if err != nil {
177-
return fmt.Errorf("error getting private key: %v", err)
178+
return fmt.Errorf("error parsing delay base point: %v",
179+
err)
178180
}
179-
delayBase := delayPrivKey.PubKey()
180181

181182
lockScript, err := hex.DecodeString(fc.Outs[txindex].Script)
182183
if err != nil {
183184
return fmt.Errorf("error parsing target script: %v",
184185
err)
185186
}
186187

188+
// Create the transaction input.
189+
txHash, err := chainhash.NewHashFromStr(fc.TXID)
190+
if err != nil {
191+
return fmt.Errorf("error parsing tx hash: %v", err)
192+
}
193+
194+
targets = append(targets, &sweepTarget{
195+
channelPoint: entry.ChannelPoint,
196+
txid: *txHash,
197+
index: uint32(txindex),
198+
lockScript: lockScript,
199+
value: int64(fc.Outs[txindex].Value),
200+
commitPoint: commitPoint,
201+
revocationBasePoint: revBase,
202+
delayBasePointDesc: delayDesc,
203+
})
204+
}
205+
206+
return sweepTimeLock(
207+
extendedKey, apiURL, targets, sweepAddr, maxCsvTimeout, publish,
208+
feeRate,
209+
)
210+
}
211+
212+
func sweepTimeLock(extendedKey *hdkeychain.ExtendedKey, apiURL string,
213+
targets []*sweepTarget, sweepAddr string, maxCsvTimeout uint16,
214+
publish bool, feeRate uint16) error {
215+
216+
// Create signer and transaction template.
217+
signer := &lnd.Signer{
218+
ExtendedKey: extendedKey,
219+
ChainParams: chainParams,
220+
}
221+
api := &btc.ExplorerAPI{BaseURL: apiURL}
222+
223+
sweepTx := wire.NewMsgTx(2)
224+
totalOutputValue := int64(0)
225+
signDescs := make([]*input.SignDescriptor, 0)
226+
var estimator input.TxWeightEstimator
227+
228+
for _, target := range targets {
187229
// We can't rely on the CSV delay of the channel DB to be
188230
// correct. But it doesn't cost us a lot to just brute force it.
189231
csvTimeout, script, scriptHash, err := bruteForceDelay(
190-
input.TweakPubKey(delayBase, commitPoint),
191-
input.DeriveRevocationPubkey(revBase, commitPoint),
192-
lockScript, maxCsvTimeout,
232+
input.TweakPubKey(
233+
target.delayBasePointDesc.PubKey,
234+
target.commitPoint,
235+
), input.DeriveRevocationPubkey(
236+
target.revocationBasePoint,
237+
target.commitPoint,
238+
), target.lockScript, maxCsvTimeout,
193239
)
194240
if err != nil {
195241
log.Errorf("Could not create matching script for %s "+
196-
"or csv too high: %v", entry.ChannelPoint,
197-
err)
242+
"or csv too high: %v", target.channelPoint, err)
198243
continue
199244
}
200245

201246
// Create the transaction input.
202-
txHash, err := chainhash.NewHashFromStr(fc.TXID)
203-
if err != nil {
204-
return fmt.Errorf("error parsing tx hash: %v", err)
205-
}
206247
sweepTx.TxIn = append(sweepTx.TxIn, &wire.TxIn{
207248
PreviousOutPoint: wire.OutPoint{
208-
Hash: *txHash,
209-
Index: uint32(txindex),
249+
Hash: target.txid,
250+
Index: target.index,
210251
},
211252
Sequence: input.LockTimeToSequence(
212253
false, uint32(csvTimeout),
@@ -215,18 +256,19 @@ func sweepTimeLock(extendedKey *hdkeychain.ExtendedKey, apiURL string,
215256

216257
// Create the sign descriptor for the input.
217258
signDesc := &input.SignDescriptor{
218-
KeyDesc: *delayDesc,
259+
KeyDesc: *target.delayBasePointDesc,
219260
SingleTweak: input.SingleTweakBytes(
220-
commitPoint, delayBase,
261+
target.commitPoint,
262+
target.delayBasePointDesc.PubKey,
221263
),
222264
WitnessScript: script,
223265
Output: &wire.TxOut{
224266
PkScript: scriptHash,
225-
Value: int64(fc.Outs[txindex].Value),
267+
Value: target.value,
226268
},
227269
HashType: txscript.SigHashAll,
228270
}
229-
totalOutputValue += int64(fc.Outs[txindex].Value)
271+
totalOutputValue += target.value
230272
signDescs = append(signDescs, signDesc)
231273

232274
// Account for the input weight.

dataformat/summary.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package dataformat
22

33
import (
4+
"encoding/hex"
5+
"fmt"
6+
"github.com/btcsuite/btcd/btcec"
47
"github.com/lightningnetwork/lnd/keychain"
58
)
69

@@ -20,13 +23,25 @@ type BasePoint struct {
2023
PubKey string `json:"pubkey"`
2124
}
2225

23-
func (b *BasePoint) Desc() *keychain.KeyDescriptor {
26+
func (b *BasePoint) Desc() (*keychain.KeyDescriptor, error) {
27+
pubKeyHex, err := hex.DecodeString(b.PubKey)
28+
if err != nil {
29+
return nil, fmt.Errorf("error decoding base point pubkey: %v",
30+
err)
31+
}
32+
pubKey, err := btcec.ParsePubKey(pubKeyHex, btcec.S256())
33+
if err != nil {
34+
return nil, fmt.Errorf("error parsing base point pubkey: %v",
35+
err)
36+
}
37+
2438
return &keychain.KeyDescriptor{
2539
KeyLocator: keychain.KeyLocator{
2640
Family: keychain.KeyFamily(b.Family),
2741
Index: b.Index,
2842
},
29-
}
43+
PubKey: pubKey,
44+
}, nil
3045
}
3146

3247
type Out struct {

0 commit comments

Comments
 (0)