Skip to content

Commit 82e1d04

Browse files
committed
add dumphtlcsummary command.
1 parent b0097ad commit 82e1d04

File tree

2 files changed

+177
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)