7
7
8
8
from datatypes import BTC , TXID , btc_to_sat
9
9
from paths import LN
10
- from txs_graph import build_txs_graph , get_downstream
11
-
12
-
13
- def get_htlcs_claimed_by_timeout (graph : DiGraph , commitment_txid : TXID ) -> List [TXID ]:
14
- """
15
- return a list of txids that claimed an HTLC output from the given
16
- commitment transaction, using timeout-claim (as opposed to success-claim)
17
- """
18
-
19
- # from the bolt:
20
- # " HTLC-Timeout and HTLC-Success Transactions... are almost identical,
21
- # except the HTLC-timeout transaction is timelocked "
22
- #
23
- # i.e. if the child_tx has a non-zero locktime, it is an HTLC-timeout
24
- # TODO: what about claiming of local/remote outputs? are they locked? check it
25
-
26
- return [
27
- child_tx
28
- for _ , child_tx in graph .out_edges (commitment_txid )
29
- if graph .nodes [child_tx ]["tx" ]["locktime" ] > 0
30
- ]
10
+ from txs_graph .txs_graph import TxsGraph
31
11
32
12
33
13
# ---------- txid-to-label functions ----------
@@ -110,19 +90,15 @@ def extract_bitcoin_funding_txids(simulation_outfile: str) -> Set[TXID]:
110
90
return txids
111
91
112
92
113
- def get_all_direct_children (txid , graph : DiGraph ) -> Set [TXID ]:
114
- return {txid for _ , txid in graph .out_edges (txid )}
115
-
116
-
117
93
def flatten (s : Iterable [Iterable [Any ]]) -> List [Any ]:
118
94
return list (itertools .chain .from_iterable (s ))
119
95
120
96
121
- def find_commitments (simulation_outfile : str , graph : DiGraph ) -> List [TXID ]:
97
+ def find_commitments (simulation_outfile : str , graph : TxsGraph ) -> List [TXID ]:
122
98
bitcoin_fundings = extract_bitcoin_funding_txids (simulation_outfile = simulation_outfile )
123
99
124
100
ln_channel_fundings = flatten (
125
- get_all_direct_children (txid , graph = graph )
101
+ graph . get_all_direct_children (txid )
126
102
for txid in bitcoin_fundings
127
103
)
128
104
@@ -132,7 +108,7 @@ def find_commitments(simulation_outfile: str, graph: DiGraph) -> List[TXID]:
132
108
list (filter (
133
109
# only keep those with the expected balance
134
110
lambda child_txid : graph .edges [(channel_funding_txid , child_txid )]["value" ] == LN_CHANNEL_BALANCE ,
135
- get_all_direct_children (txid = channel_funding_txid , graph = graph )
111
+ graph . get_all_direct_children (txid = channel_funding_txid )
136
112
))
137
113
for channel_funding_txid in ln_channel_fundings
138
114
)
@@ -151,24 +127,28 @@ def find_commitments(simulation_outfile: str, graph: DiGraph) -> List[TXID]:
151
127
f"Failed to find commitments. "
152
128
f"txid { commitment_txid [- 4 :]} expected to have exactly 1 input, but has { num_inputs } "
153
129
)
154
-
130
+
155
131
return commitments
156
132
157
133
158
- def is_replaceable_by_fee (txid , graph : DiGraph ) -> bool :
159
- for input_dict in graph .nodes [txid ]["tx" ]["vin" ]:
160
- if input_dict ['sequence' ] < (0xffffffff - 1 ):
161
- return True
162
- return False
163
-
164
-
165
- def print_nsequence (txids : Iterable [TXID ], graph : DiGraph ):
166
- for txid in txids :
167
- print (f"txid { txid_to_short_txid (txid )} :" )
168
- for i , input_dict in enumerate (graph .nodes [txid ]["tx" ]["vin" ]):
169
- sequence : int = input_dict ['sequence' ]
170
- sequence_str = format (sequence , 'x' )
171
- print (f"input { i } : sequence={ sequence_str } " )
134
+ def get_htlcs_claimed_by_timeout (graph : TxsGraph , commitment_txid : TXID ) -> List [TXID ]:
135
+ """
136
+ return a list of txids that claimed an HTLC output from the given
137
+ commitment transaction, using timeout-claim (as opposed to success-claim)
138
+ """
139
+
140
+ # from the bolt:
141
+ # " HTLC-Timeout and HTLC-Success Transactions... are almost identical,
142
+ # except the HTLC-timeout transaction is timelocked "
143
+ #
144
+ # i.e. if the child_tx has a non-zero locktime, it is an HTLC-timeout
145
+ # TODO: what about claiming of local/remote outputs? are they locked? check it
146
+
147
+ return [
148
+ child_tx
149
+ for _ , child_tx in graph .out_edges (commitment_txid )
150
+ if graph .nodes [child_tx ]["tx" ]["locktime" ] > 0
151
+ ]
172
152
173
153
174
154
def main (simulation_name ):
@@ -177,26 +157,27 @@ def main(simulation_name):
177
157
outfile = os .path .join (LN , "simulations" , f"{ simulation_name } .out" )
178
158
dotfile = os .path .join (LN , f"{ simulation_name } .dot" )
179
159
jpgfile = os .path .join (LN , f"{ simulation_name } .jpg" )
180
-
181
- txs_graph = build_txs_graph (datadir )
160
+
161
+ txs_graph = TxsGraph . from_datadir (datadir )
182
162
183
163
commitments = find_commitments (simulation_outfile = outfile , graph = txs_graph )
184
164
185
165
for commitment_txid in commitments :
186
166
short_txid = txid_to_short_txid (commitment_txid )
187
167
num_outputs = len (txs_graph .nodes [commitment_txid ]["tx" ]["vout" ])
188
- replaceable = is_replaceable_by_fee (txid = commitment_txid , graph = txs_graph )
189
- num_htlcs_stolen = len (get_htlcs_claimed_by_timeout (commitment_txid = commitment_txid , graph = txs_graph ))
168
+ replaceable = txs_graph .is_replaceable_by_fee (txid = commitment_txid )
169
+ nsequence = txs_graph .get_minimal_nsequence (commitment_txid )
170
+ num_htlcs_stolen = len (get_htlcs_claimed_by_timeout (graph = txs_graph , commitment_txid = commitment_txid ))
190
171
print (
191
172
f"commitment: { short_txid :<5} "
192
173
f"num-outputs: { num_outputs :<4} "
193
174
f"replaceable: { str (replaceable ):<5} "
175
+ f"nsequence: { nsequence :x} "
194
176
f"htlcs-stolen: { num_htlcs_stolen } "
195
177
)
196
178
197
179
# this graph includes only interesting txs (no coinbase and other junk)
198
- restricted_txs_graph = get_downstream (
199
- graph = txs_graph ,
180
+ restricted_txs_graph = txs_graph .get_downstream (
200
181
sources = extract_bitcoin_funding_txids (simulation_outfile = outfile ),
201
182
)
202
183
0 commit comments