Skip to content

Commit 7171ec4

Browse files
committed
LN: pass updatechanpolicy args from graphml file to ln node
1 parent d4de9bc commit 7171ec4

File tree

4 files changed

+56
-17
lines changed

4 files changed

+56
-17
lines changed

src/scenarios/ln_init.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def run_test(self):
4646
# TODO: This might belong in Warnet class as connect_ln_edges()
4747
# but that would need to ensure spendable funds first.
4848
# For now we consider this scenario "special".
49-
opening_txs = []
49+
chan_pts = []
5050
ln_edges = []
5151
for edge in self.warnet.graph.edges(data=True):
5252
(src, dst, data) = edge
@@ -55,15 +55,15 @@ def run_test(self):
5555
assert src_node is not None
5656
assert self.warnet.get_ln_node_from_tank(dst) is not None
5757
ln_edges.append(edge)
58-
tx = src_node.open_channel_to_tank(dst, data["source-policy"])["funding_txid"]
59-
opening_txs.append(tx)
58+
chan_pt = src_node.open_channel_to_tank(dst, data["source-policy"])
59+
chan_pts.append(chan_pt)
6060

6161
self.log.info("Waiting for all channel open txs in mempool")
6262
while True:
6363
all_set = True
6464
mp = self.nodes[3].getrawmempool()
65-
for tx in opening_txs:
66-
if tx not in mp:
65+
for chan_pt in chan_pts:
66+
if chan_pt[:64] not in mp:
6767
all_set = False
6868
if all_set:
6969
break
@@ -84,8 +84,14 @@ def run_test(self):
8484
break
8585
sleep(2)
8686

87-
self.log.info(f"Warnet LN ready with {len(recv_addrs)} nodes and {len(ln_edges)} channels.")
87+
self.log.info("Updating channel policies")
88+
for i, edge in enumerate(ln_edges):
89+
(src, dst, data) = edge
90+
if "target-policy" in data:
91+
target_node = self.warnet.get_ln_node_from_tank(dst)
92+
target_node.update_channel_policy(chan_pts[i], data["target-policy"])
8893

94+
self.log.info(f"Warnet LN ready with {len(recv_addrs)} nodes and {len(ln_edges)} channels.")
8995

9096
if __name__ == "__main__":
9197
LNInit().main()

src/warnet/lnnode.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,21 @@ def get_wallet_balance(self):
7373
res = self.lncli("walletbalance")
7474
return res
7575

76+
# returns the channel point in the form txid:output_index
7677
def open_channel_to_tank(self, index: int, policy: str) -> str:
7778
tank = self.warnet.tanks[index]
7879
[pubkey, host] = tank.lnnode.getURI().split("@")
79-
res = self.lncli(f"openchannel --node_key={pubkey} --connect={host} {policy}")
80-
return res
80+
txid = self.lncli(f"openchannel --node_key={pubkey} --connect={host} {policy}")["funding_txid"]
81+
# Why doesn't LND return the output index as well?
82+
# Do they charge by the RPC call or something?!
83+
pending = self.lncli("pendingchannels")
84+
for chan in pending["pending_open_channels"]:
85+
if txid in chan["channel"]["channel_point"]:
86+
return chan["channel"]["channel_point"]
87+
raise Exception(f"Opened channel with txid {txid} not found in pending channels")
88+
89+
def update_channel_policy(self, chan_point: str, policy: str) -> str:
90+
return self.lncli(f"updatechanpolicy --chan_point={chan_point} {policy}")
8191

8292
def connect_to_tank(self, index):
8393
tank = self.warnet.tanks[index]

