Skip to content

Commit f35a469

Browse files
authored
Merge pull request #63 from ziggie1984/sweep-tolocal-bugfix
Minor Bugfixes and new sweeptimelockmanual logic
2 parents 298a278 + f56f426 commit f35a469

File tree

3 files changed

+97
-16
lines changed

3 files changed

+97
-16
lines changed

cmd/chantools/sweeptimelockmanual.go

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,8 @@ func tryKey(baseKey *hdkeychain.ExtendedKey, remoteRevPoint *btcec.PublicKey,
317317

318318
// Get the revocation base point first, so we can calculate our
319319
// commit point. We start with the old way where the revocation index
320-
// was the same as the other indices.
320+
// was the same as the other indices. This applies to all channels
321+
// opened with versions prior to and including lnd v0.12.0-beta.
321322
revPath := []uint32{
322323
lnd.HardenedKey(uint32(
323324
keychain.KeyFamilyRevocationRoot,
@@ -346,21 +347,56 @@ func tryKey(baseKey *hdkeychain.ExtendedKey, remoteRevPoint *btcec.PublicKey,
346347
}, nil
347348
}
348349

349-
// Now let's try with the new format where the index is one larger than
350-
// the other indices.
351-
revPath = []uint32{
350+
// We could not derive the secrets to sweep the to_local output using
351+
// the old shachain root creation. Starting with lnd release
352+
// v0.13.0-beta the index for the revocation path creating the shachain
353+
// root changed. Now the shachain root is created using ECDH
354+
// with the local multisig public key
355+
// (for mainnet: m/1017'/0'/1'/0/idx). But we need to account for a
356+
// special case here. If the node was started with a version prior to
357+
// and including v0.12.0-beta the idx for the new shachain root
358+
// revocation is not one larger because idx 0 was already used for the
359+
// old creation scheme hence we need to replicate this behaviour here.
360+
// First trying the shachain root creation with the same index and if
361+
// this does not derive the secrets we increase the index of the
362+
// revocation key path by one (for mainnet: m/1017'/0'/5'/0/idx+1).
363+
// The exact path which was used for the shachain root can be seen
364+
// in the channel.backup file for every specific channel. The old
365+
// scheme has always a public key specified.The new one uses a key
366+
// locator and does not have a public key specified (nil).
367+
// Example
368+
// ShaChainRootDesc: (dump.KeyDescriptor) {
369+
// Path: (string) (len=17) "m/1017'/1'/5'/0/1",
370+
// PubKey: (string) (len=5) "<nil>"
371+
//
372+
// For more details:
373+
// https://github.com/lightningnetwork/lnd/commit/bb84f0ebc88620050dec7cf4be6283f5cba8b920
374+
//
375+
// Now the new shachain root revocation scheme is tried with
376+
// two different indicies as described above.
377+
revPath2 := []uint32{
352378
lnd.HardenedKey(uint32(
353379
keychain.KeyFamilyRevocationRoot,
354-
)), 0, idx + 1,
380+
)), 0, idx,
381+
}
382+
383+
// Now we try the same with the new revocation producer format.
384+
multiSigPath := []uint32{
385+
lnd.HardenedKey(uint32(keychain.KeyFamilyMultiSig)),
386+
0, idx,
355387
}
356-
revRoot2, err := lnd.ShaChainFromPath(baseKey, revPath, nil)
388+
multiSigPrivKey, err := lnd.PrivKeyFromPath(baseKey, multiSigPath)
389+
if err != nil {
390+
return 0, nil, nil, nil, nil, err
391+
}
392+
393+
revRoot2, err := lnd.ShaChainFromPath(
394+
baseKey, revPath2, multiSigPrivKey.PubKey(),
395+
)
357396
if err != nil {
358397
return 0, nil, nil, nil, nil, err
359398
}
360399

361-
// We now have everything to brute force the lock script. This
362-
// will take a long while as we both have to go through commit
363-
// points and CSV values.
364400
csvTimeout, script, scriptHash, commitPoint, err = bruteForceDelayPoint(
365401
delayPrivKey.PubKey(), remoteRevPoint, revRoot2, lockScript,
366402
maxCsvTimeout, maxNumChanUpdates,
@@ -376,18 +412,27 @@ func tryKey(baseKey *hdkeychain.ExtendedKey, remoteRevPoint *btcec.PublicKey,
376412
}, nil
377413
}
378414

415+
// Now we try to increase the index by 1 to account for the situation
416+
// where the node was started with a version after (including)
417+
// v0.13.0-beta
418+
revPath3 := []uint32{
419+
lnd.HardenedKey(uint32(
420+
keychain.KeyFamilyRevocationRoot,
421+
)), 0, idx + 1,
422+
}
423+
379424
// Now we try the same with the new revocation producer format.
380-
multiSigPath := []uint32{
425+
multiSigPath = []uint32{
381426
lnd.HardenedKey(uint32(keychain.KeyFamilyMultiSig)),
382427
0, idx,
383428
}
384-
multiSigPrivKey, err := lnd.PrivKeyFromPath(baseKey, multiSigPath)
429+
multiSigPrivKey, err = lnd.PrivKeyFromPath(baseKey, multiSigPath)
385430
if err != nil {
386431
return 0, nil, nil, nil, nil, err
387432
}
388433

389434
revRoot3, err := lnd.ShaChainFromPath(
390-
baseKey, revPath, multiSigPrivKey.PubKey(),
435+
baseKey, revPath3, multiSigPrivKey.PubKey(),
391436
)
392437
if err != nil {
393438
return 0, nil, nil, nil, nil, err

cmd/chantools/sweeptimelockmanual_test.go

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,50 @@ var sweepTimeLockManualCases = []struct {
2323
keyIndex: 7,
2424
timeLockAddr: "bcrt1qf9zv4qtxh27c954rhlzg4tx58xh0vgssuu0csrlep0jdnv" +
2525
"lx9xesmcl5qx",
26-
remoteRevPubKey: "03235261ed5aaaf9fec0e91d5e1a4d17f1a2c7442f1c43806d32" +
27-
"c9bd34abd002a3",
26+
remoteRevPubKey: "03235261ed5aaaf9fec0e91d5e1a4d17f1a2c7442f1c43806d" +
27+
"32c9bd34abd002a3",
2828
}, {
2929
// Old format with plain private key as revocation root.
3030
baseKey: "tprv8dgoXnQWBN4CGGceRYMW495kWcrUZKZVFwMmbzpduFp1D4pi" +
3131
"3B2t37zTG5Fx66XWPDQYi3Q5vqDgmmZ5ffrqZ9H4s2EhJu9WaJjY3SKaWDK",
3232
keyIndex: 6,
3333
timeLockAddr: "bcrt1qa5rrlswxefc870k7rsza5hhqd37uytczldjk5t0vzd95u9" +
3434
"hs8xlsfdc3zf",
35-
remoteRevPubKey: "03e82cdf164ce5aba253890e066129f134ca8d7e072ce5ad55c7" +
36-
"21b9a13545ee04",
35+
remoteRevPubKey: "03e82cdf164ce5aba253890e066129f134ca8d7e072ce5ad55" +
36+
"c721b9a13545ee04",
37+
}, {
38+
// New format with ECDH revocation root.
39+
baseKey: "tprv8fCiPGhoYhWESQg3kgubCizcHo21drnP9Fa5j9fFKCmbME" +
40+
"ipgodofyXcf4NFhD4k55GM1Ym3JUUDonpEXcsjnyTDUMmkzMK9pCnGPH3NJ5i",
41+
keyIndex: 0,
42+
timeLockAddr: "bcrt1qmkyn0tqx6mpg5aujgjhzaw27rvvymdfc3xhgawp48zy8v" +
43+
"3rlw45qzmjqrr",
44+
remoteRevPubKey: "02dfecdc259a7e1cff36a67328ded3b4dae30369a3035e4f91" +
45+
"1ce7ac4a80b28e5d",
46+
}, {
47+
// Old format with plain private key as revocation root. Test data
48+
// created with lnd v0.12.0-beta (old shachain root creation)
49+
baseKey: "tprv8e3Mee42NcUd2MbwxBCJyEEhvKa8KqjiDR76M7ym4DJSfZk" +
50+
"fDyA46XZeA4kTj8YKktWrjGBDThxxcL4HBF89jDKseu24XtugVMNsm3GhHwK",
51+
keyIndex: 0,
52+
timeLockAddr: "bcrt1qux548e45wlg9sufhgd8ldfzqrapl303g5sj7xg5w637sge" +
53+
"dst0wsk0xags",
54+
remoteRevPubKey: "03647afa9c04025e997a5b7ecd2dd949f8f60f6880a94af73a" +
55+
"0d4f48f166d127d1",
56+
}, {
57+
// New format with ECDH revocation root but this test data was created
58+
// when already the old format was present, this leads to the situation
59+
// where the idx for the shachain root (revocation root) is equal to
60+
// the delay basepoint index. Normally when starting a node after
61+
// lnd with the version v0.13.0-beta onwords, the index is always
62+
// +1 compared to the delay basepoint index.
63+
baseKey: "tprv8e3Mee42NcUd2MbwxBCJyEEhvKa8KqjiDR76M7ym4DJSfZ" +
64+
"kfDyA46XZeA4kTj8YKktWrjGBDThxxcL4HBF89jDKseu24XtugVMNsm3GhHwK",
65+
keyIndex: 1,
66+
timeLockAddr: "bcrt1qsj7c97fj9xh8znlkjtg4x45xstypk5zp3kcnt5f5u6ps" +
67+
"rhetju2srseqrh",
68+
remoteRevPubKey: "0341692a025ad552c62689a630ff24d9439e3752d8e0ac5cb4" +
69+
"1b5e71ab2bd46d0f",
3770
}}
3871

3972
func TestSweepTimeLockManual(t *testing.T) {

lnd/channel.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ func (lc *LightningChannel) CreateSignDesc() error {
4545
},
4646
HashType: txscript.SigHashAll,
4747
InputIndex: 0,
48+
PrevOutputFetcher: txscript.NewCannedPrevOutputFetcher(
49+
fundingPkScript, int64(lc.ChannelState.Capacity),
50+
),
4851
}
4952

5053
return nil

0 commit comments

Comments
 (0)