Skip to content

Commit b5ac710

Browse files
committed
add dumphtlcsummary command.
1 parent b0097ad commit b5ac710

File tree

2 files changed

+168
-0
lines changed

2 files changed

+168
-0
lines changed

cmd/chantools/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ func main() {
119119
newVanityGenCommand(),
120120
newWalletInfoCommand(),
121121
newZombieRecoveryCommand(),
122+
dumphtlcsummary(),
122123
)
123124

124125
if err := rootCmd.Execute(); err != nil {

cmd/chantools/summaryhtlc.go

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package main
2+
3+
import (
4+
"crypto/sha256"
5+
"encoding/hex"
6+
"encoding/json"
7+
"errors"
8+
"fmt"
9+
"strconv"
10+
"strings"
11+
12+
"github.com/btcsuite/btcd/btcutil"
13+
"github.com/btcsuite/btcd/chaincfg"
14+
"github.com/btcsuite/btcd/chaincfg/chainhash"
15+
"github.com/btcsuite/btcd/wire"
16+
"github.com/lightninglabs/chantools/lnd"
17+
"github.com/lightningnetwork/lnd/channeldb"
18+
"github.com/lightningnetwork/lnd/input"
19+
"github.com/lightningnetwork/lnd/lnrpc"
20+
"github.com/lightningnetwork/lnd/lnwallet"
21+
"github.com/spf13/cobra"
22+
)
23+
24+
type summaryHTLC struct {
25+
ChannelDB string
26+
ChannelPoint string
27+
28+
rootKey *rootKey
29+
cmd *cobra.Command
30+
}
31+
32+
var errBadChanPoint = errors.New("expecting chan_point to be in format of: " +
33+
"txid:index")
34+
35+
func parseChanPoint(s string) (*lnrpc.ChannelPoint, error) {
36+
split := strings.Split(s, ":")
37+
if len(split) != 2 || len(split[0]) == 0 || len(split[1]) == 0 {
38+
return nil, errBadChanPoint
39+
}
40+
41+
index, err := strconv.ParseInt(split[1], 10, 64)
42+
if err != nil {
43+
return nil, fmt.Errorf("unable to decode output index: %v", err)
44+
}
45+
46+
txid, err := chainhash.NewHashFromStr(split[0])
47+
if err != nil {
48+
return nil, fmt.Errorf("unable to parse hex string: %v", err)
49+
}
50+
51+
return &lnrpc.ChannelPoint{
52+
FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
53+
FundingTxidBytes: txid[:],
54+
},
55+
OutputIndex: uint32(index),
56+
}, nil
57+
}
58+
59+
func dumphtlcsummary() *cobra.Command {
60+
cc := &summaryHTLC{}
61+
cc.cmd = &cobra.Command{
62+
Use: "dumphtlcsummary",
63+
Short: "dump all the necessary htlc information which are " +
64+
"needed for the peer to recover his funds",
65+
Long: `...`,
66+
Example: `chantools dumphtlcsummary \
67+
--channeldb ~/.lnd/data/graph/mainnet/channel.db`,
68+
RunE: cc.Execute,
69+
}
70+
cc.cmd.Flags().StringVar(
71+
&cc.ChannelDB, "channeldb", "", "lnd channel.db file to dump "+
72+
"channels from",
73+
)
74+
cc.cmd.Flags().StringVar(
75+
&cc.ChannelPoint, "ChannelPoint", "", "",
76+
)
77+
78+
cc.rootKey = newRootKey(cc.cmd, "deriving keys")
79+
80+
return cc.cmd
81+
}
82+
83+
func (c *summaryHTLC) Execute(_ *cobra.Command, _ []string) error {
84+
// Check that we have a channel DB.
85+
if c.ChannelDB == "" {
86+
return fmt.Errorf("channel DB is required")
87+
}
88+
db, err := lnd.OpenDB(c.ChannelDB, true)
89+
if err != nil {
90+
return fmt.Errorf("error opening rescue DB: %w", err)
91+
}
92+
defer func() { _ = db.Close() }()
93+
94+
return dumpHtlcInfos(db.ChannelStateDB(), c.ChannelPoint)
95+
}
96+
97+
type hltcInfo struct {
98+
HtlcAddress string
99+
WitnessScript string
100+
CommitPoint string
101+
}
102+
103+
func dumpHtlcInfos(chanDb *channeldb.ChannelStateDB, channel string) error {
104+
105+
var htlcs []hltcInfo
106+
107+
chanPoint, err := parseChanPoint(channel)
108+
if err != nil {
109+
return err
110+
}
111+
112+
//Open the Historical Bucket
113+
fundingHash, err := chainhash.NewHash(chanPoint.GetFundingTxidBytes())
114+
115+
if err != nil {
116+
return err
117+
}
118+
outPoint := wire.NewOutPoint(fundingHash, chanPoint.OutputIndex)
119+
120+
dbChannel, err := chanDb.FetchHistoricalChannel(outPoint)
121+
if err != nil {
122+
return err
123+
}
124+
125+
for _, htlc := range dbChannel.LocalCommitment.Htlcs {
126+
// Only Incoming HTLCs for now.
127+
if !htlc.Incoming {
128+
continue
129+
}
130+
131+
revocationPreimage, err := dbChannel.RevocationProducer.AtIndex(
132+
dbChannel.LocalCommitment.CommitHeight,
133+
)
134+
if err != nil {
135+
return err
136+
}
137+
localCommitPoint := input.ComputeCommitmentPoint(revocationPreimage[:])
138+
139+
keyRing := lnwallet.DeriveCommitmentKeys(
140+
localCommitPoint, true, dbChannel.ChanType,
141+
&dbChannel.LocalChanCfg,
142+
&dbChannel.RemoteChanCfg,
143+
)
144+
145+
witnessScript, err := input.ReceiverHTLCScript(
146+
htlc.RefundTimeout, keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
147+
keyRing.RevocationKey, htlc.RHash[:], dbChannel.ChanType.HasAnchors(),
148+
)
149+
witnessScriptHash := sha256.Sum256(witnessScript)
150+
htlcAddr, err := btcutil.NewAddressWitnessScriptHash(
151+
witnessScriptHash[:], &chaincfg.RegressionNetParams,
152+
)
153+
154+
htlcs = append(htlcs, hltcInfo{
155+
HtlcAddress: htlcAddr.String(),
156+
WitnessScript: hex.EncodeToString(witnessScript),
157+
CommitPoint: hex.EncodeToString(localCommitPoint.SerializeCompressed()),
158+
})
159+
}
160+
161+
data, err := json.MarshalIndent(htlcs, "", " ")
162+
163+
fmt.Printf("%v", string(data))
164+
165+
return nil
166+
167+
}

0 commit comments

Comments
 (0)