Skip to content

Commit 9eb9761

Browse files
committed
summary: add ancient channel extraction
1 parent 3134e5c commit 9eb9761

File tree

1 file changed

+95
-0
lines changed

1 file changed

+95
-0
lines changed

cmd/chantools/summary.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@ import (
66
"os"
77
"time"
88

9+
"github.com/btcsuite/btcd/btcutil"
910
"github.com/lightninglabs/chantools/btc"
1011
"github.com/lightninglabs/chantools/dataformat"
12+
"github.com/lightninglabs/chantools/lnd"
1113
"github.com/spf13/cobra"
1214
)
1315

1416
type summaryCommand struct {
1517
APIURL string
1618

19+
Ancient bool
20+
1721
inputs *inputFlags
1822
cmd *cobra.Command
1923
}
@@ -35,6 +39,10 @@ chantools summary --fromchanneldb ~/.lnd/data/graph/mainnet/channel.db`,
3539
&cc.APIURL, "apiurl", defaultAPIURL, "API URL to use (must "+
3640
"be esplora compatible)",
3741
)
42+
cc.cmd.Flags().BoolVar(
43+
&cc.Ancient, "ancient", false, "Create summary of ancient "+
44+
"channel closes with un-swept outputs",
45+
)
3846

3947
cc.inputs = newInputFlags(cc.cmd)
4048

@@ -47,6 +55,11 @@ func (c *summaryCommand) Execute(_ *cobra.Command, _ []string) error {
4755
if err != nil {
4856
return err
4957
}
58+
59+
if c.Ancient {
60+
return summarizeAncientChannels(c.APIURL, entries)
61+
}
62+
5063
return summarizeChannels(c.APIURL, entries)
5164
}
5265

@@ -90,3 +103,85 @@ func summarizeChannels(apiURL string,
90103
log.Infof("Writing result to %s", fileName)
91104
return os.WriteFile(fileName, summaryBytes, 0644)
92105
}
106+
107+
func summarizeAncientChannels(apiURL string,
108+
channels []*dataformat.SummaryEntry) error {
109+
110+
api := newExplorerAPI(apiURL)
111+
112+
var results []*ancientChannel
113+
for _, target := range channels {
114+
if target.ClosingTX == nil {
115+
continue
116+
}
117+
118+
closeTx := target.ClosingTX
119+
if !closeTx.ForceClose {
120+
continue
121+
}
122+
123+
if closeTx.AllOutsSpent {
124+
continue
125+
}
126+
127+
if closeTx.OurAddr != "" {
128+
log.Infof("Channel %s has potential funds: %d in %s",
129+
target.ChannelPoint, target.LocalBalance,
130+
closeTx.OurAddr)
131+
}
132+
133+
if target.LocalUnrevokedCommitPoint == "" {
134+
log.Warnf("Channel %s has no unrevoked commit point",
135+
target.ChannelPoint)
136+
continue
137+
}
138+
139+
if closeTx.ToRemoteAddr == "" {
140+
log.Warnf("Close TX %s has no remote address",
141+
closeTx.TXID)
142+
continue
143+
}
144+
145+
addr, err := lnd.ParseAddress(closeTx.ToRemoteAddr, chainParams)
146+
if err != nil {
147+
return fmt.Errorf("error parsing address %s of %s: %w",
148+
closeTx.ToRemoteAddr, closeTx.TXID, err)
149+
}
150+
151+
if _, ok := addr.(*btcutil.AddressWitnessPubKeyHash); !ok {
152+
log.Infof("Channel close %s has non-p2wkh output: %s",
153+
closeTx.TXID, closeTx.ToRemoteAddr)
154+
continue
155+
}
156+
157+
tx, err := api.Transaction(closeTx.TXID)
158+
if err != nil {
159+
return fmt.Errorf("error fetching transaction %s: %w",
160+
closeTx.TXID, err)
161+
}
162+
163+
for idx, txOut := range tx.Vout {
164+
if txOut.Outspend.Spent {
165+
continue
166+
}
167+
168+
if txOut.ScriptPubkeyAddr == closeTx.ToRemoteAddr {
169+
results = append(results, &ancientChannel{
170+
OP: fmt.Sprintf("%s:%d", closeTx.TXID,
171+
idx),
172+
Addr: closeTx.ToRemoteAddr,
173+
CP: target.LocalUnrevokedCommitPoint,
174+
})
175+
}
176+
}
177+
}
178+
179+
summaryBytes, err := json.MarshalIndent(results, "", " ")
180+
if err != nil {
181+
return err
182+
}
183+
fileName := fmt.Sprintf("results/summary-ancient-%s.json",
184+
time.Now().Format("2006-01-02-15-04-05"))
185+
log.Infof("Writing result to %s", fileName)
186+
return os.WriteFile(fileName, summaryBytes, 0644)
187+
}

0 commit comments

Comments
 (0)