test/data/ln.graphml

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<key attr.name="ln_cb_image" attr.type="string" for="node" id="ln_cb_image"/>
88
<key attr.name="ln_config" attr.type="string" for="node" id="ln_config"/>
99
<key attr.name="source-policy" attr.type="string" for="edge" id="source-policy"/>
10+
<key attr.name="target-policy" attr.type="string" for="edge" id="target-policy"/>
1011
<key attr.name="collect_logs" attr.type="boolean" for="node" id="collect_logs"/>
1112
<key attr.name="image" attr.type="string" for="node" id="image"/>
1213
<graph edgedefault="directed">
@@ -23,13 +24,13 @@
2324
<data key="ln">lnd</data>
2425
<data key="ln_cb_image">pinheadmz/circuitbreaker:278737d</data>
2526
<data key="collect_logs">true</data>
26-
<data key="ln_config">--bitcoin.timelockdelta=20</data>
2727
</node>
2828
<node id="2">
2929
<data key="version">26.0</data>
3030
<data key="bitcoin_config">-uacomment=w2</data>
3131
<data key="ln">lnd</data>
3232
<data key="ln_cb_image">pinheadmz/circuitbreaker:278737d</data>
33+
<data key="ln_config">--bitcoin.timelockdelta=33</data>
3334
</node>
3435
<node id="3">
3536
<data key="version">26.0</data>
@@ -42,6 +43,7 @@
4243
<!-- LN channels -->
4344
<edge id="5" source="0" target="1">
4445
<data key="source-policy">--local_amt=100000</data>
46+
<data key="target-policy">--base_fee_msat=2200 --fee_rate_ppm=13 --time_lock_delta=20</data>
4547
</edge>
4648
<edge id="6" source="1" target="2">
4749
<data key="source-policy">--local_amt=100000 --push_amt=50000 --base_fee_msat=5500 --fee_rate_ppm=3</data>

test/ln_test.py

+29-8
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,17 @@ def get_cb_forwards(index):
4545
base.wait_for_all_scenarios()
4646

4747
print("\nEnsuring node-level channel policy settings")
48-
chans = json.loads(base.warcli("lncli 1 describegraph"))["edges"]
49-
for chan in chans:
50-
# node_1 or node_2 is tank 1 with its non-default --bitcoin.timelockdelta=20
51-
if chan["node1_policy"]["time_lock_delta"] != 20:
52-
assert chan["node2_policy"]["time_lock_delta"] == 20
48+
chan_id = json.loads(base.warcli("lncli 2 listchannels"))["channels"][0]["chan_id"]
49+
chan = json.loads(base.warcli(f"lncli 2 getchaninfo {chan_id}"))
50+
# node_1 or node_2 is tank 2 with its non-default --bitcoin.timelockdelta=33
51+
if chan["node1_policy"]["time_lock_delta"] != 33:
52+
assert chan["node2_policy"]["time_lock_delta"] == 33
5353

5454
print("\nEnsuring no circuit breaker forwards yet")
5555
assert len(get_cb_forwards(1)["forwards"]) == 0
5656

5757
print("\nTest LN payment from 0 -> 2")
58-
inv = json.loads(base.warcli("lncli 2 addinvoice --amt=1234"))["payment_request"]
58+
inv = json.loads(base.warcli("lncli 2 addinvoice --amt=2000"))["payment_request"]
5959

6060
print(f"\nGot invoice from node 2: {inv}")
6161
print("\nPaying invoice from node 0...")
@@ -71,11 +71,32 @@ def check_invoices():
7171
return False
7272
base.wait_for_predicate(check_invoices)
7373

74-
print("\nEnsuring channel-level channel policy settings")
74+
print("\nEnsuring channel-level channel policy settings: source")
7575
payment = json.loads(base.warcli("lncli 0 listpayments"))["payments"][0]
76-
assert payment["fee_msat"] == "5503"
76+
assert payment["fee_msat"] == "5506"
7777

7878
print("\nEnsuring circuit breaker tracked payment")
7979
assert len(get_cb_forwards(1)["forwards"]) == 1
8080

81+
print("\nTest LN payment from 2 -> 0")
82+
inv = json.loads(base.warcli("lncli 0 addinvoice --amt=1000"))["payment_request"]
83+
84+
print(f"\nGot invoice from node 0: {inv}")
85+
print("\nPaying invoice from node 2...")
86+
print(base.warcli(f"lncli 2 payinvoice -f {inv}"))
87+
88+
print("Waiting for payment success")
89+
def check_invoices():
90+
invs = json.loads(base.warcli("lncli 0 listinvoices"))["invoices"]
91+
if len(invs) > 0 and invs[0]["state"] == "SETTLED":
92+
print("\nSettled!")
93+
return True
94+
else:
95+
return False
96+
base.wait_for_predicate(check_invoices)
97+
98+
print("\nEnsuring channel-level channel policy settings: target")
99+
payment = json.loads(base.warcli("lncli 2 listpayments"))["payments"][0]
100+
assert payment["fee_msat"] == "2213"
101+
81102
base.stop_server()

0 commit comments

Comments
 (0)