xpay should give us a better report of what's going on when this
payment fails. Also, enable the test for v1 as well.
```
2025-05-13T03:30:44.7519949Z > l1.rpc.pay(inv['bolt11'])
2025-05-13T03:30:44.7520207Z
2025-05-13T03:30:44.7520362Z tests/test_connection.py:4101:
2025-05-13T03:30:44.7520795Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2025-05-13T03:30:44.7521385Z contrib/pyln-client/pyln/client/lightning.py:1174: in pay
2025-05-13T03:30:44.7521915Z return self.call("pay", payload)
2025-05-13T03:30:44.7522424Z contrib/pyln-testing/pyln/testing/utils.py:769: in call
2025-05-13T03:30:44.7523417Z res = LightningRpc.call(self, method, payload, cmdprefix, filter)
2025-05-13T03:30:44.7524062Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2025-05-13T03:30:44.7524406Z
2025-05-13T03:30:44.7524789Z self = <pyln.testing.utils.PrettyPrintingLightningRpc object at 0x7f3d4a216080>
2025-05-13T03:30:44.7525439Z method = 'pay'
2025-05-13T03:30:44.7527668Z payload = {'bolt11': 'lnbcrt500u1p5z9w7usp5fshywh40am006xc99743qtfhq6reurf5amzslg85h4uc9hvc4d8spp59d36m7fkzasavt46pfe97nwx9nzk3n...xpqysgqwd2nzn3gmsagdfruy9jsn0zdhy9cjy4wsj9cttlc4wftmslpm5cjtczjtn0qeqca696m6xd9vmx8vc62whty4y7wmncymletrdp9zaqqk5sf2c'}
2025-05-13T03:30:44.7530070Z cmdprefix = None, filter = None
2025-05-13T03:30:44.7530347Z
2025-05-13T03:30:44.7530637Z def call(self, method, payload=None, cmdprefix=None, filter=None):
2025-05-13T03:30:44.7531329Z """Generic call API: you can set cmdprefix here, or set self.cmdprefix
2025-05-13T03:30:44.7531884Z before the call is made.
2025-05-13T03:30:44.7532252Z
2025-05-13T03:30:44.7532517Z """
2025-05-13T03:30:44.7533106Z self.logger.debug("Calling %s with payload %r", method, payload)
2025-05-13T03:30:44.7533637Z
2025-05-13T03:30:44.7533923Z if payload is None:
2025-05-13T03:30:44.7534292Z payload = {}
2025-05-13T03:30:44.7534662Z # Filter out arguments that are None
2025-05-13T03:30:44.7535120Z if isinstance(payload, dict):
2025-05-13T03:30:44.7535634Z payload = {k: v for k, v in payload.items() if v is not None}
2025-05-13T03:30:44.7536152Z
2025-05-13T03:30:44.7536487Z this_id = self.get_json_id(method, cmdprefix)
2025-05-13T03:30:44.7536944Z self.next_id += 1
2025-05-13T03:30:44.7537274Z
2025-05-13T03:30:44.7537635Z # FIXME: we open a new socket for every readobj call...
2025-05-13T03:30:44.7538146Z sock = UnixSocket(self.socket_path)
2025-05-13T03:30:44.7538550Z
2025-05-13T03:30:44.7538809Z buf = b''
2025-05-13T03:30:44.7539097Z
2025-05-13T03:30:44.7539424Z if self._notify is not None:
2025-05-13T03:30:44.7539861Z # Opt into the notifications support
2025-05-13T03:30:44.7540297Z self._writeobj(sock, {
2025-05-13T03:30:44.7540685Z "jsonrpc": "2.0",
2025-05-13T03:30:44.7541088Z "method": "notifications",
2025-05-13T03:30:44.7541600Z "id": this_id + "+notify-enable",
2025-05-13T03:30:44.7542190Z "params": {
2025-05-13T03:30:44.7542810Z "enable": True
2025-05-13T03:30:44.7543294Z },
2025-05-13T03:30:44.7543617Z })
2025-05-13T03:30:44.7543853Z # FIXME: Notification schema support?
2025-05-13T03:30:44.7544297Z _, buf = self._readobj(sock, buf)
2025-05-13T03:30:44.7544530Z
2025-05-13T03:30:44.7544688Z request = {
2025-05-13T03:30:44.7544880Z "jsonrpc": "2.0",
2025-05-13T03:30:44.7545094Z "method": method,
2025-05-13T03:30:44.7545309Z "params": payload,
2025-05-13T03:30:44.7545521Z "id": this_id,
2025-05-13T03:30:44.7545714Z }
2025-05-13T03:30:44.7545869Z
2025-05-13T03:30:44.7546033Z if filter is None:
2025-05-13T03:30:44.7546240Z filter = self._filter
2025-05-13T03:30:44.7546466Z if filter is not None:
2025-05-13T03:30:44.7546856Z request["filter"] = filter
2025-05-13T03:30:44.7547231Z
2025-05-13T03:30:44.7547543Z self._writeobj(sock, request)
2025-05-13T03:30:44.7547964Z while True:
2025-05-13T03:30:44.7548350Z resp, buf = self._readobj(sock, buf)
2025-05-13T03:30:44.7548833Z id = resp.get("id", None)
2025-05-13T03:30:44.7549299Z meth = resp.get("method", None)
2025-05-13T03:30:44.7549729Z
2025-05-13T03:30:44.7550095Z if meth == 'message' and self._notify is not None:
2025-05-13T03:30:44.7550584Z n = resp['params']
2025-05-13T03:30:44.7550983Z self._notify(
2025-05-13T03:30:44.7551594Z message=n.get('message', None),
2025-05-13T03:30:44.7552133Z progress=n.get('progress', None),
2025-05-13T03:30:44.7552592Z request=request
2025-05-13T03:30:44.7553142Z )
2025-05-13T03:30:44.7553445Z continue
2025-05-13T03:30:44.7553775Z
2025-05-13T03:30:44.7554076Z if meth is None or id is None:
2025-05-13T03:30:44.7554483Z break
2025-05-13T03:30:44.7554783Z
2025-05-13T03:30:44.7555228Z self.logger.debug("Received response for %s call: %r", method, resp)
2025-05-13T03:30:44.7555847Z if 'id' in resp and resp['id'] != this_id:
2025-05-13T03:30:44.7556537Z raise ValueError("Malformed response, id is not {}: {}.".format(this_id, resp))
2025-05-13T03:30:44.7557171Z sock.close()
2025-05-13T03:30:44.7557477Z
2025-05-13T03:30:44.7557769Z if not isinstance(resp, dict):
2025-05-13T03:30:44.7558413Z raise TypeError("Malformed response, response is not a dictionary %s." % resp)
2025-05-13T03:30:44.7559049Z elif "error" in resp:
2025-05-13T03:30:44.7559492Z > raise RpcError(method, payload, resp['error'])
2025-05-13T03:30:44.8303393Z E pyln.client.lightning.RpcError: RPC call failed: method: pay, payload: {'bolt11': 'lnbcrt500u1p5z9w7usp5fshywh40am006xc99743qtfhq6reurf5amzslg85h4uc9hvc4d8spp59d36m7fkzasavt46pfe97nwx9nzk3nhnkgl9qtw6t7mcswknt73sdqdd9h8vmmfvdjngxqyjw5qcqp9rzjqgkjyd3q5dv6gllh77kygly9c3kfy0d9xwyjyxsq2nq3c83u5vw4jqqqdyqqqqgqqyqqqqqpqqqqqzsqqc9qxpqysgqwd2nzn3gmsagdfruy9jsn0zdhy9cjy4wsj9cttlc4wftmslpm5cjtczjtn0qeqca696m6xd9vmx8vc62whty4y7wmncymletrdp9zaqqk5sf2c'}, error: {'code': 210, 'message': 'Ran out of routes to try after 2182 attempts: see `paystatus`', 'attempts': [{'status': 'pending', 'failreason': 'No path found', 'partid': 0, 'amount_msat': 50000000}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1, 'amount_msat': 25202136, 'parent_partid': 0}, {'status': 'failed', 'failreason': 'No path found', 'partid': 6, 'amount_msat': 11590044, 'parent_partid': 1}, {'status': 'pending', 'failreason': 'No path found', 'partid': 13, 'amount_msat': 11590044, 'parent_partid': 6}, {'status': 'failed', 'failreason': 'No path found', 'partid': 20, 'amount_msat': 5340691, 'parent_partid': 13}, {'status': 'pending', 'failreason': 'No path found', 'partid': 29, 'amount_msat': 5340691, 'parent_partid': 20}, {'status': 'failed', 'failreason': 'No path found', 'partid': 38, 'amount_msat': 2860412, 'parent_partid': 29}, {'status': 'pending', 'failreason': 'No path found', 'partid': 75, 'amount_msat': 2860412, 'parent_partid': 38}, {'status': 'pending', 'failreason': 'No path found', 'partid': 165, 'amount_msat': 1301697, 'parent_partid': 75}, {'status': 'pending', 'failreason': 'No path found', 'partid': 335, 'amount_msat': 658637, 'parent_partid': 165}, {'status': 'failed', 'failreason': 'No path found', 'partid': 404, 'amount_msat': 329074, 'parent_partid': 335}, {'status': 'pending', 'failreason': 'No path found', 'partid': 509, 'amount_msat': 329074, 'parent_partid': 404}, {'status': 'failed', 'failreason': 'No path found', 'partid': 924, 'amount_msat': 151909, 'parent_partid': 509}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1075, 'amount_msat': 151909, 'parent_partid': 924}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1277, 'amount_msat': 73636, 'parent_partid': 1075}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1278, 'amount_msat': 78273, 'parent_partid': 1075}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1521, 'amount_msat': 78273, 'parent_partid': 1278}, {'status': 'pending', 'failreason': 'No path found', 'partid': 925, 'amount_msat': 177165, 'parent_partid': 509}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1444, 'amount_msat': 85860, 'parent_partid': 925}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1883, 'amount_msat': 85860, 'parent_partid': 1444}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1445, 'amount_msat': 91305, 'parent_partid': 925}, {'status': 'pending', 'failreason': 'No path found', 'partid': 405, 'amount_msat': 329563, 'parent_partid': 335}, {'status': 'failed', 'failreason': 'No path found', 'partid': 510, 'amount_msat': 174463, 'parent_partid': 405}, {'status': 'pending', 'failreason': 'No path found', 'partid': 643, 'amount_msat': 174463, 'parent_partid': 510}, {'status': 'failed', 'failreason': 'No path found', 'partid': 808, 'amount_msat': 88417, 'parent_partid': 643}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1378, 'amount_msat': 88417, 'parent_partid': 808}, {'status': 'failed', 'failreason': 'No path found', 'partid': 809, 'amount_msat': 86046, 'parent_partid': 643}, {'status': 'pending', 'failreason': 'No path found', 'partid': 511, 'amount_msat': 155100, 'parent_partid': 405}, {'status': 'failed', 'failreason': 'No path found', 'partid': 644, 'amount_msat': 72741, 'parent_partid': 511}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1148, 'amount_msat': 72741, 'parent_partid': 644}, {'status': 'failed', 'failreason': 'No path found', 'partid': 645, 'amount_msat': 82359, 'parent_partid': 511}, {'status': 'failed', 'failreason': 'No path found', 'partid': 336, 'amount_msat': 643060, 'parent_partid': 165}, {'status': 'pending', 'failreason': 'No path found', 'partid': 621, 'amount_msat': 643060, 'parent_partid': 336}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1021, 'amount_msat': 312772, 'parent_partid': 621}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1511, 'amount_msat': 165980, 'parent_partid': 1021}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1610, 'amount_msat': 76290, 'parent_partid': 1511}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1756, 'amount_msat': 76290, 'parent_partid': 1610}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1611, 'amount_msat': 89690, 'parent_partid': 1511}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1512, 'amount_msat': 146792, 'parent_partid': 1021}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1612, 'amount_msat': 146792, 'parent_partid': 1512}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1990, 'amount_msat': 67396, 'parent_partid': 1612}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2137, 'amount_msat': 67396, 'parent_partid': 1990}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1991, 'amount_msat': 79396, 'parent_partid': 1612}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1022, 'amount_msat': 330288, 'parent_partid': 621}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1135, 'amount_msat': 330288, 'parent_partid': 1022}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1675, 'amount_msat': 171325, 'parent_partid': 1135}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2007, 'amount_msat': 80351, 'parent_partid': 1675}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2008, 'amount_msat': 90974, 'parent_partid': 1675}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2142, 'amount_msat': 90974, 'parent_partid': 2008}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1676, 'amount_msat': 158963, 'parent_partid': 1135}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1777, 'amount_msat': 158963, 'parent_partid': 1676}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1925, 'amount_msat': 78229, 'parent_partid': 1777}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1926, 'amount_msat': 80734, 'parent_partid': 1777}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2117, 'amount_msat': 80734, 'parent_partid': 1926}, {'status': 'failed', 'failreason': 'No path found', 'partid': 166, 'amount_msat': 1558715, 'parent_partid': 75}, {'status': 'pending', 'failreason': 'No path found', 'partid': 210, 'amount_msat': 1558715, 'parent_partid': 166}, {'status': 'failed', 'failreason': 'No path found', 'partid': 428, 'amount_msat': 801413, 'parent_partid': 210}, {'status': 'pending', 'failreason': 'No path found', 'partid': 527, 'amount_msat': 801413, 'parent_partid': 428}, {'status': 'pending', 'failreason': 'No path found', 'partid': 657, 'amount_msat': 377626, 'parent_partid': 527}, {'status': 'pending', 'failreason': 'No path found', 'partid': 813, 'amount_msat': 193287, 'parent_partid': 657}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1028, 'amount_msat': 88356, 'parent_partid': 813}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1616, 'amount_msat': 88356, 'parent_partid': 1028}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1029, 'amount_msat': 104931, 'parent_partid': 813}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1617, 'amount_msat': 53645, 'parent_partid': 1029}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1618, 'amount_msat': 51286, 'parent_partid': 1029}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1761, 'amount_msat': 51286, 'parent_partid': 1618}, {'status': 'failed', 'failreason': 'No path found', 'partid': 814, 'amount_msat': 184339, 'parent_partid': 657}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1030, 'amount_msat': 184339, 'parent_partid': 814}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1619, 'amount_msat': 99183, 'parent_partid': 1030}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1620, 'amount_msat': 85156, 'parent_partid': 1030}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1762, 'amount_msat': 85156, 'parent_partid': 1620}, {'status': 'failed', 'failreason': 'No path found', 'partid': 658, 'amount_msat': 423787, 'parent_partid': 527}, {'status': 'pending', 'failreason': 'No path found', 'partid': 815, 'amount_msat': 423787, 'parent_partid': 658}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1382, 'amount_msat': 226989, 'parent_partid': 815}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1561, 'amount_msat': 226989, 'parent_partid': 1382}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1968, 'amount_msat': 114759, 'parent_partid': 1561}, {'status': 'pending', 'failreason': 'No path found', 'partid': 2124, 'amount_msat': 114759, 'parent_partid': 1968}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2173, 'amount_msat': 57814, 'parent_partid': 2124}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2174, 'amount_msat': 56945, 'parent_partid': 2124}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2179, 'amount_msat': 56945, 'parent_partid': 2174}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1969, 'amount_msat': 112230, 'parent_partid': 1561}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2033, 'amount_msat': 61293, 'parent_partid': 1969}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2034, 'amount_msat': 50937, 'parent_partid': 1969}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2102, 'amount_msat': 50937, 'parent_partid': 2034}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1383, 'amount_msat': 196798, 'parent_partid': 815}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1562, 'amount_msat': 97322, 'parent_partid': 1383}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1743, 'amount_msat': 97322, 'parent_partid': 1562}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1563, 'amount_msat': 99476, 'parent_partid': 1383}, {'status': 'pending', 'failreason': 'No path found', 'partid': 429, 'amount_msat': 757302, 'parent_partid': 210}, {'status': 'failed', 'failreason': 'No path found', 'partid': 528, 'amount_msat': 359933, 'parent_partid': 429}, {'status': 'pending', 'failreason': 'No path found', 'partid': 659, 'amount_msat': 359933, 'parent_partid': 528}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1156, 'amount_msat': 174252, 'parent_partid': 659}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1317, 'amount_msat': 174252, 'parent_partid': 1156}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1821, 'amount_msat': 92755, 'parent_partid': 1317}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1822, 'amount_msat': 81497, 'parent_partid': 1317}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1934, 'amount_msat': 81497, 'parent_partid': 1822}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1157, 'amount_msat': 185681, 'parent_partid': 659}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1318, 'amount_msat': 98121, 'parent_partid': 1157}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1823, 'amount_msat': 98121, 'parent_partid': 1318}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1319, 'amount_msat': 87560, 'parent_partid': 1157}, {'status': 'pending', 'failreason': 'No path found', 'partid': 529, 'amount_msat': 397369, 'parent_partid': 429}, {'status': 'failed', 'failreason': 'No path found', 'partid': 660, 'amount_msat': 214870, 'parent_partid': 529}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1158, 'amount_msat': 214870, 'parent_partid': 660}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1684, 'amount_msat': 116297, 'parent_partid': 1158}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1784, 'amount_msat': 116297, 'parent_partid': 1684}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2059, 'amount_msat': 57248, 'parent_partid': 1784}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2060, 'amount_msat': 59049, 'parent_partid': 1784}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2158, 'amount_msat': 59049, 'parent_partid': 2060}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1685, 'amount_msat': 98573, 'parent_partid': 1158}, {'status': 'pending', 'failreason': 'No path found', 'partid': 661, 'amount_msat': 182499, 'parent_partid': 529}, {'status': 'failed', 'failreason': 'No path found', 'partid': 816, 'amount_msat': 96426, 'parent_partid': 661}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1384, 'amount_msat': 96426, 'parent_partid': 816}, {'status': 'failed', 'failreason': 'No path found', 'partid': 817, 'amount_msat': 86073, 'parent_partid': 661}, {'status': 'pending', 'failreason': 'No path found', 'partid': 39, 'amount_msat': 2480279, 'parent_partid': 29}, {'status': 'failed', 'failreason': 'No path found', 'partid': 76, 'amount_msat': 1341671, 'parent_partid': 39}, {'status': 'pending', 'failreason': 'No path found', 'partid': 100, 'amount_msat': 1341671, 'parent_partid': 76}, {'status': 'failed', 'failreason': 'No path found', 'partid': 228, 'amount_msat': 620344, 'parent_partid': 100}, {'status': 'pending', 'failreason': 'No path found', 'partid': 450, 'amount_msat': 620344, 'parent_partid': 228}, {'status': 'failed', 'failreason': 'No path found', 'partid': 546, 'amount_msat': 328317, 'parent_partid': 450}, {'status': 'pending', 'failreason': 'No path found', 'partid': 672, 'amount_msat': 328317, 'parent_partid': 546}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1163, 'amount_msat': 177416, 'parent_partid': 672}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1323, 'amount_msat': 85578, 'parent_partid': 1163}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1324, 'amount_msat': 91838, 'parent_partid': 1163}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1825, 'amount_msat': 91838, 'parent_partid': 1324}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1164, 'amount_msat': 150901, 'parent_partid': 672}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1686, 'amount_msat': 150901, 'parent_partid': 1164}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1785, 'amount_msat': 74808, 'parent_partid': 1686}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1786, 'amount_msat': 76093, 'parent_partid': 1686}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2061, 'amount_msat': 76093, 'parent_partid': 1786}, {'status': 'pending', 'failreason': 'No path found', 'partid': 547, 'amount_msat': 292027, 'parent_partid': 450}, {'status': 'failed', 'failreason': 'No path found', 'partid': 952, 'amount_msat': 141900, 'parent_partid': 547}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1088, 'amount_msat': 141900, 'parent_partid': 952}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1287, 'amount_msat': 63901, 'parent_partid': 1088}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1288, 'amount_msat': 77999, 'parent_partid': 1088}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1806, 'amount_msat': 77999, 'parent_partid': 1288}, {'status': 'pending', 'failreason': 'No path found', 'partid': 953, 'amount_msat': 150127, 'parent_partid': 547}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1466, 'amount_msat': 81153, 'parent_partid': 953}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1897, 'amount_msat': 81153, 'parent_partid': 1466}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1467, 'amount_msat': 68974, 'parent_partid': 953}, {'status': 'pending', 'failreason': 'No path found', 'partid': 229, 'amount_msat': 721327, 'parent_partid': 100}, {'status': 'pending', 'failreason': 'No path found', 'partid': 451, 'amount_msat': 346727, 'parent_partid': 229}, {'status': 'failed', 'failreason': 'No path found', 'partid': 548, 'amount_msat': 165113, 'parent_partid': 451}, {'status': 'pending', 'failreason': 'No path found', 'partid': 673, 'amount_msat': 165113, 'parent_partid': 548}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1165, 'amount_msat': 85646, 'parent_partid': 673}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1166, 'amount_msat': 79467, 'parent_partid': 673}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1687, 'amount_msat': 79467, 'parent_partid': 1166}, {'status': 'pending', 'failreason': 'No path found', 'partid': 549, 'amount_msat': 181614, 'parent_partid': 451}, {'status': 'failed', 'failreason': 'No path found', 'partid': 954, 'amount_msat': 86180, 'parent_partid': 549}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1089, 'amount_msat': 86180, 'parent_partid': 954}, {'status': 'failed', 'failreason': 'No path found', 'partid': 955, 'amount_msat': 95434, 'parent_partid': 549}, {'status': 'failed', 'failreason': 'No path found', 'partid': 452, 'amount_msat': 374600, 'parent_partid': 229}, {'status': 'pending', 'failreason': 'No path found', 'partid': 783, 'amount_msat': 374600, 'parent_partid': 452}, {'status': 'pending', 'failreason': 'No path found', 'partid': 889, 'amount_msat': 198755, 'parent_partid': 783}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1423, 'amount_msat': 108131, 'parent_partid': 889}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1864, 'amount_msat': 57820, 'parent_partid': 1423}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1940, 'amount_msat': 57820, 'parent_partid': 1864}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1865, 'amount_msat': 50311, 'parent_partid': 1423}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1424, 'amount_msat': 90624, 'parent_partid': 889}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1576, 'amount_msat': 90624, 'parent_partid': 1424}, {'status': 'failed', 'failreason': 'No path found', 'partid': 890, 'amount_msat': 175845, 'parent_partid': 783}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1055, 'amount_msat': 175845, 'parent_partid': 890}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1266, 'amount_msat': 93465, 'parent_partid': 1055}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1519, 'amount_msat': 93465, 'parent_partid': 1266}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1267, 'amount_msat': 82380, 'parent_partid': 1055}, {'status': 'pending', 'failreason': 'No path found', 'partid': 77, 'amount_msat': 1138608, 'parent_partid': 39}, {'status': 'pending', 'failreason': 'No path found', 'partid': 167, 'amount_msat': 563284, 'parent_partid': 77}, {'status': 'pending', 'failreason': 'No path found', 'partid': 211, 'amount_msat': 286967, 'parent_partid': 167}, {'status': 'failed', 'failreason': 'No path found', 'partid': 430, 'amount_msat': 132425, 'parent_partid': 211}, {'status': 'pending', 'failreason': 'No path found', 'partid': 769, 'amount_msat': 132425, 'parent_partid': 430}, {'status': 'failed', 'failreason': 'No path found', 'partid': 884, 'amount_msat': 63488, 'parent_partid': 769}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1422, 'amount_msat': 63488, 'parent_partid': 884}, {'status': 'failed', 'failreason': 'No path found', 'partid': 885, 'amount_msat': 68937, 'parent_partid': 769}, {'status': 'pending', 'failreason': 'No path found', 'partid': 431, 'amount_msat': 154542, 'parent_partid': 211}, {'status': 'failed', 'failreason': 'No path found', 'partid': 770, 'amount_msat': 81294, 'parent_partid': 431}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1230, 'amount_msat': 81294, 'parent_partid': 770}, {'status': 'failed', 'failreason': 'No path found', 'partid': 771, 'amount_msat': 73248, 'parent_partid': 431}, {'status': 'failed', 'failreason': 'No path found', 'partid': 212, 'amount_msat': 276317, 'parent_partid': 167}, {'status': 'pending', 'failreason': 'No path found', 'partid': 290, 'amount_msat': 276317, 'parent_partid': 212}, {'status': 'pending', 'failreason': 'No path found', 'partid': 367, 'amount_msat': 134849, 'parent_partid': 290}, {'status': 'failed', 'failreason': 'No path found', 'partid': 725, 'amount_msat': 68680, 'parent_partid': 367}, {'status': 'failed', 'failreason': 'No path found', 'partid': 726, 'amount_msat': 66169, 'parent_partid': 367}, {'status': 'failed', 'failreason': 'No path found', 'partid': 858, 'amount_msat': 66169, 'parent_partid': 726}, {'status': 'failed', 'failreason': 'No path found', 'partid': 368, 'amount_msat': 141468, 'parent_partid': 290}, {'status': 'pending', 'failreason': 'No path found', 'partid': 481, 'amount_msat': 141468, 'parent_partid': 368}, {'status': 'failed', 'failreason': 'No path found', 'partid': 901, 'amount_msat': 71681, 'parent_partid': 481}, {'status': 'failed', 'failreason': 'No path found', 'partid': 902, 'amount_msat': 69787, 'parent_partid': 481}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1060, 'amount_msat': 69787, 'parent_partid': 902}, {'status': 'failed', 'failreason': 'No path found', 'partid': 168, 'amount_msat': 575324, 'parent_partid': 77}, {'status': 'pending', 'failreason': 'No path found', 'partid': 337, 'amount_msat': 575324, 'parent_partid': 168}, {'status': 'failed', 'failreason': 'No path found', 'partid': 622, 'amount_msat': 315685, 'parent_partid': 337}, {'status': 'pending', 'failreason': 'No path found', 'partid': 708, 'amount_msat': 315685, 'parent_partid': 622}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1183, 'amount_msat': 149551, 'parent_partid': 708}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1697, 'amount_msat': 79509, 'parent_partid': 1183}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1698, 'amount_msat': 70042, 'parent_partid': 1183}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1791, 'amount_msat': 70042, 'parent_partid': 1698}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1184, 'amount_msat': 166134, 'parent_partid': 708}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1699, 'amount_msat': 166134, 'parent_partid': 1184}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2012, 'amount_msat': 87333, 'parent_partid': 1699}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2144, 'amount_msat': 87333, 'parent_partid': 2012}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2013, 'amount_msat': 78801, 'parent_partid': 1699}, {'status': 'pending', 'failreason': 'No path found', 'partid': 623, 'amount_msat': 259639, 'parent_partid': 337}, {'status': 'pending', 'failreason': 'No path found', 'partid': 709, 'amount_msat': 130083, 'parent_partid': 623}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1185, 'amount_msat': 62022, 'parent_partid': 709}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1186, 'amount_msat': 68061, 'parent_partid': 709}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1330, 'amount_msat': 68061, 'parent_partid': 1186}, {'status': 'failed', 'failreason': 'No path found', 'partid': 710, 'amount_msat': 129556, 'parent_partid': 623}, {'status': 'pending', 'failreason': 'No path found', 'partid': 853, 'amount_msat': 129556, 'parent_partid': 710}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1040, 'amount_msat': 64789, 'parent_partid': 853}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1262, 'amount_msat': 64789, 'parent_partid': 1040}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1041, 'amount_msat': 64767, 'parent_partid': 853}, {'status': 'pending', 'failreason': 'No path found', 'partid': 21, 'amount_msat': 6249353, 'parent_partid': 13}, {'status': 'pending', 'failreason': 'No path found', 'partid': 43, 'amount_msat': 3278901, 'parent_partid': 21}, {'status': 'failed', 'failreason': 'No path found', 'partid': 82, 'amount_msat': 1557184, 'parent_partid': 43}, {'status': 'pending', 'failreason': 'No path found', 'partid': 170, 'amount_msat': 1557184, 'parent_partid': 82}, {'status': 'failed', 'failreason': 'No path found', 'partid': 340, 'amount_msat': 796327, 'parent_partid': 170}, {'status': 'pending', 'failreason': 'No path found', 'partid': 408, 'amount_msat': 796327, 'parent_partid': 340}, {'status': 'failed', 'failreason': 'No path found', 'partid': 514, 'amount_msat': 377079, 'parent_partid': 408}, {'status': 'pending', 'failreason': 'No path found', 'partid': 646, 'amount_msat': 377079, 'parent_partid': 514}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1149, 'amount_msat': 190647, 'parent_partid': 646}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1312, 'amount_msat': 88150, 'parent_partid': 1149}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1534, 'amount_msat': 88150, 'parent_partid': 1312}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1313, 'amount_msat': 102497, 'parent_partid': 1149}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1818, 'amount_msat': 53153, 'parent_partid': 1313}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2066, 'amount_msat': 53153, 'parent_partid': 1818}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1819, 'amount_msat': 49344, 'parent_partid': 1313}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1150, 'amount_msat': 186432, 'parent_partid': 646}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1314, 'amount_msat': 186432, 'parent_partid': 1150}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1535, 'amount_msat': 90325, 'parent_partid': 1314}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1536, 'amount_msat': 96107, 'parent_partid': 1314}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1955, 'amount_msat': 96107, 'parent_partid': 1536}, {'status': 'pending', 'failreason': 'No path found', 'partid': 515, 'amount_msat': 419248, 'parent_partid': 408}, {'status': 'pending', 'failreason': 'No path found', 'partid': 647, 'amount_msat': 227560, 'parent_partid': 515}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1151, 'amount_msat': 115214, 'parent_partid': 647}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1315, 'amount_msat': 59991, 'parent_partid': 1151}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1316, 'amount_msat': 55223, 'parent_partid': 1151}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1820, 'amount_msat': 55223, 'parent_partid': 1316}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1152, 'amount_msat': 112346, 'parent_partid': 647}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1681, 'amount_msat': 112346, 'parent_partid': 1152}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1781, 'amount_msat': 58702, 'parent_partid': 1681}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1782, 'amount_msat': 53644, 'parent_partid': 1681}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1930, 'amount_msat': 53644, 'parent_partid': 1782}, {'status': 'failed', 'failreason': 'No path found', 'partid': 648, 'amount_msat': 191688, 'parent_partid': 515}, {'status': 'pending', 'failreason': 'No path found', 'partid': 810, 'amount_msat': 191688, 'parent_partid': 648}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1379, 'amount_msat': 91459, 'parent_partid': 810}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1380, 'amount_msat': 100229, 'parent_partid': 810}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1850, 'amount_msat': 100229, 'parent_partid': 1380}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2076, 'amount_msat': 47738, 'parent_partid': 1850}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2163, 'amount_msat': 47738, 'parent_partid': 2076}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2077, 'amount_msat': 52491, 'parent_partid': 1850}, {'status': 'pending', 'failreason': 'No path found', 'partid': 341, 'amount_msat': 760857, 'parent_partid': 170}, {'status': 'pending', 'failreason': 'No path found', 'partid': 625, 'amount_msat': 408211, 'parent_partid': 341}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1023, 'amount_msat': 204958, 'parent_partid': 625}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1136, 'amount_msat': 109033, 'parent_partid': 1023}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1308, 'amount_msat': 109033, 'parent_partid': 1136}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1815, 'amount_msat': 57939, 'parent_partid': 1308}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1816, 'amount_msat': 51094, 'parent_partid': 1308}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1933, 'amount_msat': 51094, 'parent_partid': 1816}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1137, 'amount_msat': 95925, 'parent_partid': 1023}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1024, 'amount_msat': 203253, 'parent_partid': 625}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1513, 'amount_msat': 203253, 'parent_partid': 1024}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1613, 'amount_msat': 109349, 'parent_partid': 1513}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1757, 'amount_msat': 50515, 'parent_partid': 1613}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1758, 'amount_msat': 58834, 'parent_partid': 1613}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2056, 'amount_msat': 58834, 'parent_partid': 1758}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1614, 'amount_msat': 93904, 'parent_partid': 1513}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1992, 'amount_msat': 93904, 'parent_partid': 1614}, {'status': 'failed', 'failreason': 'No path found', 'partid': 626, 'amount_msat': 352646, 'parent_partid': 341}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1025, 'amount_msat': 352646, 'parent_partid': 626}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1514, 'amount_msat': 164352, 'parent_partid': 1025}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1615, 'amount_msat': 164352, 'parent_partid': 1514}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1759, 'amount_msat': 89392, 'parent_partid': 1615}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1760, 'amount_msat': 74960, 'parent_partid': 1615}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1922, 'amount_msat': 74960, 'parent_partid': 1760}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1515, 'amount_msat': 188294, 'parent_partid': 1025}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1915, 'amount_msat': 92358, 'parent_partid': 1515}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1916, 'amount_msat': 95936, 'parent_partid': 1515}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2100, 'amount_msat': 95936, 'parent_partid': 1916}, {'status': 'pending', 'failreason': 'No path found', 'partid': 83, 'amount_msat': 1721717, 'parent_partid': 43}, {'status': 'failed', 'failreason': 'No path found', 'partid': 106, 'amount_msat': 925248, 'parent_partid': 83}, {'status': 'pending', 'failreason': 'No path found', 'partid': 233, 'amount_msat': 925248, 'parent_partid': 106}, {'status': 'pending', 'failreason': 'No path found', 'partid': 297, 'amount_msat': 458761, 'parent_partid': 233}, {'status': 'failed', 'failreason': 'No path found', 'partid': 592, 'amount_msat': 244389, 'parent_partid': 297}, {'status': 'pending', 'failreason': 'No path found', 'partid': 690, 'amount_msat': 244389, 'parent_partid': 592}, {'status': 'failed', 'failreason': 'No path found', 'partid': 838, 'amount_msat': 129641, 'parent_partid': 690}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1400, 'amount_msat': 129641, 'parent_partid': 838}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1857, 'amount_msat': 68380, 'parent_partid': 1400}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1858, 'amount_msat': 61261, 'parent_partid': 1400}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1939, 'amount_msat': 61261, 'parent_partid': 1858}, {'status': 'pending', 'failreason': 'No path found', 'partid': 839, 'amount_msat': 114748, 'parent_partid': 690}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1401, 'amount_msat': 54890, 'parent_partid': 839}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1402, 'amount_msat': 59858, 'parent_partid': 839}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1859, 'amount_msat': 59858, 'parent_partid': 1402}, {'status': 'pending', 'failreason': 'No path found', 'partid': 593, 'amount_msat': 214372, 'parent_partid': 297}, {'status': 'failed', 'failreason': 'No path found', 'partid': 992, 'amount_msat': 111862, 'parent_partid': 593}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1120, 'amount_msat': 111862, 'parent_partid': 992}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1295, 'amount_msat': 61052, 'parent_partid': 1120}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1296, 'amount_msat': 50810, 'parent_partid': 1120}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1527, 'amount_msat': 50810, 'parent_partid': 1296}, {'status': 'pending', 'failreason': 'No path found', 'partid': 993, 'amount_msat': 102510, 'parent_partid': 593}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1488, 'amount_msat': 50408, 'parent_partid': 993}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1905, 'amount_msat': 50408, 'parent_partid': 1488}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1489, 'amount_msat': 52102, 'parent_partid': 993}, {'status': 'failed', 'failreason': 'No path found', 'partid': 298, 'amount_msat': 466487, 'parent_partid': 233}, {'status': 'pending', 'failreason': 'No path found', 'partid': 594, 'amount_msat': 466487, 'parent_partid': 298}, {'status': 'failed', 'failreason': 'No path found', 'partid': 994, 'amount_msat': 215749, 'parent_partid': 594}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1490, 'amount_msat': 215749, 'parent_partid': 994}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1594, 'amount_msat': 104373, 'parent_partid': 1490}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1986, 'amount_msat': 104373, 'parent_partid': 1594}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2131, 'amount_msat': 55654, 'parent_partid': 1986}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2132, 'amount_msat': 48719, 'parent_partid': 1986}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2149, 'amount_msat': 48719, 'parent_partid': 2132}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1595, 'amount_msat': 111376, 'parent_partid': 1490}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1748, 'amount_msat': 54109, 'parent_partid': 1595}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2052, 'amount_msat': 54109, 'parent_partid': 1748}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1749, 'amount_msat': 57267, 'parent_partid': 1595}, {'status': 'pending', 'failreason': 'No path found', 'partid': 995, 'amount_msat': 250738, 'parent_partid': 594}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1121, 'amount_msat': 126195, 'parent_partid': 995}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1297, 'amount_msat': 62444, 'parent_partid': 1121}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1298, 'amount_msat': 63751, 'parent_partid': 1121}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1811, 'amount_msat': 63751, 'parent_partid': 1298}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1122, 'amount_msat': 124543, 'parent_partid': 995}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1299, 'amount_msat': 124543, 'parent_partid': 1122}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1528, 'amount_msat': 60961, 'parent_partid': 1299}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1731, 'amount_msat': 60961, 'parent_partid': 1528}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1529, 'amount_msat': 63582, 'parent_partid': 1299}, {'status': 'pending', 'failreason': 'No path found', 'partid': 107, 'amount_msat': 796469, 'parent_partid': 83}, {'status': 'pending', 'failreason': 'No path found', 'partid': 141, 'amount_msat': 360383, 'parent_partid': 107}, {'status': 'pending', 'failreason': 'No path found', 'partid': 185, 'amount_msat': 164534, 'parent_partid': 141}, {'status': 'failed', 'failreason': 'No path found', 'partid': 262, 'amount_msat': 80672, 'parent_partid': 185}, {'status': 'failed', 'failreason': 'No path found', 'partid': 566, 'amount_msat': 80672, 'parent_partid': 262}, {'status': 'failed', 'failreason': 'No path found', 'partid': 263, 'amount_msat': 83862, 'parent_partid': 185}, {'status': 'failed', 'failreason': 'No path found', 'partid': 186, 'amount_msat': 195849, 'parent_partid': 141}, {'status': 'pending', 'failreason': 'No path found', 'partid': 264, 'amount_msat': 195849, 'parent_partid': 186}, {'status': 'failed', 'failreason': 'No path found', 'partid': 348, 'amount_msat': 90197, 'parent_partid': 264}, {'status': 'failed', 'failreason': 'No path found', 'partid': 473, 'amount_msat': 90197, 'parent_partid': 348}, {'status': 'pending', 'failreason': 'No path found', 'partid': 349, 'amount_msat': 105652, 'parent_partid': 264}, {'status': 'failed', 'failreason': 'No path found', 'partid': 713, 'amount_msat': 57623, 'parent_partid': 349}, {'status': 'failed', 'failreason': 'No path found', 'partid': 714, 'amount_msat': 48029, 'parent_partid': 349}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1188, 'amount_msat': 48029, 'parent_partid': 714}, {'status': 'failed', 'failreason': 'No path found', 'partid': 142, 'amount_msat': 436086, 'parent_partid': 107}, {'status': 'pending', 'failreason': 'No path found', 'partid': 320, 'amount_msat': 436086, 'parent_partid': 142}, {'status': 'pending', 'failreason': 'No path found', 'partid': 611, 'amount_msat': 203712, 'parent_partid': 320}, {'status': 'failed', 'failreason': 'No path found', 'partid': 698, 'amount_msat': 97970, 'parent_partid': 611}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1177, 'amount_msat': 97970, 'parent_partid': 698}, {'status': 'pending', 'failreason': 'No path found', 'partid': 699, 'amount_msat': 105742, 'parent_partid': 611}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1178, 'amount_msat': 49532, 'parent_partid': 699}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1329, 'amount_msat': 49532, 'parent_partid': 1178}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1179, 'amount_msat': 56210, 'parent_partid': 699}, {'status': 'failed', 'failreason': 'No path found', 'partid': 612, 'amount_msat': 232374, 'parent_partid': 320}, {'status': 'pending', 'failreason': 'No path found', 'partid': 700, 'amount_msat': 232374, 'parent_partid': 612}, {'status': 'pending', 'failreason': 'No path found', 'partid': 847, 'amount_msat': 113893, 'parent_partid': 700}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1407, 'amount_msat': 55534, 'parent_partid': 847}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1408, 'amount_msat': 58359, 'parent_partid': 847}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1861, 'amount_msat': 58359, 'parent_partid': 1408}, {'status': 'failed', 'failreason': 'No path found', 'partid': 848, 'amount_msat': 118481, 'parent_partid': 700}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1038, 'amount_msat': 118481, 'parent_partid': 848}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1260, 'amount_msat': 57632, 'parent_partid': 1038}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1516, 'amount_msat': 57632, 'parent_partid': 1260}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1261, 'amount_msat': 60849, 'parent_partid': 1038}, {'status': 'failed', 'failreason': 'No path found', 'partid': 44, 'amount_msat': 2970452, 'parent_partid': 21}, {'status': 'pending', 'failreason': 'No path found', 'partid': 84, 'amount_msat': 2970452, 'parent_partid': 44}, {'status': 'failed', 'failreason': 'No path found', 'partid': 108, 'amount_msat': 1422639, 'parent_partid': 84}, {'status': 'pending', 'failreason': 'No path found', 'partid': 143, 'amount_msat': 1422639, 'parent_partid': 108}, {'status': 'pending', 'failreason': 'No path found', 'partid': 187, 'amount_msat': 758781, 'parent_partid': 143}, {'status': 'pending', 'failreason': 'No path found', 'partid': 265, 'amount_msat': 347693, 'parent_partid': 187}, {'status': 'failed', 'failreason': 'No path found', 'partid': 350, 'amount_msat': 185104, 'parent_partid': 265}, {'status': 'pending', 'failreason': 'No path found', 'partid': 474, 'amount_msat': 185104, 'parent_partid': 350}, {'status': 'failed', 'failreason': 'No path found', 'partid': 897, 'amount_msat': 97549, 'parent_partid': 474}, {'status': 'failed', 'failreason': 'No path found', 'partid': 898, 'amount_msat': 87555, 'parent_partid': 474}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1429, 'amount_msat': 87555, 'parent_partid': 898}, {'status': 'pending', 'failreason': 'No path found', 'partid': 351, 'amount_msat': 162589, 'parent_partid': 265}, {'status': 'failed', 'failreason': 'No path found', 'partid': 715, 'amount_msat': 73245, 'parent_partid': 351}, {'status': 'failed', 'failreason': 'No path found', 'partid': 716, 'amount_msat': 89344, 'parent_partid': 351}, {'status': 'failed', 'failreason': 'No path found', 'partid': 856, 'amount_msat': 89344, 'parent_partid': 716}, {'status': 'failed', 'failreason': 'No path found', 'partid': 266, 'amount_msat': 411088, 'parent_partid': 187}, {'status': 'pending', 'failreason': 'No path found', 'partid': 567, 'amount_msat': 411088, 'parent_partid': 266}, {'status': 'failed', 'failreason': 'No path found', 'partid': 974, 'amount_msat': 213374, 'parent_partid': 567}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1103, 'amount_msat': 213374, 'parent_partid': 974}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1289, 'amount_msat': 114303, 'parent_partid': 1103}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1807, 'amount_msat': 55066, 'parent_partid': 1289}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1808, 'amount_msat': 59237, 'parent_partid': 1289}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2065, 'amount_msat': 59237, 'parent_partid': 1808}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1290, 'amount_msat': 99071, 'parent_partid': 1103}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1809, 'amount_msat': 99071, 'parent_partid': 1290}, {'status': 'pending', 'failreason': 'No path found', 'partid': 975, 'amount_msat': 197714, 'parent_partid': 567}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1104, 'amount_msat': 91184, 'parent_partid': 975}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1655, 'amount_msat': 91184, 'parent_partid': 1104}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1105, 'amount_msat': 106530, 'parent_partid': 975}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1656, 'amount_msat': 55499, 'parent_partid': 1105}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2000, 'amount_msat': 55499, 'parent_partid': 1656}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1657, 'amount_msat': 51031, 'parent_partid': 1105}, {'status': 'failed', 'failreason': 'No path found', 'partid': 188, 'amount_msat': 663858, 'parent_partid': 143}, {'status': 'pending', 'failreason': 'No path found', 'partid': 417, 'amount_msat': 663858, 'parent_partid': 188}, {'status': 'failed', 'failreason': 'No path found', 'partid': 522, 'amount_msat': 308638, 'parent_partid': 417}, {'status': 'pending', 'failreason': 'No path found', 'partid': 936, 'amount_msat': 308638, 'parent_partid': 522}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1454, 'amount_msat': 156915, 'parent_partid': 936}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1890, 'amount_msat': 156915, 'parent_partid': 1454}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2090, 'amount_msat': 75009, 'parent_partid': 1890}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2164, 'amount_msat': 75009, 'parent_partid': 2090}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2091, 'amount_msat': 81906, 'parent_partid': 1890}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1455, 'amount_msat': 151723, 'parent_partid': 936}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1891, 'amount_msat': 73261, 'parent_partid': 1455}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1892, 'amount_msat': 78462, 'parent_partid': 1455}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2092, 'amount_msat': 78462, 'parent_partid': 1892}, {'status': 'pending', 'failreason': 'No path found', 'partid': 523, 'amount_msat': 355220, 'parent_partid': 417}, {'status': 'failed', 'failreason': 'No path found', 'partid': 652, 'amount_msat': 163945, 'parent_partid': 523}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1154, 'amount_msat': 163945, 'parent_partid': 652}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1682, 'amount_msat': 88265, 'parent_partid': 1154}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1783, 'amount_msat': 88265, 'parent_partid': 1682}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1683, 'amount_msat': 75680, 'parent_partid': 1154}, {'status': 'pending', 'failreason': 'No path found', 'partid': 653, 'amount_msat': 191275, 'parent_partid': 523}, {'status': 'failed', 'failreason': 'No path found', 'partid': 811, 'amount_msat': 92684, 'parent_partid': 653}, {'status': 'failed', 'failreason': 'No path found', 'partid': 812, 'amount_msat': 98591, 'parent_partid': 653}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1381, 'amount_msat': 98591, 'parent_partid': 812}, {'status': 'pending', 'failreason': 'No path found', 'partid': 109, 'amount_msat': 1547813, 'parent_partid': 84}, {'status': 'failed', 'failreason': 'No path found', 'partid': 144, 'amount_msat': 791897, 'parent_partid': 109}, {'status': 'pending', 'failreason': 'No path found', 'partid': 189, 'amount_msat': 791897, 'parent_partid': 144}, {'status': 'pending', 'failreason': 'No path found', 'partid': 267, 'amount_msat': 361080, 'parent_partid': 189}, {'status': 'failed', 'failreason': 'No path found', 'partid': 568, 'amount_msat': 183859, 'parent_partid': 267}, {'status': 'pending', 'failreason': 'No path found', 'partid': 976, 'amount_msat': 183859, 'parent_partid': 568}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1479, 'amount_msat': 83082, 'parent_partid': 976}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1480, 'amount_msat': 100777, 'parent_partid': 976}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1590, 'amount_msat': 100777, 'parent_partid': 1480}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1979, 'amount_msat': 53201, 'parent_partid': 1590}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1980, 'amount_msat': 47576, 'parent_partid': 1590}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2129, 'amount_msat': 47576, 'parent_partid': 1980}, {'status': 'pending', 'failreason': 'No path found', 'partid': 569, 'amount_msat': 177221, 'parent_partid': 267}, {'status': 'failed', 'failreason': 'No path found', 'partid': 677, 'amount_msat': 85241, 'parent_partid': 569}, {'status': 'failed', 'failreason': 'No path found', 'partid': 678, 'amount_msat': 91980, 'parent_partid': 569}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1171, 'amount_msat': 91980, 'parent_partid': 678}, {'status': 'failed', 'failreason': 'No path found', 'partid': 268, 'amount_msat': 430817, 'parent_partid': 189}, {'status': 'pending', 'failreason': 'No path found', 'partid': 570, 'amount_msat': 430817, 'parent_partid': 268}, {'status': 'pending', 'failreason': 'No path found', 'partid': 977, 'amount_msat': 196434, 'parent_partid': 570}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1106, 'amount_msat': 95338, 'parent_partid': 977}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1658, 'amount_msat': 95338, 'parent_partid': 1106}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1107, 'amount_msat': 101096, 'parent_partid': 977}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1291, 'amount_msat': 52630, 'parent_partid': 1107}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1292, 'amount_msat': 48466, 'parent_partid': 1107}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1810, 'amount_msat': 48466, 'parent_partid': 1292}, {'status': 'failed', 'failreason': 'No path found', 'partid': 978, 'amount_msat': 234383, 'parent_partid': 570}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1108, 'amount_msat': 234383, 'parent_partid': 978}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1659, 'amount_msat': 116012, 'parent_partid': 1108}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2001, 'amount_msat': 58861, 'parent_partid': 1659}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2002, 'amount_msat': 57151, 'parent_partid': 1659}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2139, 'amount_msat': 57151, 'parent_partid': 2002}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1660, 'amount_msat': 118371, 'parent_partid': 1108}, {'status': 'pending', 'failreason': 'No path found', 'partid': 2003, 'amount_msat': 118371, 'parent_partid': 1660}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2140, 'amount_msat': 58092, 'parent_partid': 2003}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2177, 'amount_msat': 58092, 'parent_partid': 2140}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2141, 'amount_msat': 60279, 'parent_partid': 2003}, {'status': 'pending', 'failreason': 'No path found', 'partid': 145, 'amount_msat': 755916, 'parent_partid': 109}, {'status': 'failed', 'failreason': 'No path found', 'partid': 190, 'amount_msat': 411361, 'parent_partid': 145}, {'status': 'pending', 'failreason': 'No path found', 'partid': 269, 'amount_msat': 411361, 'parent_partid': 190}, {'status': 'failed', 'failreason': 'No path found', 'partid': 352, 'amount_msat': 208549, 'parent_partid': 269}, {'status': 'pending', 'failreason': 'No path found', 'partid': 717, 'amount_msat': 208549, 'parent_partid': 352}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1189, 'amount_msat': 99996, 'parent_partid': 717}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1190, 'amount_msat': 108553, 'parent_partid': 717}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1333, 'amount_msat': 108553, 'parent_partid': 1190}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1828, 'amount_msat': 55505, 'parent_partid': 1333}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1935, 'amount_msat': 55505, 'parent_partid': 1828}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1829, 'amount_msat': 53048, 'parent_partid': 1333}, {'status': 'pending', 'failreason': 'No path found', 'partid': 353, 'amount_msat': 202812, 'parent_partid': 269}, {'status': 'failed', 'failreason': 'No path found', 'partid': 718, 'amount_msat': 98191, 'parent_partid': 353}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1191, 'amount_msat': 98191, 'parent_partid': 718}, {'status': 'pending', 'failreason': 'No path found', 'partid': 719, 'amount_msat': 104621, 'parent_partid': 353}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1192, 'amount_msat': 49156, 'parent_partid': 719}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1700, 'amount_msat': 49156, 'parent_partid': 1192}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1193, 'amount_msat': 55465, 'parent_partid': 719}, {'status': 'pending', 'failreason': 'No path found', 'partid': 191, 'amount_msat': 344555, 'parent_partid': 145}, {'status': 'failed', 'failreason': 'No path found', 'partid': 418, 'amount_msat': 177431, 'parent_partid': 191}, {'status': 'pending', 'failreason': 'No path found', 'partid': 524, 'amount_msat': 177431, 'parent_partid': 418}, {'status': 'failed', 'failreason': 'No path found', 'partid': 654, 'amount_msat': 94731, 'parent_partid': 524}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1155, 'amount_msat': 94731, 'parent_partid': 654}, {'status': 'failed', 'failreason': 'No path found', 'partid': 655, 'amount_msat': 82700, 'parent_partid': 524}, {'status': 'pending', 'failreason': 'No path found', 'partid': 419, 'amount_msat': 167124, 'parent_partid': 191}, {'status': 'failed', 'failreason': 'No path found', 'partid': 525, 'amount_msat': 89227, 'parent_partid': 419}, {'status': 'failed', 'failreason': 'No path found', 'partid': 526, 'amount_msat': 77897, 'parent_partid': 419}, {'status': 'failed', 'failreason': 'No path found', 'partid': 656, 'amount_msat': 77897, 'parent_partid': 526}, {'status': 'pending', 'failreason': 'No path found', 'partid': 7, 'amount_msat': 13612092, 'parent_partid': 1}, {'status': 'failed', 'failreason': 'No path found', 'partid': 14, 'amount_msat': 6823774, 'parent_partid': 7}, {'status': 'pending', 'failreason': 'No path found', 'partid': 22, 'amount_msat': 6823774, 'parent_partid': 14}, {'status': 'failed', 'failreason': 'No path found', 'partid': 30, 'amount_msat': 3660597, 'parent_partid': 22}, {'status': 'pending', 'failreason': 'No path found', 'partid': 58, 'amount_msat': 3660597, 'parent_partid': 30}, {'status': 'failed', 'failreason': 'No path found', 'partid': 122, 'amount_msat': 1980677, 'parent_partid': 58}, {'status': 'pending', 'failreason': 'No path found', 'partid': 155, 'amount_msat': 1980677, 'parent_partid': 122}, {'status': 'pending', 'failreason': 'No path found', 'partid': 325, 'amount_msat': 1003890, 'parent_partid': 155}, {'status': 'pending', 'failreason': 'No path found', 'partid': 393, 'amount_msat': 536229, 'parent_partid': 325}, {'status': 'failed', 'failreason': 'No path found', 'partid': 500, 'amount_msat': 248089, 'parent_partid': 393}, {'status': 'pending', 'failreason': 'No path found', 'partid': 918, 'amount_msat': 248089, 'parent_partid': 500}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1439, 'amount_msat': 124372, 'parent_partid': 918}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1878, 'amount_msat': 66928, 'parent_partid': 1439}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1945, 'amount_msat': 66928, 'parent_partid': 1878}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1879, 'amount_msat': 57444, 'parent_partid': 1439}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1440, 'amount_msat': 123717, 'parent_partid': 918}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1578, 'amount_msat': 123717, 'parent_partid': 1440}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1746, 'amount_msat': 63506, 'parent_partid': 1578}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2051, 'amount_msat': 63506, 'parent_partid': 1746}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1747, 'amount_msat': 60211, 'parent_partid': 1578}, {'status': 'pending', 'failreason': 'No path found', 'partid': 501, 'amount_msat': 288140, 'parent_partid': 393}, {'status': 'pending', 'failreason': 'No path found', 'partid': 919, 'amount_msat': 137401, 'parent_partid': 501}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1070, 'amount_msat': 69009, 'parent_partid': 919}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1640, 'amount_msat': 69009, 'parent_partid': 1070}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1071, 'amount_msat': 68392, 'parent_partid': 919}, {'status': 'failed', 'failreason': 'No path found', 'partid': 920, 'amount_msat': 150739, 'parent_partid': 501}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1072, 'amount_msat': 150739, 'parent_partid': 920}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1272, 'amount_msat': 68287, 'parent_partid': 1072}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1520, 'amount_msat': 68287, 'parent_partid': 1272}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1273, 'amount_msat': 82452, 'parent_partid': 1072}, {'status': 'failed', 'failreason': 'No path found', 'partid': 394, 'amount_msat': 467661, 'parent_partid': 325}, {'status': 'pending', 'failreason': 'No path found', 'partid': 502, 'amount_msat': 467661, 'parent_partid': 394}, {'status': 'pending', 'failreason': 'No path found', 'partid': 921, 'amount_msat': 242003, 'parent_partid': 502}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1441, 'amount_msat': 115729, 'parent_partid': 921}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1880, 'amount_msat': 58270, 'parent_partid': 1441}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1946, 'amount_msat': 58270, 'parent_partid': 1880}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1881, 'amount_msat': 57459, 'parent_partid': 1441}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1442, 'amount_msat': 126274, 'parent_partid': 921}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1882, 'amount_msat': 126274, 'parent_partid': 1442}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2084, 'amount_msat': 66011, 'parent_partid': 1882}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2109, 'amount_msat': 66011, 'parent_partid': 2084}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2085, 'amount_msat': 60263, 'parent_partid': 1882}, {'status': 'failed', 'failreason': 'No path found', 'partid': 922, 'amount_msat': 225658, 'parent_partid': 502}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1443, 'amount_msat': 225658, 'parent_partid': 922}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1579, 'amount_msat': 117424, 'parent_partid': 1443}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1974, 'amount_msat': 62393, 'parent_partid': 1579}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2126, 'amount_msat': 62393, 'parent_partid': 1974}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1975, 'amount_msat': 55031, 'parent_partid': 1579}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1580, 'amount_msat': 108234, 'parent_partid': 1443}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1976, 'amount_msat': 108234, 'parent_partid': 1580}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2127, 'amount_msat': 54194, 'parent_partid': 1976}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2128, 'amount_msat': 54040, 'parent_partid': 1976}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2175, 'amount_msat': 54040, 'parent_partid': 2128}, {'status': 'failed', 'failreason': 'No path found', 'partid': 326, 'amount_msat': 976787, 'parent_partid': 155}, {'status': 'pending', 'failreason': 'No path found', 'partid': 395, 'amount_msat': 976787, 'parent_partid': 326}, {'status': 'pending', 'failreason': 'No path found', 'partid': 503, 'amount_msat': 474071, 'parent_partid': 395}, {'status': 'failed', 'failreason': 'No path found', 'partid': 634, 'amount_msat': 215595, 'parent_partid': 503}, {'status': 'pending', 'failreason': 'No path found', 'partid': 802, 'amount_msat': 215595, 'parent_partid': 634}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1371, 'amount_msat': 112948, 'parent_partid': 802}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1556, 'amount_msat': 54070, 'parent_partid': 1371}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1742, 'amount_msat': 54070, 'parent_partid': 1556}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1557, 'amount_msat': 58878, 'parent_partid': 1371}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1372, 'amount_msat': 102647, 'parent_partid': 802}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1558, 'amount_msat': 102647, 'parent_partid': 1372}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1965, 'amount_msat': 49624, 'parent_partid': 1558}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1966, 'amount_msat': 53023, 'parent_partid': 1558}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2032, 'amount_msat': 53023, 'parent_partid': 1966}, {'status': 'pending', 'failreason': 'No path found', 'partid': 635, 'amount_msat': 258476, 'parent_partid': 503}, {'status': 'pending', 'failreason': 'No path found', 'partid': 803, 'amount_msat': 120654, 'parent_partid': 635}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1373, 'amount_msat': 60554, 'parent_partid': 803}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1374, 'amount_msat': 60100, 'parent_partid': 803}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1848, 'amount_msat': 60100, 'parent_partid': 1374}, {'status': 'failed', 'failreason': 'No path found', 'partid': 804, 'amount_msat': 137822, 'parent_partid': 635}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1375, 'amount_msat': 137822, 'parent_partid': 804}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1559, 'amount_msat': 69716, 'parent_partid': 1375}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1560, 'amount_msat': 68106, 'parent_partid': 1375}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1967, 'amount_msat': 68106, 'parent_partid': 1560}, {'status': 'failed', 'failreason': 'No path found', 'partid': 504, 'amount_msat': 502716, 'parent_partid': 395}, {'status': 'pending', 'failreason': 'No path found', 'partid': 636, 'amount_msat': 502716, 'parent_partid': 504}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1142, 'amount_msat': 261754, 'parent_partid': 636}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1677, 'amount_msat': 261754, 'parent_partid': 1142}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1778, 'amount_msat': 123357, 'parent_partid': 1677}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1927, 'amount_msat': 123357, 'parent_partid': 1778}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2026, 'amount_msat': 65267, 'parent_partid': 1927}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2146, 'amount_msat': 65267, 'parent_partid': 2026}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2027, 'amount_msat': 58090, 'parent_partid': 1927}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1779, 'amount_msat': 138397, 'parent_partid': 1677}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1928, 'amount_msat': 72290, 'parent_partid': 1779}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2118, 'amount_msat': 72290, 'parent_partid': 1928}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1929, 'amount_msat': 66107, 'parent_partid': 1779}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1143, 'amount_msat': 240962, 'parent_partid': 636}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1678, 'amount_msat': 121178, 'parent_partid': 1143}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1780, 'amount_msat': 121178, 'parent_partid': 1678}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2057, 'amount_msat': 56068, 'parent_partid': 1780}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2058, 'amount_msat': 65110, 'parent_partid': 1780}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2157, 'amount_msat': 65110, 'parent_partid': 2058}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1679, 'amount_msat': 119784, 'parent_partid': 1143}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2009, 'amount_msat': 61485, 'parent_partid': 1679}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2010, 'amount_msat': 58299, 'parent_partid': 1679}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2143, 'amount_msat': 58299, 'parent_partid': 2010}, {'status': 'pending', 'failreason': 'No path found', 'partid': 123, 'amount_msat': 1679920, 'parent_partid': 58}, {'status': 'failed', 'failreason': 'No path found', 'partid': 156, 'amount_msat': 820769, 'parent_partid': 123}, {'status': 'pending', 'failreason': 'No path found', 'partid': 203, 'amount_msat': 820769, 'parent_partid': 156}, {'status': 'failed', 'failreason': 'No path found', 'partid': 284, 'amount_msat': 375125, 'parent_partid': 203}, {'status': 'pending', 'failreason': 'No path found', 'partid': 364, 'amount_msat': 375125, 'parent_partid': 284}, {'status': 'failed', 'failreason': 'No path found', 'partid': 722, 'amount_msat': 198739, 'parent_partid': 364}, {'status': 'pending', 'failreason': 'No path found', 'partid': 857, 'amount_msat': 198739, 'parent_partid': 722}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1412, 'amount_msat': 92398, 'parent_partid': 857}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1570, 'amount_msat': 92398, 'parent_partid': 1412}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1413, 'amount_msat': 106341, 'parent_partid': 857}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1571, 'amount_msat': 54375, 'parent_partid': 1413}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1572, 'amount_msat': 51966, 'parent_partid': 1413}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1744, 'amount_msat': 51966, 'parent_partid': 1572}, {'status': 'pending', 'failreason': 'No path found', 'partid': 723, 'amount_msat': 176386, 'parent_partid': 364}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1194, 'amount_msat': 92485, 'parent_partid': 723}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1701, 'amount_msat': 92485, 'parent_partid': 1194}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1195, 'amount_msat': 83901, 'parent_partid': 723}, {'status': 'pending', 'failreason': 'No path found', 'partid': 285, 'amount_msat': 445644, 'parent_partid': 203}, {'status': 'failed', 'failreason': 'No path found', 'partid': 578, 'amount_msat': 239562, 'parent_partid': 285}, {'status': 'pending', 'failreason': 'No path found', 'partid': 983, 'amount_msat': 239562, 'parent_partid': 578}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1112, 'amount_msat': 118770, 'parent_partid': 983}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1662, 'amount_msat': 118770, 'parent_partid': 1112}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1772, 'amount_msat': 56761, 'parent_partid': 1662}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1923, 'amount_msat': 56761, 'parent_partid': 1772}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1773, 'amount_msat': 62009, 'parent_partid': 1662}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1113, 'amount_msat': 120792, 'parent_partid': 983}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1663, 'amount_msat': 62912, 'parent_partid': 1113}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1664, 'amount_msat': 57880, 'parent_partid': 1113}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2004, 'amount_msat': 57880, 'parent_partid': 1664}, {'status': 'pending', 'failreason': 'No path found', 'partid': 579, 'amount_msat': 206082, 'parent_partid': 285}, {'status': 'failed', 'failreason': 'No path found', 'partid': 679, 'amount_msat': 93733, 'parent_partid': 579}, {'status': 'failed', 'failreason': 'No path found', 'partid': 680, 'amount_msat': 112349, 'parent_partid': 579}, {'status': 'pending', 'failreason': 'No path found', 'partid': 830, 'amount_msat': 112349, 'parent_partid': 680}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1394, 'amount_msat': 51109, 'parent_partid': 830}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1855, 'amount_msat': 51109, 'parent_partid': 1394}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1395, 'amount_msat': 61240, 'parent_partid': 830}, {'status': 'pending', 'failreason': 'No path found', 'partid': 157, 'amount_msat': 859151, 'parent_partid': 123}, {'status': 'failed', 'failreason': 'No path found', 'partid': 204, 'amount_msat': 398859, 'parent_partid': 157}, {'status': 'pending', 'failreason': 'No path found', 'partid': 423, 'amount_msat': 398859, 'parent_partid': 204}, {'status': 'failed', 'failreason': 'No path found', 'partid': 760, 'amount_msat': 217507, 'parent_partid': 423}, {'status': 'pending', 'failreason': 'No path found', 'partid': 877, 'amount_msat': 217507, 'parent_partid': 760}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1050, 'amount_msat': 117427, 'parent_partid': 877}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1630, 'amount_msat': 117427, 'parent_partid': 1050}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1994, 'amount_msat': 60333, 'parent_partid': 1630}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2138, 'amount_msat': 60333, 'parent_partid': 1994}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1995, 'amount_msat': 57094, 'parent_partid': 1630}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1051, 'amount_msat': 100080, 'parent_partid': 877}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1631, 'amount_msat': 52636, 'parent_partid': 1051}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1632, 'amount_msat': 47444, 'parent_partid': 1051}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1766, 'amount_msat': 47444, 'parent_partid': 1632}, {'status': 'pending', 'failreason': 'No path found', 'partid': 761, 'amount_msat': 181352, 'parent_partid': 423}, {'status': 'failed', 'failreason': 'No path found', 'partid': 878, 'amount_msat': 84661, 'parent_partid': 761}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1052, 'amount_msat': 84661, 'parent_partid': 878}, {'status': 'failed', 'failreason': 'No path found', 'partid': 879, 'amount_msat': 96691, 'parent_partid': 761}, {'status': 'pending', 'failreason': 'No path found', 'partid': 205, 'amount_msat': 460292, 'parent_partid': 157}, {'status': 'failed', 'failreason': 'No path found', 'partid': 286, 'amount_msat': 237483, 'parent_partid': 205}, {'status': 'pending', 'failreason': 'No path found', 'partid': 580, 'amount_msat': 237483, 'parent_partid': 286}, {'status': 'pending', 'failreason': 'No path found', 'partid': 681, 'amount_msat': 107034, 'parent_partid': 580}, {'status': 'failed', 'failreason': 'No path found', 'partid': 831, 'amount_msat': 51275, 'parent_partid': 681}, {'status': 'failed', 'failreason': 'No path found', 'partid': 832, 'amount_msat': 55759, 'parent_partid': 681}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1396, 'amount_msat': 55759, 'parent_partid': 832}, {'status': 'failed', 'failreason': 'No path found', 'partid': 682, 'amount_msat': 130449, 'parent_partid': 580}, {'status': 'pending', 'failreason': 'No path found', 'partid': 833, 'amount_msat': 130449, 'parent_partid': 682}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1397, 'amount_msat': 64221, 'parent_partid': 833}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1398, 'amount_msat': 66228, 'parent_partid': 833}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1856, 'amount_msat': 66228, 'parent_partid': 1398}, {'status': 'pending', 'failreason': 'No path found', 'partid': 287, 'amount_msat': 222809, 'parent_partid': 205}, {'status': 'pending', 'failreason': 'No path found', 'partid': 581, 'amount_msat': 109435, 'parent_partid': 287}, {'status': 'failed', 'failreason': 'No path found', 'partid': 984, 'amount_msat': 56224, 'parent_partid': 581}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1483, 'amount_msat': 56224, 'parent_partid': 984}, {'status': 'failed', 'failreason': 'No path found', 'partid': 985, 'amount_msat': 53211, 'parent_partid': 581}, {'status': 'failed', 'failreason': 'No path found', 'partid': 582, 'amount_msat': 113374, 'parent_partid': 287}, {'status': 'pending', 'failreason': 'No path found', 'partid': 683, 'amount_msat': 113374, 'parent_partid': 582}, {'status': 'failed', 'failreason': 'No path found', 'partid': 834, 'amount_msat': 53275, 'parent_partid': 683}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1399, 'amount_msat': 53275, 'parent_partid': 834}, {'status': 'failed', 'failreason': 'No path found', 'partid': 835, 'amount_msat': 60099, 'parent_partid': 683}, {'status': 'pending', 'failreason': 'No path found', 'partid': 31, 'amount_msat': 3163177, 'parent_partid': 22}, {'status': 'pending', 'failreason': 'No path found', 'partid': 59, 'amount_msat': 1709313, 'parent_partid': 31}, {'status': 'failed', 'failreason': 'No path found', 'partid': 72, 'amount_msat': 895721, 'parent_partid': 59}, {'status': 'pending', 'failreason': 'No path found', 'partid': 164, 'amount_msat': 895721, 'parent_partid': 72}, {'status': 'pending', 'failreason': 'No path found', 'partid': 333, 'amount_msat': 420920, 'parent_partid': 164}, {'status': 'failed', 'failreason': 'No path found', 'partid': 402, 'amount_msat': 196580, 'parent_partid': 333}, {'status': 'pending', 'failreason': 'No path found', 'partid': 508, 'amount_msat': 196580, 'parent_partid': 402}, {'status': 'failed', 'failreason': 'No path found', 'partid': 641, 'amount_msat': 96953, 'parent_partid': 508}, {'status': 'failed', 'failreason': 'No path found', 'partid': 642, 'amount_msat': 99627, 'parent_partid': 508}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1147, 'amount_msat': 99627, 'parent_partid': 642}, {'status': 'pending', 'failreason': 'No path found', 'partid': 403, 'amount_msat': 224340, 'parent_partid': 333}, {'status': 'pending', 'failreason': 'No path found', 'partid': 749, 'amount_msat': 122279, 'parent_partid': 403}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1213, 'amount_msat': 64968, 'parent_partid': 749}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1214, 'amount_msat': 57311, 'parent_partid': 749}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1340, 'amount_msat': 57311, 'parent_partid': 1214}, {'status': 'failed', 'failreason': 'No path found', 'partid': 750, 'amount_msat': 102061, 'parent_partid': 403}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1215, 'amount_msat': 102061, 'parent_partid': 750}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1341, 'amount_msat': 45932, 'parent_partid': 1215}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1342, 'amount_msat': 56129, 'parent_partid': 1215}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1834, 'amount_msat': 56129, 'parent_partid': 1342}, {'status': 'failed', 'failreason': 'No path found', 'partid': 334, 'amount_msat': 474801, 'parent_partid': 164}, {'status': 'pending', 'failreason': 'No path found', 'partid': 620, 'amount_msat': 474801, 'parent_partid': 334}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1019, 'amount_msat': 241460, 'parent_partid': 620}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1133, 'amount_msat': 113109, 'parent_partid': 1019}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1673, 'amount_msat': 59729, 'parent_partid': 1133}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1674, 'amount_msat': 53380, 'parent_partid': 1133}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2006, 'amount_msat': 53380, 'parent_partid': 1674}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1134, 'amount_msat': 128351, 'parent_partid': 1019}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1307, 'amount_msat': 128351, 'parent_partid': 1134}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1813, 'amount_msat': 66401, 'parent_partid': 1307}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1814, 'amount_msat': 61950, 'parent_partid': 1307}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1932, 'amount_msat': 61950, 'parent_partid': 1814}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1020, 'amount_msat': 233341, 'parent_partid': 620}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1510, 'amount_msat': 233341, 'parent_partid': 1020}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1913, 'amount_msat': 121421, 'parent_partid': 1510}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1952, 'amount_msat': 66640, 'parent_partid': 1913}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2120, 'amount_msat': 66640, 'parent_partid': 1952}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1953, 'amount_msat': 54781, 'parent_partid': 1913}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1914, 'amount_msat': 111920, 'parent_partid': 1510}, {'status': 'pending', 'failreason': 'No path found', 'partid': 2099, 'amount_msat': 111920, 'parent_partid': 1914}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2113, 'amount_msat': 51953, 'parent_partid': 2099}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2114, 'amount_msat': 59967, 'parent_partid': 2099}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2172, 'amount_msat': 59967, 'parent_partid': 2114}, {'status': 'pending', 'failreason': 'No path found', 'partid': 73, 'amount_msat': 813592, 'parent_partid': 59}, {'status': 'failed', 'failreason': 'No path found', 'partid': 96, 'amount_msat': 402948, 'parent_partid': 73}, {'status': 'pending', 'failreason': 'No path found', 'partid': 225, 'amount_msat': 402948, 'parent_partid': 96}, {'status': 'pending', 'failreason': 'No path found', 'partid': 445, 'amount_msat': 213475, 'parent_partid': 225}, {'status': 'failed', 'failreason': 'No path found', 'partid': 778, 'amount_msat': 96141, 'parent_partid': 445}, {'status': 'failed', 'failreason': 'No path found', 'partid': 888, 'amount_msat': 96141, 'parent_partid': 778}, {'status': 'pending', 'failreason': 'No path found', 'partid': 779, 'amount_msat': 117334, 'parent_partid': 445}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1236, 'amount_msat': 57027, 'parent_partid': 779}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1719, 'amount_msat': 57027, 'parent_partid': 1236}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1237, 'amount_msat': 60307, 'parent_partid': 779}, {'status': 'failed', 'failreason': 'No path found', 'partid': 446, 'amount_msat': 189473, 'parent_partid': 225}, {'status': 'pending', 'failreason': 'No path found', 'partid': 543, 'amount_msat': 189473, 'parent_partid': 446}, {'status': 'failed', 'failreason': 'No path found', 'partid': 668, 'amount_msat': 93706, 'parent_partid': 543}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1162, 'amount_msat': 93706, 'parent_partid': 668}, {'status': 'failed', 'failreason': 'No path found', 'partid': 669, 'amount_msat': 95767, 'parent_partid': 543}, {'status': 'pending', 'failreason': 'No path found', 'partid': 97, 'amount_msat': 410644, 'parent_partid': 73}, {'status': 'pending', 'failreason': 'No path found', 'partid': 133, 'amount_msat': 209817, 'parent_partid': 97}, {'status': 'failed', 'failreason': 'No path found', 'partid': 176, 'amount_msat': 114299, 'parent_partid': 133}, {'status': 'pending', 'failreason': 'No path found', 'partid': 345, 'amount_msat': 114299, 'parent_partid': 176}, {'status': 'failed', 'failreason': 'No path found', 'partid': 627, 'amount_msat': 60980, 'parent_partid': 345}, {'status': 'failed', 'failreason': 'No path found', 'partid': 628, 'amount_msat': 53319, 'parent_partid': 345}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1026, 'amount_msat': 53319, 'parent_partid': 628}, {'status': 'failed', 'failreason': 'No path found', 'partid': 177, 'amount_msat': 95518, 'parent_partid': 133}, {'status': 'failed', 'failreason': 'No path found', 'partid': 134, 'amount_msat': 200827, 'parent_partid': 97}, {'status': 'pending', 'failreason': 'No path found', 'partid': 316, 'amount_msat': 200827, 'parent_partid': 134}, {'status': 'failed', 'failreason': 'No path found', 'partid': 385, 'amount_msat': 99753, 'parent_partid': 316}, {'status': 'failed', 'failreason': 'No path found', 'partid': 386, 'amount_msat': 101074, 'parent_partid': 316}, {'status': 'pending', 'failreason': 'No path found', 'partid': 736, 'amount_msat': 101074, 'parent_partid': 386}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1202, 'amount_msat': 46180, 'parent_partid': 736}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1703, 'amount_msat': 46180, 'parent_partid': 1202}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1203, 'amount_msat': 54894, 'parent_partid': 736}, {'status': 'failed', 'failreason': 'No path found', 'partid': 60, 'amount_msat': 1453864, 'parent_partid': 31}, {'status': 'pending', 'failreason': 'No path found', 'partid': 124, 'amount_msat': 1453864, 'parent_partid': 60}, {'status': 'failed', 'failreason': 'No path found', 'partid': 244, 'amount_msat': 778915, 'parent_partid': 124}, {'status': 'pending', 'failreason': 'No path found', 'partid': 305, 'amount_msat': 778915, 'parent_partid': 244}, {'status': 'pending', 'failreason': 'No path found', 'partid': 601, 'amount_msat': 372070, 'parent_partid': 305}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1003, 'amount_msat': 202720, 'parent_partid': 601}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1495, 'amount_msat': 109886, 'parent_partid': 1003}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1597, 'amount_msat': 50251, 'parent_partid': 1495}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1598, 'amount_msat': 59635, 'parent_partid': 1495}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1750, 'amount_msat': 59635, 'parent_partid': 1598}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1496, 'amount_msat': 92834, 'parent_partid': 1003}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1599, 'amount_msat': 92834, 'parent_partid': 1496}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1004, 'amount_msat': 169350, 'parent_partid': 601}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1124, 'amount_msat': 169350, 'parent_partid': 1004}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1300, 'amount_msat': 92099, 'parent_partid': 1124}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1812, 'amount_msat': 92099, 'parent_partid': 1300}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1301, 'amount_msat': 77251, 'parent_partid': 1124}, {'status': 'failed', 'failreason': 'No path found', 'partid': 602, 'amount_msat': 406845, 'parent_partid': 305}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1005, 'amount_msat': 406845, 'parent_partid': 602}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1125, 'amount_msat': 188152, 'parent_partid': 1005}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1302, 'amount_msat': 91322, 'parent_partid': 1125}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1530, 'amount_msat': 91322, 'parent_partid': 1302}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1303, 'amount_msat': 96830, 'parent_partid': 1125}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1126, 'amount_msat': 218693, 'parent_partid': 1005}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1304, 'amount_msat': 218693, 'parent_partid': 1126}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1531, 'amount_msat': 105400, 'parent_partid': 1304}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1732, 'amount_msat': 48666, 'parent_partid': 1531}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2048, 'amount_msat': 48666, 'parent_partid': 1732}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1733, 'amount_msat': 56734, 'parent_partid': 1531}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1532, 'amount_msat': 113293, 'parent_partid': 1304}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1734, 'amount_msat': 113293, 'parent_partid': 1532}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1917, 'amount_msat': 59226, 'parent_partid': 1734}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1918, 'amount_msat': 54067, 'parent_partid': 1734}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2023, 'amount_msat': 54067, 'parent_partid': 1918}, {'status': 'pending', 'failreason': 'No path found', 'partid': 245, 'amount_msat': 674949, 'parent_partid': 124}, {'status': 'failed', 'failreason': 'No path found', 'partid': 306, 'amount_msat': 348382, 'parent_partid': 245}, {'status': 'pending', 'failreason': 'No path found', 'partid': 375, 'amount_msat': 348382, 'parent_partid': 306}, {'status': 'failed', 'failreason': 'No path found', 'partid': 488, 'amount_msat': 184586, 'parent_partid': 375}, {'status': 'pending', 'failreason': 'No path found', 'partid': 907, 'amount_msat': 184586, 'parent_partid': 488}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1431, 'amount_msat': 86079, 'parent_partid': 907}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1432, 'amount_msat': 98507, 'parent_partid': 907}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1577, 'amount_msat': 98507, 'parent_partid': 1432}, {'status': 'pending', 'failreason': 'No path found', 'partid': 489, 'amount_msat': 163796, 'parent_partid': 375}, {'status': 'failed', 'failreason': 'No path found', 'partid': 908, 'amount_msat': 86410, 'parent_partid': 489}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1065, 'amount_msat': 86410, 'parent_partid': 908}, {'status': 'failed', 'failreason': 'No path found', 'partid': 909, 'amount_msat': 77386, 'parent_partid': 489}, {'status': 'pending', 'failreason': 'No path found', 'partid': 307, 'amount_msat': 326567, 'parent_partid': 245}, {'status': 'failed', 'failreason': 'No path found', 'partid': 376, 'amount_msat': 159043, 'parent_partid': 307}, {'status': 'pending', 'failreason': 'No path found', 'partid': 730, 'amount_msat': 159043, 'parent_partid': 376}, {'status': 'failed', 'failreason': 'No path found', 'partid': 860, 'amount_msat': 76070, 'parent_partid': 730}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1414, 'amount_msat': 76070, 'parent_partid': 860}, {'status': 'failed', 'failreason': 'No path found', 'partid': 861, 'amount_msat': 82973, 'parent_partid': 730}, {'status': 'pending', 'failreason': 'No path found', 'partid': 377, 'amount_msat': 167524, 'parent_partid': 307}, {'status': 'failed', 'failreason': 'No path found', 'partid': 490, 'amount_msat': 80420, 'parent_partid': 377}, {'status': 'failed', 'failreason': 'No path found', 'partid': 910, 'amount_msat': 80420, 'parent_partid': 490}, {'status': 'failed', 'failreason': 'No path found', 'partid': 491, 'amount_msat': 87104, 'parent_partid': 377}, {'status': 'pending', 'failreason': 'No path found', 'partid': 15, 'amount_msat': 6788318, 'parent_partid': 7}, {'status': 'pending', 'failreason': 'No path found', 'partid': 23, 'amount_msat': 3653594, 'parent_partid': 15}, {'status': 'pending', 'failreason': 'No path found', 'partid': 45, 'amount_msat': 1861440, 'parent_partid': 23}, {'status': 'pending', 'failreason': 'No path found', 'partid': 85, 'amount_msat': 958835, 'parent_partid': 45}, {'status': 'failed', 'failreason': 'No path found', 'partid': 110, 'amount_msat': 438347, 'parent_partid': 85}, {'status': 'pending', 'failreason': 'No path found', 'partid': 234, 'amount_msat': 438347, 'parent_partid': 110}, {'status': 'failed', 'failreason': 'No path found', 'partid': 456, 'amount_msat': 223108, 'parent_partid': 234}, {'status': 'pending', 'failreason': 'No path found', 'partid': 552, 'amount_msat': 223108, 'parent_partid': 456}, {'status': 'failed', 'failreason': 'No path found', 'partid': 958, 'amount_msat': 101602, 'parent_partid': 552}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1470, 'amount_msat': 101602, 'parent_partid': 958}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1899, 'amount_msat': 48962, 'parent_partid': 1470}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1900, 'amount_msat': 52640, 'parent_partid': 1470}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1948, 'amount_msat': 52640, 'parent_partid': 1900}, {'status': 'pending', 'failreason': 'No path found', 'partid': 959, 'amount_msat': 121506, 'parent_partid': 552}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1091, 'amount_msat': 63927, 'parent_partid': 959}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1092, 'amount_msat': 57579, 'parent_partid': 959}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1647, 'amount_msat': 57579, 'parent_partid': 1092}, {'status': 'pending', 'failreason': 'No path found', 'partid': 457, 'amount_msat': 215239, 'parent_partid': 234}, {'status': 'pending', 'failreason': 'No path found', 'partid': 787, 'amount_msat': 107052, 'parent_partid': 457}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1242, 'amount_msat': 50309, 'parent_partid': 787}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1358, 'amount_msat': 50309, 'parent_partid': 1242}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1243, 'amount_msat': 56743, 'parent_partid': 787}, {'status': 'failed', 'failreason': 'No path found', 'partid': 788, 'amount_msat': 108187, 'parent_partid': 457}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1244, 'amount_msat': 108187, 'parent_partid': 788}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1359, 'amount_msat': 53380, 'parent_partid': 1244}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1360, 'amount_msat': 54807, 'parent_partid': 1244}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1844, 'amount_msat': 54807, 'parent_partid': 1360}, {'status': 'pending', 'failreason': 'No path found', 'partid': 111, 'amount_msat': 520488, 'parent_partid': 85}, {'status': 'failed', 'failreason': 'No path found', 'partid': 146, 'amount_msat': 265919, 'parent_partid': 111}, {'status': 'pending', 'failreason': 'No path found', 'partid': 321, 'amount_msat': 265919, 'parent_partid': 146}, {'status': 'pending', 'failreason': 'No path found', 'partid': 613, 'amount_msat': 123501, 'parent_partid': 321}, {'status': 'failed', 'failreason': 'No path found', 'partid': 701, 'amount_msat': 55820, 'parent_partid': 613}, {'status': 'failed', 'failreason': 'No path found', 'partid': 702, 'amount_msat': 67681, 'parent_partid': 613}, {'status': 'failed', 'failreason': 'No path found', 'partid': 849, 'amount_msat': 67681, 'parent_partid': 702}, {'status': 'failed', 'failreason': 'No path found', 'partid': 614, 'amount_msat': 142418, 'parent_partid': 321}, {'status': 'pending', 'failreason': 'No path found', 'partid': 703, 'amount_msat': 142418, 'parent_partid': 614}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1180, 'amount_msat': 70819, 'parent_partid': 703}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1694, 'amount_msat': 70819, 'parent_partid': 1180}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1181, 'amount_msat': 71599, 'parent_partid': 703}, {'status': 'pending', 'failreason': 'No path found', 'partid': 147, 'amount_msat': 254569, 'parent_partid': 111}, {'status': 'failed', 'failreason': 'No path found', 'partid': 192, 'amount_msat': 131799, 'parent_partid': 147}, {'status': 'pending', 'failreason': 'No path found', 'partid': 270, 'amount_msat': 131799, 'parent_partid': 192}, {'status': 'failed', 'failreason': 'No path found', 'partid': 354, 'amount_msat': 66290, 'parent_partid': 270}, {'status': 'failed', 'failreason': 'No path found', 'partid': 475, 'amount_msat': 66290, 'parent_partid': 354}, {'status': 'failed', 'failreason': 'No path found', 'partid': 355, 'amount_msat': 65509, 'parent_partid': 270}, {'status': 'pending', 'failreason': 'No path found', 'partid': 193, 'amount_msat': 122770, 'parent_partid': 147}, {'status': 'failed', 'failreason': 'No path found', 'partid': 271, 'amount_msat': 59301, 'parent_partid': 193}, {'status': 'failed', 'failreason': 'No path found', 'partid': 272, 'amount_msat': 63469, 'parent_partid': 193}, {'status': 'failed', 'failreason': 'No path found', 'partid': 571, 'amount_msat': 63469, 'parent_partid': 272}, {'status': 'failed', 'failreason': 'No path found', 'partid': 86, 'amount_msat': 902605, 'parent_partid': 45}, {'status': 'pending', 'failreason': 'No path found', 'partid': 112, 'amount_msat': 902605, 'parent_partid': 86}, {'status': 'pending', 'failreason': 'No path found', 'partid': 235, 'amount_msat': 455637, 'parent_partid': 112}, {'status': 'pending', 'failreason': 'No path found', 'partid': 299, 'amount_msat': 241424, 'parent_partid': 235}, {'status': 'pending', 'failreason': 'No path found', 'partid': 595, 'amount_msat': 122387, 'parent_partid': 299}, {'status': 'failed', 'failreason': 'No path found', 'partid': 996, 'amount_msat': 64994, 'parent_partid': 595}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1491, 'amount_msat': 64994, 'parent_partid': 996}, {'status': 'failed', 'failreason': 'No path found', 'partid': 997, 'amount_msat': 57393, 'parent_partid': 595}, {'status': 'failed', 'failreason': 'No path found', 'partid': 596, 'amount_msat': 119037, 'parent_partid': 299}, {'status': 'pending', 'failreason': 'No path found', 'partid': 691, 'amount_msat': 119037, 'parent_partid': 596}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1174, 'amount_msat': 60875, 'parent_partid': 691}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1328, 'amount_msat': 60875, 'parent_partid': 1174}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1175, 'amount_msat': 58162, 'parent_partid': 691}, {'status': 'failed', 'failreason': 'No path found', 'partid': 300, 'amount_msat': 214213, 'parent_partid': 235}, {'status': 'pending', 'failreason': 'No path found', 'partid': 371, 'amount_msat': 214213, 'parent_partid': 300}, {'status': 'failed', 'failreason': 'No path found', 'partid': 486, 'amount_msat': 117458, 'parent_partid': 371}, {'status': 'pending', 'failreason': 'No path found', 'partid': 906, 'amount_msat': 117458, 'parent_partid': 486}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1063, 'amount_msat': 60674, 'parent_partid': 906}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1064, 'amount_msat': 56784, 'parent_partid': 906}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1269, 'amount_msat': 56784, 'parent_partid': 1064}, {'status': 'failed', 'failreason': 'No path found', 'partid': 487, 'amount_msat': 96755, 'parent_partid': 371}, {'status': 'failed', 'failreason': 'No path found', 'partid': 236, 'amount_msat': 446968, 'parent_partid': 112}, {'status': 'pending', 'failreason': 'No path found', 'partid': 458, 'amount_msat': 446968, 'parent_partid': 236}, {'status': 'pending', 'failreason': 'No path found', 'partid': 553, 'amount_msat': 210111, 'parent_partid': 458}, {'status': 'failed', 'failreason': 'No path found', 'partid': 960, 'amount_msat': 101820, 'parent_partid': 553}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1093, 'amount_msat': 101820, 'parent_partid': 960}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1648, 'amount_msat': 45836, 'parent_partid': 1093}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1999, 'amount_msat': 45836, 'parent_partid': 1648}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1649, 'amount_msat': 55984, 'parent_partid': 1093}, {'status': 'pending', 'failreason': 'No path found', 'partid': 961, 'amount_msat': 108291, 'parent_partid': 553}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1094, 'amount_msat': 58744, 'parent_partid': 961}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1650, 'amount_msat': 58744, 'parent_partid': 1094}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1095, 'amount_msat': 49547, 'parent_partid': 961}, {'status': 'failed', 'failreason': 'No path found', 'partid': 554, 'amount_msat': 236857, 'parent_partid': 458}, {'status': 'pending', 'failreason': 'No path found', 'partid': 675, 'amount_msat': 236857, 'parent_partid': 554}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1167, 'amount_msat': 108672, 'parent_partid': 675}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1688, 'amount_msat': 48938, 'parent_partid': 1167}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1787, 'amount_msat': 48938, 'parent_partid': 1688}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1689, 'amount_msat': 59734, 'parent_partid': 1167}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1168, 'amount_msat': 128185, 'parent_partid': 675}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1690, 'amount_msat': 128185, 'parent_partid': 1168}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1788, 'amount_msat': 64504, 'parent_partid': 1690}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2062, 'amount_msat': 64504, 'parent_partid': 1788}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1789, 'amount_msat': 63681, 'parent_partid': 1690}, {'status': 'failed', 'failreason': 'No path found', 'partid': 46, 'amount_msat': 1792154, 'parent_partid': 23}, {'status': 'pending', 'failreason': 'No path found', 'partid': 87, 'amount_msat': 1792154, 'parent_partid': 46}, {'status': 'pending', 'failreason': 'No path found', 'partid': 171, 'amount_msat': 945978, 'parent_partid': 87}, {'status': 'pending', 'failreason': 'No path found', 'partid': 213, 'amount_msat': 495148, 'parent_partid': 171}, {'status': 'failed', 'failreason': 'No path found', 'partid': 432, 'amount_msat': 272298, 'parent_partid': 213}, {'status': 'pending', 'failreason': 'No path found', 'partid': 530, 'amount_msat': 272298, 'parent_partid': 432}, {'status': 'failed', 'failreason': 'No path found', 'partid': 662, 'amount_msat': 136019, 'parent_partid': 530}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1159, 'amount_msat': 136019, 'parent_partid': 662}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1320, 'amount_msat': 70609, 'parent_partid': 1159}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1824, 'amount_msat': 70609, 'parent_partid': 1320}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1321, 'amount_msat': 65410, 'parent_partid': 1159}, {'status': 'pending', 'failreason': 'No path found', 'partid': 663, 'amount_msat': 136279, 'parent_partid': 530}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1160, 'amount_msat': 68334, 'parent_partid': 663}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1322, 'amount_msat': 68334, 'parent_partid': 1160}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1161, 'amount_msat': 67945, 'parent_partid': 663}, {'status': 'pending', 'failreason': 'No path found', 'partid': 433, 'amount_msat': 222850, 'parent_partid': 213}, {'status': 'failed', 'failreason': 'No path found', 'partid': 772, 'amount_msat': 107805, 'parent_partid': 433}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1231, 'amount_msat': 107805, 'parent_partid': 772}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1717, 'amount_msat': 59232, 'parent_partid': 1231}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1718, 'amount_msat': 48573, 'parent_partid': 1231}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1797, 'amount_msat': 48573, 'parent_partid': 1718}, {'status': 'pending', 'failreason': 'No path found', 'partid': 773, 'amount_msat': 115045, 'parent_partid': 433}, {'status': 'failed', 'failreason': 'No path found', 'partid': 886, 'amount_msat': 58104, 'parent_partid': 773}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1054, 'amount_msat': 58104, 'parent_partid': 886}, {'status': 'failed', 'failreason': 'No path found', 'partid': 887, 'amount_msat': 56941, 'parent_partid': 773}, {'status': 'failed', 'failreason': 'No path found', 'partid': 214, 'amount_msat': 450830, 'parent_partid': 171}, {'status': 'pending', 'failreason': 'No path found', 'partid': 434, 'amount_msat': 450830, 'parent_partid': 214}, {'status': 'failed', 'failreason': 'No path found', 'partid': 774, 'amount_msat': 214574, 'parent_partid': 434}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1232, 'amount_msat': 214574, 'parent_partid': 774}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1353, 'amount_msat': 106209, 'parent_partid': 1232}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1546, 'amount_msat': 49861, 'parent_partid': 1353}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1741, 'amount_msat': 49861, 'parent_partid': 1546}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1547, 'amount_msat': 56348, 'parent_partid': 1353}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1354, 'amount_msat': 108365, 'parent_partid': 1232}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1548, 'amount_msat': 108365, 'parent_partid': 1354}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1959, 'amount_msat': 59485, 'parent_partid': 1548}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1960, 'amount_msat': 48880, 'parent_partid': 1548}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2121, 'amount_msat': 48880, 'parent_partid': 1960}, {'status': 'pending', 'failreason': 'No path found', 'partid': 775, 'amount_msat': 236256, 'parent_partid': 434}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1233, 'amount_msat': 107628, 'parent_partid': 775}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1355, 'amount_msat': 51826, 'parent_partid': 1233}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1356, 'amount_msat': 55802, 'parent_partid': 1233}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1841, 'amount_msat': 55802, 'parent_partid': 1356}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1234, 'amount_msat': 128628, 'parent_partid': 775}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1357, 'amount_msat': 128628, 'parent_partid': 1234}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1842, 'amount_msat': 61846, 'parent_partid': 1357}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2073, 'amount_msat': 61846, 'parent_partid': 1842}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1843, 'amount_msat': 66782, 'parent_partid': 1357}, {'status': 'failed', 'failreason': 'No path found', 'partid': 172, 'amount_msat': 846176, 'parent_partid': 87}, {'status': 'pending', 'failreason': 'No path found', 'partid': 342, 'amount_msat': 846176, 'parent_partid': 172}, {'status': 'pending', 'failreason': 'No path found', 'partid': 409, 'amount_msat': 420558, 'parent_partid': 342}, {'status': 'failed', 'failreason': 'No path found', 'partid': 516, 'amount_msat': 190546, 'parent_partid': 409}, {'status': 'pending', 'failreason': 'No path found', 'partid': 929, 'amount_msat': 190546, 'parent_partid': 516}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1448, 'amount_msat': 91764, 'parent_partid': 929}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1885, 'amount_msat': 91764, 'parent_partid': 1448}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1449, 'amount_msat': 98782, 'parent_partid': 929}, {'status': 'pending', 'failreason': 'No path found', 'partid': 517, 'amount_msat': 230012, 'parent_partid': 409}, {'status': 'failed', 'failreason': 'No path found', 'partid': 930, 'amount_msat': 108688, 'parent_partid': 517}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1079, 'amount_msat': 108688, 'parent_partid': 930}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1641, 'amount_msat': 59413, 'parent_partid': 1079}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1642, 'amount_msat': 49275, 'parent_partid': 1079}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1769, 'amount_msat': 49275, 'parent_partid': 1642}, {'status': 'pending', 'failreason': 'No path found', 'partid': 931, 'amount_msat': 121324, 'parent_partid': 517}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1080, 'amount_msat': 57215, 'parent_partid': 931}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1643, 'amount_msat': 57215, 'parent_partid': 1080}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1081, 'amount_msat': 64109, 'parent_partid': 931}, {'status': 'failed', 'failreason': 'No path found', 'partid': 410, 'amount_msat': 425618, 'parent_partid': 342}, {'status': 'pending', 'failreason': 'No path found', 'partid': 518, 'amount_msat': 425618, 'parent_partid': 410}, {'status': 'failed', 'failreason': 'No path found', 'partid': 932, 'amount_msat': 213667, 'parent_partid': 518}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1450, 'amount_msat': 213667, 'parent_partid': 932}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1886, 'amount_msat': 96241, 'parent_partid': 1450}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2086, 'amount_msat': 96241, 'parent_partid': 1886}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1887, 'amount_msat': 117426, 'parent_partid': 1450}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2087, 'amount_msat': 55479, 'parent_partid': 1887}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2088, 'amount_msat': 61947, 'parent_partid': 1887}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2110, 'amount_msat': 61947, 'parent_partid': 2088}, {'status': 'pending', 'failreason': 'No path found', 'partid': 933, 'amount_msat': 211951, 'parent_partid': 518}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1451, 'amount_msat': 114640, 'parent_partid': 933}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1888, 'amount_msat': 61771, 'parent_partid': 1451}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2089, 'amount_msat': 61771, 'parent_partid': 1888}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1889, 'amount_msat': 52869, 'parent_partid': 1451}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1452, 'amount_msat': 97311, 'parent_partid': 933}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1581, 'amount_msat': 97311, 'parent_partid': 1452}, {'status': 'failed', 'failreason': 'No path found', 'partid': 24, 'amount_msat': 3134724, 'parent_partid': 15}, {'status': 'pending', 'failreason': 'No path found', 'partid': 47, 'amount_msat': 3134724, 'parent_partid': 24}, {'status': 'failed', 'failreason': 'No path found', 'partid': 54, 'amount_msat': 1698585, 'parent_partid': 47}, {'status': 'pending', 'failreason': 'No path found', 'partid': 67, 'amount_msat': 1698585, 'parent_partid': 54}, {'status': 'pending', 'failreason': 'No path found', 'partid': 159, 'amount_msat': 880051, 'parent_partid': 67}, {'status': 'failed', 'failreason': 'No path found', 'partid': 206, 'amount_msat': 470430, 'parent_partid': 159}, {'status': 'pending', 'failreason': 'No path found', 'partid': 424, 'amount_msat': 470430, 'parent_partid': 206}, {'status': 'failed', 'failreason': 'No path found', 'partid': 762, 'amount_msat': 227032, 'parent_partid': 424}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1223, 'amount_msat': 227032, 'parent_partid': 762}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1349, 'amount_msat': 103979, 'parent_partid': 1223}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1837, 'amount_msat': 49706, 'parent_partid': 1349}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1838, 'amount_msat': 54273, 'parent_partid': 1349}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2070, 'amount_msat': 54273, 'parent_partid': 1838}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1350, 'amount_msat': 123053, 'parent_partid': 1223}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1839, 'amount_msat': 123053, 'parent_partid': 1350}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2071, 'amount_msat': 59082, 'parent_partid': 1839}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2072, 'amount_msat': 63971, 'parent_partid': 1839}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2107, 'amount_msat': 63971, 'parent_partid': 2072}, {'status': 'pending', 'failreason': 'No path found', 'partid': 763, 'amount_msat': 243398, 'parent_partid': 424}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1224, 'amount_msat': 120613, 'parent_partid': 763}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1711, 'amount_msat': 120613, 'parent_partid': 1224}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2016, 'amount_msat': 65986, 'parent_partid': 1711}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2041, 'amount_msat': 65986, 'parent_partid': 2016}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2017, 'amount_msat': 54627, 'parent_partid': 1711}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1225, 'amount_msat': 122785, 'parent_partid': 763}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1712, 'amount_msat': 63086, 'parent_partid': 1225}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1795, 'amount_msat': 63086, 'parent_partid': 1712}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1713, 'amount_msat': 59699, 'parent_partid': 1225}, {'status': 'pending', 'failreason': 'No path found', 'partid': 207, 'amount_msat': 409621, 'parent_partid': 159}, {'status': 'pending', 'failreason': 'No path found', 'partid': 425, 'amount_msat': 222067, 'parent_partid': 207}, {'status': 'failed', 'failreason': 'No path found', 'partid': 764, 'amount_msat': 118602, 'parent_partid': 425}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1226, 'amount_msat': 118602, 'parent_partid': 764}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1351, 'amount_msat': 56822, 'parent_partid': 1226}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1352, 'amount_msat': 61780, 'parent_partid': 1226}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1840, 'amount_msat': 61780, 'parent_partid': 1352}, {'status': 'pending', 'failreason': 'No path found', 'partid': 765, 'amount_msat': 103465, 'parent_partid': 425}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1227, 'amount_msat': 53554, 'parent_partid': 765}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1228, 'amount_msat': 49911, 'parent_partid': 765}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1714, 'amount_msat': 49911, 'parent_partid': 1228}, {'status': 'failed', 'failreason': 'No path found', 'partid': 426, 'amount_msat': 187554, 'parent_partid': 207}, {'status': 'pending', 'failreason': 'No path found', 'partid': 766, 'amount_msat': 187554, 'parent_partid': 426}, {'status': 'failed', 'failreason': 'No path found', 'partid': 880, 'amount_msat': 101456, 'parent_partid': 766}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1421, 'amount_msat': 101456, 'parent_partid': 880}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1574, 'amount_msat': 51467, 'parent_partid': 1421}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1745, 'amount_msat': 51467, 'parent_partid': 1574}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1575, 'amount_msat': 49989, 'parent_partid': 1421}, {'status': 'failed', 'failreason': 'No path found', 'partid': 881, 'amount_msat': 86098, 'parent_partid': 766}, {'status': 'failed', 'failreason': 'No path found', 'partid': 160, 'amount_msat': 818534, 'parent_partid': 67}, {'status': 'pending', 'failreason': 'No path found', 'partid': 329, 'amount_msat': 818534, 'parent_partid': 160}, {'status': 'failed', 'failreason': 'No path found', 'partid': 398, 'amount_msat': 390234, 'parent_partid': 329}, {'status': 'pending', 'failreason': 'No path found', 'partid': 745, 'amount_msat': 390234, 'parent_partid': 398}, {'status': 'failed', 'failreason': 'No path found', 'partid': 864, 'amount_msat': 181460, 'parent_partid': 745}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1044, 'amount_msat': 181460, 'parent_partid': 864}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1626, 'amount_msat': 86862, 'parent_partid': 1044}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1764, 'amount_msat': 86862, 'parent_partid': 1626}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1627, 'amount_msat': 94598, 'parent_partid': 1044}, {'status': 'pending', 'failreason': 'No path found', 'partid': 865, 'amount_msat': 208774, 'parent_partid': 745}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1045, 'amount_msat': 102781, 'parent_partid': 865}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1628, 'amount_msat': 56134, 'parent_partid': 1045}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1765, 'amount_msat': 56134, 'parent_partid': 1628}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1629, 'amount_msat': 46647, 'parent_partid': 1045}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1046, 'amount_msat': 105993, 'parent_partid': 865}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1264, 'amount_msat': 105993, 'parent_partid': 1046}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1517, 'amount_msat': 54559, 'parent_partid': 1264}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1518, 'amount_msat': 51434, 'parent_partid': 1264}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1730, 'amount_msat': 51434, 'parent_partid': 1518}, {'status': 'pending', 'failreason': 'No path found', 'partid': 399, 'amount_msat': 428300, 'parent_partid': 329}, {'status': 'failed', 'failreason': 'No path found', 'partid': 506, 'amount_msat': 211565, 'parent_partid': 399}, {'status': 'pending', 'failreason': 'No path found', 'partid': 923, 'amount_msat': 211565, 'parent_partid': 506}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1073, 'amount_msat': 116050, 'parent_partid': 923}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1274, 'amount_msat': 54445, 'parent_partid': 1073}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1804, 'amount_msat': 54445, 'parent_partid': 1274}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1275, 'amount_msat': 61605, 'parent_partid': 1073}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1074, 'amount_msat': 95515, 'parent_partid': 923}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1276, 'amount_msat': 95515, 'parent_partid': 1074}, {'status': 'pending', 'failreason': 'No path found', 'partid': 507, 'amount_msat': 216735, 'parent_partid': 399}, {'status': 'pending', 'failreason': 'No path found', 'partid': 639, 'amount_msat': 110170, 'parent_partid': 507}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1144, 'amount_msat': 51817, 'parent_partid': 639}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1680, 'amount_msat': 51817, 'parent_partid': 1144}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1145, 'amount_msat': 58353, 'parent_partid': 639}, {'status': 'failed', 'failreason': 'No path found', 'partid': 640, 'amount_msat': 106565, 'parent_partid': 507}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1146, 'amount_msat': 106565, 'parent_partid': 640}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1310, 'amount_msat': 48168, 'parent_partid': 1146}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1817, 'amount_msat': 48168, 'parent_partid': 1310}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1311, 'amount_msat': 58397, 'parent_partid': 1146}, {'status': 'pending', 'failreason': 'No path found', 'partid': 55, 'amount_msat': 1436139, 'parent_partid': 47}, {'status': 'failed', 'failreason': 'No path found', 'partid': 68, 'amount_msat': 711492, 'parent_partid': 55}, {'status': 'pending', 'failreason': 'No path found', 'partid': 161, 'amount_msat': 711492, 'parent_partid': 68}, {'status': 'failed', 'failreason': 'No path found', 'partid': 208, 'amount_msat': 361538, 'parent_partid': 161}, {'status': 'pending', 'failreason': 'No path found', 'partid': 427, 'amount_msat': 361538, 'parent_partid': 208}, {'status': 'pending', 'failreason': 'No path found', 'partid': 767, 'amount_msat': 178214, 'parent_partid': 427}, {'status': 'failed', 'failreason': 'No path found', 'partid': 882, 'amount_msat': 87187, 'parent_partid': 767}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1053, 'amount_msat': 87187, 'parent_partid': 882}, {'status': 'failed', 'failreason': 'No path found', 'partid': 883, 'amount_msat': 91027, 'parent_partid': 767}, {'status': 'failed', 'failreason': 'No path found', 'partid': 768, 'amount_msat': 183324, 'parent_partid': 427}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1229, 'amount_msat': 183324, 'parent_partid': 768}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1715, 'amount_msat': 90052, 'parent_partid': 1229}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1716, 'amount_msat': 93272, 'parent_partid': 1229}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1796, 'amount_msat': 93272, 'parent_partid': 1716}, {'status': 'pending', 'failreason': 'No path found', 'partid': 209, 'amount_msat': 349954, 'parent_partid': 161}, {'status': 'failed', 'failreason': 'No path found', 'partid': 288, 'amount_msat': 174126, 'parent_partid': 209}, {'status': 'pending', 'failreason': 'No path found', 'partid': 583, 'amount_msat': 174126, 'parent_partid': 288}, {'status': 'failed', 'failreason': 'No path found', 'partid': 684, 'amount_msat': 86530, 'parent_partid': 583}, {'status': 'failed', 'failreason': 'No path found', 'partid': 836, 'amount_msat': 86530, 'parent_partid': 684}, {'status': 'failed', 'failreason': 'No path found', 'partid': 685, 'amount_msat': 87596, 'parent_partid': 583}, {'status': 'pending', 'failreason': 'No path found', 'partid': 289, 'amount_msat': 175828, 'parent_partid': 209}, {'status': 'failed', 'failreason': 'No path found', 'partid': 365, 'amount_msat': 91599, 'parent_partid': 289}, {'status': 'failed', 'failreason': 'No path found', 'partid': 366, 'amount_msat': 84229, 'parent_partid': 289}, {'status': 'failed', 'failreason': 'No path found', 'partid': 724, 'amount_msat': 84229, 'parent_partid': 366}, {'status': 'pending', 'failreason': 'No path found', 'partid': 69, 'amount_msat': 724647, 'parent_partid': 55}, {'status': 'pending', 'failreason': 'No path found', 'partid': 93, 'amount_msat': 393097, 'parent_partid': 69}, {'status': 'failed', 'failreason': 'No path found', 'partid': 130, 'amount_msat': 178817, 'parent_partid': 93}, {'status': 'pending', 'failreason': 'No path found', 'partid': 173, 'amount_msat': 178817, 'parent_partid': 130}, {'status': 'failed', 'failreason': 'No path found', 'partid': 343, 'amount_msat': 80974, 'parent_partid': 173}, {'status': 'failed', 'failreason': 'No path found', 'partid': 344, 'amount_msat': 97843, 'parent_partid': 173}, {'status': 'failed', 'failreason': 'No path found', 'partid': 411, 'amount_msat': 97843, 'parent_partid': 344}, {'status': 'pending', 'failreason': 'No path found', 'partid': 131, 'amount_msat': 214280, 'parent_partid': 93}, {'status': 'failed', 'failreason': 'No path found', 'partid': 174, 'amount_msat': 111301, 'parent_partid': 131}, {'status': 'pending', 'failreason': 'No path found', 'partid': 253, 'amount_msat': 111301, 'parent_partid': 174}, {'status': 'failed', 'failreason': 'No path found', 'partid': 469, 'amount_msat': 55706, 'parent_partid': 253}, {'status': 'failed', 'failreason': 'No path found', 'partid': 470, 'amount_msat': 55595, 'parent_partid': 253}, {'status': 'failed', 'failreason': 'No path found', 'partid': 559, 'amount_msat': 55595, 'parent_partid': 470}, {'status': 'pending', 'failreason': 'No path found', 'partid': 175, 'amount_msat': 102979, 'parent_partid': 131}, {'status': 'failed', 'failreason': 'No path found', 'partid': 254, 'amount_msat': 53470, 'parent_partid': 175}, {'status': 'failed', 'failreason': 'No path found', 'partid': 471, 'amount_msat': 53470, 'parent_partid': 254}, {'status': 'failed', 'failreason': 'No path found', 'partid': 255, 'amount_msat': 49509, 'parent_partid': 175}, {'status': 'failed', 'failreason': 'No path found', 'partid': 94, 'amount_msat': 331550, 'parent_partid': 69}, {'status': 'pending', 'failreason': 'No path found', 'partid': 132, 'amount_msat': 331550, 'parent_partid': 94}, {'status': 'failed', 'failreason': 'No path found', 'partid': 314, 'amount_msat': 153138, 'parent_partid': 132}, {'status': 'pending', 'failreason': 'No path found', 'partid': 382, 'amount_msat': 153138, 'parent_partid': 314}, {'status': 'failed', 'failreason': 'No path found', 'partid': 734, 'amount_msat': 80360, 'parent_partid': 382}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1201, 'amount_msat': 80360, 'parent_partid': 734}, {'status': 'failed', 'failreason': 'No path found', 'partid': 735, 'amount_msat': 72778, 'parent_partid': 382}, {'status': 'pending', 'failreason': 'No path found', 'partid': 315, 'amount_msat': 178412, 'parent_partid': 132}, {'status': 'failed', 'failreason': 'No path found', 'partid': 383, 'amount_msat': 97106, 'parent_partid': 315}, {'status': 'failed', 'failreason': 'No path found', 'partid': 384, 'amount_msat': 81306, 'parent_partid': 315}, {'status': 'failed', 'failreason': 'No path found', 'partid': 496, 'amount_msat': 81306, 'parent_partid': 384}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2, 'amount_msat': 24797864, 'parent_partid': 0}, {'status': 'pending', 'failreason': 'No path found', 'partid': 3, 'amount_msat': 24797864, 'parent_partid': 2}, {'status': 'failed', 'failreason': 'No path found', 'partid': 4, 'amount_msat': 12189568, 'parent_partid': 3}, {'status': 'pending', 'failreason': 'No path found', 'partid': 8, 'amount_msat': 12189568, 'parent_partid': 4}, {'status': 'pending', 'failreason': 'No path found', 'partid': 9, 'amount_msat': 6153317, 'parent_partid': 8}, {'status': 'failed', 'failreason': 'No path found', 'partid': 16, 'amount_msat': 2835438, 'parent_partid': 9}, {'status': 'pending', 'failreason': 'No path found', 'partid': 40, 'amount_msat': 2835438, 'parent_partid': 16}, {'status': 'failed', 'failreason': 'No path found', 'partid': 78, 'amount_msat': 1313297, 'parent_partid': 40}, {'status': 'pending', 'failreason': 'No path found', 'partid': 101, 'amount_msat': 1313297, 'parent_partid': 78}, {'status': 'failed', 'failreason': 'No path found', 'partid': 230, 'amount_msat': 602826, 'parent_partid': 101}, {'status': 'pending', 'failreason': 'No path found', 'partid': 453, 'amount_msat': 602826, 'parent_partid': 230}, {'status': 'failed', 'failreason': 'No path found', 'partid': 784, 'amount_msat': 277240, 'parent_partid': 453}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1241, 'amount_msat': 277240, 'parent_partid': 784}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1723, 'amount_msat': 133458, 'parent_partid': 1241}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1799, 'amount_msat': 73292, 'parent_partid': 1723}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1800, 'amount_msat': 60166, 'parent_partid': 1723}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2064, 'amount_msat': 60166, 'parent_partid': 1800}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1724, 'amount_msat': 143782, 'parent_partid': 1241}, {'status': 'pending', 'failreason': 'No path found', 'partid': 2018, 'amount_msat': 143782, 'parent_partid': 1724}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2042, 'amount_msat': 66860, 'parent_partid': 2018}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2153, 'amount_msat': 66860, 'parent_partid': 2042}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2043, 'amount_msat': 76922, 'parent_partid': 2018}, {'status': 'pending', 'failreason': 'No path found', 'partid': 785, 'amount_msat': 325586, 'parent_partid': 453}, {'status': 'pending', 'failreason': 'No path found', 'partid': 891, 'amount_msat': 178796, 'parent_partid': 785}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1425, 'amount_msat': 97609, 'parent_partid': 891}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1426, 'amount_msat': 81187, 'parent_partid': 891}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1866, 'amount_msat': 81187, 'parent_partid': 1426}, {'status': 'failed', 'failreason': 'No path found', 'partid': 892, 'amount_msat': 146790, 'parent_partid': 785}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1056, 'amount_msat': 146790, 'parent_partid': 892}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1633, 'amount_msat': 76060, 'parent_partid': 1056}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1634, 'amount_msat': 70730, 'parent_partid': 1056}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1767, 'amount_msat': 70730, 'parent_partid': 1634}, {'status': 'pending', 'failreason': 'No path found', 'partid': 231, 'amount_msat': 710471, 'parent_partid': 101}, {'status': 'pending', 'failreason': 'No path found', 'partid': 295, 'amount_msat': 346630, 'parent_partid': 231}, {'status': 'failed', 'failreason': 'No path found', 'partid': 590, 'amount_msat': 183925, 'parent_partid': 295}, {'status': 'pending', 'failreason': 'No path found', 'partid': 991, 'amount_msat': 183925, 'parent_partid': 590}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1118, 'amount_msat': 96078, 'parent_partid': 991}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1668, 'amount_msat': 96078, 'parent_partid': 1118}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1119, 'amount_msat': 87847, 'parent_partid': 991}, {'status': 'pending', 'failreason': 'No path found', 'partid': 591, 'amount_msat': 162705, 'parent_partid': 295}, {'status': 'failed', 'failreason': 'No path found', 'partid': 688, 'amount_msat': 84192, 'parent_partid': 591}, {'status': 'failed', 'failreason': 'No path found', 'partid': 837, 'amount_msat': 84192, 'parent_partid': 688}, {'status': 'failed', 'failreason': 'No path found', 'partid': 689, 'amount_msat': 78513, 'parent_partid': 591}, {'status': 'failed', 'failreason': 'No path found', 'partid': 296, 'amount_msat': 363841, 'parent_partid': 231}, {'status': 'pending', 'failreason': 'No path found', 'partid': 370, 'amount_msat': 363841, 'parent_partid': 296}, {'status': 'failed', 'failreason': 'No path found', 'partid': 484, 'amount_msat': 166928, 'parent_partid': 370}, {'status': 'pending', 'failreason': 'No path found', 'partid': 905, 'amount_msat': 166928, 'parent_partid': 484}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1061, 'amount_msat': 84785, 'parent_partid': 905}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1062, 'amount_msat': 82143, 'parent_partid': 905}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1639, 'amount_msat': 82143, 'parent_partid': 1062}, {'status': 'pending', 'failreason': 'No path found', 'partid': 485, 'amount_msat': 196913, 'parent_partid': 370}, {'status': 'failed', 'failreason': 'No path found', 'partid': 630, 'amount_msat': 92214, 'parent_partid': 485}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1138, 'amount_msat': 92214, 'parent_partid': 630}, {'status': 'pending', 'failreason': 'No path found', 'partid': 631, 'amount_msat': 104699, 'parent_partid': 485}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1139, 'amount_msat': 48766, 'parent_partid': 631}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1140, 'amount_msat': 55933, 'parent_partid': 631}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1309, 'amount_msat': 55933, 'parent_partid': 1140}, {'status': 'pending', 'failreason': 'No path found', 'partid': 79, 'amount_msat': 1522141, 'parent_partid': 40}, {'status': 'failed', 'failreason': 'No path found', 'partid': 102, 'amount_msat': 823961, 'parent_partid': 79}, {'status': 'pending', 'failreason': 'No path found', 'partid': 232, 'amount_msat': 823961, 'parent_partid': 102}, {'status': 'failed', 'failreason': 'No path found', 'partid': 454, 'amount_msat': 393346, 'parent_partid': 232}, {'status': 'pending', 'failreason': 'No path found', 'partid': 786, 'amount_msat': 393346, 'parent_partid': 454}, {'status': 'pending', 'failreason': 'No path found', 'partid': 893, 'amount_msat': 215983, 'parent_partid': 786}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1057, 'amount_msat': 118509, 'parent_partid': 893}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1635, 'amount_msat': 63096, 'parent_partid': 1057}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1636, 'amount_msat': 55413, 'parent_partid': 1057}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1768, 'amount_msat': 55413, 'parent_partid': 1636}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1058, 'amount_msat': 97474, 'parent_partid': 893}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1268, 'amount_msat': 97474, 'parent_partid': 1058}, {'status': 'failed', 'failreason': 'No path found', 'partid': 894, 'amount_msat': 177363, 'parent_partid': 786}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1059, 'amount_msat': 177363, 'parent_partid': 894}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1637, 'amount_msat': 92814, 'parent_partid': 1059}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1638, 'amount_msat': 84549, 'parent_partid': 1059}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1996, 'amount_msat': 84549, 'parent_partid': 1638}, {'status': 'pending', 'failreason': 'No path found', 'partid': 455, 'amount_msat': 430615, 'parent_partid': 232}, {'status': 'failed', 'failreason': 'No path found', 'partid': 550, 'amount_msat': 229423, 'parent_partid': 455}, {'status': 'pending', 'failreason': 'No path found', 'partid': 674, 'amount_msat': 229423, 'parent_partid': 550}, {'status': 'failed', 'failreason': 'No path found', 'partid': 828, 'amount_msat': 106435, 'parent_partid': 674}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1036, 'amount_msat': 106435, 'parent_partid': 828}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1258, 'amount_msat': 51450, 'parent_partid': 1036}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1729, 'amount_msat': 51450, 'parent_partid': 1258}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1259, 'amount_msat': 54985, 'parent_partid': 1036}, {'status': 'pending', 'failreason': 'No path found', 'partid': 829, 'amount_msat': 122988, 'parent_partid': 674}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1392, 'amount_msat': 57448, 'parent_partid': 829}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1854, 'amount_msat': 57448, 'parent_partid': 1392}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1393, 'amount_msat': 65540, 'parent_partid': 829}, {'status': 'pending', 'failreason': 'No path found', 'partid': 551, 'amount_msat': 201192, 'parent_partid': 455}, {'status': 'failed', 'failreason': 'No path found', 'partid': 956, 'amount_msat': 93025, 'parent_partid': 551}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1090, 'amount_msat': 93025, 'parent_partid': 956}, {'status': 'pending', 'failreason': 'No path found', 'partid': 957, 'amount_msat': 108167, 'parent_partid': 551}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1468, 'amount_msat': 52133, 'parent_partid': 957}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1898, 'amount_msat': 52133, 'parent_partid': 1468}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1469, 'amount_msat': 56034, 'parent_partid': 957}, {'status': 'pending', 'failreason': 'No path found', 'partid': 103, 'amount_msat': 698180, 'parent_partid': 79}, {'status': 'failed', 'failreason': 'No path found', 'partid': 136, 'amount_msat': 370452, 'parent_partid': 103}, {'status': 'pending', 'failreason': 'No path found', 'partid': 178, 'amount_msat': 370452, 'parent_partid': 136}, {'status': 'failed', 'failreason': 'No path found', 'partid': 412, 'amount_msat': 179994, 'parent_partid': 178}, {'status': 'pending', 'failreason': 'No path found', 'partid': 519, 'amount_msat': 179994, 'parent_partid': 412}, {'status': 'failed', 'failreason': 'No path found', 'partid': 649, 'amount_msat': 89462, 'parent_partid': 519}, {'status': 'failed', 'failreason': 'No path found', 'partid': 650, 'amount_msat': 90532, 'parent_partid': 519}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1153, 'amount_msat': 90532, 'parent_partid': 650}, {'status': 'pending', 'failreason': 'No path found', 'partid': 413, 'amount_msat': 190458, 'parent_partid': 178}, {'status': 'failed', 'failreason': 'No path found', 'partid': 520, 'amount_msat': 89663, 'parent_partid': 413}, {'status': 'failed', 'failreason': 'No path found', 'partid': 651, 'amount_msat': 89663, 'parent_partid': 520}, {'status': 'pending', 'failreason': 'No path found', 'partid': 521, 'amount_msat': 100795, 'parent_partid': 413}, {'status': 'failed', 'failreason': 'No path found', 'partid': 934, 'amount_msat': 55208, 'parent_partid': 521}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1453, 'amount_msat': 55208, 'parent_partid': 934}, {'status': 'failed', 'failreason': 'No path found', 'partid': 935, 'amount_msat': 45587, 'parent_partid': 521}, {'status': 'pending', 'failreason': 'No path found', 'partid': 137, 'amount_msat': 327728, 'parent_partid': 103}, {'status': 'pending', 'failreason': 'No path found', 'partid': 179, 'amount_msat': 174352, 'parent_partid': 137}, {'status': 'failed', 'failreason': 'No path found', 'partid': 256, 'amount_msat': 86509, 'parent_partid': 179}, {'status': 'failed', 'failreason': 'No path found', 'partid': 560, 'amount_msat': 86509, 'parent_partid': 256}, {'status': 'failed', 'failreason': 'No path found', 'partid': 257, 'amount_msat': 87843, 'parent_partid': 179}, {'status': 'failed', 'failreason': 'No path found', 'partid': 180, 'amount_msat': 153376, 'parent_partid': 137}, {'status': 'pending', 'failreason': 'No path found', 'partid': 258, 'amount_msat': 153376, 'parent_partid': 180}, {'status': 'failed', 'failreason': 'No path found', 'partid': 346, 'amount_msat': 73357, 'parent_partid': 258}, {'status': 'failed', 'failreason': 'No path found', 'partid': 472, 'amount_msat': 73357, 'parent_partid': 346}, {'status': 'failed', 'failreason': 'No path found', 'partid': 347, 'amount_msat': 80019, 'parent_partid': 258}, {'status': 'pending', 'failreason': 'No path found', 'partid': 17, 'amount_msat': 3317879, 'parent_partid': 9}, {'status': 'pending', 'failreason': 'No path found', 'partid': 25, 'amount_msat': 1552702, 'parent_partid': 17}, {'status': 'failed', 'failreason': 'No path found', 'partid': 34, 'amount_msat': 784945, 'parent_partid': 25}, {'status': 'pending', 'failreason': 'No path found', 'partid': 48, 'amount_msat': 784945, 'parent_partid': 34}, {'status': 'pending', 'failreason': 'No path found', 'partid': 113, 'amount_msat': 431390, 'parent_partid': 48}, {'status': 'pending', 'failreason': 'No path found', 'partid': 237, 'amount_msat': 217127, 'parent_partid': 113}, {'status': 'pending', 'failreason': 'No path found', 'partid': 459, 'amount_msat': 107872, 'parent_partid': 237}, {'status': 'failed', 'failreason': 'No path found', 'partid': 789, 'amount_msat': 57396, 'parent_partid': 459}, {'status': 'failed', 'failreason': 'No path found', 'partid': 790, 'amount_msat': 50476, 'parent_partid': 459}, {'status': 'failed', 'failreason': 'No path found', 'partid': 895, 'amount_msat': 50476, 'parent_partid': 790}, {'status': 'failed', 'failreason': 'No path found', 'partid': 460, 'amount_msat': 109255, 'parent_partid': 237}, {'status': 'pending', 'failreason': 'No path found', 'partid': 555, 'amount_msat': 109255, 'parent_partid': 460}, {'status': 'failed', 'failreason': 'No path found', 'partid': 962, 'amount_msat': 51120, 'parent_partid': 555}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1096, 'amount_msat': 51120, 'parent_partid': 962}, {'status': 'failed', 'failreason': 'No path found', 'partid': 963, 'amount_msat': 58135, 'parent_partid': 555}, {'status': 'failed', 'failreason': 'No path found', 'partid': 238, 'amount_msat': 214263, 'parent_partid': 113}, {'status': 'pending', 'failreason': 'No path found', 'partid': 301, 'amount_msat': 214263, 'parent_partid': 238}, {'status': 'pending', 'failreason': 'No path found', 'partid': 597, 'amount_msat': 114003, 'parent_partid': 301}, {'status': 'failed', 'failreason': 'No path found', 'partid': 998, 'amount_msat': 52058, 'parent_partid': 597}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1492, 'amount_msat': 52058, 'parent_partid': 998}, {'status': 'failed', 'failreason': 'No path found', 'partid': 999, 'amount_msat': 61945, 'parent_partid': 597}, {'status': 'failed', 'failreason': 'No path found', 'partid': 598, 'amount_msat': 100260, 'parent_partid': 301}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1000, 'amount_msat': 100260, 'parent_partid': 598}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1493, 'amount_msat': 55119, 'parent_partid': 1000}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1494, 'amount_msat': 45141, 'parent_partid': 1000}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1596, 'amount_msat': 45141, 'parent_partid': 1494}, {'status': 'failed', 'failreason': 'No path found', 'partid': 114, 'amount_msat': 353555, 'parent_partid': 48}, {'status': 'pending', 'failreason': 'No path found', 'partid': 239, 'amount_msat': 353555, 'parent_partid': 114}, {'status': 'pending', 'failreason': 'No path found', 'partid': 461, 'amount_msat': 178217, 'parent_partid': 239}, {'status': 'failed', 'failreason': 'No path found', 'partid': 791, 'amount_msat': 90368, 'parent_partid': 461}, {'status': 'failed', 'failreason': 'No path found', 'partid': 792, 'amount_msat': 87849, 'parent_partid': 461}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1245, 'amount_msat': 87849, 'parent_partid': 792}, {'status': 'failed', 'failreason': 'No path found', 'partid': 462, 'amount_msat': 175338, 'parent_partid': 239}, {'status': 'pending', 'failreason': 'No path found', 'partid': 793, 'amount_msat': 175338, 'parent_partid': 462}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1246, 'amount_msat': 92469, 'parent_partid': 793}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1361, 'amount_msat': 92469, 'parent_partid': 1246}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1247, 'amount_msat': 82869, 'parent_partid': 793}, {'status': 'pending', 'failreason': 'No path found', 'partid': 35, 'amount_msat': 767757, 'parent_partid': 25}, {'status': 'pending', 'failreason': 'No path found', 'partid': 49, 'amount_msat': 409798, 'parent_partid': 35}, {'status': 'pending', 'failreason': 'No path found', 'partid': 115, 'amount_msat': 192473, 'parent_partid': 49}, {'status': 'failed', 'failreason': 'No path found', 'partid': 240, 'amount_msat': 93160, 'parent_partid': 115}, {'status': 'failed', 'failreason': 'No path found', 'partid': 463, 'amount_msat': 93160, 'parent_partid': 240}, {'status': 'failed', 'failreason': 'No path found', 'partid': 241, 'amount_msat': 99313, 'parent_partid': 115}, {'status': 'failed', 'failreason': 'No path found', 'partid': 116, 'amount_msat': 217325, 'parent_partid': 49}, {'status': 'pending', 'failreason': 'No path found', 'partid': 148, 'amount_msat': 217325, 'parent_partid': 116}, {'status': 'failed', 'failreason': 'No path found', 'partid': 194, 'amount_msat': 114399, 'parent_partid': 148}, {'status': 'pending', 'failreason': 'No path found', 'partid': 273, 'amount_msat': 114399, 'parent_partid': 194}, {'status': 'failed', 'failreason': 'No path found', 'partid': 572, 'amount_msat': 58291, 'parent_partid': 273}, {'status': 'failed', 'failreason': 'No path found', 'partid': 979, 'amount_msat': 58291, 'parent_partid': 572}, {'status': 'failed', 'failreason': 'No path found', 'partid': 573, 'amount_msat': 56108, 'parent_partid': 273}, {'status': 'pending', 'failreason': 'No path found', 'partid': 195, 'amount_msat': 102926, 'parent_partid': 148}, {'status': 'failed', 'failreason': 'No path found', 'partid': 274, 'amount_msat': 53898, 'parent_partid': 195}, {'status': 'failed', 'failreason': 'No path found', 'partid': 574, 'amount_msat': 53898, 'parent_partid': 274}, {'status': 'failed', 'failreason': 'No path found', 'partid': 275, 'amount_msat': 49028, 'parent_partid': 195}, {'status': 'failed', 'failreason': 'No path found', 'partid': 50, 'amount_msat': 357959, 'parent_partid': 35}, {'status': 'pending', 'failreason': 'No path found', 'partid': 64, 'amount_msat': 357959, 'parent_partid': 50}, {'status': 'failed', 'failreason': 'No path found', 'partid': 88, 'amount_msat': 166701, 'parent_partid': 64}, {'status': 'pending', 'failreason': 'No path found', 'partid': 215, 'amount_msat': 166701, 'parent_partid': 88}, {'status': 'failed', 'failreason': 'No path found', 'partid': 435, 'amount_msat': 77478, 'parent_partid': 215}, {'status': 'failed', 'failreason': 'No path found', 'partid': 436, 'amount_msat': 89223, 'parent_partid': 215}, {'status': 'failed', 'failreason': 'No path found', 'partid': 531, 'amount_msat': 89223, 'parent_partid': 436}, {'status': 'pending', 'failreason': 'No path found', 'partid': 89, 'amount_msat': 191258, 'parent_partid': 64}, {'status': 'failed', 'failreason': 'No path found', 'partid': 216, 'amount_msat': 101663, 'parent_partid': 89}, {'status': 'pending', 'failreason': 'No path found', 'partid': 291, 'amount_msat': 101663, 'parent_partid': 216}, {'status': 'failed', 'failreason': 'No path found', 'partid': 584, 'amount_msat': 47793, 'parent_partid': 291}, {'status': 'failed', 'failreason': 'No path found', 'partid': 686, 'amount_msat': 47793, 'parent_partid': 584}, {'status': 'failed', 'failreason': 'No path found', 'partid': 585, 'amount_msat': 53870, 'parent_partid': 291}, {'status': 'failed', 'failreason': 'No path found', 'partid': 217, 'amount_msat': 89595, 'parent_partid': 89}, {'status': 'failed', 'failreason': 'No path found', 'partid': 26, 'amount_msat': 1765177, 'parent_partid': 17}, {'status': 'pending', 'failreason': 'No path found', 'partid': 56, 'amount_msat': 1765177, 'parent_partid': 26}, {'status': 'failed', 'failreason': 'No path found', 'partid': 70, 'amount_msat': 873865, 'parent_partid': 56}, {'status': 'pending', 'failreason': 'No path found', 'partid': 95, 'amount_msat': 873865, 'parent_partid': 70}, {'status': 'pending', 'failreason': 'No path found', 'partid': 223, 'amount_msat': 440914, 'parent_partid': 95}, {'status': 'failed', 'failreason': 'No path found', 'partid': 442, 'amount_msat': 221670, 'parent_partid': 223}, {'status': 'pending', 'failreason': 'No path found', 'partid': 538, 'amount_msat': 221670, 'parent_partid': 442}, {'status': 'pending', 'failreason': 'No path found', 'partid': 943, 'amount_msat': 118881, 'parent_partid': 538}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1460, 'amount_msat': 56970, 'parent_partid': 943}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1896, 'amount_msat': 56970, 'parent_partid': 1460}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1461, 'amount_msat': 61911, 'parent_partid': 943}, {'status': 'failed', 'failreason': 'No path found', 'partid': 944, 'amount_msat': 102789, 'parent_partid': 538}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1462, 'amount_msat': 102789, 'parent_partid': 944}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1582, 'amount_msat': 52463, 'parent_partid': 1462}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1977, 'amount_msat': 52463, 'parent_partid': 1582}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1583, 'amount_msat': 50326, 'parent_partid': 1462}, {'status': 'pending', 'failreason': 'No path found', 'partid': 443, 'amount_msat': 219244, 'parent_partid': 223}, {'status': 'pending', 'failreason': 'No path found', 'partid': 539, 'amount_msat': 113533, 'parent_partid': 443}, {'status': 'failed', 'failreason': 'No path found', 'partid': 945, 'amount_msat': 60354, 'parent_partid': 539}, {'status': 'failed', 'failreason': 'No path found', 'partid': 946, 'amount_msat': 53179, 'parent_partid': 539}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1083, 'amount_msat': 53179, 'parent_partid': 946}, {'status': 'failed', 'failreason': 'No path found', 'partid': 540, 'amount_msat': 105711, 'parent_partid': 443}, {'status': 'pending', 'failreason': 'No path found', 'partid': 947, 'amount_msat': 105711, 'parent_partid': 540}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1463, 'amount_msat': 48849, 'parent_partid': 947}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1464, 'amount_msat': 56862, 'parent_partid': 947}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1584, 'amount_msat': 56862, 'parent_partid': 1464}, {'status': 'failed', 'failreason': 'No path found', 'partid': 224, 'amount_msat': 432951, 'parent_partid': 95}, {'status': 'pending', 'failreason': 'No path found', 'partid': 444, 'amount_msat': 432951, 'parent_partid': 224}, {'status': 'pending', 'failreason': 'No path found', 'partid': 541, 'amount_msat': 197059, 'parent_partid': 444}, {'status': 'failed', 'failreason': 'No path found', 'partid': 948, 'amount_msat': 103372, 'parent_partid': 541}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1465, 'amount_msat': 103372, 'parent_partid': 948}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1585, 'amount_msat': 49883, 'parent_partid': 1465}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1586, 'amount_msat': 53489, 'parent_partid': 1465}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1978, 'amount_msat': 53489, 'parent_partid': 1586}, {'status': 'failed', 'failreason': 'No path found', 'partid': 949, 'amount_msat': 93687, 'parent_partid': 541}, {'status': 'failed', 'failreason': 'No path found', 'partid': 542, 'amount_msat': 235892, 'parent_partid': 444}, {'status': 'pending', 'failreason': 'No path found', 'partid': 950, 'amount_msat': 235892, 'parent_partid': 542}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1084, 'amount_msat': 129612, 'parent_partid': 950}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1644, 'amount_msat': 129612, 'parent_partid': 1084}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1997, 'amount_msat': 65593, 'parent_partid': 1644}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1998, 'amount_msat': 64019, 'parent_partid': 1644}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2040, 'amount_msat': 64019, 'parent_partid': 1998}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1085, 'amount_msat': 106280, 'parent_partid': 950}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1645, 'amount_msat': 50294, 'parent_partid': 1085}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1646, 'amount_msat': 55986, 'parent_partid': 1085}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1770, 'amount_msat': 55986, 'parent_partid': 1646}, {'status': 'pending', 'failreason': 'No path found', 'partid': 71, 'amount_msat': 891312, 'parent_partid': 56}, {'status': 'failed', 'failreason': 'No path found', 'partid': 162, 'amount_msat': 464517, 'parent_partid': 71}, {'status': 'pending', 'failreason': 'No path found', 'partid': 330, 'amount_msat': 464517, 'parent_partid': 162}, {'status': 'pending', 'failreason': 'No path found', 'partid': 617, 'amount_msat': 223241, 'parent_partid': 330}, {'status': 'failed', 'failreason': 'No path found', 'partid': 704, 'amount_msat': 110404, 'parent_partid': 617}, {'status': 'pending', 'failreason': 'No path found', 'partid': 850, 'amount_msat': 110404, 'parent_partid': 704}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1409, 'amount_msat': 60448, 'parent_partid': 850}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1410, 'amount_msat': 49956, 'parent_partid': 850}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1567, 'amount_msat': 49956, 'parent_partid': 1410}, {'status': 'pending', 'failreason': 'No path found', 'partid': 705, 'amount_msat': 112837, 'parent_partid': 617}, {'status': 'failed', 'failreason': 'No path found', 'partid': 851, 'amount_msat': 53657, 'parent_partid': 705}, {'status': 'failed', 'failreason': 'No path found', 'partid': 852, 'amount_msat': 59180, 'parent_partid': 705}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1039, 'amount_msat': 59180, 'parent_partid': 852}, {'status': 'failed', 'failreason': 'No path found', 'partid': 618, 'amount_msat': 241276, 'parent_partid': 330}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1018, 'amount_msat': 241276, 'parent_partid': 618}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1508, 'amount_msat': 130997, 'parent_partid': 1018}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1910, 'amount_msat': 130997, 'parent_partid': 1508}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2097, 'amount_msat': 64559, 'parent_partid': 1910}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2098, 'amount_msat': 66438, 'parent_partid': 1910}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2165, 'amount_msat': 66438, 'parent_partid': 2098}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1509, 'amount_msat': 110279, 'parent_partid': 1018}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1911, 'amount_msat': 50165, 'parent_partid': 1509}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1912, 'amount_msat': 60114, 'parent_partid': 1509}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1951, 'amount_msat': 60114, 'parent_partid': 1912}, {'status': 'pending', 'failreason': 'No path found', 'partid': 163, 'amount_msat': 426795, 'parent_partid': 71}, {'status': 'pending', 'failreason': 'No path found', 'partid': 331, 'amount_msat': 230367, 'parent_partid': 163}, {'status': 'failed', 'failreason': 'No path found', 'partid': 400, 'amount_msat': 107384, 'parent_partid': 331}, {'status': 'pending', 'failreason': 'No path found', 'partid': 746, 'amount_msat': 107384, 'parent_partid': 400}, {'status': 'failed', 'failreason': 'No path found', 'partid': 866, 'amount_msat': 52077, 'parent_partid': 746}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1047, 'amount_msat': 52077, 'parent_partid': 866}, {'status': 'failed', 'failreason': 'No path found', 'partid': 867, 'amount_msat': 55307, 'parent_partid': 746}, {'status': 'pending', 'failreason': 'No path found', 'partid': 401, 'amount_msat': 122983, 'parent_partid': 331}, {'status': 'failed', 'failreason': 'No path found', 'partid': 747, 'amount_msat': 59427, 'parent_partid': 401}, {'status': 'failed', 'failreason': 'No path found', 'partid': 748, 'amount_msat': 63556, 'parent_partid': 401}, {'status': 'failed', 'failreason': 'No path found', 'partid': 868, 'amount_msat': 63556, 'parent_partid': 748}, {'status': 'failed', 'failreason': 'No path found', 'partid': 332, 'amount_msat': 196428, 'parent_partid': 163}, {'status': 'pending', 'failreason': 'No path found', 'partid': 619, 'amount_msat': 196428, 'parent_partid': 332}, {'status': 'failed', 'failreason': 'No path found', 'partid': 706, 'amount_msat': 105412, 'parent_partid': 619}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1182, 'amount_msat': 105412, 'parent_partid': 706}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1695, 'amount_msat': 49847, 'parent_partid': 1182}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1696, 'amount_msat': 55565, 'parent_partid': 1182}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1790, 'amount_msat': 55565, 'parent_partid': 1696}, {'status': 'failed', 'failreason': 'No path found', 'partid': 707, 'amount_msat': 91016, 'parent_partid': 619}, {'status': 'failed', 'failreason': 'No path found', 'partid': 10, 'amount_msat': 6036251, 'parent_partid': 8}, {'status': 'pending', 'failreason': 'No path found', 'partid': 18, 'amount_msat': 6036251, 'parent_partid': 10}, {'status': 'pending', 'failreason': 'No path found', 'partid': 27, 'amount_msat': 3240573, 'parent_partid': 18}, {'status': 'failed', 'failreason': 'No path found', 'partid': 36, 'amount_msat': 1685588, 'parent_partid': 27}, {'status': 'pending', 'failreason': 'No path found', 'partid': 74, 'amount_msat': 1685588, 'parent_partid': 36}, {'status': 'failed', 'failreason': 'No path found', 'partid': 98, 'amount_msat': 904573, 'parent_partid': 74}, {'status': 'pending', 'failreason': 'No path found', 'partid': 135, 'amount_msat': 904573, 'parent_partid': 98}, {'status': 'pending', 'failreason': 'No path found', 'partid': 317, 'amount_msat': 469844, 'parent_partid': 135}, {'status': 'failed', 'failreason': 'No path found', 'partid': 608, 'amount_msat': 215968, 'parent_partid': 317}, {'status': 'pending', 'failreason': 'No path found', 'partid': 695, 'amount_msat': 215968, 'parent_partid': 608}, {'status': 'pending', 'failreason': 'No path found', 'partid': 843, 'amount_msat': 107627, 'parent_partid': 695}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1404, 'amount_msat': 57598, 'parent_partid': 843}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1860, 'amount_msat': 57598, 'parent_partid': 1404}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1405, 'amount_msat': 50029, 'parent_partid': 843}, {'status': 'failed', 'failreason': 'No path found', 'partid': 844, 'amount_msat': 108341, 'parent_partid': 695}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1037, 'amount_msat': 108341, 'parent_partid': 844}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1622, 'amount_msat': 59026, 'parent_partid': 1037}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1763, 'amount_msat': 59026, 'parent_partid': 1622}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1623, 'amount_msat': 49315, 'parent_partid': 1037}, {'status': 'pending', 'failreason': 'No path found', 'partid': 609, 'amount_msat': 253876, 'parent_partid': 317}, {'status': 'failed', 'failreason': 'No path found', 'partid': 696, 'amount_msat': 135754, 'parent_partid': 609}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1176, 'amount_msat': 135754, 'parent_partid': 696}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1692, 'amount_msat': 70840, 'parent_partid': 1176}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2011, 'amount_msat': 70840, 'parent_partid': 1692}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1693, 'amount_msat': 64914, 'parent_partid': 1176}, {'status': 'pending', 'failreason': 'No path found', 'partid': 697, 'amount_msat': 118122, 'parent_partid': 609}, {'status': 'failed', 'failreason': 'No path found', 'partid': 845, 'amount_msat': 60773, 'parent_partid': 697}, {'status': 'failed', 'failreason': 'No path found', 'partid': 846, 'amount_msat': 57349, 'parent_partid': 697}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1406, 'amount_msat': 57349, 'parent_partid': 846}, {'status': 'failed', 'failreason': 'No path found', 'partid': 318, 'amount_msat': 434729, 'parent_partid': 135}, {'status': 'pending', 'failreason': 'No path found', 'partid': 610, 'amount_msat': 434729, 'parent_partid': 318}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1012, 'amount_msat': 208702, 'parent_partid': 610}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1501, 'amount_msat': 208702, 'parent_partid': 1012}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1603, 'amount_msat': 94568, 'parent_partid': 1501}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1604, 'amount_msat': 114134, 'parent_partid': 1501}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1987, 'amount_msat': 114134, 'parent_partid': 1604}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2133, 'amount_msat': 58368, 'parent_partid': 1987}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2134, 'amount_msat': 55766, 'parent_partid': 1987}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2150, 'amount_msat': 55766, 'parent_partid': 2134}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1013, 'amount_msat': 226027, 'parent_partid': 610}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1502, 'amount_msat': 106473, 'parent_partid': 1013}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1907, 'amount_msat': 106473, 'parent_partid': 1502}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2093, 'amount_msat': 53984, 'parent_partid': 1907}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2094, 'amount_msat': 52489, 'parent_partid': 1907}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2111, 'amount_msat': 52489, 'parent_partid': 2094}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1503, 'amount_msat': 119554, 'parent_partid': 1013}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1605, 'amount_msat': 62223, 'parent_partid': 1503}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1606, 'amount_msat': 57331, 'parent_partid': 1503}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1988, 'amount_msat': 57331, 'parent_partid': 1606}, {'status': 'pending', 'failreason': 'No path found', 'partid': 99, 'amount_msat': 781015, 'parent_partid': 74}, {'status': 'failed', 'failreason': 'No path found', 'partid': 226, 'amount_msat': 403362, 'parent_partid': 99}, {'status': 'pending', 'failreason': 'No path found', 'partid': 447, 'amount_msat': 403362, 'parent_partid': 226}, {'status': 'failed', 'failreason': 'No path found', 'partid': 544, 'amount_msat': 184791, 'parent_partid': 447}, {'status': 'pending', 'failreason': 'No path found', 'partid': 951, 'amount_msat': 184791, 'parent_partid': 544}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1086, 'amount_msat': 89920, 'parent_partid': 951}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1286, 'amount_msat': 89920, 'parent_partid': 1086}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1087, 'amount_msat': 94871, 'parent_partid': 951}, {'status': 'pending', 'failreason': 'No path found', 'partid': 545, 'amount_msat': 218571, 'parent_partid': 447}, {'status': 'failed', 'failreason': 'No path found', 'partid': 670, 'amount_msat': 100940, 'parent_partid': 545}, {'status': 'pending', 'failreason': 'No path found', 'partid': 825, 'amount_msat': 100940, 'parent_partid': 670}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1033, 'amount_msat': 50886, 'parent_partid': 825}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1034, 'amount_msat': 50054, 'parent_partid': 825}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1621, 'amount_msat': 50054, 'parent_partid': 1034}, {'status': 'pending', 'failreason': 'No path found', 'partid': 671, 'amount_msat': 117631, 'parent_partid': 545}, {'status': 'failed', 'failreason': 'No path found', 'partid': 826, 'amount_msat': 64649, 'parent_partid': 671}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1035, 'amount_msat': 64649, 'parent_partid': 826}, {'status': 'failed', 'failreason': 'No path found', 'partid': 827, 'amount_msat': 52982, 'parent_partid': 671}, {'status': 'pending', 'failreason': 'No path found', 'partid': 227, 'amount_msat': 377653, 'parent_partid': 99}, {'status': 'failed', 'failreason': 'No path found', 'partid': 448, 'amount_msat': 180338, 'parent_partid': 227}, {'status': 'pending', 'failreason': 'No path found', 'partid': 780, 'amount_msat': 180338, 'parent_partid': 448}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1238, 'amount_msat': 91635, 'parent_partid': 780}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1720, 'amount_msat': 91635, 'parent_partid': 1238}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1239, 'amount_msat': 88703, 'parent_partid': 780}, {'status': 'pending', 'failreason': 'No path found', 'partid': 449, 'amount_msat': 197315, 'parent_partid': 227}, {'status': 'failed', 'failreason': 'No path found', 'partid': 781, 'amount_msat': 92692, 'parent_partid': 449}, {'status': 'failed', 'failreason': 'No path found', 'partid': 782, 'amount_msat': 104623, 'parent_partid': 449}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1240, 'amount_msat': 104623, 'parent_partid': 782}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1721, 'amount_msat': 57503, 'parent_partid': 1240}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1722, 'amount_msat': 47120, 'parent_partid': 1240}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1798, 'amount_msat': 47120, 'parent_partid': 1722}, {'status': 'pending', 'failreason': 'No path found', 'partid': 37, 'amount_msat': 1554985, 'parent_partid': 27}, {'status': 'pending', 'failreason': 'No path found', 'partid': 51, 'amount_msat': 850950, 'parent_partid': 37}, {'status': 'pending', 'failreason': 'No path found', 'partid': 117, 'amount_msat': 436364, 'parent_partid': 51}, {'status': 'pending', 'failreason': 'No path found', 'partid': 149, 'amount_msat': 215443, 'parent_partid': 117}, {'status': 'failed', 'failreason': 'No path found', 'partid': 196, 'amount_msat': 112203, 'parent_partid': 149}, {'status': 'pending', 'failreason': 'No path found', 'partid': 276, 'amount_msat': 112203, 'parent_partid': 196}, {'status': 'failed', 'failreason': 'No path found', 'partid': 356, 'amount_msat': 58871, 'parent_partid': 276}, {'status': 'failed', 'failreason': 'No path found', 'partid': 476, 'amount_msat': 58871, 'parent_partid': 356}, {'status': 'failed', 'failreason': 'No path found', 'partid': 357, 'amount_msat': 53332, 'parent_partid': 276}, {'status': 'pending', 'failreason': 'No path found', 'partid': 197, 'amount_msat': 103240, 'parent_partid': 149}, {'status': 'failed', 'failreason': 'No path found', 'partid': 277, 'amount_msat': 48304, 'parent_partid': 197}, {'status': 'failed', 'failreason': 'No path found', 'partid': 278, 'amount_msat': 54936, 'parent_partid': 197}, {'status': 'failed', 'failreason': 'No path found', 'partid': 575, 'amount_msat': 54936, 'parent_partid': 278}, {'status': 'failed', 'failreason': 'No path found', 'partid': 150, 'amount_msat': 220921, 'parent_partid': 117}, {'status': 'pending', 'failreason': 'No path found', 'partid': 198, 'amount_msat': 220921, 'parent_partid': 150}, {'status': 'pending', 'failreason': 'No path found', 'partid': 279, 'amount_msat': 113502, 'parent_partid': 198}, {'status': 'failed', 'failreason': 'No path found', 'partid': 358, 'amount_msat': 51732, 'parent_partid': 279}, {'status': 'failed', 'failreason': 'No path found', 'partid': 720, 'amount_msat': 51732, 'parent_partid': 358}, {'status': 'failed', 'failreason': 'No path found', 'partid': 359, 'amount_msat': 61770, 'parent_partid': 279}, {'status': 'failed', 'failreason': 'No path found', 'partid': 280, 'amount_msat': 107419, 'parent_partid': 198}, {'status': 'pending', 'failreason': 'No path found', 'partid': 360, 'amount_msat': 107419, 'parent_partid': 280}, {'status': 'failed', 'failreason': 'No path found', 'partid': 477, 'amount_msat': 51208, 'parent_partid': 360}, {'status': 'failed', 'failreason': 'No path found', 'partid': 478, 'amount_msat': 56211, 'parent_partid': 360}, {'status': 'failed', 'failreason': 'No path found', 'partid': 899, 'amount_msat': 56211, 'parent_partid': 478}, {'status': 'failed', 'failreason': 'No path found', 'partid': 118, 'amount_msat': 414586, 'parent_partid': 51}, {'status': 'pending', 'failreason': 'No path found', 'partid': 151, 'amount_msat': 414586, 'parent_partid': 118}, {'status': 'failed', 'failreason': 'No path found', 'partid': 322, 'amount_msat': 188623, 'parent_partid': 151}, {'status': 'pending', 'failreason': 'No path found', 'partid': 615, 'amount_msat': 188623, 'parent_partid': 322}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1014, 'amount_msat': 94024, 'parent_partid': 615}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1504, 'amount_msat': 94024, 'parent_partid': 1014}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1015, 'amount_msat': 94599, 'parent_partid': 615}, {'status': 'pending', 'failreason': 'No path found', 'partid': 323, 'amount_msat': 225963, 'parent_partid': 151}, {'status': 'pending', 'failreason': 'No path found', 'partid': 389, 'amount_msat': 120679, 'parent_partid': 323}, {'status': 'failed', 'failreason': 'No path found', 'partid': 740, 'amount_msat': 56457, 'parent_partid': 389}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1209, 'amount_msat': 56457, 'parent_partid': 740}, {'status': 'failed', 'failreason': 'No path found', 'partid': 741, 'amount_msat': 64222, 'parent_partid': 389}, {'status': 'failed', 'failreason': 'No path found', 'partid': 390, 'amount_msat': 105284, 'parent_partid': 323}, {'status': 'pending', 'failreason': 'No path found', 'partid': 742, 'amount_msat': 105284, 'parent_partid': 390}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1210, 'amount_msat': 54626, 'parent_partid': 742}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1339, 'amount_msat': 54626, 'parent_partid': 1210}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1211, 'amount_msat': 50658, 'parent_partid': 742}, {'status': 'failed', 'failreason': 'No path found', 'partid': 52, 'amount_msat': 704035, 'parent_partid': 37}, {'status': 'pending', 'failreason': 'No path found', 'partid': 119, 'amount_msat': 704035, 'parent_partid': 52}, {'status': 'failed', 'failreason': 'No path found', 'partid': 242, 'amount_msat': 358629, 'parent_partid': 119}, {'status': 'pending', 'failreason': 'No path found', 'partid': 302, 'amount_msat': 358629, 'parent_partid': 242}, {'status': 'pending', 'failreason': 'No path found', 'partid': 599, 'amount_msat': 190082, 'parent_partid': 302}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1001, 'amount_msat': 88792, 'parent_partid': 599}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1002, 'amount_msat': 101290, 'parent_partid': 599}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1123, 'amount_msat': 101290, 'parent_partid': 1002}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1669, 'amount_msat': 48452, 'parent_partid': 1123}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1670, 'amount_msat': 52838, 'parent_partid': 1123}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1776, 'amount_msat': 52838, 'parent_partid': 1670}, {'status': 'failed', 'failreason': 'No path found', 'partid': 600, 'amount_msat': 168547, 'parent_partid': 302}, {'status': 'pending', 'failreason': 'No path found', 'partid': 692, 'amount_msat': 168547, 'parent_partid': 600}, {'status': 'failed', 'failreason': 'No path found', 'partid': 840, 'amount_msat': 83411, 'parent_partid': 692}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1403, 'amount_msat': 83411, 'parent_partid': 840}, {'status': 'failed', 'failreason': 'No path found', 'partid': 841, 'amount_msat': 85136, 'parent_partid': 692}, {'status': 'pending', 'failreason': 'No path found', 'partid': 243, 'amount_msat': 345406, 'parent_partid': 119}, {'status': 'pending', 'failreason': 'No path found', 'partid': 303, 'amount_msat': 184873, 'parent_partid': 243}, {'status': 'failed', 'failreason': 'No path found', 'partid': 372, 'amount_msat': 97191, 'parent_partid': 303}, {'status': 'failed', 'failreason': 'No path found', 'partid': 727, 'amount_msat': 97191, 'parent_partid': 372}, {'status': 'failed', 'failreason': 'No path found', 'partid': 373, 'amount_msat': 87682, 'parent_partid': 303}, {'status': 'failed', 'failreason': 'No path found', 'partid': 304, 'amount_msat': 160533, 'parent_partid': 243}, {'status': 'pending', 'failreason': 'No path found', 'partid': 374, 'amount_msat': 160533, 'parent_partid': 304}, {'status': 'failed', 'failreason': 'No path found', 'partid': 728, 'amount_msat': 86107, 'parent_partid': 374}, {'status': 'failed', 'failreason': 'No path found', 'partid': 859, 'amount_msat': 86107, 'parent_partid': 728}, {'status': 'failed', 'failreason': 'No path found', 'partid': 729, 'amount_msat': 74426, 'parent_partid': 374}, {'status': 'failed', 'failreason': 'No path found', 'partid': 28, 'amount_msat': 2795678, 'parent_partid': 18}, {'status': 'pending', 'failreason': 'No path found', 'partid': 57, 'amount_msat': 2795678, 'parent_partid': 28}, {'status': 'failed', 'failreason': 'No path found', 'partid': 120, 'amount_msat': 1345312, 'parent_partid': 57}, {'status': 'pending', 'failreason': 'No path found', 'partid': 152, 'amount_msat': 1345312, 'parent_partid': 120}, {'status': 'pending', 'failreason': 'No path found', 'partid': 199, 'amount_msat': 617735, 'parent_partid': 152}, {'status': 'failed', 'failreason': 'No path found', 'partid': 420, 'amount_msat': 328903, 'parent_partid': 199}, {'status': 'pending', 'failreason': 'No path found', 'partid': 755, 'amount_msat': 328903, 'parent_partid': 420}, {'status': 'failed', 'failreason': 'No path found', 'partid': 874, 'amount_msat': 178516, 'parent_partid': 755}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1418, 'amount_msat': 178516, 'parent_partid': 874}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1862, 'amount_msat': 96384, 'parent_partid': 1418}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2079, 'amount_msat': 96384, 'parent_partid': 1862}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1863, 'amount_msat': 82132, 'parent_partid': 1418}, {'status': 'pending', 'failreason': 'No path found', 'partid': 875, 'amount_msat': 150387, 'parent_partid': 755}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1419, 'amount_msat': 74394, 'parent_partid': 875}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1420, 'amount_msat': 75993, 'parent_partid': 875}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1573, 'amount_msat': 75993, 'parent_partid': 1420}, {'status': 'pending', 'failreason': 'No path found', 'partid': 421, 'amount_msat': 288832, 'parent_partid': 199}, {'status': 'failed', 'failreason': 'No path found', 'partid': 756, 'amount_msat': 147701, 'parent_partid': 421}, {'status': 'pending', 'failreason': 'No path found', 'partid': 876, 'amount_msat': 147701, 'parent_partid': 756}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1048, 'amount_msat': 78110, 'parent_partid': 876}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1265, 'amount_msat': 78110, 'parent_partid': 1048}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1049, 'amount_msat': 69591, 'parent_partid': 876}, {'status': 'pending', 'failreason': 'No path found', 'partid': 757, 'amount_msat': 141131, 'parent_partid': 421}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1218, 'amount_msat': 65463, 'parent_partid': 757}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1344, 'amount_msat': 65463, 'parent_partid': 1218}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1219, 'amount_msat': 75668, 'parent_partid': 757}, {'status': 'failed', 'failreason': 'No path found', 'partid': 200, 'amount_msat': 727577, 'parent_partid': 152}, {'status': 'pending', 'failreason': 'No path found', 'partid': 422, 'amount_msat': 727577, 'parent_partid': 200}, {'status': 'failed', 'failreason': 'No path found', 'partid': 758, 'amount_msat': 353265, 'parent_partid': 422}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1220, 'amount_msat': 353265, 'parent_partid': 758}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1345, 'amount_msat': 159804, 'parent_partid': 1220}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1835, 'amount_msat': 73352, 'parent_partid': 1345}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1836, 'amount_msat': 86452, 'parent_partid': 1345}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1937, 'amount_msat': 86452, 'parent_partid': 1836}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1346, 'amount_msat': 193461, 'parent_partid': 1220}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1544, 'amount_msat': 193461, 'parent_partid': 1346}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1739, 'amount_msat': 89059, 'parent_partid': 1544}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1740, 'amount_msat': 104402, 'parent_partid': 1544}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1920, 'amount_msat': 104402, 'parent_partid': 1740}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2024, 'amount_msat': 51618, 'parent_partid': 1920}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2145, 'amount_msat': 51618, 'parent_partid': 2024}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2025, 'amount_msat': 52784, 'parent_partid': 1920}, {'status': 'pending', 'failreason': 'No path found', 'partid': 759, 'amount_msat': 374312, 'parent_partid': 422}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1221, 'amount_msat': 183817, 'parent_partid': 759}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1347, 'amount_msat': 98061, 'parent_partid': 1221}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1348, 'amount_msat': 85756, 'parent_partid': 1221}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1545, 'amount_msat': 85756, 'parent_partid': 1348}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1222, 'amount_msat': 190495, 'parent_partid': 759}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1710, 'amount_msat': 190495, 'parent_partid': 1222}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1793, 'amount_msat': 89608, 'parent_partid': 1710}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1794, 'amount_msat': 100887, 'parent_partid': 1710}, {'status': 'pending', 'failreason': 'No path found', 'partid': 2063, 'amount_msat': 100887, 'parent_partid': 1794}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2159, 'amount_msat': 49890, 'parent_partid': 2063}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2160, 'amount_msat': 50997, 'parent_partid': 2063}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2180, 'amount_msat': 50997, 'parent_partid': 2160}, {'status': 'pending', 'failreason': 'No path found', 'partid': 121, 'amount_msat': 1450366, 'parent_partid': 57}, {'status': 'pending', 'failreason': 'No path found', 'partid': 153, 'amount_msat': 759550, 'parent_partid': 121}, {'status': 'pending', 'failreason': 'No path found', 'partid': 201, 'amount_msat': 352996, 'parent_partid': 153}, {'status': 'pending', 'failreason': 'No path found', 'partid': 281, 'amount_msat': 158994, 'parent_partid': 201}, {'status': 'failed', 'failreason': 'No path found', 'partid': 361, 'amount_msat': 77454, 'parent_partid': 281}, {'status': 'failed', 'failreason': 'No path found', 'partid': 362, 'amount_msat': 81540, 'parent_partid': 281}, {'status': 'failed', 'failreason': 'No path found', 'partid': 721, 'amount_msat': 81540, 'parent_partid': 362}, {'status': 'failed', 'failreason': 'No path found', 'partid': 282, 'amount_msat': 194002, 'parent_partid': 201}, {'status': 'pending', 'failreason': 'No path found', 'partid': 363, 'amount_msat': 194002, 'parent_partid': 282}, {'status': 'failed', 'failreason': 'No path found', 'partid': 479, 'amount_msat': 97166, 'parent_partid': 363}, {'status': 'failed', 'failreason': 'No path found', 'partid': 480, 'amount_msat': 96836, 'parent_partid': 363}, {'status': 'failed', 'failreason': 'No path found', 'partid': 900, 'amount_msat': 96836, 'parent_partid': 480}, {'status': 'failed', 'failreason': 'No path found', 'partid': 202, 'amount_msat': 406554, 'parent_partid': 153}, {'status': 'pending', 'failreason': 'No path found', 'partid': 283, 'amount_msat': 406554, 'parent_partid': 202}, {'status': 'failed', 'failreason': 'No path found', 'partid': 576, 'amount_msat': 184946, 'parent_partid': 283}, {'status': 'pending', 'failreason': 'No path found', 'partid': 980, 'amount_msat': 184946, 'parent_partid': 576}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1109, 'amount_msat': 90017, 'parent_partid': 980}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1110, 'amount_msat': 94929, 'parent_partid': 980}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1661, 'amount_msat': 94929, 'parent_partid': 1110}, {'status': 'pending', 'failreason': 'No path found', 'partid': 577, 'amount_msat': 221608, 'parent_partid': 283}, {'status': 'pending', 'failreason': 'No path found', 'partid': 981, 'amount_msat': 121873, 'parent_partid': 577}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1481, 'amount_msat': 65532, 'parent_partid': 981}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1482, 'amount_msat': 56341, 'parent_partid': 981}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1903, 'amount_msat': 56341, 'parent_partid': 1482}, {'status': 'failed', 'failreason': 'No path found', 'partid': 982, 'amount_msat': 99735, 'parent_partid': 577}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1111, 'amount_msat': 99735, 'parent_partid': 982}, {'status': 'failed', 'failreason': 'No path found', 'partid': 154, 'amount_msat': 690816, 'parent_partid': 121}, {'status': 'pending', 'failreason': 'No path found', 'partid': 324, 'amount_msat': 690816, 'parent_partid': 154}, {'status': 'pending', 'failreason': 'No path found', 'partid': 391, 'amount_msat': 334654, 'parent_partid': 324}, {'status': 'pending', 'failreason': 'No path found', 'partid': 497, 'amount_msat': 169158, 'parent_partid': 391}, {'status': 'failed', 'failreason': 'No path found', 'partid': 632, 'amount_msat': 86935, 'parent_partid': 497}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1141, 'amount_msat': 86935, 'parent_partid': 632}, {'status': 'failed', 'failreason': 'No path found', 'partid': 633, 'amount_msat': 82223, 'parent_partid': 497}, {'status': 'failed', 'failreason': 'No path found', 'partid': 498, 'amount_msat': 165496, 'parent_partid': 391}, {'status': 'pending', 'failreason': 'No path found', 'partid': 915, 'amount_msat': 165496, 'parent_partid': 498}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1068, 'amount_msat': 85637, 'parent_partid': 915}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1271, 'amount_msat': 85637, 'parent_partid': 1068}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1069, 'amount_msat': 79859, 'parent_partid': 915}, {'status': 'failed', 'failreason': 'No path found', 'partid': 392, 'amount_msat': 356162, 'parent_partid': 324}, {'status': 'pending', 'failreason': 'No path found', 'partid': 499, 'amount_msat': 356162, 'parent_partid': 392}, {'status': 'failed', 'failreason': 'No path found', 'partid': 916, 'amount_msat': 169615, 'parent_partid': 499}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1436, 'amount_msat': 169615, 'parent_partid': 916}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1875, 'amount_msat': 86640, 'parent_partid': 1436}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1876, 'amount_msat': 82975, 'parent_partid': 1436}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1944, 'amount_msat': 82975, 'parent_partid': 1876}, {'status': 'pending', 'failreason': 'No path found', 'partid': 917, 'amount_msat': 186547, 'parent_partid': 499}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1437, 'amount_msat': 92228, 'parent_partid': 917}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1438, 'amount_msat': 94319, 'parent_partid': 917}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1877, 'amount_msat': 94319, 'parent_partid': 1438}, {'status': 'pending', 'failreason': 'No path found', 'partid': 5, 'amount_msat': 12608296, 'parent_partid': 3}, {'status': 'pending', 'failreason': 'No path found', 'partid': 11, 'amount_msat': 5967366, 'parent_partid': 5}, {'status': 'failed', 'failreason': 'No path found', 'partid': 32, 'amount_msat': 2862097, 'parent_partid': 11}, {'status': 'pending', 'failreason': 'No path found', 'partid': 61, 'amount_msat': 2862097, 'parent_partid': 32}, {'status': 'pending', 'failreason': 'No path found', 'partid': 125, 'amount_msat': 1406187, 'parent_partid': 61}, {'status': 'failed', 'failreason': 'No path found', 'partid': 246, 'amount_msat': 705481, 'parent_partid': 125}, {'status': 'pending', 'failreason': 'No path found', 'partid': 464, 'amount_msat': 705481, 'parent_partid': 246}, {'status': 'failed', 'failreason': 'No path found', 'partid': 794, 'amount_msat': 325513, 'parent_partid': 464}, {'status': 'pending', 'failreason': 'No path found', 'partid': 896, 'amount_msat': 325513, 'parent_partid': 794}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1427, 'amount_msat': 151609, 'parent_partid': 896}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1867, 'amount_msat': 82500, 'parent_partid': 1427}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1868, 'amount_msat': 69109, 'parent_partid': 1427}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2080, 'amount_msat': 69109, 'parent_partid': 1868}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1428, 'amount_msat': 173904, 'parent_partid': 896}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1869, 'amount_msat': 173904, 'parent_partid': 1428}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2081, 'amount_msat': 83451, 'parent_partid': 1869}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2082, 'amount_msat': 90453, 'parent_partid': 1869}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2108, 'amount_msat': 90453, 'parent_partid': 2082}, {'status': 'pending', 'failreason': 'No path found', 'partid': 795, 'amount_msat': 379968, 'parent_partid': 464}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1248, 'amount_msat': 192565, 'parent_partid': 795}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1725, 'amount_msat': 192565, 'parent_partid': 1248}, {'status': 'pending', 'failreason': 'No path found', 'partid': 2019, 'amount_msat': 102893, 'parent_partid': 1725}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2044, 'amount_msat': 47888, 'parent_partid': 2019}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2154, 'amount_msat': 47888, 'parent_partid': 2044}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2045, 'amount_msat': 55005, 'parent_partid': 2019}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2020, 'amount_msat': 89672, 'parent_partid': 1725}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2046, 'amount_msat': 89672, 'parent_partid': 2020}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1249, 'amount_msat': 187403, 'parent_partid': 795}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1362, 'amount_msat': 86841, 'parent_partid': 1249}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1549, 'amount_msat': 86841, 'parent_partid': 1362}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1363, 'amount_msat': 100562, 'parent_partid': 1249}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1550, 'amount_msat': 54272, 'parent_partid': 1363}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1961, 'amount_msat': 54272, 'parent_partid': 1550}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1551, 'amount_msat': 46290, 'parent_partid': 1363}, {'status': 'pending', 'failreason': 'No path found', 'partid': 247, 'amount_msat': 700706, 'parent_partid': 125}, {'status': 'failed', 'failreason': 'No path found', 'partid': 308, 'amount_msat': 376123, 'parent_partid': 247}, {'status': 'pending', 'failreason': 'No path found', 'partid': 603, 'amount_msat': 376123, 'parent_partid': 308}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1006, 'amount_msat': 184175, 'parent_partid': 603}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1127, 'amount_msat': 184175, 'parent_partid': 1006}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1305, 'amount_msat': 99447, 'parent_partid': 1127}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1306, 'amount_msat': 84728, 'parent_partid': 1127}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1533, 'amount_msat': 84728, 'parent_partid': 1306}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1007, 'amount_msat': 191948, 'parent_partid': 603}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1497, 'amount_msat': 102014, 'parent_partid': 1007}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1600, 'amount_msat': 54112, 'parent_partid': 1497}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1751, 'amount_msat': 54112, 'parent_partid': 1600}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1601, 'amount_msat': 47902, 'parent_partid': 1497}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1498, 'amount_msat': 89934, 'parent_partid': 1007}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1602, 'amount_msat': 89934, 'parent_partid': 1498}, {'status': 'pending', 'failreason': 'No path found', 'partid': 309, 'amount_msat': 324583, 'parent_partid': 247}, {'status': 'failed', 'failreason': 'No path found', 'partid': 378, 'amount_msat': 175246, 'parent_partid': 309}, {'status': 'pending', 'failreason': 'No path found', 'partid': 731, 'amount_msat': 175246, 'parent_partid': 378}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1196, 'amount_msat': 84585, 'parent_partid': 731}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1702, 'amount_msat': 84585, 'parent_partid': 1196}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1197, 'amount_msat': 90661, 'parent_partid': 731}, {'status': 'pending', 'failreason': 'No path found', 'partid': 379, 'amount_msat': 149337, 'parent_partid': 309}, {'status': 'failed', 'failreason': 'No path found', 'partid': 492, 'amount_msat': 72840, 'parent_partid': 379}, {'status': 'failed', 'failreason': 'No path found', 'partid': 911, 'amount_msat': 72840, 'parent_partid': 492}, {'status': 'failed', 'failreason': 'No path found', 'partid': 493, 'amount_msat': 76497, 'parent_partid': 379}, {'status': 'failed', 'failreason': 'No path found', 'partid': 126, 'amount_msat': 1455910, 'parent_partid': 61}, {'status': 'pending', 'failreason': 'No path found', 'partid': 158, 'amount_msat': 1455910, 'parent_partid': 126}, {'status': 'pending', 'failreason': 'No path found', 'partid': 327, 'amount_msat': 661924, 'parent_partid': 158}, {'status': 'failed', 'failreason': 'No path found', 'partid': 396, 'amount_msat': 360013, 'parent_partid': 327}, {'status': 'pending', 'failreason': 'No path found', 'partid': 505, 'amount_msat': 360013, 'parent_partid': 396}, {'status': 'pending', 'failreason': 'No path found', 'partid': 637, 'amount_msat': 192359, 'parent_partid': 505}, {'status': 'failed', 'failreason': 'No path found', 'partid': 805, 'amount_msat': 95792, 'parent_partid': 637}, {'status': 'failed', 'failreason': 'No path found', 'partid': 806, 'amount_msat': 96567, 'parent_partid': 637}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1027, 'amount_msat': 96567, 'parent_partid': 806}, {'status': 'failed', 'failreason': 'No path found', 'partid': 638, 'amount_msat': 167654, 'parent_partid': 505}, {'status': 'pending', 'failreason': 'No path found', 'partid': 807, 'amount_msat': 167654, 'parent_partid': 638}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1376, 'amount_msat': 82674, 'parent_partid': 807}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1849, 'amount_msat': 82674, 'parent_partid': 1376}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1377, 'amount_msat': 84980, 'parent_partid': 807}, {'status': 'pending', 'failreason': 'No path found', 'partid': 397, 'amount_msat': 301911, 'parent_partid': 327}, {'status': 'pending', 'failreason': 'No path found', 'partid': 743, 'amount_msat': 149824, 'parent_partid': 397}, {'status': 'failed', 'failreason': 'No path found', 'partid': 862, 'amount_msat': 80195, 'parent_partid': 743}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1415, 'amount_msat': 80195, 'parent_partid': 862}, {'status': 'failed', 'failreason': 'No path found', 'partid': 863, 'amount_msat': 69629, 'parent_partid': 743}, {'status': 'failed', 'failreason': 'No path found', 'partid': 744, 'amount_msat': 152087, 'parent_partid': 397}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1212, 'amount_msat': 152087, 'parent_partid': 744}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1706, 'amount_msat': 69605, 'parent_partid': 1212}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1792, 'amount_msat': 69605, 'parent_partid': 1706}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1707, 'amount_msat': 82482, 'parent_partid': 1212}, {'status': 'failed', 'failreason': 'No path found', 'partid': 328, 'amount_msat': 793986, 'parent_partid': 158}, {'status': 'pending', 'failreason': 'No path found', 'partid': 616, 'amount_msat': 793986, 'parent_partid': 328}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1016, 'amount_msat': 368179, 'parent_partid': 616}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1505, 'amount_msat': 368179, 'parent_partid': 1016}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1607, 'amount_msat': 181686, 'parent_partid': 1505}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1752, 'amount_msat': 97805, 'parent_partid': 1607}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2053, 'amount_msat': 97805, 'parent_partid': 1752}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1753, 'amount_msat': 83881, 'parent_partid': 1607}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1608, 'amount_msat': 186493, 'parent_partid': 1505}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1989, 'amount_msat': 186493, 'parent_partid': 1608}, {'status': 'pending', 'failreason': 'No path found', 'partid': 2135, 'amount_msat': 100519, 'parent_partid': 1989}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2151, 'amount_msat': 49646, 'parent_partid': 2135}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2152, 'amount_msat': 50873, 'parent_partid': 2135}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2166, 'amount_msat': 50873, 'parent_partid': 2152}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2136, 'amount_msat': 85974, 'parent_partid': 1989}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2176, 'amount_msat': 85974, 'parent_partid': 2136}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1017, 'amount_msat': 425807, 'parent_partid': 616}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1506, 'amount_msat': 219322, 'parent_partid': 1017}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1609, 'amount_msat': 219322, 'parent_partid': 1506}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1754, 'amount_msat': 102219, 'parent_partid': 1609}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1921, 'amount_msat': 102219, 'parent_partid': 1754}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2115, 'amount_msat': 52513, 'parent_partid': 1921}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2116, 'amount_msat': 49706, 'parent_partid': 1921}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2147, 'amount_msat': 49706, 'parent_partid': 2116}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1755, 'amount_msat': 117103, 'parent_partid': 1609}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2054, 'amount_msat': 56110, 'parent_partid': 1755}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2156, 'amount_msat': 56110, 'parent_partid': 2054}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2055, 'amount_msat': 60993, 'parent_partid': 1755}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1507, 'amount_msat': 206485, 'parent_partid': 1017}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1908, 'amount_msat': 101803, 'parent_partid': 1507}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1950, 'amount_msat': 101803, 'parent_partid': 1908}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2028, 'amount_msat': 46677, 'parent_partid': 1950}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2101, 'amount_msat': 46677, 'parent_partid': 2028}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2029, 'amount_msat': 55126, 'parent_partid': 1950}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1909, 'amount_msat': 104682, 'parent_partid': 1507}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2095, 'amount_msat': 56784, 'parent_partid': 1909}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2096, 'amount_msat': 47898, 'parent_partid': 1909}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2112, 'amount_msat': 47898, 'parent_partid': 2096}, {'status': 'pending', 'failreason': 'No path found', 'partid': 33, 'amount_msat': 3105269, 'parent_partid': 11}, {'status': 'failed', 'failreason': 'No path found', 'partid': 62, 'amount_msat': 1538301, 'parent_partid': 33}, {'status': 'pending', 'failreason': 'No path found', 'partid': 127, 'amount_msat': 1538301, 'parent_partid': 62}, {'status': 'failed', 'failreason': 'No path found', 'partid': 248, 'amount_msat': 806245, 'parent_partid': 127}, {'status': 'pending', 'failreason': 'No path found', 'partid': 465, 'amount_msat': 806245, 'parent_partid': 248}, {'status': 'failed', 'failreason': 'No path found', 'partid': 796, 'amount_msat': 421463, 'parent_partid': 465}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1250, 'amount_msat': 421463, 'parent_partid': 796}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1364, 'amount_msat': 197377, 'parent_partid': 1250}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1845, 'amount_msat': 197377, 'parent_partid': 1364}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2074, 'amount_msat': 104228, 'parent_partid': 1845}, {'status': 'pending', 'failreason': 'No path found', 'partid': 2162, 'amount_msat': 104228, 'parent_partid': 2074}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2169, 'amount_msat': 51965, 'parent_partid': 2162}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2170, 'amount_msat': 52263, 'parent_partid': 2162}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2178, 'amount_msat': 52263, 'parent_partid': 2170}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2075, 'amount_msat': 93149, 'parent_partid': 1845}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1365, 'amount_msat': 224086, 'parent_partid': 1250}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1552, 'amount_msat': 115764, 'parent_partid': 1365}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1962, 'amount_msat': 115764, 'parent_partid': 1552}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2122, 'amount_msat': 52298, 'parent_partid': 1962}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2148, 'amount_msat': 52298, 'parent_partid': 2122}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2123, 'amount_msat': 63466, 'parent_partid': 1962}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1553, 'amount_msat': 108322, 'parent_partid': 1365}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1963, 'amount_msat': 53400, 'parent_partid': 1553}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1964, 'amount_msat': 54922, 'parent_partid': 1553}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2031, 'amount_msat': 54922, 'parent_partid': 1964}, {'status': 'pending', 'failreason': 'No path found', 'partid': 797, 'amount_msat': 384782, 'parent_partid': 465}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1251, 'amount_msat': 202279, 'parent_partid': 797}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1366, 'amount_msat': 93006, 'parent_partid': 1251}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1554, 'amount_msat': 93006, 'parent_partid': 1366}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1367, 'amount_msat': 109273, 'parent_partid': 1251}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1846, 'amount_msat': 49690, 'parent_partid': 1367}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1938, 'amount_msat': 49690, 'parent_partid': 1846}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1847, 'amount_msat': 59583, 'parent_partid': 1367}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1252, 'amount_msat': 182503, 'parent_partid': 797}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1726, 'amount_msat': 182503, 'parent_partid': 1252}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2021, 'amount_msat': 85729, 'parent_partid': 1726}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2022, 'amount_msat': 96774, 'parent_partid': 1726}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2047, 'amount_msat': 96774, 'parent_partid': 2022}, {'status': 'pending', 'failreason': 'No path found', 'partid': 249, 'amount_msat': 732056, 'parent_partid': 127}, {'status': 'failed', 'failreason': 'No path found', 'partid': 310, 'amount_msat': 392827, 'parent_partid': 249}, {'status': 'pending', 'failreason': 'No path found', 'partid': 380, 'amount_msat': 392827, 'parent_partid': 310}, {'status': 'failed', 'failreason': 'No path found', 'partid': 732, 'amount_msat': 177644, 'parent_partid': 380}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1198, 'amount_msat': 177644, 'parent_partid': 732}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1334, 'amount_msat': 89180, 'parent_partid': 1198}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1541, 'amount_msat': 89180, 'parent_partid': 1334}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1335, 'amount_msat': 88464, 'parent_partid': 1198}, {'status': 'pending', 'failreason': 'No path found', 'partid': 733, 'amount_msat': 215183, 'parent_partid': 380}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1199, 'amount_msat': 98359, 'parent_partid': 733}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1200, 'amount_msat': 116824, 'parent_partid': 733}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1336, 'amount_msat': 116824, 'parent_partid': 1200}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1830, 'amount_msat': 59464, 'parent_partid': 1336}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2069, 'amount_msat': 59464, 'parent_partid': 1830}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1831, 'amount_msat': 57360, 'parent_partid': 1336}, {'status': 'pending', 'failreason': 'No path found', 'partid': 311, 'amount_msat': 339229, 'parent_partid': 249}, {'status': 'failed', 'failreason': 'No path found', 'partid': 604, 'amount_msat': 166958, 'parent_partid': 311}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1008, 'amount_msat': 166958, 'parent_partid': 604}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1499, 'amount_msat': 83095, 'parent_partid': 1008}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1500, 'amount_msat': 83863, 'parent_partid': 1008}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1906, 'amount_msat': 83863, 'parent_partid': 1500}, {'status': 'pending', 'failreason': 'No path found', 'partid': 605, 'amount_msat': 172271, 'parent_partid': 311}, {'status': 'failed', 'failreason': 'No path found', 'partid': 693, 'amount_msat': 89711, 'parent_partid': 605}, {'status': 'failed', 'failreason': 'No path found', 'partid': 694, 'amount_msat': 82560, 'parent_partid': 605}, {'status': 'failed', 'failreason': 'No path found', 'partid': 842, 'amount_msat': 82560, 'parent_partid': 694}, {'status': 'pending', 'failreason': 'No path found', 'partid': 63, 'amount_msat': 1566968, 'parent_partid': 33}, {'status': 'failed', 'failreason': 'No path found', 'partid': 128, 'amount_msat': 816993, 'parent_partid': 63}, {'status': 'pending', 'failreason': 'No path found', 'partid': 250, 'amount_msat': 816993, 'parent_partid': 128}, {'status': 'failed', 'failreason': 'No path found', 'partid': 312, 'amount_msat': 444458, 'parent_partid': 250}, {'status': 'pending', 'failreason': 'No path found', 'partid': 381, 'amount_msat': 444458, 'parent_partid': 312}, {'status': 'failed', 'failreason': 'No path found', 'partid': 494, 'amount_msat': 207501, 'parent_partid': 381}, {'status': 'pending', 'failreason': 'No path found', 'partid': 912, 'amount_msat': 207501, 'parent_partid': 494}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1433, 'amount_msat': 102477, 'parent_partid': 912}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1870, 'amount_msat': 53854, 'parent_partid': 1433}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1941, 'amount_msat': 53854, 'parent_partid': 1870}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1871, 'amount_msat': 48623, 'parent_partid': 1433}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1434, 'amount_msat': 105024, 'parent_partid': 912}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1872, 'amount_msat': 105024, 'parent_partid': 1434}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1942, 'amount_msat': 48341, 'parent_partid': 1872}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2119, 'amount_msat': 48341, 'parent_partid': 1942}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1943, 'amount_msat': 56683, 'parent_partid': 1872}, {'status': 'pending', 'failreason': 'No path found', 'partid': 495, 'amount_msat': 236957, 'parent_partid': 381}, {'status': 'pending', 'failreason': 'No path found', 'partid': 913, 'amount_msat': 122890, 'parent_partid': 495}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1066, 'amount_msat': 55824, 'parent_partid': 913}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1270, 'amount_msat': 55824, 'parent_partid': 1066}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1067, 'amount_msat': 67066, 'parent_partid': 913}, {'status': 'failed', 'failreason': 'No path found', 'partid': 914, 'amount_msat': 114067, 'parent_partid': 495}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1435, 'amount_msat': 114067, 'parent_partid': 914}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1873, 'amount_msat': 58662, 'parent_partid': 1435}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1874, 'amount_msat': 55405, 'parent_partid': 1435}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2083, 'amount_msat': 55405, 'parent_partid': 1874}, {'status': 'pending', 'failreason': 'No path found', 'partid': 313, 'amount_msat': 372535, 'parent_partid': 250}, {'status': 'failed', 'failreason': 'No path found', 'partid': 606, 'amount_msat': 177978, 'parent_partid': 313}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1009, 'amount_msat': 177978, 'parent_partid': 606}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1128, 'amount_msat': 84421, 'parent_partid': 1009}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1671, 'amount_msat': 84421, 'parent_partid': 1128}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1129, 'amount_msat': 93557, 'parent_partid': 1009}, {'status': 'pending', 'failreason': 'No path found', 'partid': 607, 'amount_msat': 194557, 'parent_partid': 313}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1010, 'amount_msat': 88229, 'parent_partid': 607}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1130, 'amount_msat': 88229, 'parent_partid': 1010}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1011, 'amount_msat': 106328, 'parent_partid': 607}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1131, 'amount_msat': 50627, 'parent_partid': 1011}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1132, 'amount_msat': 55701, 'parent_partid': 1011}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1672, 'amount_msat': 55701, 'parent_partid': 1132}, {'status': 'pending', 'failreason': 'No path found', 'partid': 129, 'amount_msat': 749975, 'parent_partid': 63}, {'status': 'pending', 'failreason': 'No path found', 'partid': 251, 'amount_msat': 390742, 'parent_partid': 129}, {'status': 'failed', 'failreason': 'No path found', 'partid': 466, 'amount_msat': 197324, 'parent_partid': 251}, {'status': 'pending', 'failreason': 'No path found', 'partid': 556, 'amount_msat': 197324, 'parent_partid': 466}, {'status': 'failed', 'failreason': 'No path found', 'partid': 964, 'amount_msat': 92364, 'parent_partid': 556}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1471, 'amount_msat': 92364, 'parent_partid': 964}, {'status': 'pending', 'failreason': 'No path found', 'partid': 965, 'amount_msat': 104960, 'parent_partid': 556}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1472, 'amount_msat': 50679, 'parent_partid': 965}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1587, 'amount_msat': 50679, 'parent_partid': 1472}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1473, 'amount_msat': 54281, 'parent_partid': 965}, {'status': 'pending', 'failreason': 'No path found', 'partid': 467, 'amount_msat': 193418, 'parent_partid': 251}, {'status': 'failed', 'failreason': 'No path found', 'partid': 557, 'amount_msat': 88435, 'parent_partid': 467}, {'status': 'failed', 'failreason': 'No path found', 'partid': 558, 'amount_msat': 104983, 'parent_partid': 467}, {'status': 'pending', 'failreason': 'No path found', 'partid': 966, 'amount_msat': 104983, 'parent_partid': 558}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1474, 'amount_msat': 48670, 'parent_partid': 966}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1588, 'amount_msat': 48670, 'parent_partid': 1474}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1475, 'amount_msat': 56313, 'parent_partid': 966}, {'status': 'failed', 'failreason': 'No path found', 'partid': 252, 'amount_msat': 359233, 'parent_partid': 129}, {'status': 'pending', 'failreason': 'No path found', 'partid': 468, 'amount_msat': 359233, 'parent_partid': 252}, {'status': 'failed', 'failreason': 'No path found', 'partid': 798, 'amount_msat': 184907, 'parent_partid': 468}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1253, 'amount_msat': 184907, 'parent_partid': 798}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1727, 'amount_msat': 87288, 'parent_partid': 1253}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1728, 'amount_msat': 97619, 'parent_partid': 1253}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1801, 'amount_msat': 97619, 'parent_partid': 1728}, {'status': 'pending', 'failreason': 'No path found', 'partid': 799, 'amount_msat': 174326, 'parent_partid': 468}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1254, 'amount_msat': 81794, 'parent_partid': 799}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1368, 'amount_msat': 81794, 'parent_partid': 1254}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1255, 'amount_msat': 92532, 'parent_partid': 799}, {'status': 'failed', 'failreason': 'No path found', 'partid': 12, 'amount_msat': 6640930, 'parent_partid': 5}, {'status': 'pending', 'failreason': 'No path found', 'partid': 19, 'amount_msat': 6640930, 'parent_partid': 12}, {'status': 'pending', 'failreason': 'No path found', 'partid': 41, 'amount_msat': 3513680, 'parent_partid': 19}, {'status': 'failed', 'failreason': 'No path found', 'partid': 80, 'amount_msat': 1768897, 'parent_partid': 41}, {'status': 'pending', 'failreason': 'No path found', 'partid': 169, 'amount_msat': 1768897, 'parent_partid': 80}, {'status': 'failed', 'failreason': 'No path found', 'partid': 338, 'amount_msat': 952500, 'parent_partid': 169}, {'status': 'pending', 'failreason': 'No path found', 'partid': 624, 'amount_msat': 952500, 'parent_partid': 338}, {'status': 'pending', 'failreason': 'No path found', 'partid': 711, 'amount_msat': 435774, 'parent_partid': 624}, {'status': 'failed', 'failreason': 'No path found', 'partid': 854, 'amount_msat': 217261, 'parent_partid': 711}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1411, 'amount_msat': 217261, 'parent_partid': 854}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1568, 'amount_msat': 115335, 'parent_partid': 1411}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1971, 'amount_msat': 115335, 'parent_partid': 1568}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2035, 'amount_msat': 58201, 'parent_partid': 1971}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2036, 'amount_msat': 57134, 'parent_partid': 1971}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2103, 'amount_msat': 57134, 'parent_partid': 2036}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1569, 'amount_msat': 101926, 'parent_partid': 1411}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1972, 'amount_msat': 46471, 'parent_partid': 1569}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2125, 'amount_msat': 46471, 'parent_partid': 1972}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1973, 'amount_msat': 55455, 'parent_partid': 1569}, {'status': 'pending', 'failreason': 'No path found', 'partid': 855, 'amount_msat': 218513, 'parent_partid': 711}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1042, 'amount_msat': 115428, 'parent_partid': 855}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1263, 'amount_msat': 115428, 'parent_partid': 1042}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1802, 'amount_msat': 56926, 'parent_partid': 1263}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1931, 'amount_msat': 56926, 'parent_partid': 1802}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1803, 'amount_msat': 58502, 'parent_partid': 1263}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1043, 'amount_msat': 103085, 'parent_partid': 855}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1624, 'amount_msat': 53574, 'parent_partid': 1043}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1993, 'amount_msat': 53574, 'parent_partid': 1624}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1625, 'amount_msat': 49511, 'parent_partid': 1043}, {'status': 'failed', 'failreason': 'No path found', 'partid': 712, 'amount_msat': 516726, 'parent_partid': 624}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1187, 'amount_msat': 516726, 'parent_partid': 712}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1331, 'amount_msat': 266551, 'parent_partid': 1187}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1539, 'amount_msat': 144175, 'parent_partid': 1331}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1735, 'amount_msat': 72598, 'parent_partid': 1539}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1736, 'amount_msat': 71577, 'parent_partid': 1539}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1919, 'amount_msat': 71577, 'parent_partid': 1736}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1540, 'amount_msat': 122376, 'parent_partid': 1331}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1737, 'amount_msat': 122376, 'parent_partid': 1540}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2049, 'amount_msat': 58436, 'parent_partid': 1737}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2050, 'amount_msat': 63940, 'parent_partid': 1737}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2155, 'amount_msat': 63940, 'parent_partid': 2050}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1332, 'amount_msat': 250175, 'parent_partid': 1187}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1827, 'amount_msat': 250175, 'parent_partid': 1332}, {'status': 'pending', 'failreason': 'No path found', 'partid': 2067, 'amount_msat': 119084, 'parent_partid': 1827}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2105, 'amount_msat': 54110, 'parent_partid': 2067}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2106, 'amount_msat': 64974, 'parent_partid': 2067}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2171, 'amount_msat': 64974, 'parent_partid': 2106}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2068, 'amount_msat': 131091, 'parent_partid': 1827}, {'status': 'pending', 'failreason': 'No path found', 'partid': 2161, 'amount_msat': 131091, 'parent_partid': 2068}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2167, 'amount_msat': 60102, 'parent_partid': 2161}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2168, 'amount_msat': 70989, 'parent_partid': 2161}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2181, 'amount_msat': 70989, 'parent_partid': 2168}, {'status': 'pending', 'failreason': 'No path found', 'partid': 339, 'amount_msat': 816397, 'parent_partid': 169}, {'status': 'failed', 'failreason': 'No path found', 'partid': 406, 'amount_msat': 387608, 'parent_partid': 339}, {'status': 'pending', 'failreason': 'No path found', 'partid': 751, 'amount_msat': 387608, 'parent_partid': 406}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1216, 'amount_msat': 211284, 'parent_partid': 751}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1343, 'amount_msat': 211284, 'parent_partid': 1216}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1542, 'amount_msat': 95849, 'parent_partid': 1343}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1738, 'amount_msat': 95849, 'parent_partid': 1542}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1543, 'amount_msat': 115435, 'parent_partid': 1343}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1957, 'amount_msat': 59028, 'parent_partid': 1543}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1958, 'amount_msat': 56407, 'parent_partid': 1543}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2030, 'amount_msat': 56407, 'parent_partid': 1958}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1217, 'amount_msat': 176324, 'parent_partid': 751}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1708, 'amount_msat': 87772, 'parent_partid': 1217}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2015, 'amount_msat': 87772, 'parent_partid': 1708}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1709, 'amount_msat': 88552, 'parent_partid': 1217}, {'status': 'pending', 'failreason': 'No path found', 'partid': 407, 'amount_msat': 428789, 'parent_partid': 339}, {'status': 'failed', 'failreason': 'No path found', 'partid': 512, 'amount_msat': 218088, 'parent_partid': 407}, {'status': 'pending', 'failreason': 'No path found', 'partid': 926, 'amount_msat': 218088, 'parent_partid': 512}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1076, 'amount_msat': 110311, 'parent_partid': 926}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1279, 'amount_msat': 110311, 'parent_partid': 1076}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1522, 'amount_msat': 58894, 'parent_partid': 1279}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1954, 'amount_msat': 58894, 'parent_partid': 1522}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1523, 'amount_msat': 51417, 'parent_partid': 1279}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1077, 'amount_msat': 107777, 'parent_partid': 926}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1280, 'amount_msat': 55839, 'parent_partid': 1077}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1805, 'amount_msat': 55839, 'parent_partid': 1280}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1281, 'amount_msat': 51938, 'parent_partid': 1077}, {'status': 'pending', 'failreason': 'No path found', 'partid': 513, 'amount_msat': 210701, 'parent_partid': 407}, {'status': 'pending', 'failreason': 'No path found', 'partid': 927, 'amount_msat': 103406, 'parent_partid': 513}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1446, 'amount_msat': 54827, 'parent_partid': 927}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1884, 'amount_msat': 54827, 'parent_partid': 1446}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1447, 'amount_msat': 48579, 'parent_partid': 927}, {'status': 'failed', 'failreason': 'No path found', 'partid': 928, 'amount_msat': 107295, 'parent_partid': 513}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1078, 'amount_msat': 107295, 'parent_partid': 928}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1282, 'amount_msat': 54715, 'parent_partid': 1078}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1524, 'amount_msat': 54715, 'parent_partid': 1282}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1283, 'amount_msat': 52580, 'parent_partid': 1078}, {'status': 'pending', 'failreason': 'No path found', 'partid': 81, 'amount_msat': 1744783, 'parent_partid': 41}, {'status': 'failed', 'failreason': 'No path found', 'partid': 104, 'amount_msat': 917461, 'parent_partid': 81}, {'status': 'pending', 'failreason': 'No path found', 'partid': 138, 'amount_msat': 917461, 'parent_partid': 104}, {'status': 'pending', 'failreason': 'No path found', 'partid': 181, 'amount_msat': 492605, 'parent_partid': 138}, {'status': 'pending', 'failreason': 'No path found', 'partid': 259, 'amount_msat': 260057, 'parent_partid': 181}, {'status': 'pending', 'failreason': 'No path found', 'partid': 561, 'amount_msat': 141958, 'parent_partid': 259}, {'status': 'failed', 'failreason': 'No path found', 'partid': 967, 'amount_msat': 66111, 'parent_partid': 561}, {'status': 'failed', 'failreason': 'No path found', 'partid': 968, 'amount_msat': 75847, 'parent_partid': 561}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1097, 'amount_msat': 75847, 'parent_partid': 968}, {'status': 'failed', 'failreason': 'No path found', 'partid': 562, 'amount_msat': 118099, 'parent_partid': 259}, {'status': 'pending', 'failreason': 'No path found', 'partid': 969, 'amount_msat': 118099, 'parent_partid': 562}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1098, 'amount_msat': 63110, 'parent_partid': 969}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1651, 'amount_msat': 63110, 'parent_partid': 1098}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1099, 'amount_msat': 54989, 'parent_partid': 969}, {'status': 'failed', 'failreason': 'No path found', 'partid': 260, 'amount_msat': 232548, 'parent_partid': 181}, {'status': 'pending', 'failreason': 'No path found', 'partid': 563, 'amount_msat': 232548, 'parent_partid': 260}, {'status': 'failed', 'failreason': 'No path found', 'partid': 970, 'amount_msat': 105210, 'parent_partid': 563}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1476, 'amount_msat': 105210, 'parent_partid': 970}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1901, 'amount_msat': 53656, 'parent_partid': 1476}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1902, 'amount_msat': 51554, 'parent_partid': 1476}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1949, 'amount_msat': 51554, 'parent_partid': 1902}, {'status': 'pending', 'failreason': 'No path found', 'partid': 971, 'amount_msat': 127338, 'parent_partid': 563}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1100, 'amount_msat': 57916, 'parent_partid': 971}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1652, 'amount_msat': 57916, 'parent_partid': 1100}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1101, 'amount_msat': 69422, 'parent_partid': 971}, {'status': 'failed', 'failreason': 'No path found', 'partid': 182, 'amount_msat': 424856, 'parent_partid': 138}, {'status': 'pending', 'failreason': 'No path found', 'partid': 261, 'amount_msat': 424856, 'parent_partid': 182}, {'status': 'failed', 'failreason': 'No path found', 'partid': 564, 'amount_msat': 208154, 'parent_partid': 261}, {'status': 'pending', 'failreason': 'No path found', 'partid': 676, 'amount_msat': 208154, 'parent_partid': 564}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1169, 'amount_msat': 104620, 'parent_partid': 676}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1325, 'amount_msat': 48395, 'parent_partid': 1169}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1326, 'amount_msat': 56225, 'parent_partid': 1169}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1826, 'amount_msat': 56225, 'parent_partid': 1326}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1170, 'amount_msat': 103534, 'parent_partid': 676}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1327, 'amount_msat': 103534, 'parent_partid': 1170}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1537, 'amount_msat': 50418, 'parent_partid': 1327}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1538, 'amount_msat': 53116, 'parent_partid': 1327}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1956, 'amount_msat': 53116, 'parent_partid': 1538}, {'status': 'pending', 'failreason': 'No path found', 'partid': 565, 'amount_msat': 216702, 'parent_partid': 261}, {'status': 'failed', 'failreason': 'No path found', 'partid': 972, 'amount_msat': 105749, 'parent_partid': 565}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1102, 'amount_msat': 105749, 'parent_partid': 972}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1653, 'amount_msat': 54947, 'parent_partid': 1102}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1654, 'amount_msat': 50802, 'parent_partid': 1102}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1771, 'amount_msat': 50802, 'parent_partid': 1654}, {'status': 'pending', 'failreason': 'No path found', 'partid': 973, 'amount_msat': 110953, 'parent_partid': 565}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1477, 'amount_msat': 52094, 'parent_partid': 973}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1478, 'amount_msat': 58859, 'parent_partid': 973}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1589, 'amount_msat': 58859, 'parent_partid': 1478}, {'status': 'pending', 'failreason': 'No path found', 'partid': 105, 'amount_msat': 827322, 'parent_partid': 81}, {'status': 'pending', 'failreason': 'No path found', 'partid': 139, 'amount_msat': 384757, 'parent_partid': 105}, {'status': 'pending', 'failreason': 'No path found', 'partid': 183, 'amount_msat': 201430, 'parent_partid': 139}, {'status': 'failed', 'failreason': 'No path found', 'partid': 414, 'amount_msat': 108113, 'parent_partid': 183}, {'status': 'pending', 'failreason': 'No path found', 'partid': 752, 'amount_msat': 108113, 'parent_partid': 414}, {'status': 'failed', 'failreason': 'No path found', 'partid': 869, 'amount_msat': 52126, 'parent_partid': 752}, {'status': 'failed', 'failreason': 'No path found', 'partid': 870, 'amount_msat': 55987, 'parent_partid': 752}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1416, 'amount_msat': 55987, 'parent_partid': 870}, {'status': 'failed', 'failreason': 'No path found', 'partid': 415, 'amount_msat': 93317, 'parent_partid': 183}, {'status': 'failed', 'failreason': 'No path found', 'partid': 184, 'amount_msat': 183327, 'parent_partid': 139}, {'status': 'pending', 'failreason': 'No path found', 'partid': 416, 'amount_msat': 183327, 'parent_partid': 184}, {'status': 'pending', 'failreason': 'No path found', 'partid': 753, 'amount_msat': 100477, 'parent_partid': 416}, {'status': 'failed', 'failreason': 'No path found', 'partid': 871, 'amount_msat': 52565, 'parent_partid': 753}, {'status': 'failed', 'failreason': 'No path found', 'partid': 872, 'amount_msat': 47912, 'parent_partid': 753}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1417, 'amount_msat': 47912, 'parent_partid': 872}, {'status': 'failed', 'failreason': 'No path found', 'partid': 754, 'amount_msat': 82850, 'parent_partid': 416}, {'status': 'failed', 'failreason': 'No path found', 'partid': 873, 'amount_msat': 82850, 'parent_partid': 754}, {'status': 'failed', 'failreason': 'No path found', 'partid': 140, 'amount_msat': 442565, 'parent_partid': 105}, {'status': 'pending', 'failreason': 'No path found', 'partid': 319, 'amount_msat': 442565, 'parent_partid': 140}, {'status': 'pending', 'failreason': 'No path found', 'partid': 387, 'amount_msat': 212916, 'parent_partid': 319}, {'status': 'pending', 'failreason': 'No path found', 'partid': 737, 'amount_msat': 116925, 'parent_partid': 387}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1204, 'amount_msat': 61491, 'parent_partid': 737}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1337, 'amount_msat': 61491, 'parent_partid': 1204}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1205, 'amount_msat': 55434, 'parent_partid': 737}, {'status': 'failed', 'failreason': 'No path found', 'partid': 738, 'amount_msat': 95991, 'parent_partid': 387}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1206, 'amount_msat': 95991, 'parent_partid': 738}, {'status': 'failed', 'failreason': 'No path found', 'partid': 388, 'amount_msat': 229649, 'parent_partid': 319}, {'status': 'pending', 'failreason': 'No path found', 'partid': 739, 'amount_msat': 229649, 'parent_partid': 388}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1207, 'amount_msat': 106491, 'parent_partid': 739}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1704, 'amount_msat': 56351, 'parent_partid': 1207}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2014, 'amount_msat': 56351, 'parent_partid': 1704}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1705, 'amount_msat': 50140, 'parent_partid': 1207}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1208, 'amount_msat': 123158, 'parent_partid': 739}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1338, 'amount_msat': 123158, 'parent_partid': 1208}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1832, 'amount_msat': 59687, 'parent_partid': 1338}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1936, 'amount_msat': 59687, 'parent_partid': 1832}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1833, 'amount_msat': 63471, 'parent_partid': 1338}, {'status': 'failed', 'failreason': 'No path found', 'partid': 42, 'amount_msat': 3127250, 'parent_partid': 19}, {'status': 'pending', 'failreason': 'No path found', 'partid': 53, 'amount_msat': 3127250, 'parent_partid': 42}, {'status': 'pending', 'failreason': 'No path found', 'partid': 65, 'amount_msat': 1473763, 'parent_partid': 53}, {'status': 'failed', 'failreason': 'No path found', 'partid': 90, 'amount_msat': 763842, 'parent_partid': 65}, {'status': 'pending', 'failreason': 'No path found', 'partid': 218, 'amount_msat': 763842, 'parent_partid': 90}, {'status': 'failed', 'failreason': 'No path found', 'partid': 292, 'amount_msat': 354170, 'parent_partid': 218}, {'status': 'pending', 'failreason': 'No path found', 'partid': 369, 'amount_msat': 354170, 'parent_partid': 292}, {'status': 'failed', 'failreason': 'No path found', 'partid': 482, 'amount_msat': 194645, 'parent_partid': 369}, {'status': 'pending', 'failreason': 'No path found', 'partid': 629, 'amount_msat': 194645, 'parent_partid': 482}, {'status': 'failed', 'failreason': 'No path found', 'partid': 800, 'amount_msat': 104503, 'parent_partid': 629}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1256, 'amount_msat': 104503, 'parent_partid': 800}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1369, 'amount_msat': 47061, 'parent_partid': 1256}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1370, 'amount_msat': 57442, 'parent_partid': 1256}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1555, 'amount_msat': 57442, 'parent_partid': 1370}, {'status': 'failed', 'failreason': 'No path found', 'partid': 801, 'amount_msat': 90142, 'parent_partid': 629}, {'status': 'pending', 'failreason': 'No path found', 'partid': 483, 'amount_msat': 159525, 'parent_partid': 369}, {'status': 'failed', 'failreason': 'No path found', 'partid': 903, 'amount_msat': 82720, 'parent_partid': 483}, {'status': 'failed', 'failreason': 'No path found', 'partid': 904, 'amount_msat': 76805, 'parent_partid': 483}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1430, 'amount_msat': 76805, 'parent_partid': 904}, {'status': 'pending', 'failreason': 'No path found', 'partid': 293, 'amount_msat': 409672, 'parent_partid': 218}, {'status': 'failed', 'failreason': 'No path found', 'partid': 586, 'amount_msat': 191699, 'parent_partid': 293}, {'status': 'pending', 'failreason': 'No path found', 'partid': 687, 'amount_msat': 191699, 'parent_partid': 586}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1172, 'amount_msat': 93950, 'parent_partid': 687}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1691, 'amount_msat': 93950, 'parent_partid': 1172}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1173, 'amount_msat': 97749, 'parent_partid': 687}, {'status': 'pending', 'failreason': 'No path found', 'partid': 587, 'amount_msat': 217973, 'parent_partid': 293}, {'status': 'failed', 'failreason': 'No path found', 'partid': 986, 'amount_msat': 100627, 'parent_partid': 587}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1114, 'amount_msat': 100627, 'parent_partid': 986}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1293, 'amount_msat': 52655, 'parent_partid': 1114}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1294, 'amount_msat': 47972, 'parent_partid': 1114}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1526, 'amount_msat': 47972, 'parent_partid': 1294}, {'status': 'pending', 'failreason': 'No path found', 'partid': 987, 'amount_msat': 117346, 'parent_partid': 587}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1484, 'amount_msat': 60067, 'parent_partid': 987}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1904, 'amount_msat': 60067, 'parent_partid': 1484}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1485, 'amount_msat': 57279, 'parent_partid': 987}, {'status': 'pending', 'failreason': 'No path found', 'partid': 91, 'amount_msat': 709921, 'parent_partid': 65}, {'status': 'pending', 'failreason': 'No path found', 'partid': 219, 'amount_msat': 381818, 'parent_partid': 91}, {'status': 'pending', 'failreason': 'No path found', 'partid': 437, 'amount_msat': 191083, 'parent_partid': 219}, {'status': 'failed', 'failreason': 'No path found', 'partid': 776, 'amount_msat': 99992, 'parent_partid': 437}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1235, 'amount_msat': 99992, 'parent_partid': 776}, {'status': 'failed', 'failreason': 'No path found', 'partid': 777, 'amount_msat': 91091, 'parent_partid': 437}, {'status': 'failed', 'failreason': 'No path found', 'partid': 438, 'amount_msat': 190735, 'parent_partid': 219}, {'status': 'pending', 'failreason': 'No path found', 'partid': 532, 'amount_msat': 190735, 'parent_partid': 438}, {'status': 'failed', 'failreason': 'No path found', 'partid': 937, 'amount_msat': 88321, 'parent_partid': 532}, {'status': 'failed', 'failreason': 'No path found', 'partid': 938, 'amount_msat': 102414, 'parent_partid': 532}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1456, 'amount_msat': 102414, 'parent_partid': 938}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1893, 'amount_msat': 46966, 'parent_partid': 1456}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1894, 'amount_msat': 55448, 'parent_partid': 1456}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1947, 'amount_msat': 55448, 'parent_partid': 1894}, {'status': 'failed', 'failreason': 'No path found', 'partid': 220, 'amount_msat': 328103, 'parent_partid': 91}, {'status': 'pending', 'failreason': 'No path found', 'partid': 439, 'amount_msat': 328103, 'parent_partid': 220}, {'status': 'pending', 'failreason': 'No path found', 'partid': 533, 'amount_msat': 167090, 'parent_partid': 439}, {'status': 'failed', 'failreason': 'No path found', 'partid': 939, 'amount_msat': 78133, 'parent_partid': 533}, {'status': 'failed', 'failreason': 'No path found', 'partid': 940, 'amount_msat': 88957, 'parent_partid': 533}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1457, 'amount_msat': 88957, 'parent_partid': 940}, {'status': 'failed', 'failreason': 'No path found', 'partid': 534, 'amount_msat': 161013, 'parent_partid': 439}, {'status': 'pending', 'failreason': 'No path found', 'partid': 664, 'amount_msat': 161013, 'parent_partid': 534}, {'status': 'failed', 'failreason': 'No path found', 'partid': 818, 'amount_msat': 78528, 'parent_partid': 664}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1385, 'amount_msat': 78528, 'parent_partid': 818}, {'status': 'failed', 'failreason': 'No path found', 'partid': 819, 'amount_msat': 82485, 'parent_partid': 664}, {'status': 'failed', 'failreason': 'No path found', 'partid': 66, 'amount_msat': 1653487, 'parent_partid': 53}, {'status': 'pending', 'failreason': 'No path found', 'partid': 92, 'amount_msat': 1653487, 'parent_partid': 66}, {'status': 'pending', 'failreason': 'No path found', 'partid': 221, 'amount_msat': 869622, 'parent_partid': 92}, {'status': 'failed', 'failreason': 'No path found', 'partid': 440, 'amount_msat': 407966, 'parent_partid': 221}, {'status': 'pending', 'failreason': 'No path found', 'partid': 535, 'amount_msat': 407966, 'parent_partid': 440}, {'status': 'pending', 'failreason': 'No path found', 'partid': 665, 'amount_msat': 217493, 'parent_partid': 535}, {'status': 'failed', 'failreason': 'No path found', 'partid': 820, 'amount_msat': 107211, 'parent_partid': 665}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1386, 'amount_msat': 107211, 'parent_partid': 820}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1564, 'amount_msat': 55075, 'parent_partid': 1386}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1970, 'amount_msat': 55075, 'parent_partid': 1564}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1565, 'amount_msat': 52136, 'parent_partid': 1386}, {'status': 'pending', 'failreason': 'No path found', 'partid': 821, 'amount_msat': 110282, 'parent_partid': 665}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1387, 'amount_msat': 58562, 'parent_partid': 821}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1388, 'amount_msat': 51720, 'parent_partid': 821}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1851, 'amount_msat': 51720, 'parent_partid': 1388}, {'status': 'failed', 'failreason': 'No path found', 'partid': 666, 'amount_msat': 190473, 'parent_partid': 535}, {'status': 'pending', 'failreason': 'No path found', 'partid': 822, 'amount_msat': 190473, 'parent_partid': 666}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1389, 'amount_msat': 93596, 'parent_partid': 822}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1390, 'amount_msat': 96877, 'parent_partid': 822}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1566, 'amount_msat': 96877, 'parent_partid': 1390}, {'status': 'pending', 'failreason': 'No path found', 'partid': 441, 'amount_msat': 461656, 'parent_partid': 221}, {'status': 'failed', 'failreason': 'No path found', 'partid': 536, 'amount_msat': 235819, 'parent_partid': 441}, {'status': 'pending', 'failreason': 'No path found', 'partid': 667, 'amount_msat': 235819, 'parent_partid': 536}, {'status': 'pending', 'failreason': 'No path found', 'partid': 823, 'amount_msat': 110920, 'parent_partid': 667}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1031, 'amount_msat': 58725, 'parent_partid': 823}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1032, 'amount_msat': 52195, 'parent_partid': 823}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1257, 'amount_msat': 52195, 'parent_partid': 1032}, {'status': 'failed', 'failreason': 'No path found', 'partid': 824, 'amount_msat': 124899, 'parent_partid': 667}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1391, 'amount_msat': 124899, 'parent_partid': 824}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1852, 'amount_msat': 66739, 'parent_partid': 1391}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2078, 'amount_msat': 66739, 'parent_partid': 1852}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1853, 'amount_msat': 58160, 'parent_partid': 1391}, {'status': 'pending', 'failreason': 'No path found', 'partid': 537, 'amount_msat': 225837, 'parent_partid': 441}, {'status': 'pending', 'failreason': 'No path found', 'partid': 941, 'amount_msat': 102240, 'parent_partid': 537}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1458, 'amount_msat': 46907, 'parent_partid': 941}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1895, 'amount_msat': 46907, 'parent_partid': 1458}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1459, 'amount_msat': 55333, 'parent_partid': 941}, {'status': 'failed', 'failreason': 'No path found', 'partid': 942, 'amount_msat': 123597, 'parent_partid': 537}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1082, 'amount_msat': 123597, 'parent_partid': 942}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1284, 'amount_msat': 65250, 'parent_partid': 1082}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1525, 'amount_msat': 65250, 'parent_partid': 1284}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1285, 'amount_msat': 58347, 'parent_partid': 1082}, {'status': 'failed', 'failreason': 'No path found', 'partid': 222, 'amount_msat': 783865, 'parent_partid': 92}, {'status': 'pending', 'failreason': 'No path found', 'partid': 294, 'amount_msat': 783865, 'parent_partid': 222}, {'status': 'failed', 'failreason': 'No path found', 'partid': 588, 'amount_msat': 407720, 'parent_partid': 294}, {'status': 'pending', 'failreason': 'No path found', 'partid': 988, 'amount_msat': 407720, 'parent_partid': 588}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1486, 'amount_msat': 207799, 'parent_partid': 988}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1591, 'amount_msat': 207799, 'parent_partid': 1486}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1981, 'amount_msat': 108379, 'parent_partid': 1591}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2037, 'amount_msat': 51888, 'parent_partid': 1981}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2038, 'amount_msat': 56491, 'parent_partid': 1981}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2104, 'amount_msat': 56491, 'parent_partid': 2038}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1982, 'amount_msat': 99420, 'parent_partid': 1591}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2130, 'amount_msat': 99420, 'parent_partid': 1982}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1487, 'amount_msat': 199921, 'parent_partid': 988}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1592, 'amount_msat': 97442, 'parent_partid': 1487}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1983, 'amount_msat': 97442, 'parent_partid': 1592}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1593, 'amount_msat': 102479, 'parent_partid': 1487}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1984, 'amount_msat': 53739, 'parent_partid': 1593}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2039, 'amount_msat': 53739, 'parent_partid': 1984}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1985, 'amount_msat': 48740, 'parent_partid': 1593}, {'status': 'pending', 'failreason': 'No path found', 'partid': 589, 'amount_msat': 376145, 'parent_partid': 294}, {'status': 'pending', 'failreason': 'No path found', 'partid': 989, 'amount_msat': 180716, 'parent_partid': 589}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1115, 'amount_msat': 97298, 'parent_partid': 989}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1116, 'amount_msat': 83418, 'parent_partid': 989}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1665, 'amount_msat': 83418, 'parent_partid': 1116}, {'status': 'failed', 'failreason': 'No path found', 'partid': 990, 'amount_msat': 195429, 'parent_partid': 589}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1117, 'amount_msat': 195429, 'parent_partid': 990}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1666, 'amount_msat': 88500, 'parent_partid': 1117}, {'status': 'failed', 'failreason': 'No path found', 'partid': 2005, 'amount_msat': 88500, 'parent_partid': 1666}, {'status': 'pending', 'failreason': 'No path found', 'partid': 1667, 'amount_msat': 106929, 'parent_partid': 1117}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1774, 'amount_msat': 50193, 'parent_partid': 1667}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1924, 'amount_msat': 50193, 'parent_partid': 1774}, {'status': 'failed', 'failreason': 'No path found', 'partid': 1775, 'amount_msat': 56736, 'parent_partid': 1667}]}
```
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
4899 lines
195 KiB
Python
4899 lines
195 KiB
Python
from fixtures import * # noqa: F401,F403
|
|
from fixtures import TEST_NETWORK
|
|
from decimal import Decimal
|
|
from pyln.client import RpcError, Millisatoshi
|
|
import pyln.proto.wire as wire
|
|
from utils import (
|
|
only_one, wait_for, sync_blockheight, TIMEOUT,
|
|
expected_peer_features, expected_node_features,
|
|
expected_channel_features,
|
|
check_coin_moves, first_channel_id, account_balance, basic_fee,
|
|
scriptpubkey_addr, default_ln_port,
|
|
mine_funding_to_announce, first_scid,
|
|
CHANNEL_SIZE
|
|
)
|
|
from pyln.testing.utils import SLOW_MACHINE, VALGRIND, EXPERIMENTAL_DUAL_FUND, FUNDAMOUNT
|
|
|
|
import os
|
|
import pytest
|
|
import random
|
|
import re
|
|
import time
|
|
import unittest
|
|
import websocket
|
|
import signal
|
|
import ssl
|
|
|
|
|
|
def test_connect_basic(node_factory):
|
|
l1, l2 = node_factory.line_graph(2, fundchannel=False)
|
|
l1id = l1.info['id']
|
|
l2id = l2.info['id']
|
|
|
|
# These should be in openingd.
|
|
assert l1.rpc.getpeer(l2id)['connected']
|
|
assert l2.rpc.getpeer(l1id)['connected']
|
|
assert len(l1.rpc.listpeerchannels(l2id)['channels']) == 0
|
|
assert len(l2.rpc.listpeerchannels(l1id)['channels']) == 0
|
|
|
|
# Reconnect should be a noop
|
|
ret = l1.rpc.connect(l2id, 'localhost', port=l2.port)
|
|
assert ret['id'] == l2id
|
|
assert ret['address'] == {'type': 'ipv4', 'address': '127.0.0.1', 'port': l2.port}
|
|
|
|
ret = l2.rpc.connect(l1id, host='localhost', port=l1.port)
|
|
assert ret['id'] == l1id
|
|
# FIXME: This gives a bogus address (since they connected to us): better to give none!
|
|
assert 'address' in ret
|
|
|
|
# Should still only have one peer!
|
|
assert len(l1.rpc.listpeers()['peers']) == 1
|
|
assert len(l2.rpc.listpeers()['peers']) == 1
|
|
|
|
# Should get reasonable error if unknown addr for peer.
|
|
with pytest.raises(RpcError, match=r'Unable to connect, no address known'):
|
|
l1.rpc.connect('032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e')
|
|
|
|
# Should get reasonable error if connection refuse.
|
|
with pytest.raises(RpcError, match=r'Connection establishment: Connection refused'):
|
|
l1.rpc.connect('032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e', 'localhost', 1)
|
|
|
|
# Should get reasonable error if wrong key for peer.
|
|
with pytest.raises(RpcError, match=r'Cryptographic handshake: peer closed connection \(wrong key\?\)'):
|
|
l1.rpc.connect('032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e', 'localhost', l2.port)
|
|
|
|
# test new `num_channels` param
|
|
assert l1.rpc.listpeers(l2id)['peers'][0]['num_channels'] == 0
|
|
l1.fundchannel(l2)
|
|
assert l1.rpc.listpeers(l2id)['peers'][0]['num_channels'] == 1
|
|
l1.fundchannel(l2)
|
|
assert l1.rpc.listpeers(l2id)['peers'][0]['num_channels'] == 2
|
|
|
|
|
|
def test_remote_addr(node_factory, bitcoind):
|
|
"""Check address discovery (BOLT1 #917) init remote_addr works as designed:
|
|
|
|
`node_announcement` update must only be send out when:
|
|
- at least two peers
|
|
- we have a channel with
|
|
- report the same `remote_addr`
|
|
|
|
We perform logic tests on L2, setup:
|
|
l1 --> [l2] <-- l3
|
|
"""
|
|
# don't announce anything per se
|
|
opts = {'may_reconnect': True,
|
|
'dev-allow-localhost': None,
|
|
'dev-no-reconnect': None,
|
|
'announce-addr-discovered': True}
|
|
l1, l2, l3 = node_factory.get_nodes(3, opts)
|
|
|
|
# Disable announcing local autobind addresses with dev-allow-localhost.
|
|
# We need to have l2 opts 'bind-addr' to the (generated) value of 'addr'.
|
|
# So we stop, set 'bind-addr' option, delete 'addr' and restart first.
|
|
l2.stop()
|
|
l2.daemon.opts['bind-addr'] = l2.daemon.opts['addr']
|
|
del l2.daemon.opts['addr']
|
|
l2.start()
|
|
assert len(l2.rpc.getinfo()['address']) == 0
|
|
|
|
l2.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
|
logmsg = l2.daemon.wait_for_log("Peer says it sees our address as: 127.0.0.1:[0-9]{5}")
|
|
# check 'listpeers' contains the 'remote_addr' as logged
|
|
assert logmsg.endswith(l2.rpc.listpeers()['peers'][0]['remote_addr'])
|
|
|
|
# Fund first channel so initial node_announcement is send
|
|
# and also check no addresses have been announced yet
|
|
l1.fundchannel(l2)
|
|
bitcoind.generate_block(5)
|
|
l1.daemon.wait_for_log(f"Received node_announcement for node {l2.info['id']}")
|
|
assert(len(l1.rpc.listnodes(l2.info['id'])['nodes'][0]['addresses']) == 0)
|
|
assert len(l2.rpc.getinfo()['address']) == 0
|
|
|
|
def_port = default_ln_port(l2.info["network"])
|
|
|
|
# when we restart l1 with a channel and reconnect, node_announcement update
|
|
# must not yet be send as we need the same `remote_addr` confirmed from a
|
|
# another peer we have a channel with.
|
|
# Note: In this state l2 stores remote_addr as reported by l1
|
|
assert not l2.daemon.is_in_log("Update our node_announcement for discovered address: 127.0.0.1:{}".format(def_port))
|
|
l1.restart()
|
|
l2.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
|
l2.daemon.wait_for_log("Peer says it sees our address as: 127.0.0.1:[0-9]{5}")
|
|
|
|
# Now l1 sees l2 but without announced addresses.
|
|
assert(len(l1.rpc.listnodes(l2.info['id'])['nodes'][0]['addresses']) == 0)
|
|
assert not l2.daemon.is_in_log("Update our node_announcement for discovered address: 127.0.0.1:{}".format(def_port))
|
|
assert len(l2.rpc.getinfo()['address']) == 0
|
|
|
|
# connect second node. This will trigger `node_announcement` update.
|
|
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
l2.daemon.wait_for_log("Peer says it sees our address as: 127.0.0.1:[0-9]{5}")
|
|
l2.daemon.wait_for_log("Update our node_announcement for discovered address: 127.0.0.1:{}".format(def_port))
|
|
|
|
# check l1 sees the updated node announcement via CLI listnodes
|
|
l1.daemon.wait_for_log(f"Received node_announcement for node {l2.info['id']}")
|
|
address = l1.rpc.listnodes(l2.info['id'])['nodes'][0]['addresses'][0]
|
|
assert address['type'] == "ipv4"
|
|
assert address['address'] == "127.0.0.1"
|
|
assert address['port'] == def_port
|
|
|
|
# also check l2 returns the announced address (and port) via CLI getinfo
|
|
getinfo = l2.rpc.getinfo()
|
|
assert len(getinfo['address']) == 1
|
|
assert getinfo['address'][0]['type'] == 'ipv4'
|
|
assert getinfo['address'][0]['address'] == '127.0.0.1'
|
|
assert getinfo['address'][0]['port'] == def_port
|
|
|
|
|
|
def test_remote_addr_disabled(node_factory, bitcoind):
|
|
"""Simply tests that IP address discovery announcements can be turned off
|
|
|
|
We perform logic tests on L2, setup:
|
|
l1 --> [l2] <-- l3
|
|
"""
|
|
opts = {'dev-allow-localhost': None,
|
|
'announce-addr-discovered': False,
|
|
'may_reconnect': True,
|
|
'dev-no-reconnect': None}
|
|
l1, l2, l3 = node_factory.get_nodes(3, opts=[opts, opts, opts])
|
|
|
|
# l1->l2
|
|
l2.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
|
l2.daemon.wait_for_log("Peer says it sees our address as: 127.0.0.1:[0-9]{5}")
|
|
l1.fundchannel(l2)
|
|
bitcoind.generate_block(6)
|
|
l1.daemon.wait_for_log(f"Received node_announcement for node {l2.info['id']}")
|
|
# l2->l3
|
|
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
l2.daemon.wait_for_log("Peer says it sees our address as: 127.0.0.1:[0-9]{5}")
|
|
l2.fundchannel(l3)
|
|
bitcoind.generate_block(6)
|
|
l3.daemon.wait_for_log(f"Received node_announcement for node {l2.info['id']}")
|
|
|
|
# restart both and wait for channels to be ready
|
|
l1.restart()
|
|
l2.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
|
l2.daemon.wait_for_log(f"{l1.info['id']}.*Already have funding locked in")
|
|
l3.restart()
|
|
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
l2.daemon.wait_for_log(f"{l3.info['id']}.*Already have funding locked in")
|
|
|
|
# if ip discovery would have been enabled, we would have send an updated
|
|
# node_announcement by now. Check we didn't...
|
|
bitcoind.generate_block(6) # ugly, but we need to wait for gossip...
|
|
assert not l2.daemon.is_in_log("Update our node_announcement for discovered address")
|
|
|
|
|
|
def test_remote_addr_port(node_factory, bitcoind):
|
|
"""Check address discovery (BOLT1 #917) can be done with non-default TCP ports
|
|
We perform logic tests on L2, setup same as above:
|
|
l1 --> [l2] <-- l3
|
|
"""
|
|
port = 1234
|
|
opts = {'dev-allow-localhost': None,
|
|
'may_reconnect': True,
|
|
'dev-no-reconnect': None,
|
|
'announce-addr-discovered-port': port}
|
|
l1, l2, l3 = node_factory.get_nodes(3, opts=[opts, opts, opts])
|
|
|
|
# Disable announcing local autobind addresses with dev-allow-localhost.
|
|
# We need to have l2 opts 'bind-addr' to the (generated) value of 'addr'.
|
|
# So we stop, set 'bind-addr' option, delete 'addr' and restart first.
|
|
l2.stop()
|
|
l2.daemon.opts['bind-addr'] = l2.daemon.opts['addr']
|
|
del l2.daemon.opts['addr']
|
|
l2.start()
|
|
assert len(l2.rpc.getinfo()['address']) == 0
|
|
|
|
# l1->l2
|
|
l2.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
|
l2.daemon.wait_for_log("Peer says it sees our address as: 127.0.0.1:[0-9]{5}")
|
|
l1.fundchannel(l2)
|
|
bitcoind.generate_block(5)
|
|
l1.daemon.wait_for_log(f"Received node_announcement for node {l2.info['id']}")
|
|
# l2->l3
|
|
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
l2.daemon.wait_for_log("Peer says it sees our address as: 127.0.0.1:[0-9]{5}")
|
|
l2.fundchannel(l3)
|
|
bitcoind.generate_block(5)
|
|
|
|
# restart both and wait for channels to be ready
|
|
l1.restart()
|
|
l2.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
|
l2.daemon.wait_for_log("Already have funding locked in")
|
|
l3.restart()
|
|
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
|
|
# if ip discovery would have been enabled, we would have send an updated
|
|
# node_announcement by now. Check we didn't...
|
|
l2.daemon.wait_for_logs(["Already have funding locked in",
|
|
"Update our node_announcement for discovered address"])
|
|
info = l2.rpc.getinfo()
|
|
assert len(info['address']) == 1
|
|
assert info['address'][0]['type'] == 'ipv4'
|
|
assert info['address'][0]['address'] == '127.0.0.1'
|
|
assert info['address'][0]['port'] == port
|
|
|
|
|
|
def test_connect_standard_addr(node_factory):
|
|
"""Test standard node@host:port address
|
|
"""
|
|
l1, l2, l3 = node_factory.get_nodes(3)
|
|
|
|
# node@host
|
|
ret = l1.rpc.connect("{}@{}".format(l2.info['id'], 'localhost'), port=l2.port)
|
|
assert ret['id'] == l2.info['id']
|
|
assert ret['address'] == {'type': 'ipv4', 'address': '127.0.0.1', 'port': l2.port}
|
|
|
|
# node@host:port
|
|
ret = l1.rpc.connect("{}@localhost:{}".format(l3.info['id'], l3.port))
|
|
assert ret['id'] == l3.info['id']
|
|
|
|
# node@[ipv6]:port --- not supported by our CI
|
|
# ret = l1.rpc.connect("{}@[::1]:{}".format(l3.info['id'], l3.port))
|
|
# assert ret['id'] == l3.info['id']
|
|
|
|
|
|
def test_reconnect_channel_peers(node_factory, executor):
|
|
l1 = node_factory.get_node(may_reconnect=True)
|
|
l2 = node_factory.get_node(may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.fundchannel(l2, 10**6)
|
|
l2.restart()
|
|
|
|
# Should reconnect.
|
|
wait_for(lambda: only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected'])
|
|
wait_for(lambda: only_one(l2.rpc.listpeers(l1.info['id'])['peers'])['connected'])
|
|
# Connect command should succeed.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# Stop l2 and wait for l1 to notice.
|
|
l2.stop()
|
|
wait_for(lambda: not only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected'])
|
|
|
|
# Now should fail.
|
|
with pytest.raises(RpcError, match=r'(Connection refused|Bad file descriptor)'):
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# Wait for exponential backoff to give us a 2 second window.
|
|
l1.daemon.wait_for_log('Will try reconnect in 2 seconds')
|
|
|
|
# It should now succeed when it restarts.
|
|
l2.start()
|
|
|
|
# Multiples should be fine!
|
|
fut1 = executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.port)
|
|
fut2 = executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.port)
|
|
fut3 = executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.port)
|
|
fut1.result(10)
|
|
fut2.result(10)
|
|
fut3.result(10)
|
|
|
|
|
|
def test_connection_moved(node_factory, executor):
|
|
slow_start = os.path.join(os.getcwd(), 'tests/plugins/slow_start.py')
|
|
options = {'may_reconnect': True, 'plugin': slow_start}
|
|
l1, l2 = node_factory.get_nodes(2, opts=options)
|
|
|
|
# Set up the plugin to wait for a connection
|
|
executor.submit(l1.rpc.waitconn)
|
|
log = l1.daemon.wait_for_log('listening for connections')
|
|
match = re.search(r'on port (\d*)', log)
|
|
assert match and len(match.groups()) == 1
|
|
hang_port = int(match.groups()[0])
|
|
|
|
# Attempt connection
|
|
fut_hang = executor.submit(l1.rpc.connect, l2.info['id'],
|
|
'localhost', hang_port)
|
|
l1.daemon.wait_for_log('connection from')
|
|
|
|
# Provide correct connection details
|
|
ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
assert ret['address'] == {'type': 'ipv4', 'address': '127.0.0.1', 'port': l2.port}
|
|
|
|
# If we failed to update the connection, this call will error
|
|
fut_hang.result(TIMEOUT)
|
|
|
|
|
|
def test_balance(node_factory):
|
|
l1, l2 = node_factory.line_graph(2, fundchannel=True)
|
|
p1 = only_one(l1.rpc.listpeerchannels(peer_id=l2.info['id'])['channels'])
|
|
p2 = only_one(l2.rpc.listpeerchannels(l1.info['id'])['channels'])
|
|
assert p1['to_us_msat'] == 10**6 * 1000
|
|
assert p1['total_msat'] == 10**6 * 1000
|
|
assert p2['to_us_msat'] == 0
|
|
assert p2['total_msat'] == 10**6 * 1000
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_bad_opening(node_factory):
|
|
# l1 asks for a too-long locktime
|
|
l1 = node_factory.get_node(options={'watchtime-blocks': 2017})
|
|
l2 = node_factory.get_node()
|
|
ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
assert ret['id'] == l2.info['id']
|
|
|
|
l1.daemon.wait_for_log('Handed peer, entering loop')
|
|
l2.daemon.wait_for_log('Handed peer, entering loop')
|
|
|
|
l1.fundwallet(10**6 + 1000000)
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6)
|
|
|
|
l2.daemon.wait_for_log('to_self_delay 2017 larger than 2016')
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', "Fee computation and limits are network specific")
|
|
@pytest.mark.slow_test
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
@pytest.mark.parametrize("anchors", [False, True])
|
|
def test_opening_tiny_channel(node_factory, anchors):
|
|
# Test custom min-capacity-sat parameters
|
|
#
|
|
# [l1]-----> [l2] (~6000) - technical minimal value that wont be rejected
|
|
# \
|
|
# o---> [l3] (10000) - the current default
|
|
# \
|
|
# o-> [l4] (20000) - a node with a higher minimal value
|
|
#
|
|
# For each:
|
|
# 1. Try to establish channel with capacity 1sat smaller than min_capacity_sat
|
|
# 2. Try to establish channel with capacity exact min_capacity_sat
|
|
#
|
|
# BOLT2
|
|
# The receiving node MAY fail the channel if:
|
|
# - funding_satoshis is too small
|
|
# - it considers `feerate_per_kw` too small for timely processing or unreasonably large.
|
|
#
|
|
dustlimit = 546
|
|
reserves = 2 * dustlimit
|
|
if anchors:
|
|
min_commit_tx_fees = basic_fee(3750, True)
|
|
else:
|
|
min_commit_tx_fees = basic_fee(7500, False)
|
|
overhead = reserves + min_commit_tx_fees
|
|
if anchors:
|
|
# Gotta fund those anchors too!
|
|
overhead += 660
|
|
|
|
l2_min_capacity = 1 # just enough to get past capacity filter
|
|
l3_min_capacity = 10000 # the current default
|
|
l4_min_capacity = 20000 # a server with more than default minimum
|
|
|
|
opts = [{'min-capacity-sat': 0, 'dev-no-reconnect': None},
|
|
{'min-capacity-sat': l2_min_capacity, 'dev-no-reconnect': None},
|
|
{'min-capacity-sat': l3_min_capacity, 'dev-no-reconnect': None},
|
|
{'min-capacity-sat': l4_min_capacity, 'dev-no-reconnect': None}]
|
|
if anchors is False:
|
|
for opt in opts:
|
|
opt['dev-force-features'] = "-23"
|
|
l1, l2, l3, l4 = node_factory.get_nodes(4, opts=opts)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
l1.rpc.connect(l4.info['id'], 'localhost', l4.port)
|
|
|
|
with pytest.raises(RpcError, match=r'They sent (ERROR|WARNING|ABORT).*channel capacity is .*, which is below .*sat'):
|
|
l1.fundchannel(l2, l2_min_capacity + overhead - 1)
|
|
assert only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected']
|
|
|
|
l1.fundchannel(l2, l2_min_capacity + overhead)
|
|
|
|
with pytest.raises(RpcError, match=r'They sent (ERROR|WARNING|ABORT).*channel capacity is .*, which is below .*sat'):
|
|
l1.fundchannel(l3, l3_min_capacity + overhead - 1)
|
|
assert only_one(l1.rpc.listpeers(l3.info['id'])['peers'])['connected']
|
|
l1.fundchannel(l3, l3_min_capacity + overhead)
|
|
|
|
with pytest.raises(RpcError, match=r'They sent (ERROR|WARNING|ABORT).*channel capacity is .*, which is below .*sat'):
|
|
l1.fundchannel(l4, l4_min_capacity + overhead - 1)
|
|
assert only_one(l1.rpc.listpeers(l4.info['id'])['peers'])['connected']
|
|
l1.fundchannel(l4, l4_min_capacity + overhead)
|
|
|
|
# Note that this check applies locally too, so you can't open it if
|
|
# you would reject it.
|
|
l3.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
with pytest.raises(RpcError, match=r"channel capacity is .*, which is below .*sat"):
|
|
l3.fundchannel(l2, l3_min_capacity + overhead - 1)
|
|
|
|
assert only_one(l3.rpc.listpeers(l2.info['id'])['peers'])['connected']
|
|
l3.fundchannel(l2, l3_min_capacity + overhead)
|
|
|
|
|
|
def test_second_channel(node_factory):
|
|
l1, l2, l3 = node_factory.get_nodes(3)
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
l1.fundchannel(l2, 10**6)
|
|
l1.fundchannel(l3, 10**6)
|
|
|
|
|
|
def test_channel_abandon(node_factory, bitcoind):
|
|
"""Our open tx isn't mined, we doublespend it away"""
|
|
l1, l2 = node_factory.get_nodes(2)
|
|
|
|
SATS = 10**6
|
|
|
|
# Add some for fees/emergency-reserve
|
|
l1.fundwallet(SATS + 35000)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], SATS, feerate='1875perkw')
|
|
|
|
opening_utxo = only_one([o for o in l1.rpc.listfunds()['outputs'] if o['reserved']])
|
|
psbt = l1.rpc.utxopsbt(0, "253perkw", 0, [opening_utxo['txid'] + ':' + str(opening_utxo['output'])], reserve=0, reservedok=True)['psbt']
|
|
|
|
# We expect a reservation for 2016 blocks; unreserve it.
|
|
reservations = only_one(l1.rpc.unreserveinputs(psbt, reserve=2015)['reservations'])
|
|
assert reservations['reserved']
|
|
assert reservations['reserved_to_block'] == bitcoind.rpc.getblockchaininfo()['blocks'] + 1
|
|
|
|
assert only_one(l1.rpc.unreserveinputs(psbt, reserve=1)['reservations'])['reserved'] is False
|
|
|
|
# Now it's unreserved, we can doublespend it (as long as we exceed
|
|
# previous fee to RBF!).
|
|
withdraw = l1.rpc.withdraw(l1.rpc.newaddr()['bech32'], "all")
|
|
|
|
assert bitcoind.rpc.decoderawtransaction(withdraw['tx'])['vout'][0]['value'] > SATS / 10**8
|
|
bitcoind.generate_block(1, wait_for_mempool=withdraw['txid'])
|
|
|
|
# FIXME: lightningd should notice channel will never now open!
|
|
assert (only_one(l1.rpc.listpeerchannels()['channels'])['state']
|
|
== 'CHANNELD_AWAITING_LOCKIN')
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_disconnect(node_factory):
|
|
# These should all make us fail
|
|
disconnects = ['-WIRE_INIT',
|
|
'+WIRE_INIT']
|
|
l1 = node_factory.get_node(disconnect=disconnects)
|
|
l2 = node_factory.get_node()
|
|
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# Should have 3 connect fails.
|
|
for d in disconnects:
|
|
l1.daemon.wait_for_log('{}-.*Failed connected out'
|
|
.format(l2.info['id']))
|
|
|
|
# Should still only have one peer!
|
|
assert len(l1.rpc.listpeers()) == 1
|
|
assert len(l2.rpc.listpeers()) == 1
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_disconnect_opener(node_factory):
|
|
# Now error on opener side during channel open.
|
|
disconnects = ['-WIRE_OPEN_CHANNEL',
|
|
'+WIRE_OPEN_CHANNEL',
|
|
'-WIRE_FUNDING_CREATED']
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
disconnects = ['-WIRE_OPEN_CHANNEL2',
|
|
'+WIRE_OPEN_CHANNEL2',
|
|
'-WIRE_TX_ADD_INPUT',
|
|
'+WIRE_TX_ADD_INPUT',
|
|
'-WIRE_TX_ADD_OUTPUT',
|
|
'+WIRE_TX_ADD_OUTPUT',
|
|
'-WIRE_TX_COMPLETE',
|
|
'=WIRE_TX_COMPLETE']
|
|
|
|
l1 = node_factory.get_node(disconnect=disconnects,
|
|
may_reconnect=EXPERIMENTAL_DUAL_FUND,
|
|
options={'dev-no-reconnect': None})
|
|
l2 = node_factory.get_node(may_reconnect=EXPERIMENTAL_DUAL_FUND,
|
|
options={'dev-no-reconnect': None})
|
|
|
|
l1.fundwallet(2000000)
|
|
|
|
for d in disconnects:
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
# First peer valishes, but later it just disconnects
|
|
wait_for(lambda: all([p['connected'] is False for p in l1.rpc.listpeers()['peers']]))
|
|
|
|
# This one will succeed.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
|
|
# Should still only have one peer!
|
|
assert len(l1.rpc.listpeers()['peers']) == 1
|
|
assert len(l2.rpc.listpeers()['peers']) == 1
|
|
|
|
|
|
def test_remote_disconnect(node_factory):
|
|
l1, l2 = node_factory.get_nodes(2)
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
wait_for(lambda: l2.rpc.listpeers()['peers'] != [])
|
|
l2.rpc.disconnect(l1.info['id'])
|
|
|
|
# l1 should notice!
|
|
wait_for(lambda: l1.rpc.listpeers()['peers'] == [])
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_disconnect_fundee(node_factory):
|
|
# Now error on fundee side during channel open.
|
|
disconnects = ['-WIRE_ACCEPT_CHANNEL',
|
|
'+WIRE_ACCEPT_CHANNEL']
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
disconnects = ['-WIRE_ACCEPT_CHANNEL2',
|
|
'+WIRE_ACCEPT_CHANNEL2',
|
|
'-WIRE_TX_COMPLETE',
|
|
'+WIRE_TX_COMPLETE']
|
|
|
|
l1 = node_factory.get_node()
|
|
l2 = node_factory.get_node(disconnect=disconnects)
|
|
|
|
l1.fundwallet(2000000)
|
|
|
|
for d in disconnects:
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
# First peer valishes, but later it just disconnects
|
|
wait_for(lambda: all([p['connected'] is False for p in l1.rpc.listpeers()['peers']]))
|
|
|
|
# This one will succeed.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
|
|
# Should still only have one peer!
|
|
assert len(l1.rpc.listpeers()) == 1
|
|
assert len(l2.rpc.listpeers()) == 1
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_disconnect_fundee_v2(node_factory):
|
|
# Now error on fundee side during channel open, with them funding
|
|
disconnects = ['-WIRE_ACCEPT_CHANNEL2',
|
|
'+WIRE_ACCEPT_CHANNEL2',
|
|
'-WIRE_TX_ADD_INPUT',
|
|
'+WIRE_TX_ADD_INPUT',
|
|
'-WIRE_TX_ADD_OUTPUT',
|
|
'+WIRE_TX_ADD_OUTPUT',
|
|
'-WIRE_TX_COMPLETE']
|
|
|
|
l1 = node_factory.get_node()
|
|
l2 = node_factory.get_node(disconnect=disconnects,
|
|
options={'funder-policy': 'match',
|
|
'funder-policy-mod': 100,
|
|
'funder-fuzz-percent': 0,
|
|
'funder-lease-requests-only': False})
|
|
|
|
l1.fundwallet(2000000)
|
|
l2.fundwallet(2000000)
|
|
|
|
for d in disconnects:
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
assert l1.rpc.getpeer(l2.info['id']) is None
|
|
|
|
# This one will succeed.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
|
|
# Should still only have one peer!
|
|
assert len(l1.rpc.listpeers()['peers']) == 1
|
|
assert len(l2.rpc.listpeers()['peers']) == 1
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
def test_disconnect_half_signed(node_factory):
|
|
# Now, these are the corner cases. Fundee sends funding_signed,
|
|
# but opener doesn't receive it.
|
|
disconnects = ['-WIRE_FUNDING_SIGNED']
|
|
l1 = node_factory.get_node()
|
|
l2 = node_factory.get_node(disconnect=disconnects)
|
|
|
|
l1.fundwallet(2000000)
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
|
|
# Peer remembers, opener doesn't.
|
|
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'] == [])
|
|
assert len(l2.rpc.listpeerchannels(l1.info['id'])['channels']) == 1
|
|
|
|
|
|
@pytest.mark.openchannel('v2')
|
|
def test_disconnect_half_signed_v2(node_factory):
|
|
# Now, these are the corner cases.
|
|
# L1 remembers the channel, L2 doesn't
|
|
disconnects = ['-WIRE_TX_COMPLETE']
|
|
l1 = node_factory.get_node(disconnect=disconnects)
|
|
l2 = node_factory.get_node()
|
|
|
|
l1.fundwallet(2000000)
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
|
|
# Opener remembers, peer doesn't.
|
|
wait_for(lambda: l2.rpc.listpeers(l1.info['id'])['peers'] == [])
|
|
wait_for(lambda: only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected'] is False)
|
|
assert len(l1.rpc.listpeerchannels(l2.info['id'])['channels']) == 1
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_reconnect_signed(node_factory):
|
|
# This will fail *after* both sides consider channel opening.
|
|
disconnects = ['<WIRE_FUNDING_SIGNED']
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
disconnects = ['<WIRE_COMMITMENT_SIGNED']
|
|
|
|
l1 = node_factory.get_node(may_reconnect=True, disconnect=disconnects)
|
|
l2 = node_factory.get_node(may_reconnect=True)
|
|
|
|
l1.fundwallet(2000000)
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
|
|
# They haven't forgotten each other.
|
|
assert l1.rpc.getpeer(l2.info['id'])['id'] == l2.info['id']
|
|
assert l2.rpc.getpeer(l1.info['id'])['id'] == l1.info['id']
|
|
|
|
# Technically, this is async to fundchannel (and could reconnect first)
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
l1.daemon.wait_for_logs(['sendrawtx exit 0',
|
|
'Peer has reconnected, state DUALOPEND_OPEN_COMMITTED'])
|
|
else:
|
|
l1.daemon.wait_for_logs(['sendrawtx exit 0',
|
|
'Peer has reconnected, state CHANNELD_AWAITING_LOCKIN'])
|
|
|
|
l1.bitcoin.generate_block(6)
|
|
|
|
l1.daemon.wait_for_log(' to CHANNELD_NORMAL')
|
|
l2.daemon.wait_for_log(' to CHANNELD_NORMAL')
|
|
|
|
|
|
@pytest.mark.skip('needs blackhold support')
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_reconnect_openingd(node_factory):
|
|
# Openingd thinks we're still opening; opener reconnects..
|
|
disconnects = ['0WIRE_ACCEPT_CHANNEL']
|
|
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
disconnects = ['0WIRE_ACCEPT_CHANNEL2']
|
|
|
|
l1 = node_factory.get_node(may_reconnect=True)
|
|
l2 = node_factory.get_node(disconnect=disconnects,
|
|
may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.fundwallet(2000000)
|
|
|
|
# l2 closes on l1, l1 forgets.
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
assert l1.rpc.getpeer(l2.info['id']) is None
|
|
|
|
# Reconnect.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# We should get a message about reconnecting.
|
|
l2.daemon.wait_for_log('Killing opening daemon: Reconnected')
|
|
l2.daemon.wait_for_log('Handed peer, entering loop')
|
|
|
|
# Should work fine.
|
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
|
l1.daemon.wait_for_log('sendrawtx exit 0')
|
|
|
|
l1.bitcoin.generate_block(3)
|
|
|
|
# Just to be sure, second openingd hand over to channeld. This log line is about channeld being started
|
|
l2.daemon.wait_for_log(r'channeld-chan#[0-9]: pid [0-9]+, msgfd [0-9]+')
|
|
|
|
|
|
@pytest.mark.skip('needs blackhold support')
|
|
def test_reconnect_gossiping(node_factory):
|
|
# connectd thinks we're still gossiping; peer reconnects.
|
|
disconnects = ['0INVALID 33333']
|
|
l1 = node_factory.get_node(may_reconnect=True)
|
|
l2 = node_factory.get_node(disconnect=disconnects,
|
|
may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
# Make sure l2 knows about l1
|
|
wait_for(lambda: l2.rpc.listpeers(l1.info['id'])['peers'] != [])
|
|
|
|
l2.rpc.sendcustommsg(l1.info['id'], bytes([0x82, 0x35]).hex())
|
|
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'] == [])
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l2.daemon.wait_for_log('processing now old peer gone')
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_reconnect_no_update(node_factory, executor, bitcoind):
|
|
"""Test that channel_ready is retransmitted on reconnect if new channel
|
|
|
|
This tests if the `channel_ready` is sent if we receive a
|
|
`channel_reestablish` message with `next_commitment_number` == 1
|
|
and our `next_commitment_number` == 1.
|
|
|
|
This test makes extensive use of disconnects followed by automatic
|
|
reconnects. See comments for details.
|
|
|
|
"""
|
|
disconnects = ["-WIRE_CHANNEL_READY", "-WIRE_SHUTDOWN"]
|
|
# Allow bad gossip because it might receive WIRE_CHANNEL_UPDATE before
|
|
# announcement of the disconnection
|
|
l1 = node_factory.get_node(may_reconnect=True, allow_bad_gossip=True)
|
|
l2 = node_factory.get_node(disconnect=disconnects, may_reconnect=True)
|
|
|
|
# For channeld reconnection
|
|
l1.rpc.connect(l2.info["id"], "localhost", l2.port)
|
|
|
|
# LightningNode.fundchannel will fund the channel and generate a
|
|
# block. The block triggers the channel_ready message, which
|
|
# causes a disconnect. The retransmission is then caused by the
|
|
# automatic retry.
|
|
fundchannel_exec = executor.submit(l1.fundchannel, l2, 10**6, False)
|
|
if l1.config('experimental-dual-fund'):
|
|
l1.daemon.wait_for_log(r"dualopend.* Retransmitting channel_ready for channel")
|
|
else:
|
|
l1.daemon.wait_for_log(r"channeld.* Retransmitting channel_ready for channel")
|
|
sync_blockheight(bitcoind, [l1, l2])
|
|
fundchannel_exec.result()
|
|
l1.stop()
|
|
|
|
# For closingd reconnection
|
|
l1.daemon.start()
|
|
# Close will trigger the -WIRE_SHUTDOWN and we then wait for the
|
|
# automatic reconnection to trigger the retransmission.
|
|
l1.rpc.close(l2.info['id'], 0)
|
|
l2.daemon.wait_for_log(r"channeld.* Retransmitting channel_ready for channel")
|
|
l1.daemon.wait_for_log(r"CLOSINGD_COMPLETE")
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_reconnect_normal(node_factory):
|
|
# Should reconnect fine even if locked message gets lost.
|
|
disconnects = ['-WIRE_CHANNEL_READY',
|
|
'+WIRE_CHANNEL_READY']
|
|
l1 = node_factory.get_node(disconnect=disconnects,
|
|
may_reconnect=True)
|
|
l2 = node_factory.get_node(may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.fundchannel(l2, 10**6)
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_reconnect_sender_add1(node_factory):
|
|
# Fail after add is OK, will cause payment failure though.
|
|
# Make sure it doesn't send commit before it sees disconnect though.
|
|
disconnects = ['-WIRE_UPDATE_ADD_HTLC',
|
|
'+WIRE_UPDATE_ADD_HTLC']
|
|
|
|
# Feerates identical so we don't get gratuitous commit to update them
|
|
l1 = node_factory.get_node(disconnect=disconnects,
|
|
may_reconnect=True,
|
|
options={'commit-time': 2000},
|
|
feerates=(7500, 7500, 7500, 7500))
|
|
l2 = node_factory.get_node(may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.fundchannel(l2, 10**6)
|
|
|
|
amt = 200000000
|
|
inv = l2.rpc.invoice(amt, 'test_reconnect_sender_add1', 'desc')
|
|
rhash = inv['payment_hash']
|
|
assert only_one(l2.rpc.listinvoices('test_reconnect_sender_add1')['invoices'])['status'] == 'unpaid'
|
|
|
|
route = [{'amount_msat': amt, 'id': l2.info['id'], 'delay': 5, 'channel': first_scid(l1, l2)}]
|
|
|
|
for i in range(0, len(disconnects)):
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret'])
|
|
l1.rpc.waitsendpay(rhash)
|
|
|
|
# Wait for reconnection.
|
|
l1.daemon.wait_for_log('Already have funding locked in')
|
|
|
|
# This will send commit, so will reconnect as required.
|
|
l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret'])
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_reconnect_sender_add(node_factory):
|
|
disconnects = ['-WIRE_COMMITMENT_SIGNED',
|
|
'+WIRE_COMMITMENT_SIGNED',
|
|
'-WIRE_REVOKE_AND_ACK',
|
|
'+WIRE_REVOKE_AND_ACK']
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
disconnects = ['=WIRE_COMMITMENT_SIGNED'] + disconnects
|
|
|
|
# Feerates identical so we don't get gratuitous commit to update them
|
|
l1 = node_factory.get_node(disconnect=disconnects,
|
|
may_reconnect=True,
|
|
feerates=(7500, 7500, 7500, 7500))
|
|
l2 = node_factory.get_node(may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.fundchannel(l2, 10**6)
|
|
|
|
amt = 200000000
|
|
inv = l2.rpc.invoice(amt, 'testpayment', 'desc')
|
|
rhash = inv['payment_hash']
|
|
assert only_one(l2.rpc.listinvoices('testpayment')['invoices'])['status'] == 'unpaid'
|
|
|
|
route = [{'amount_msat': amt, 'id': l2.info['id'], 'delay': 5, 'channel': first_scid(l1, l2)}]
|
|
|
|
# This will send commit, so will reconnect as required.
|
|
l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret'])
|
|
# Should have printed this for every reconnect.
|
|
for i in range(0, len(disconnects)):
|
|
l1.daemon.wait_for_log('Already have funding locked in')
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_reconnect_receiver_add(node_factory):
|
|
disconnects = ['-WIRE_COMMITMENT_SIGNED',
|
|
'+WIRE_COMMITMENT_SIGNED',
|
|
'-WIRE_REVOKE_AND_ACK',
|
|
'+WIRE_REVOKE_AND_ACK']
|
|
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
disconnects = ['=WIRE_COMMITMENT_SIGNED'] + disconnects
|
|
|
|
# Feerates identical so we don't get gratuitous commit to update them
|
|
l1 = node_factory.get_node(may_reconnect=True, feerates=(7500, 7500, 7500, 7500))
|
|
l2 = node_factory.get_node(disconnect=disconnects,
|
|
may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.fundchannel(l2, 10**6)
|
|
|
|
amt = 200000000
|
|
inv = l2.rpc.invoice(amt, 'testpayment2', 'desc')
|
|
rhash = inv['payment_hash']
|
|
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid'
|
|
|
|
route = [{'amount_msat': amt, 'id': l2.info['id'], 'delay': 5, 'channel': first_scid(l1, l2)}]
|
|
l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret'])
|
|
for i in range(len(disconnects)):
|
|
l1.daemon.wait_for_log('Already have funding locked in')
|
|
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'paid'
|
|
|
|
|
|
def test_reconnect_receiver_fulfill(node_factory):
|
|
# Ordering matters: after +WIRE_UPDATE_FULFILL_HTLC, channeld
|
|
# will continue and try to send WIRE_COMMITMENT_SIGNED: if
|
|
# that's the next failure, it will do two in one run.
|
|
disconnects = ['+WIRE_UPDATE_FULFILL_HTLC',
|
|
'-WIRE_UPDATE_FULFILL_HTLC',
|
|
'-WIRE_COMMITMENT_SIGNED',
|
|
'+WIRE_COMMITMENT_SIGNED',
|
|
'-WIRE_REVOKE_AND_ACK',
|
|
'+WIRE_REVOKE_AND_ACK']
|
|
l1 = node_factory.get_node(may_reconnect=True)
|
|
l2 = node_factory.get_node(disconnect=disconnects,
|
|
may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.fundchannel(l2, 10**6)
|
|
|
|
amt = 200000000
|
|
inv = l2.rpc.invoice(amt, 'testpayment2', 'desc')
|
|
rhash = inv['payment_hash']
|
|
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid'
|
|
|
|
route = [{'amount_msat': amt, 'id': l2.info['id'], 'delay': 5, 'channel': first_scid(l1, l2)}]
|
|
l1.rpc.sendpay(route, rhash, payment_secret=inv['payment_secret'])
|
|
for i in range(len(disconnects)):
|
|
l1.daemon.wait_for_log('Already have funding locked in')
|
|
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'paid'
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_shutdown_reconnect(node_factory):
|
|
disconnects = ['-WIRE_SHUTDOWN',
|
|
'+WIRE_SHUTDOWN']
|
|
l1 = node_factory.get_node(disconnect=disconnects,
|
|
may_reconnect=True)
|
|
l2 = node_factory.get_node(may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
chan, _ = l1.fundchannel(l2, 10**6)
|
|
l1.pay(l2, 200000000)
|
|
|
|
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 0
|
|
|
|
# This should wait until we're closed.
|
|
l1.rpc.close(chan)
|
|
|
|
l1.daemon.wait_for_log(' to CHANNELD_SHUTTING_DOWN')
|
|
l2.daemon.wait_for_log(' to CHANNELD_SHUTTING_DOWN')
|
|
|
|
l1.daemon.wait_for_log(' to CLOSINGD_SIGEXCHANGE')
|
|
l2.daemon.wait_for_log(' to CLOSINGD_SIGEXCHANGE')
|
|
|
|
# And should put closing into mempool (happens async, so
|
|
# CLOSINGD_COMPLETE may come first).
|
|
l1.daemon.wait_for_logs(['sendrawtx exit 0', ' to CLOSINGD_COMPLETE'])
|
|
l2.daemon.wait_for_logs(['sendrawtx exit 0', ' to CLOSINGD_COMPLETE'])
|
|
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 1
|
|
|
|
|
|
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "sqlite3-specific DB manip")
|
|
def test_reconnect_remote_sends_no_sigs(node_factory):
|
|
"""We re-announce, even when remote node doesn't send its announcement_signatures on reconnect.
|
|
"""
|
|
l1, l2 = node_factory.line_graph(2, wait_for_announce=True, opts={'may_reconnect': True,
|
|
'dev-no-reconnect': None})
|
|
|
|
# Wipe l2's gossip_store
|
|
l2.stop()
|
|
gs_path = os.path.join(l2.daemon.lightning_dir, TEST_NETWORK, 'gossip_store')
|
|
os.unlink(gs_path)
|
|
l2.start()
|
|
|
|
# l2 will now uses (REMOTE's) announcement_signatures it has stored
|
|
wait_for(lambda: l2.rpc.listchannels()['channels'] != [])
|
|
|
|
# Remove remote signatures from l1 so it asks for them (and delete gossip store)
|
|
l1.db_manip("UPDATE channels SET remote_ann_node_sig=NULL, remote_ann_bitcoin_sig=NULL")
|
|
gs_path = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store')
|
|
os.unlink(gs_path)
|
|
l1.restart()
|
|
|
|
l1.connect(l2)
|
|
l1needle = l1.daemon.logsearch_start
|
|
l2needle = l2.daemon.logsearch_start
|
|
|
|
# l1 asks once, l2 replies once.
|
|
# Make sure we get all the msgs!
|
|
time.sleep(5)
|
|
|
|
l1.daemon.wait_for_logs(['peer_out WIRE_ANNOUNCEMENT_SIGNATURES',
|
|
'peer_in WIRE_ANNOUNCEMENT_SIGNATURES'])
|
|
l2.daemon.wait_for_log('peer_out WIRE_ANNOUNCEMENT_SIGNATURES')
|
|
|
|
l1msgs = [l.split()[4] for l in l1.daemon.logs[l1needle:] if 'WIRE_ANNOUNCEMENT_SIGNATURES' in l]
|
|
assert l1msgs == ['peer_out', 'peer_in']
|
|
|
|
# l2 only sends one.
|
|
assert len([l for l in l2.daemon.logs[l2needle:] if 'peer_out WIRE_ANNOUNCEMENT_SIGNATURES' in l]) == 1
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_shutdown_awaiting_lockin(node_factory, bitcoind):
|
|
l1 = node_factory.get_node()
|
|
l2 = node_factory.get_node(options={'funding-confirms': 3})
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundwallet(10**6 + 1000000)
|
|
chanid = l1.rpc.fundchannel(l2.info['id'], 10**6)['channel_id']
|
|
|
|
# Technically, this is async to fundchannel.
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
|
|
l1.rpc.close(chanid)
|
|
|
|
l1_state = 'DUALOPEND' if l1.config('experimental-dual-fund') else 'CHANNELD'
|
|
l2_state = 'DUALOPEND' if l1.config('experimental-dual-fund') else 'CHANNELD'
|
|
l1.daemon.wait_for_log('{}_AWAITING_LOCKIN to CHANNELD_SHUTTING_DOWN'.format(l1_state))
|
|
l2.daemon.wait_for_log('{}_AWAITING_LOCKIN to CHANNELD_SHUTTING_DOWN'.format(l2_state))
|
|
|
|
l1.daemon.wait_for_log('CHANNELD_SHUTTING_DOWN to CLOSINGD_SIGEXCHANGE')
|
|
l2.daemon.wait_for_log('CHANNELD_SHUTTING_DOWN to CLOSINGD_SIGEXCHANGE')
|
|
|
|
# And should put closing into mempool (happens async, so
|
|
# CLOSINGD_COMPLETE may come first).
|
|
l1.daemon.wait_for_logs(['sendrawtx exit 0', ' to CLOSINGD_COMPLETE'])
|
|
l2.daemon.wait_for_logs(['sendrawtx exit 0', ' to CLOSINGD_COMPLETE'])
|
|
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
l1.daemon.wait_for_log(' to ONCHAIN')
|
|
l2.daemon.wait_for_log(' to ONCHAIN')
|
|
|
|
bitcoind.generate_block(100)
|
|
|
|
# Won't disconnect!
|
|
wait_for(lambda: l1.rpc.listpeerchannels()['channels'] == [])
|
|
wait_for(lambda: l2.rpc.listpeerchannels()['channels'] == [])
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_funding_change(node_factory, bitcoind):
|
|
"""Add some funds, fund a channel, and make sure we remember the change
|
|
"""
|
|
l1, l2 = node_factory.line_graph(2, fundchannel=False)
|
|
l1.fundwallet(10000000)
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l1])
|
|
|
|
outputs = l1.db_query('SELECT value FROM outputs WHERE status=0;')
|
|
assert only_one(outputs)['value'] == 10000000
|
|
|
|
l1.rpc.fundchannel(l2.info['id'], 1000000)
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
sync_blockheight(bitcoind, [l1])
|
|
outputs = {r['status']: r['value'] for r in l1.db_query(
|
|
'SELECT status, SUM(value) AS value FROM outputs GROUP BY status;')}
|
|
|
|
# The 10m out is spent and we have a change output of 9m-fee
|
|
assert outputs[0] > 8990000
|
|
assert outputs[2] == 10000000
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_funding_all(node_factory, bitcoind):
|
|
"""Add some funds, fund a channel using all funds, make sure no funds remain
|
|
"""
|
|
l1, l2 = node_factory.line_graph(2, fundchannel=False)
|
|
|
|
l1.fundwallet(0.1 * 10**8)
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l1])
|
|
|
|
outputs = l1.db_query('SELECT value FROM outputs WHERE status=0;')
|
|
assert only_one(outputs)['value'] == 10000000
|
|
|
|
l1.rpc.fundchannel(l2.info['id'], "all")
|
|
|
|
# Keeps emergency reserve!
|
|
outputs = l1.db_query('SELECT value FROM outputs WHERE status=0;')
|
|
if 'anchors/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
|
|
assert outputs == [{'value': 25000}]
|
|
else:
|
|
assert outputs == []
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_funding_all_too_much(node_factory):
|
|
"""Add more than max possible funds, fund a channel using all funds we can.
|
|
"""
|
|
# l2 isn't wumbo, so channel should not be!
|
|
l1, l2 = node_factory.line_graph(2, fundchannel=False, opts=[{}, {'dev-force-features': '-19'}])
|
|
|
|
addr, txid = l1.fundwallet(2**24 + 35000)
|
|
l1.rpc.fundchannel(l2.info['id'], "all")
|
|
assert l1.daemon.is_in_log("'all' was too large for non-wumbo channel, trimming")
|
|
|
|
# One reserved, confirmed output spent above, and one change.
|
|
outputs = l1.rpc.listfunds()['outputs']
|
|
|
|
spent = only_one([o for o in outputs if o['status'] == 'confirmed'])
|
|
|
|
assert spent['txid'] == txid
|
|
assert spent['address'] == addr
|
|
assert spent['reserved'] is True
|
|
|
|
pending = only_one([o for o in outputs if o['status'] != 'confirmed'])
|
|
assert pending['status'] == 'unconfirmed'
|
|
assert pending['reserved'] is False
|
|
assert only_one(l1.rpc.listfunds()['channels'])['amount_msat'] == Millisatoshi(str(2**24 - 1) + "sat")
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_funding_fail(node_factory, bitcoind):
|
|
"""Add some funds, fund a channel without enough funds"""
|
|
max_locktime = 2016
|
|
l1 = node_factory.get_node()
|
|
l2 = node_factory.get_node(options={'watchtime-blocks': max_locktime + 1})
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
funds = 1000000
|
|
|
|
addr = l1.rpc.newaddr()['bech32']
|
|
l1.bitcoin.rpc.sendtoaddress(addr, funds / 10**8)
|
|
bitcoind.generate_block(1)
|
|
|
|
# Wait for it to arrive.
|
|
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) > 0)
|
|
|
|
# Fail because l1 dislikes l2's huge locktime.
|
|
with pytest.raises(RpcError, match=r'to_self_delay \d+ larger than \d+'):
|
|
l1.rpc.fundchannel(l2.info['id'], int(funds / 10))
|
|
|
|
# channels do not disconnect on failure
|
|
only_one(l1.rpc.listpeers()['peers'])
|
|
only_one(l2.rpc.listpeers()['peers'])
|
|
|
|
# Restart l2 without ridiculous locktime.
|
|
del l2.daemon.opts['watchtime-blocks']
|
|
l2.restart()
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# We don't have enough left to cover fees if we try to spend it all.
|
|
with pytest.raises(RpcError, match=r'not afford'):
|
|
l1.rpc.fundchannel(l2.info['id'], funds)
|
|
|
|
# Should still be connected (we didn't contact the peer)
|
|
assert only_one(l1.rpc.listpeers()['peers'])['connected']
|
|
l2.daemon.wait_for_log('Handed peer, entering loop')
|
|
assert only_one(l2.rpc.listpeers()['peers'])['connected']
|
|
|
|
# This works.
|
|
l1.rpc.fundchannel(l2.info['id'], int(funds / 10))
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_funding_toolarge(node_factory, bitcoind):
|
|
"""Try to create a giant channel"""
|
|
l1 = node_factory.get_node()
|
|
l2 = node_factory.get_node(options={'dev-force-features': '-19'})
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# Send funds.
|
|
amount = 2**24
|
|
bitcoind.rpc.sendtoaddress(l1.rpc.newaddr()['bech32'], amount / 10**8 + 0.01)
|
|
bitcoind.generate_block(1)
|
|
|
|
# Wait for it to arrive.
|
|
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) > 0)
|
|
|
|
# Fail to open (too large)
|
|
with pytest.raises(RpcError, match=r'Amount exceeded 16777215'):
|
|
l1.rpc.fundchannel(l2.info['id'], amount)
|
|
|
|
# This should work.
|
|
amount = amount - 1
|
|
l1.rpc.fundchannel(l2.info['id'], amount)
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_v2_open(node_factory, bitcoind, chainparams):
|
|
l1, l2 = node_factory.get_nodes(2)
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
amount = 2**24
|
|
bitcoind.rpc.sendtoaddress(l1.rpc.newaddr()['bech32'], amount / 10**8 + 0.01)
|
|
bitcoind.generate_block(1)
|
|
# Wait for it to arrive.
|
|
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) > 0)
|
|
|
|
l1.rpc.fundchannel(l2.info['id'], 'all')
|
|
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l1])
|
|
l1.daemon.wait_for_log(' to CHANNELD_NORMAL')
|
|
|
|
# Send a payment over the channel
|
|
p = l2.rpc.invoice(100000, 'testpayment', 'desc')
|
|
l1.rpc.pay(p['bolt11'])
|
|
result = l1.rpc.waitsendpay(p['payment_hash'])
|
|
assert(result['status'] == 'complete')
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
def test_funding_push(node_factory, bitcoind, chainparams):
|
|
""" Try to push peer some sats """
|
|
# We track balances, to verify that accounting is ok.
|
|
coin_mvt_plugin = os.path.join(os.getcwd(), 'tests/plugins/coin_movements.py')
|
|
|
|
l1 = node_factory.get_node(options={'plugin': coin_mvt_plugin})
|
|
l2 = node_factory.get_node(options={'plugin': coin_mvt_plugin})
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# Send funds.
|
|
amount = 2**24
|
|
push_msat = 20000 * 1000
|
|
bitcoind.rpc.sendtoaddress(l1.rpc.newaddr()['bech32'], amount / 10**8 + 0.01)
|
|
bitcoind.generate_block(1)
|
|
|
|
# Wait for it to arrive.
|
|
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) > 0)
|
|
|
|
# Fail to open (try to push too much)
|
|
with pytest.raises(RpcError, match=r'Requested to push_msat of 20000000msat is greater than available funding amount 10000sat'):
|
|
l1.rpc.fundchannel(l2.info['id'], 10000, push_msat=push_msat)
|
|
|
|
# This should work.
|
|
amount = amount - 1
|
|
l1.rpc.fundchannel(l2.info['id'], amount, push_msat=push_msat)
|
|
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l1])
|
|
funds = only_one(l1.rpc.listfunds()['channels'])
|
|
assert funds['our_amount_msat'] + push_msat == funds['amount_msat']
|
|
|
|
chanid = first_channel_id(l2, l1)
|
|
channel_mvts_1 = [
|
|
{'type': 'chain_mvt', 'credit_msat': 16777215000, 'debit_msat': 0, 'tags': ['channel_open', 'opener']},
|
|
{'type': 'channel_mvt', 'credit_msat': 0, 'debit_msat': 20000000, 'tags': ['pushed'], 'fees_msat': '0msat'},
|
|
]
|
|
channel_mvts_2 = [
|
|
{'type': 'chain_mvt', 'credit_msat': 0, 'debit_msat': 0, 'tags': ['channel_open']},
|
|
{'type': 'channel_mvt', 'credit_msat': 20000000, 'debit_msat': 0, 'tags': ['pushed'], 'fees_msat': '0msat'},
|
|
]
|
|
check_coin_moves(l1, chanid, channel_mvts_1, chainparams)
|
|
check_coin_moves(l2, chanid, channel_mvts_2, chainparams)
|
|
|
|
assert account_balance(l1, chanid) == amount * 1000 - push_msat
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_funding_by_utxos(node_factory, bitcoind):
|
|
"""Fund a channel with specific utxos"""
|
|
l1, l2, l3 = node_factory.line_graph(3, fundchannel=False)
|
|
|
|
# Get 3 differents utxo
|
|
l1.fundwallet(0.01 * 10**8)
|
|
l1.fundwallet(0.01 * 10**8)
|
|
l1.fundwallet(0.01 * 10**8)
|
|
wait_for(lambda: len(l1.rpc.listfunds()["outputs"]) == 3)
|
|
|
|
utxos = [utxo["txid"] + ":" + str(utxo["output"]) for utxo in l1.rpc.listfunds()["outputs"]]
|
|
|
|
# Fund with utxos we don't own
|
|
with pytest.raises(RpcError, match=r"Unknown UTXO "):
|
|
l3.rpc.fundchannel(l2.info["id"], int(0.01 * 10**8), utxos=utxos)
|
|
|
|
# Fund with an empty array
|
|
with pytest.raises(RpcError, match=r"Please specify an array of \\'txid:output_index\\', not \"*\""):
|
|
l1.rpc.fundchannel(l2.info["id"], int(0.01 * 10**8), utxos=[])
|
|
|
|
# Fund a channel from some of the utxos, without change
|
|
l1.rpc.fundchannel(l2.info["id"], "all", utxos=utxos[0:2])
|
|
|
|
# Fund a channel from the rest of utxos, with change
|
|
l1.rpc.connect(l3.info["id"], "localhost", l3.port)
|
|
l1.rpc.fundchannel(l3.info["id"], int(0.007 * 10**8), utxos=[utxos[2]])
|
|
|
|
# Fund another channel with already reserved utxos
|
|
with pytest.raises(RpcError, match=r"UTXO.*already reserved"):
|
|
l1.rpc.fundchannel(l3.info["id"], int(0.01 * 10**8), utxos=utxos)
|
|
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
sync_blockheight(bitcoind, [l1])
|
|
|
|
# Fund another channel with already spent utxos
|
|
with pytest.raises(RpcError, match=r"Already spent UTXO "):
|
|
l1.rpc.fundchannel(l3.info["id"], int(0.01 * 10**8), utxos=utxos)
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
def test_funding_external_wallet_corners(node_factory, bitcoind):
|
|
l1, l2 = node_factory.get_nodes(2, opts={'may_reconnect': True,
|
|
'dev-no-reconnect': None})
|
|
|
|
# We have Wumbo, it's ok!
|
|
amount = 2**24
|
|
l1.fundwallet(amount + 10000000)
|
|
|
|
# make sure we can generate PSBTs.
|
|
addr = l1.rpc.newaddr()['bech32']
|
|
bitcoind.rpc.sendtoaddress(addr, (amount + 1000000) / 10**8)
|
|
bitcoind.generate_block(1)
|
|
wait_for(lambda: len(l1.rpc.listfunds()["outputs"]) != 0)
|
|
|
|
# Some random (valid) psbt
|
|
psbt = l1.rpc.fundpsbt(amount, '253perkw', 250, reserve=0)['psbt']
|
|
|
|
with pytest.raises(RpcError, match=r'Unknown peer'):
|
|
l1.rpc.fundchannel_start(l2.info['id'], amount)
|
|
|
|
with pytest.raises(RpcError, match=r'Unknown peer'):
|
|
l1.rpc.fundchannel_complete(l2.info['id'], psbt)
|
|
|
|
# Should not be able to continue without being in progress.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
with pytest.raises(RpcError, match=r'No channel funding in progress.'):
|
|
l1.rpc.fundchannel_complete(l2.info['id'], psbt)
|
|
|
|
start = l1.rpc.fundchannel_start(l2.info['id'], amount)
|
|
with pytest.raises(RpcError, match=r'Already funding channel'):
|
|
l1.rpc.fundchannel(l2.info['id'], amount)
|
|
|
|
# Can't complete with incorrect amount (unchecked on Elements)
|
|
if TEST_NETWORK == 'regtest':
|
|
wrongamt = l1.rpc.txprepare([{start['funding_address']: amount - 1}])
|
|
with pytest.raises(RpcError, match=r'Output to open channel is .*, should be .*'):
|
|
l1.rpc.fundchannel_complete(l2.info['id'], wrongamt['psbt'])
|
|
l1.rpc.txdiscard(wrongamt['txid'])
|
|
|
|
# Can't complete with incorrect address.
|
|
wrongaddr = l1.rpc.txprepare([{l1.rpc.newaddr()['bech32']: amount}])
|
|
with pytest.raises(RpcError, match=r'No output to open channel'):
|
|
l1.rpc.fundchannel_complete(l2.info['id'], wrongaddr['psbt'])
|
|
l1.rpc.txdiscard(wrongaddr['txid'])
|
|
|
|
l1.rpc.fundchannel_cancel(l2.info['id'])
|
|
|
|
# Cancelling does NOT cause disconnection.
|
|
only_one(l1.rpc.listpeers(l2.info['id'])['peers'])
|
|
amount2 = 1000000
|
|
funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount2)['funding_address']
|
|
|
|
# Create the funding transaction
|
|
prep = l1.rpc.txprepare([{funding_addr: amount2}])
|
|
decode = bitcoind.rpc.decoderawtransaction(prep['unsigned_tx'])
|
|
assert decode['txid'] == prep['txid']
|
|
|
|
# Be sure fundchannel_complete is successful
|
|
assert l1.rpc.fundchannel_complete(l2.info['id'], prep['psbt'])['commitments_secured']
|
|
|
|
# Peer shouldn't be able to cancel channel
|
|
with pytest.raises(RpcError, match=r'Cannot cancel channel that was initiated by peer'):
|
|
l2.rpc.fundchannel_cancel(l1.info['id'])
|
|
|
|
# We can cancel channel after fundchannel_complete
|
|
assert l1.rpc.fundchannel_cancel(l2.info['id'])['cancelled']
|
|
# But must unreserve inputs manually.
|
|
l1.rpc.txdiscard(prep['txid'])
|
|
|
|
# Does not disconnect!
|
|
only_one(l1.rpc.listpeers(l2.info['id'])['peers'])
|
|
funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address']
|
|
prep = l1.rpc.txprepare([{funding_addr: amount}])
|
|
|
|
assert l1.rpc.fundchannel_complete(l2.info['id'], prep['psbt'])['commitments_secured']
|
|
|
|
# Check that can still cancel when peer is disconnected
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
wait_for(lambda: not only_one(l1.rpc.listpeers()['peers'])['connected'])
|
|
|
|
wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['state']
|
|
== 'CHANNELD_AWAITING_LOCKIN')
|
|
|
|
assert l1.rpc.fundchannel_cancel(l2.info['id'])['cancelled']
|
|
assert len(l1.rpc.listpeers()['peers']) == 0
|
|
|
|
# on reconnect, channel should get destroyed
|
|
# FIXME: if peer disconnects too fast, we get
|
|
# "disconnected during connection"
|
|
try:
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
except RpcError as err:
|
|
assert "disconnected during connection" in err.error
|
|
|
|
l1.daemon.wait_for_log('Responded to reestablish for long-closed channel')
|
|
wait_for(lambda: len(l1.rpc.listpeers()['peers']) == 0)
|
|
wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 0)
|
|
|
|
# But must unreserve inputs manually.
|
|
l1.rpc.txdiscard(prep['txid'])
|
|
|
|
# we have to connect again, because we got disconnected when everything errored
|
|
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'] == [])
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
funding_addr = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address']
|
|
prep = l1.rpc.txprepare([{funding_addr: amount}])
|
|
# A successful funding_complete will always have a commitments_secured that is true,
|
|
# otherwise it would have failed
|
|
assert l1.rpc.fundchannel_complete(l2.info['id'], prep['psbt'])['commitments_secured']
|
|
l1.rpc.txsend(prep['txid'])
|
|
with pytest.raises(RpcError, match=r'.* been broadcast.*'):
|
|
l1.rpc.fundchannel_cancel(l2.info['id'])
|
|
l1.rpc.close(l2.info['id'])
|
|
|
|
|
|
@pytest.mark.openchannel('v2')
|
|
def test_funding_v2_corners(node_factory, bitcoind):
|
|
l1 = node_factory.get_node(may_reconnect=True)
|
|
l2 = node_factory.get_node(may_reconnect=True)
|
|
|
|
# We have wumbo, it's OK
|
|
amount = 2**24
|
|
l1.fundwallet(amount + 10000000)
|
|
|
|
# make sure we can generate PSBTs.
|
|
addr = l1.rpc.newaddr()['bech32']
|
|
bitcoind.rpc.sendtoaddress(addr, (amount + 1000000) / 10**8)
|
|
bitcoind.generate_block(1)
|
|
wait_for(lambda: len(l1.rpc.listfunds()["outputs"]) != 0)
|
|
|
|
# Some random (valid) psbt
|
|
psbt = l1.rpc.fundpsbt(amount, '253perkw', 250, reserve=0)['psbt']
|
|
nonexist_chanid = '11' * 32
|
|
|
|
with pytest.raises(RpcError, match=r'Unknown peer'):
|
|
l1.rpc.openchannel_init(l2.info['id'], amount, psbt)
|
|
|
|
with pytest.raises(RpcError, match=r'Unknown channel'):
|
|
l1.rpc.openchannel_update(nonexist_chanid, psbt)
|
|
|
|
# Should not be able to continue without being in progress.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
with pytest.raises(RpcError, match=r'Unknown channel'):
|
|
l1.rpc.openchannel_signed(nonexist_chanid, psbt)
|
|
|
|
start = l1.rpc.openchannel_init(l2.info['id'], amount, psbt)
|
|
# We can abort a channel
|
|
l1.rpc.openchannel_abort(start['channel_id'])
|
|
|
|
# Should be able to 'restart' after canceling
|
|
amount2 = 1000000
|
|
l1.rpc.unreserveinputs(psbt)
|
|
psbt = l1.rpc.fundpsbt(amount2, '253perkw', 250, reserve=0)['psbt']
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
start = l1.rpc.openchannel_init(l2.info['id'], amount2, psbt)
|
|
|
|
# Check that we're connected.
|
|
# This caused a valgrind crash prior to this commit
|
|
assert only_one(l2.rpc.listpeers()['peers'])
|
|
|
|
# Disconnect peer.
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
# FIXME: dualopend doesn't notice that connectd has closed peer conn
|
|
# (until we reconnect!)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.rpc.disconnect(l2.info['id'])
|
|
wait_for(lambda: len(l1.rpc.listpeers()['peers']) == 0)
|
|
|
|
with pytest.raises(RpcError, match=r'Unknown channel'):
|
|
l1.rpc.openchannel_abort(start['channel_id'])
|
|
|
|
wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 0)
|
|
with pytest.raises(RpcError, match=r'Unknown channel'):
|
|
l2.rpc.openchannel_abort(start['channel_id'])
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
start = l1.rpc.openchannel_init(l2.info['id'], amount2, psbt)
|
|
|
|
# Be sure fundchannel_complete is successful
|
|
assert l1.rpc.openchannel_update(start['channel_id'], start['psbt'])['commitments_secured']
|
|
|
|
|
|
@unittest.skipIf(SLOW_MACHINE and not VALGRIND, "Way too taxing on CI machines")
|
|
@pytest.mark.openchannel('v1')
|
|
def test_funding_cancel_race(node_factory, bitcoind, executor):
|
|
l1 = node_factory.get_node()
|
|
|
|
# make sure we can generate PSBTs.
|
|
addr = l1.rpc.newaddr()['bech32']
|
|
bitcoind.rpc.sendtoaddress(addr, 200000 / 10**8)
|
|
bitcoind.generate_block(1)
|
|
wait_for(lambda: len(l1.rpc.listfunds()["outputs"]) != 0)
|
|
|
|
if node_factory.valgrind:
|
|
num = 5
|
|
else:
|
|
num = 100
|
|
|
|
# Allow the other nodes to log unexpected WIRE_FUNDING_CREATED messages
|
|
nodes = node_factory.get_nodes(num, opts={})
|
|
|
|
num_complete = 0
|
|
num_cancel = 0
|
|
|
|
for count, n in enumerate(nodes):
|
|
l1.rpc.connect(n.info['id'], 'localhost', n.port)
|
|
start = l1.rpc.fundchannel_start(n.info['id'], "100000sat")
|
|
|
|
prep = l1.rpc.txprepare([{start['funding_address']: "100000sat"}])
|
|
|
|
# Submit two of each at once.
|
|
completes = []
|
|
cancels = []
|
|
|
|
# Switch order around.
|
|
for i in range(4):
|
|
if (i + count) % 2 == 0:
|
|
completes.append(executor.submit(l1.rpc.fundchannel_complete, n.info['id'], prep['psbt']))
|
|
else:
|
|
cancels.append(executor.submit(l1.rpc.fundchannel_cancel, n.info['id']))
|
|
|
|
# Only up to one should succeed.
|
|
success = False
|
|
for c in completes:
|
|
try:
|
|
c.result(TIMEOUT)
|
|
num_complete += 1
|
|
assert not success
|
|
success = True
|
|
except RpcError:
|
|
pass
|
|
|
|
# At least one of these must succeed, regardless of whether
|
|
# the completes succeeded or not.
|
|
cancelled = False
|
|
for c in cancels:
|
|
try:
|
|
c.result(TIMEOUT)
|
|
cancelled = True
|
|
except RpcError:
|
|
pass
|
|
# cancel always succeeds, as per Sequential Consistency.
|
|
# Either the cancel occurred before complete, in which
|
|
# case it prevents complete from succeeding, or it
|
|
# occurred after complete, in which case it errors the
|
|
# channel to force the remote to forget it.
|
|
assert cancelled
|
|
num_cancel += 1
|
|
# Free up funds for next time
|
|
l1.rpc.txdiscard(prep['txid'])
|
|
|
|
print("Cancelled {} complete {}".format(num_cancel, num_complete))
|
|
assert num_cancel == len(nodes)
|
|
|
|
# We should have raced at least once!
|
|
if not node_factory.valgrind:
|
|
assert num_cancel > 0
|
|
assert num_complete > 0
|
|
|
|
# Speed up shutdown by stopping them all concurrently
|
|
executor.map(lambda n: n.stop(), node_factory.nodes)
|
|
|
|
|
|
@unittest.skipIf(SLOW_MACHINE and not VALGRIND, "Way too taxing on CI machines")
|
|
@pytest.mark.openchannel('v2')
|
|
def test_funding_v2_cancel_race(node_factory, bitcoind, executor):
|
|
l1 = node_factory.get_node()
|
|
|
|
# make sure we can generate PSBTs.
|
|
addr = l1.rpc.newaddr()['bech32']
|
|
bitcoind.rpc.sendtoaddress(addr, 2000000 / 10**8)
|
|
bitcoind.generate_block(1)
|
|
wait_for(lambda: len(l1.rpc.listfunds()["outputs"]) != 0)
|
|
|
|
if node_factory.valgrind:
|
|
num = 5
|
|
else:
|
|
num = 100
|
|
|
|
nodes = node_factory.get_nodes(num)
|
|
|
|
num_complete = 0
|
|
num_cancel = 0
|
|
amount = 100000
|
|
|
|
for count, n in enumerate(nodes):
|
|
l1.rpc.connect(n.info['id'], 'localhost', n.port)
|
|
psbt = l1.rpc.fundpsbt(amount, '7500perkw', 250, reserve=0,
|
|
excess_as_change=True,
|
|
min_witness_weight=110)['psbt']
|
|
start = l1.rpc.openchannel_init(n.info['id'], amount, psbt)
|
|
|
|
# Submit two of each at once.
|
|
completes = []
|
|
cancels = []
|
|
|
|
# Switch order around.
|
|
for i in range(4):
|
|
if (i + count) % 2 == 0:
|
|
completes.append(executor.submit(l1.rpc.openchannel_update,
|
|
start['channel_id'],
|
|
start['psbt']))
|
|
else:
|
|
cancels.append(executor.submit(l1.rpc.openchannel_abort,
|
|
start['channel_id']))
|
|
|
|
# Only up to one should succeed.
|
|
success = False
|
|
for c in completes:
|
|
try:
|
|
c.result(TIMEOUT)
|
|
num_complete += 1
|
|
assert not success
|
|
success = True
|
|
except RpcError:
|
|
pass
|
|
|
|
for c in cancels:
|
|
try:
|
|
c.result(TIMEOUT)
|
|
num_cancel += 1
|
|
except RpcError:
|
|
pass
|
|
# Free up funds for next time
|
|
l1.rpc.unreserveinputs(psbt)
|
|
|
|
print("Cancelled {} complete {}".format(num_cancel, num_complete))
|
|
|
|
# We should have raced at least once!
|
|
if not node_factory.valgrind:
|
|
assert num_cancel > 0
|
|
assert num_complete > 0
|
|
|
|
# Speed up shutdown by stopping them all concurrently
|
|
executor.map(lambda n: n.stop(), node_factory.nodes)
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', "External wallet support doesn't work with elements yet.")
|
|
def test_funding_close_upfront(node_factory, bitcoind):
|
|
opts = {'plugin': os.path.join(os.getcwd(), 'tests/plugins/openchannel_hook_accepter.py')}
|
|
|
|
l1 = node_factory.get_node()
|
|
l2 = node_factory.get_node(options=opts)
|
|
|
|
# The 'accepter_close_to' plugin uses the channel funding amount
|
|
# to determine whether or not to include a 'close_to' address
|
|
amt_normal = 100000 # continues without returning a close_to
|
|
amt_addr = 100003 # returns valid regtest address
|
|
|
|
remote_valid_addr = 'bcrt1q7gtnxmlaly9vklvmfj06amfdef3rtnrdazdsvw'
|
|
|
|
def has_normal_channels(l1, l2):
|
|
if l1.rpc.listpeers(l2.info['id'])['peers'] == []:
|
|
return False
|
|
return any([c['state'] == 'CHANNELD_AWAITING_LOCKIN'
|
|
or c['state'] == 'CHANNELD_NORMAL'
|
|
for c in l1.rpc.listpeerchannels(l2.info['id'])['channels']])
|
|
|
|
def _fundchannel(l1, l2, amount, close_to):
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
assert(l1.rpc.listpeers()['peers'][0]['id'] == l2.info['id'])
|
|
|
|
# Make sure both consider any previous channels closed.
|
|
wait_for(lambda: not has_normal_channels(l1, l2))
|
|
wait_for(lambda: not has_normal_channels(l2, l1))
|
|
|
|
_, resp = l1.fundchannel(l2, amount, close_to=close_to)
|
|
if close_to:
|
|
assert resp['close_to']
|
|
else:
|
|
assert 'close_to' not in resp
|
|
|
|
for node in [l1, l2]:
|
|
channel = node.rpc.listpeerchannels()['channels'][-1]
|
|
assert amount * 1000 == channel['total_msat']
|
|
|
|
def _close(src, dst, addr=None):
|
|
"""Close the channel from src to dst, with the specified address.
|
|
|
|
Returns the address of the outputs in the close tx. Raises an
|
|
error if some expectations are not met.
|
|
|
|
"""
|
|
r = l1.rpc.close(l2.info['id'], destination=addr)
|
|
assert r['type'] == 'mutual'
|
|
tx = bitcoind.rpc.decoderawtransaction(only_one(r['txs']))
|
|
|
|
addrs = [scriptpubkey_addr(vout['scriptPubKey']) for vout in tx['vout']]
|
|
bitcoind.generate_block(1, wait_for_mempool=[only_one(r['txids'])])
|
|
sync_blockheight(bitcoind, [l1, l2])
|
|
return addrs
|
|
|
|
# check that normal peer close works
|
|
_fundchannel(l1, l2, amt_normal, None)
|
|
_close(l1, l2)
|
|
|
|
# check that you can provide a closing address upfront
|
|
addr = l1.rpc.newaddr()['bech32']
|
|
_fundchannel(l1, l2, amt_normal, addr)
|
|
# confirm that it appears in listpeerchannels
|
|
assert addr == l1.rpc.listpeerchannels()['channels'][1]['close_to_addr']
|
|
assert _close(l1, l2) == [addr]
|
|
|
|
# check that passing in the same addr to close works
|
|
addr = bitcoind.rpc.getnewaddress()
|
|
_fundchannel(l1, l2, amt_normal, addr)
|
|
assert addr == l1.rpc.listpeerchannels()['channels'][2]['close_to_addr']
|
|
assert _close(l1, l2, addr) == [addr]
|
|
|
|
# check that remote peer closing works as expected (and that remote's close_to works)
|
|
_fundchannel(l1, l2, amt_addr, addr)
|
|
# send some money to remote so that they have a closeout
|
|
l1.rpc.pay(l2.rpc.invoice((amt_addr // 2) * 1000, 'test_remote_close_to', 'desc')['bolt11'])
|
|
assert l2.rpc.listpeerchannels()['channels'][-1]['close_to_addr'] == remote_valid_addr
|
|
# The tx outputs must be one of the two permutations
|
|
assert _close(l2, l1) in ([addr, remote_valid_addr], [remote_valid_addr, addr])
|
|
|
|
# check that passing in a different addr to close causes an RPC error
|
|
addr2 = l1.rpc.newaddr()['bech32']
|
|
_fundchannel(l1, l2, amt_normal, addr)
|
|
with pytest.raises(RpcError, match=r'does not match previous shutdown script'):
|
|
l1.rpc.close(l2.info['id'], destination=addr2)
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', "External wallet support doesn't work with elements yet.")
|
|
@pytest.mark.openchannel('v1')
|
|
def test_funding_external_wallet(node_factory, bitcoind):
|
|
l1, l2, l3 = node_factory.get_nodes(3, opts=[{'funding-confirms': 2},
|
|
{'funding-confirms': 2}, {}])
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
assert(l1.rpc.listpeers()['peers'][0]['id'] == l2.info['id'])
|
|
|
|
amount = 2**24 - 1
|
|
address = l1.rpc.fundchannel_start(l2.info['id'], amount)['funding_address']
|
|
assert len(address) > 0
|
|
|
|
peer = l1.rpc.listpeers()['peers'][0]
|
|
# Peer should still be connected and in state waiting for funding_txid
|
|
assert peer['id'] == l2.info['id']
|
|
r = re.compile('Funding channel start: awaiting funding_txid with output to .*')
|
|
|
|
channels = l1.rpc.listpeerchannels(peer['id'])['channels']
|
|
assert len(channels) == 1, f"Channels for peer {peer['id']} need to be not empty"
|
|
assert any(r.match(line) for line in channels[0]['status'])
|
|
assert 'OPENINGD' in channels[0]['state']
|
|
|
|
# Trying to start a second funding should not work, it's in progress.
|
|
with pytest.raises(RpcError, match=r'Already funding channel'):
|
|
l1.rpc.fundchannel_start(l2.info['id'], amount)
|
|
|
|
# 'Externally' fund the address from fundchannel_start
|
|
psbt = bitcoind.rpc.walletcreatefundedpsbt([], [{address: amount / 10**8}])['psbt']
|
|
assert l1.rpc.fundchannel_complete(l2.info['id'], psbt)['commitments_secured']
|
|
|
|
# Broadcast the transaction manually
|
|
process = bitcoind.rpc.walletprocesspsbt(psbt)
|
|
assert process['complete'] is True
|
|
tx = bitcoind.rpc.finalizepsbt(process['psbt'])
|
|
txid = bitcoind.rpc.sendrawtransaction(tx['hex'])
|
|
bitcoind.generate_block(1)
|
|
|
|
l1.daemon.wait_for_log(r'Funding tx {} depth 1 of 2'.format(txid))
|
|
|
|
# Check that tx is broadcast by a third party can be catched.
|
|
# Only when the transaction (broadcast by a third pary) is onchain, we can catch it.
|
|
with pytest.raises(RpcError, match=r'.* been broadcast.*'):
|
|
l1.rpc.fundchannel_cancel(l2.info['id'])
|
|
|
|
# Confirm that channel locks in
|
|
bitcoind.generate_block(1)
|
|
|
|
for node in [l1, l2]:
|
|
node.daemon.wait_for_log(r'State changed from CHANNELD_AWAITING_LOCKIN to CHANNELD_NORMAL')
|
|
channel = node.rpc.listpeerchannels()['channels'][0]
|
|
assert amount * 1000 == channel['total_msat']
|
|
|
|
# Test that we don't crash if peer disconnects after fundchannel_start
|
|
l2.connect(l3)
|
|
l2.rpc.fundchannel_start(l3.info["id"], amount)
|
|
l3.rpc.close(l2.info["id"])
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
@pytest.mark.openchannel('v1') # We manually turn on dual-funding for select nodes
|
|
def test_multifunding_v1_v2_mixed(node_factory, bitcoind):
|
|
'''
|
|
Simple test for multifundchannel, using v1 + v2
|
|
'''
|
|
options = [{'experimental-dual-fund': None},
|
|
{'funder-policy': 'match',
|
|
'funder-policy-mod': 100,
|
|
'funder-fuzz-percent': 0,
|
|
'experimental-dual-fund': None},
|
|
{'funder-policy': 'match',
|
|
'funder-policy-mod': 100,
|
|
'funder-fuzz-percent': 0,
|
|
'experimental-dual-fund': None},
|
|
{}]
|
|
|
|
l1, l2, l3, l4 = node_factory.get_nodes(4, opts=options)
|
|
|
|
l1.fundwallet(2000000)
|
|
l2.fundwallet(2000000)
|
|
l3.fundwallet(2000000)
|
|
|
|
destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l4.info['id'], l4.port),
|
|
"amount": 50000}]
|
|
|
|
# There should be change!
|
|
tx = l1.rpc.multifundchannel(destinations)['tx']
|
|
decoded = bitcoind.rpc.decoderawtransaction(tx)
|
|
assert len(decoded['vout']) == len(destinations) + 1
|
|
# Feerate should be about right, too!
|
|
fee = Decimal(2000000) / 10**8 * len(decoded['vin']) - sum(v['value'] for v in decoded['vout'])
|
|
assert 7450 < fee * 10**8 / decoded['weight'] * 1000 < 7550
|
|
|
|
mine_funding_to_announce(bitcoind, [l1, l2, l3, l4], wait_for_mempool=1)
|
|
|
|
for node in [l1, l2, l3, l4]:
|
|
node.daemon.wait_for_log(r'to CHANNELD_NORMAL')
|
|
|
|
for ldest in [l2, l3, l4]:
|
|
inv = ldest.rpc.invoice(5000, 'inv', 'inv')['bolt11']
|
|
l1.rpc.pay(inv)
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_multifunding_v2_exclusive(node_factory, bitcoind):
|
|
'''
|
|
Simple test for multifundchannel, using v2
|
|
'''
|
|
# Two of three will reply with inputs of their own
|
|
options = [{},
|
|
{'funder-policy': 'match',
|
|
'funder-policy-mod': 100,
|
|
'funder-fuzz-percent': 0,
|
|
'funder-lease-requests-only': False},
|
|
{'funder-policy': 'match',
|
|
'funder-policy-mod': 100,
|
|
'funder-fuzz-percent': 0,
|
|
'funder-lease-requests-only': False},
|
|
{}]
|
|
l1, l2, l3, l4 = node_factory.get_nodes(4, opts=options)
|
|
|
|
l1.fundwallet(2000000)
|
|
l2.fundwallet(2000000)
|
|
l3.fundwallet(2000000)
|
|
|
|
destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l4.info['id'], l4.port),
|
|
"amount": 50000}]
|
|
|
|
l1.rpc.multifundchannel(destinations)
|
|
mine_funding_to_announce(bitcoind, [l1, l2, l3], num_blocks=6, wait_for_mempool=1)
|
|
|
|
for node in [l1, l2, l3, l4]:
|
|
node.daemon.wait_for_log(r'to CHANNELD_NORMAL')
|
|
|
|
# For dual-funded channels, pay from accepter to initiator
|
|
for ldest in [l2, l3]:
|
|
inv = l1.rpc.invoice(5000, 'inv' + ldest.info['id'], 'inv')['bolt11']
|
|
ldest.rpc.pay(inv)
|
|
|
|
# Then pay other direction
|
|
for ldest in [l2, l3, l4]:
|
|
inv = ldest.rpc.invoice(10000, 'inv', 'inv')['bolt11']
|
|
l1.rpc.pay(inv)
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_multifunding_simple(node_factory, bitcoind):
|
|
'''
|
|
Simple test for multifundchannel.
|
|
'''
|
|
l1, l2, l3, l4 = node_factory.get_nodes(4)
|
|
|
|
l1.fundwallet(2000000)
|
|
|
|
destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l4.info['id'], l4.port),
|
|
"amount": 50000}]
|
|
|
|
l1.rpc.multifundchannel(destinations)
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
# Don't have others reject channel_announcement as too far in future.
|
|
sync_blockheight(bitcoind, [l1, l2, l3, l4])
|
|
bitcoind.generate_block(5)
|
|
|
|
for node in [l1, l2, l3, l4]:
|
|
node.daemon.wait_for_log(r'to CHANNELD_NORMAL')
|
|
|
|
for ldest in [l2, l3, l4]:
|
|
inv = ldest.rpc.invoice(5000, 'inv', 'inv')['bolt11']
|
|
l1.rpc.pay(inv)
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_listpeers_crash(node_factory, bitcoind, executor):
|
|
'''
|
|
Test for listpeers crash during dual-funding start
|
|
'''
|
|
l1, l2 = node_factory.get_nodes(2)
|
|
|
|
do_listpeers = True
|
|
|
|
# Do lots of listpeers while this is happening
|
|
def lots_of_listpeers(node):
|
|
while do_listpeers:
|
|
node.rpc.listpeers()
|
|
|
|
fut = executor.submit(lots_of_listpeers, l1)
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundwallet(10**6 + 1000000)
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6)['tx']
|
|
|
|
do_listpeers = False
|
|
fut.result()
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_multifunding_one(node_factory, bitcoind):
|
|
'''
|
|
Test that multifunding can still fund to one destination.
|
|
'''
|
|
l1, l2, l3 = node_factory.get_nodes(3)
|
|
|
|
l1.fundwallet(2000000)
|
|
|
|
destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 50000}]
|
|
|
|
l1.rpc.multifundchannel(destinations)
|
|
|
|
# Now check if we connect to the node first before
|
|
# multifundchannel.
|
|
l1.rpc.connect(l3.info['id'], 'localhost', port=l3.port)
|
|
# Omit the connect hint.
|
|
destinations = [{"id": '{}'.format(l3.info['id']),
|
|
"amount": 50000}]
|
|
|
|
l1.rpc.multifundchannel(destinations, minconf=0)
|
|
|
|
mine_funding_to_announce(bitcoind, [l1, l2, l3], num_blocks=6)
|
|
|
|
for node in [l1, l2, l3]:
|
|
node.daemon.wait_for_log(r'to CHANNELD_NORMAL')
|
|
|
|
for ldest in [l2, l3]:
|
|
inv = ldest.rpc.invoice(5000, 'inv', 'inv')['bolt11']
|
|
l1.rpc.pay(inv)
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
def test_multifunding_disconnect(node_factory):
|
|
'''
|
|
Test disconnection during multifundchannel
|
|
'''
|
|
# TODO: Note that -WIRE_FUNDING_SIGNED does not
|
|
# work.
|
|
# See test_disconnect_half_signed.
|
|
# If disconnected when the peer believes it sent
|
|
# WIRE_FUNDING_SIGNED but before we actually
|
|
# receive it, the peer continues to monitor our
|
|
# funding tx, but we have forgotten it and will
|
|
# never send it.
|
|
disconnects = ["-WIRE_INIT",
|
|
"-WIRE_ACCEPT_CHANNEL",
|
|
"+WIRE_ACCEPT_CHANNEL"]
|
|
l1, l2, l3 = node_factory.get_nodes(3, opts=[{'dev-no-reconnect': None},
|
|
{'dev-no-reconnect': None,
|
|
'disconnect': disconnects},
|
|
{'dev-no-reconnect': None}])
|
|
|
|
l1.fundwallet(2000000)
|
|
|
|
destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 50000}]
|
|
|
|
# Funding to l2 will fail, and we should properly
|
|
# inform l3 to back out as well.
|
|
for d in disconnects:
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.multifundchannel(destinations)
|
|
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'] == [])
|
|
|
|
# TODO: failing at the fundchannel_complete phase
|
|
# (-WIRE_FUNDING_SIGNED +-WIRE_FUNDING_SIGNED)
|
|
# leaves the peer (l2 in this case) in a state
|
|
# where it is waiting for an incoming channel,
|
|
# even though we no longer have a channel going to
|
|
# that peer.
|
|
# Reconnecting with the peer will clear up that
|
|
# confusion, but then the peer will disconnect
|
|
# after a random amount of time.
|
|
|
|
destinations = [{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 50000}]
|
|
|
|
# This should succeed.
|
|
l1.rpc.multifundchannel(destinations)
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_multifunding_wumbo(node_factory):
|
|
'''
|
|
Test wumbo channel imposition in multifundchannel. l3 not wumbo :(
|
|
'''
|
|
l1, l2, l3 = node_factory.get_nodes(3, opts=[{}, {},
|
|
{'dev-force-features': '-19'}])
|
|
|
|
l1.fundwallet(1 << 26)
|
|
|
|
# This should fail.
|
|
destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 1 << 24}]
|
|
with pytest.raises(RpcError, match='Amount exceeded'):
|
|
l1.rpc.multifundchannel(destinations)
|
|
|
|
# Open failure doesn't cause disconnect
|
|
assert only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected']
|
|
|
|
# This should succeed.
|
|
destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 1 << 24},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 50000}]
|
|
l1.rpc.multifundchannel(destinations)
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', "Fees on elements are different")
|
|
@pytest.mark.openchannel('v1') # v2 the weight calculation is off by 3
|
|
@pytest.mark.parametrize("anchors", [False, True])
|
|
def test_multifunding_feerates(node_factory, bitcoind, anchors):
|
|
'''
|
|
Test feerate parameters for multifundchannel
|
|
'''
|
|
funding_tx_feerate = '10000perkw'
|
|
commitment_tx_feerate_int = 2000
|
|
commitment_tx_feerate = str(commitment_tx_feerate_int) + 'perkw'
|
|
|
|
opts = {'log-level': 'debug'}
|
|
if anchors is False:
|
|
opts['dev-force-features'] = "-23"
|
|
l1, l2, l3 = node_factory.get_nodes(3, opts=opts)
|
|
|
|
l1.fundwallet(1 << 26)
|
|
|
|
def _connect_str(node):
|
|
return '{}@localhost:{}'.format(node.info['id'], node.port)
|
|
|
|
destinations = [{"id": _connect_str(l2), 'amount': 50000}]
|
|
|
|
res = l1.rpc.multifundchannel(destinations, feerate=funding_tx_feerate,
|
|
commitment_feerate=commitment_tx_feerate)
|
|
|
|
entry = bitcoind.rpc.getmempoolentry(res['txid'])
|
|
weight = entry['weight']
|
|
|
|
# If signature is unexpectedly short, we get a spurious failure here!
|
|
res = bitcoind.rpc.decoderawtransaction(res['tx'])
|
|
weight += 71 - len(res['vin'][0]['txinwitness'][0]) // 2
|
|
expected_fee = int(funding_tx_feerate[:-5]) * weight // 1000
|
|
assert expected_fee == entry['fees']['base'] * 10 ** 8
|
|
|
|
# anchors ignores commitment_feerate!
|
|
if anchors:
|
|
commitment_tx_feerate_int = 3750
|
|
commitment_tx_feerate = str(commitment_tx_feerate_int) + 'perkw'
|
|
|
|
assert only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['feerate']['perkw'] == commitment_tx_feerate_int
|
|
assert only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['feerate']['perkb'] == commitment_tx_feerate_int * 4
|
|
|
|
txfee = only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['last_tx_fee_msat']
|
|
|
|
# We get the expected close txid, force close the channel, then fish
|
|
# the details about the transaction out of the mempoool entry
|
|
close_txid = only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['scratch_txid']
|
|
l1.rpc.dev_fail(l2.info['id'])
|
|
l1.wait_for_channel_onchain(l2.info['id'])
|
|
entry = bitcoind.rpc.getmempoolentry(close_txid)
|
|
|
|
# Because of how the anchor outputs protocol is designed,
|
|
# we *always* pay for 2 anchor outs and their weight
|
|
if anchors:
|
|
weight = 1124
|
|
else:
|
|
# the commitment transactions' feerate is calculated off
|
|
# of this fixed weight
|
|
weight = 724
|
|
|
|
expected_fee = commitment_tx_feerate_int * weight // 1000
|
|
|
|
# At this point we only have one anchor output on the
|
|
# tx, but we subtract out the extra anchor output amount
|
|
# from the to_us output, so it ends up inflating
|
|
# our fee by that much.
|
|
if anchors:
|
|
expected_fee += 330
|
|
|
|
assert expected_fee == entry['fees']['base'] * 10 ** 8
|
|
assert Millisatoshi(str(expected_fee) + 'sat') == txfee
|
|
|
|
|
|
def test_multifunding_param_failures(node_factory):
|
|
'''
|
|
Test that multifunding handles errors in parameters.
|
|
'''
|
|
l1, l2, l3 = node_factory.get_nodes(3)
|
|
|
|
l1.fundwallet(1 << 26)
|
|
|
|
# No connection hint to unconnected node.
|
|
destinations = [{"id": '{}'.format(l2.info['id']),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 50000}]
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.multifundchannel(destinations)
|
|
|
|
# Duplicated destination.
|
|
destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 50000}]
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.multifundchannel(destinations)
|
|
|
|
# Empty destinations.
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.multifundchannel([])
|
|
|
|
# Required destination fields missing.
|
|
l1.rpc.check_request_schemas = False
|
|
destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port)}]
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.multifundchannel(destinations)
|
|
destinations = [{"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 50000}]
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.multifundchannel(destinations)
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
def test_multifunding_best_effort(node_factory, bitcoind):
|
|
'''
|
|
Check that best_effort flag works.
|
|
'''
|
|
disconnects = ["-WIRE_INIT",
|
|
"-WIRE_ACCEPT_CHANNEL",
|
|
"-WIRE_FUNDING_SIGNED"]
|
|
l1 = node_factory.get_node()
|
|
l2 = node_factory.get_node()
|
|
l3 = node_factory.get_node(disconnect=disconnects)
|
|
l4 = node_factory.get_node()
|
|
|
|
l1.fundwallet(2000000)
|
|
|
|
destinations = [{"id": '{}@localhost:{}'.format(l2.info['id'], l2.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l3.info['id'], l3.port),
|
|
"amount": 50000},
|
|
{"id": '{}@localhost:{}'.format(l4.info['id'], l4.port),
|
|
"amount": 50000}]
|
|
|
|
for i, d in enumerate(disconnects):
|
|
# Should succeed due to best-effort flag.
|
|
l1.rpc.multifundchannel(destinations, minchannels=2)
|
|
bitcoind.generate_block(6, wait_for_mempool=1)
|
|
|
|
# Only l3 should fail to have channels.
|
|
for node in [l1, l2, l4]:
|
|
node.daemon.wait_for_log(r'to CHANNELD_NORMAL')
|
|
|
|
# There should be working channels to l2 and l4.
|
|
for ldest in [l2, l4]:
|
|
inv = ldest.rpc.invoice(5000, 'i{}'.format(i), 'i{}'.format(i))['bolt11']
|
|
l1.rpc.pay(inv)
|
|
|
|
# Function to find the SCID of the channel that is
|
|
# currently open.
|
|
# Cannot use LightningNode.get_channel_scid since
|
|
# it assumes the *first* channel found is the one
|
|
# wanted, but in our case we close channels and
|
|
# open again, so multiple channels may remain
|
|
# listed.
|
|
def get_funded_channel_scid(n1, n2):
|
|
channels = n1.rpc.listpeerchannels(n2.info['id'])['channels']
|
|
assert channels
|
|
for c in channels:
|
|
state = c['state']
|
|
if state in ('CHANNELD_AWAITING_LOCKIN', 'CHANNELD_NORMAL'):
|
|
return c['short_channel_id']
|
|
assert False
|
|
|
|
# Now close channels to l2 and l4, for the next run.
|
|
l1.rpc.close(get_funded_channel_scid(l1, l2))
|
|
l1.rpc.close(get_funded_channel_scid(l1, l4))
|
|
|
|
for node in [l1, l2, l4]:
|
|
node.daemon.wait_for_log(r'to CLOSINGD_COMPLETE')
|
|
|
|
# With 2 down, it will fail to fund channel
|
|
l2.stop()
|
|
l3.stop()
|
|
with pytest.raises(RpcError, match=r'(Connection refused|Bad file descriptor)'):
|
|
l1.rpc.multifundchannel(destinations, minchannels=2)
|
|
|
|
# This works though.
|
|
l1.rpc.multifundchannel(destinations, minchannels=1)
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_lockin_between_restart(node_factory, bitcoind):
|
|
l1 = node_factory.get_node(may_reconnect=True)
|
|
l2 = node_factory.get_node(options={'funding-confirms': 3},
|
|
may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.fundwallet(10**6 + 1000000)
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6)['tx']
|
|
|
|
# l1 goes down.
|
|
l1.stop()
|
|
|
|
# Now 120 blocks go by...
|
|
bitcoind.generate_block(120)
|
|
|
|
# Restart
|
|
l1.start()
|
|
|
|
# All should be good.
|
|
l1.daemon.wait_for_log(' to CHANNELD_NORMAL')
|
|
l2.daemon.wait_for_log(' to CHANNELD_NORMAL')
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_funding_while_offline(node_factory, bitcoind):
|
|
l1 = node_factory.get_node()
|
|
addr = l1.rpc.newaddr()['bech32']
|
|
sync_blockheight(bitcoind, [l1])
|
|
|
|
# l1 goes down.
|
|
l1.stop()
|
|
|
|
# We send funds
|
|
bitcoind.rpc.sendtoaddress(addr, (10**6 + 1000000) / 10**8)
|
|
|
|
# Now 120 blocks go by...
|
|
bitcoind.generate_block(120)
|
|
|
|
# Restart
|
|
l1.start()
|
|
sync_blockheight(bitcoind, [l1])
|
|
|
|
assert len(l1.rpc.listfunds()['outputs']) == 1
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
@unittest.skipIf(os.environ.get("TEST_CHECK_DBSTMTS", None) == "1",
|
|
"We kill l2, dblog plugin replay will be unreliable")
|
|
def test_channel_persistence(node_factory, bitcoind, executor):
|
|
# Start two nodes and open a channel (to remember). l2 will
|
|
# mysteriously die while committing the first HTLC so we can
|
|
# check that HTLCs reloaded from the DB work.
|
|
# Feerates identical so we don't get gratuitous commit to update them
|
|
disable_commit_after = 1
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
disable_commit_after = 2
|
|
|
|
l1 = node_factory.get_node(may_reconnect=True, feerates=(7500, 7500, 7500,
|
|
7500))
|
|
l2 = node_factory.get_node(options={'dev-disable-commit-after': disable_commit_after},
|
|
may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# Neither node should have a channel open, they are just connected
|
|
for n in (l1, l2):
|
|
assert(n.db_query('SELECT COUNT(id) as count FROM channels;')[0]['count'] == 0)
|
|
|
|
l1.fundchannel(l2, 100000)
|
|
|
|
channels = l1.rpc.listpeerchannels()['channels']
|
|
assert(only_one(channels)['state'] == 'CHANNELD_NORMAL')
|
|
|
|
# Both nodes should now have exactly one channel in the database
|
|
for n in (l1, l2):
|
|
assert(n.db_query('SELECT COUNT(id) as count FROM channels;')[0]['count'] == 1)
|
|
|
|
# Fire off a sendpay request, it'll get interrupted by a restart
|
|
executor.submit(l1.pay, l2, 10000)
|
|
# Wait for it to be committed to, i.e., stored in the DB
|
|
l1.daemon.wait_for_log('peer_in WIRE_CHANNEL_READY')
|
|
l1.daemon.wait_for_log('peer_in WIRE_COMMITMENT_SIGNED')
|
|
|
|
# Stop l2, l1 will reattempt to connect
|
|
print("Killing l2 in mid HTLC")
|
|
l2.daemon.kill()
|
|
|
|
# Clear the disconnect and timer stop so we can proceed normally
|
|
del l2.daemon.opts['dev-disable-commit-after']
|
|
|
|
# Wait for l1 to notice
|
|
wait_for(lambda: 'connected' not in l1.rpc.listpeerchannels()['channels'])
|
|
|
|
# Now restart l2 and it should reload peers/channels from the DB
|
|
l2.start()
|
|
wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 1)
|
|
|
|
# Wait for the restored HTLC to finish
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['to_us_msat'] == 99990000)
|
|
|
|
wait_for(lambda: len([p for p in l1.rpc.listpeers()['peers'] if p['connected']]))
|
|
wait_for(lambda: len([p for p in l2.rpc.listpeers()['peers'] if p['connected']]))
|
|
|
|
# Now make sure this is really functional by sending a payment
|
|
l1.pay(l2, 10000)
|
|
|
|
# L1 doesn't actually update to_us_msat until it receives
|
|
# revoke_and_ack from L2, which can take a little bit.
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['to_us_msat'] == 99980000)
|
|
assert only_one(l2.rpc.listpeerchannels()['channels'])['to_us_msat'] == 20000
|
|
|
|
# Finally restart l1, and make sure it remembers
|
|
l1.restart()
|
|
assert only_one(l1.rpc.listpeerchannels()['channels'])['to_us_msat'] == 99980000
|
|
|
|
# Keep l1 from sending its onchain tx
|
|
def censoring_sendrawtx(r):
|
|
return {'id': r['id'], 'result': {}}
|
|
|
|
l1.daemon.rpcproxy.mock_rpc('sendrawtransaction', censoring_sendrawtx)
|
|
|
|
# Now make sure l1 is watching for unilateral closes
|
|
l2.rpc.dev_fail(l1.info['id'])
|
|
l2.daemon.wait_for_log('Failing due to dev-fail command')
|
|
l2.wait_for_channel_onchain(l1.info['id'])
|
|
bitcoind.generate_block(1)
|
|
|
|
# L1 must notice.
|
|
l1.daemon.wait_for_log(' to ONCHAIN')
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_private_channel(node_factory):
|
|
l1, l2 = node_factory.line_graph(2, announce_channels=False, wait_for_announce=False)
|
|
l3, l4 = node_factory.line_graph(2, announce_channels=True, wait_for_announce=True)
|
|
|
|
assert l1.daemon.is_in_log('Will open private channel with node {}'.format(l2.info['id']))
|
|
assert not l2.daemon.is_in_log('Will open private channel with node {}'.format(l1.info['id']))
|
|
assert not l3.daemon.is_in_log('Will open private channel with node {}'.format(l4.info['id']))
|
|
|
|
l3.daemon.wait_for_log('Received node_announcement for node {}'.format(l4.info['id']))
|
|
l4.daemon.wait_for_log('Received node_announcement for node {}'.format(l3.info['id']))
|
|
|
|
assert not l1.daemon.is_in_log('Received node_announcement for node {}'.format(l2.info['id']))
|
|
assert not l2.daemon.is_in_log('Received node_announcement for node {}'.format(l1.info['id']))
|
|
|
|
# test for 'private' flag in rpc output
|
|
assert only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['private']
|
|
# check non-private channel
|
|
assert not only_one(l4.rpc.listpeerchannels(l3.info['id'])['channels'])['private']
|
|
|
|
|
|
def test_channel_reenable(node_factory):
|
|
l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True}, fundchannel=True, wait_for_announce=True)
|
|
|
|
l1.daemon.wait_for_log('Received node_announcement for node {}'.format(l2.info['id']))
|
|
l2.daemon.wait_for_log('Received node_announcement for node {}'.format(l1.info['id']))
|
|
|
|
# Both directions should be active before the restart
|
|
wait_for(lambda: [c['active'] for c in l1.rpc.listchannels()['channels']] == [True, True])
|
|
|
|
# Restart l2, will cause l1 to reconnect
|
|
l2.stop()
|
|
wait_for(lambda: [c['peer_connected'] for c in l1.rpc.listpeerchannels()['channels']] == [False])
|
|
l2.start()
|
|
|
|
# Updates may be suppressed if redundant; just test results.
|
|
wait_for(lambda: [c['active'] for c in l1.rpc.listchannels()['channels']] == [True, True])
|
|
wait_for(lambda: [c['peer_connected'] for c in l1.rpc.listpeerchannels()['channels']] == [True])
|
|
wait_for(lambda: [c['active'] for c in l2.rpc.listchannels()['channels']] == [True, True])
|
|
wait_for(lambda: [c['peer_connected'] for c in l2.rpc.listpeerchannels()['channels']] == [True])
|
|
|
|
|
|
def test_update_fee(node_factory, bitcoind):
|
|
l1, l2 = node_factory.line_graph(2, fundchannel=True)
|
|
chanid = l1.get_channel_scid(l2)
|
|
|
|
# Make l1 send out feechange.
|
|
l1.set_feerates((14000, 11000, 7500, 3750))
|
|
|
|
# Make payments.
|
|
l1.pay(l2, 200000000)
|
|
# First payment causes fee update.
|
|
if 'anchors/even' in only_one(l2.rpc.listpeerchannels()['channels'])['channel_type']['names']:
|
|
l2.daemon.wait_for_log('peer updated fee to 3755')
|
|
else:
|
|
l2.daemon.wait_for_log('peer updated fee to 11005')
|
|
l2.pay(l1, 100000000)
|
|
|
|
# Now shutdown cleanly.
|
|
l1.rpc.close(chanid)
|
|
|
|
l1.daemon.wait_for_log(' to CLOSINGD_COMPLETE')
|
|
l2.daemon.wait_for_log(' to CLOSINGD_COMPLETE')
|
|
|
|
# And should put closing into mempool.
|
|
l1.wait_for_channel_onchain(l2.info['id'])
|
|
l2.wait_for_channel_onchain(l1.info['id'])
|
|
|
|
bitcoind.generate_block(1)
|
|
l1.daemon.wait_for_log(' to ONCHAIN')
|
|
l2.daemon.wait_for_log(' to ONCHAIN')
|
|
|
|
bitcoind.generate_block(99)
|
|
l1.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
l2.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
|
|
|
|
def test_fee_limits(node_factory, bitcoind):
|
|
l1, l2, l3, l4 = node_factory.get_nodes(4, opts=[{'dev-max-fee-multiplier': 5, 'may_reconnect': True,
|
|
'allow_warning': True},
|
|
{'dev-max-fee-multiplier': 5, 'may_reconnect': True,
|
|
'allow_warning': True},
|
|
{'ignore-fee-limits': True, 'may_reconnect': True},
|
|
{}])
|
|
|
|
node_factory.join_nodes([l1, l2], fundchannel=True)
|
|
|
|
# Kick off fee adjustment using HTLC.
|
|
l1.pay(l2, 1000)
|
|
assert 'ignore_fee_limits' not in only_one(l2.rpc.listpeerchannels()['channels'])
|
|
assert 'ignore_fee_limits' not in only_one(l1.rpc.listpeerchannels()['channels'])
|
|
|
|
# L1 asks for stupid low fee (will actually hit the floor of 253)
|
|
l1.stop()
|
|
l1.set_feerates((15, 15, 15, 15), False)
|
|
# We need to increase l2's floor, so it rejects l1.
|
|
l2.set_feerates((15000, 11000, 7500, 3750, 2000))
|
|
l1.start()
|
|
|
|
if 'anchors/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
|
|
fee = 1255
|
|
else:
|
|
fee = 258
|
|
l1.daemon.wait_for_log(f'Received WARNING .*: update_fee {fee} outside range 2000-75000')
|
|
# They hang up on *us*
|
|
l1.daemon.wait_for_log('Peer transient failure in CHANNELD_NORMAL: channeld: Owning subdaemon channeld died')
|
|
|
|
# Disconnects, but does not error. Make sure it's noted in their status though.
|
|
# FIXME: does not happen for l1!
|
|
# assert 'update_fee 253 outside range 1875-75000' in only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['status'][0]
|
|
assert f'update_fee {fee} outside range 2000-75000' in only_one(l2.rpc.listpeerchannels(l1.info['id'])['channels'])['status'][0]
|
|
|
|
assert only_one(l2.rpc.listpeerchannels()['channels'])['feerate']['perkw'] != fee
|
|
# Make l2 accept those fees, and it should recover.
|
|
assert only_one(l2.rpc.setchannel(l1.get_channel_scid(l2), ignorefeelimits=True)['channels'])['ignore_fee_limits'] is True
|
|
assert only_one(l2.rpc.listpeerchannels()['channels'])['ignore_fee_limits'] is True
|
|
|
|
# Now we stay happy (and connected!)
|
|
wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['feerate']['perkw'] == fee)
|
|
assert only_one(l2.rpc.listpeerchannels()['channels'])['peer_connected'] is True
|
|
|
|
# This will fail to mutual close, since l2 won't ignore insane *close* fees!
|
|
assert l1.rpc.close(l2.info['id'], unilateraltimeout=5)['type'] == 'unilateral'
|
|
|
|
# Make sure the resolution of this one doesn't interfere with the next!
|
|
# Note: may succeed, may fail with insufficient fee, depending on how
|
|
# bitcoind feels!
|
|
l1.daemon.wait_for_log('sendrawtx exit')
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l1, l2])
|
|
|
|
# Trying to open a channel with too low a fee-rate is denied
|
|
l1.rpc.connect(l4.info['id'], 'localhost', l4.port)
|
|
with pytest.raises(RpcError, match='They sent (ERROR|WARNING) .* feerate_per_kw .* below minimum'):
|
|
l1.fundchannel(l4, 10**6)
|
|
|
|
# Restore to normal.
|
|
l1.stop()
|
|
l1.set_feerates((15000, 11000, 7500, 3750), False)
|
|
l1.start()
|
|
|
|
# Try with node which sets --ignore-fee-limits
|
|
l1.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
chan, _ = l1.fundchannel(l3, 10**6)
|
|
|
|
# Kick off fee adjustment using HTLC.
|
|
l1.pay(l3, 1000)
|
|
|
|
# Try stupid high fees
|
|
l1.stop()
|
|
l1.set_feerates((15000, 15000, 15000, 15000, 15000), False)
|
|
l1.start()
|
|
|
|
l3.daemon.wait_for_log('peer_in WIRE_UPDATE_FEE')
|
|
l3.daemon.wait_for_log('peer_in WIRE_COMMITMENT_SIGNED')
|
|
|
|
# We need to wait until both have committed and revoked the
|
|
# old state, otherwise we'll still try to commit with the old
|
|
# 15sat/byte fee
|
|
l1.daemon.wait_for_log('peer_out WIRE_REVOKE_AND_ACK')
|
|
|
|
l1.rpc.close(chan)
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'Assumes anchors')
|
|
def test_update_fee_dynamic(node_factory, bitcoind):
|
|
# l1 has no fee estimates to start.
|
|
l1 = node_factory.get_node(options={'log-level': 'io',
|
|
'dev-no-fake-fees': True}, start=False)
|
|
l1.daemon.rpcproxy.mock_rpc('estimatesmartfee', {
|
|
'error': {"errors": ["Insufficient data or no feerate found"], "blocks": 0}
|
|
})
|
|
l1.start()
|
|
l2 = node_factory.get_node()
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
# Fails due to lack of fee estimate.
|
|
with pytest.raises(RpcError, match='Cannot estimate fees'):
|
|
l1.fundchannel(l2, 10**6)
|
|
|
|
# Explicit feerate does not work still (doesn't apply for anchors!)
|
|
# We could make it, but we need a separate commitment feerate for
|
|
# anchors vs non-anchors, so easier after anchors are compulsory.
|
|
with pytest.raises(RpcError, match='Cannot estimate fees'):
|
|
l1.fundchannel(l2, 10**6, feerate='10000perkw')
|
|
|
|
l1.set_feerates((2000, 2000, 2000, 2000))
|
|
l1.fundchannel(l2, 10**6)
|
|
|
|
l1.set_feerates((15000, 11000, 7500, 3750))
|
|
|
|
# It will send UPDATE_FEE when it tries to send HTLC.
|
|
inv = l2.rpc.invoice(5000, 'test_update_fee_dynamic', 'test_update_fee_dynamic')['bolt11']
|
|
l1.rpc.pay(inv)
|
|
|
|
l2.daemon.wait_for_log('peer_in.*UPDATE_FEE')
|
|
|
|
# Now we take it away again!
|
|
l1.daemon.rpcproxy.mock_rpc('estimatesmartfee', {
|
|
'error': {"errors": ["Insufficient data or no feerate found"], "blocks": 0}
|
|
})
|
|
# Make sure that registers! (--developer means polling every second)
|
|
time.sleep(2)
|
|
|
|
inv = l2.rpc.invoice(5000, 'test_update_fee_dynamic2', 'test_update_fee_dynamic2')['bolt11']
|
|
l1.rpc.pay(inv)
|
|
|
|
# Won't update fee.
|
|
assert not l2.daemon.is_in_log('peer_in.*UPDATE_FEE',
|
|
start=l2.daemon.logsearch_start)
|
|
|
|
# Bring it back.
|
|
l1.set_feerates((14000, 10000, 7000, 3000))
|
|
|
|
# It will send UPDATE_FEE when it tries to send HTLC.
|
|
inv = l2.rpc.invoice(5000, 'test_update_fee_dynamic3', 'test_update_fee_dynamic')['bolt11']
|
|
l1.rpc.pay(inv)
|
|
|
|
l2.daemon.wait_for_log('peer_in.*UPDATE_FEE')
|
|
|
|
|
|
def test_update_fee_reconnect(node_factory, bitcoind):
|
|
# Disconnect after commitsig for fee update.
|
|
disconnects = ['+WIRE_COMMITMENT_SIGNED*3']
|
|
# Feerates identical so we don't get gratuitous commit to update them
|
|
l1 = node_factory.get_node(disconnect=disconnects, may_reconnect=True,
|
|
feerates=(15000, 15000, 15000, 3750))
|
|
# We match l2's later feerate, so we agree on same closing tx for simplicity.
|
|
l2 = node_factory.get_node(may_reconnect=True,
|
|
feerates=(14000, 15000, 14000, 3750))
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
chan, _ = l1.fundchannel(l2, 10**6)
|
|
|
|
# Make an HTLC just to get us to do feechanges.
|
|
l1.pay(l2, 1000)
|
|
|
|
# Make l1 send out feechange; triggers disconnect/reconnect.
|
|
# (Note: < 10% change, so no smoothing here!)
|
|
l1.set_feerates((14000, 14000, 14000, 14000))
|
|
l1.daemon.wait_for_log('Setting REMOTE feerate to 14005')
|
|
l2.daemon.wait_for_log('Setting LOCAL feerate to 14005')
|
|
l1.daemon.wait_for_log(r'dev_disconnect: \+WIRE_COMMITMENT_SIGNED')
|
|
|
|
# Wait for reconnect....
|
|
l1.daemon.wait_for_log('Feerate:.*LOCAL now 14005')
|
|
|
|
l1.pay(l2, 200000000)
|
|
l2.pay(l1, 100000000)
|
|
|
|
# They should both have gotten commits with correct feerate.
|
|
assert l1.daemon.is_in_log('got commitsig [0-9]*: feerate 14005')
|
|
assert l2.daemon.is_in_log('got commitsig [0-9]*: feerate 14005')
|
|
|
|
# Now shutdown cleanly.
|
|
l1.rpc.close(chan)
|
|
|
|
# And should put closing into mempool.
|
|
l1.wait_for_channel_onchain(l2.info['id'])
|
|
l2.wait_for_channel_onchain(l1.info['id'])
|
|
|
|
bitcoind.generate_block(1)
|
|
l1.daemon.wait_for_log(' to ONCHAIN')
|
|
l2.daemon.wait_for_log(' to ONCHAIN')
|
|
|
|
bitcoind.generate_block(99)
|
|
l1.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
l2.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
|
|
|
|
def test_multiple_channels(node_factory):
|
|
l1 = node_factory.get_node()
|
|
l2 = node_factory.get_node()
|
|
|
|
ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
assert ret['id'] == l2.info['id']
|
|
|
|
for i in range(3):
|
|
chan, _ = l1.fundchannel(l2, 10**6)
|
|
|
|
l1.rpc.close(chan)
|
|
|
|
# If we don't wait for l2 to make the transition we can end up
|
|
# attempting to re-estabilishing the channel
|
|
l2.daemon.wait_for_log(
|
|
r'State changed from CLOSINGD_SIGEXCHANGE to CLOSINGD_COMPLETE'
|
|
)
|
|
|
|
channels = l1.rpc.listpeerchannels()['channels']
|
|
assert len(channels) == 3
|
|
# Most in state ONCHAIN, last is CLOSINGD_COMPLETE
|
|
for i in range(len(channels) - 1):
|
|
assert channels[i]['state'] == 'ONCHAIN'
|
|
assert channels[-1]['state'] == 'CLOSINGD_COMPLETE'
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_forget_channel(node_factory):
|
|
l1 = node_factory.get_node()
|
|
l2 = node_factory.get_node()
|
|
l1.fundwallet(10**6)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], 10**5)
|
|
|
|
assert len(l1.rpc.listpeers()['peers']) == 1
|
|
|
|
# This should fail, the funding tx is in the mempool and may confirm
|
|
with pytest.raises(RpcError, match=r'Cowardly refusing to forget channel'):
|
|
l1.rpc.dev_forget_channel(l2.info['id'])
|
|
|
|
assert len(l1.rpc.listpeers()['peers']) == 1
|
|
|
|
# Forcing should work
|
|
l1.rpc.dev_forget_channel(l2.info['id'], True)
|
|
wait_for(lambda: l1.rpc.listpeerchannels()['channels'] == [])
|
|
|
|
# And restarting should keep that peer forgotten
|
|
l1.restart()
|
|
assert len(l1.rpc.listpeers()['peers']) == 0
|
|
|
|
# The entry in the channels table should still be there
|
|
assert l1.db_query("SELECT count(*) as c FROM channels;")[0]['c'] == 1
|
|
assert l2.db_query("SELECT count(*) as c FROM channels;")[0]['c'] == 1
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_peerinfo(node_factory, bitcoind):
|
|
l1, l2 = node_factory.line_graph(2, fundchannel=False, opts={'may_reconnect': True})
|
|
|
|
lfeatures = expected_peer_features()
|
|
nfeatures = expected_node_features()
|
|
|
|
# Gossiping but no node announcement yet
|
|
assert l1.rpc.getpeer(l2.info['id'])['connected']
|
|
assert len(l1.rpc.listpeerchannels(l2.info['id'])['channels']) == 0
|
|
assert l1.rpc.getpeer(l2.info['id'])['features'] == lfeatures
|
|
|
|
# Fund a channel to force a node announcement
|
|
chan, _ = l1.fundchannel(l2, 10**6)
|
|
# Now proceed to funding-depth and do a full gossip round
|
|
bitcoind.generate_block(5)
|
|
l1.daemon.wait_for_logs(['Received node_announcement for node ' + l2.info['id']])
|
|
l2.daemon.wait_for_logs(['Received node_announcement for node ' + l1.info['id']])
|
|
|
|
# Should have announced the same features as told to peer.
|
|
nodes1 = l1.rpc.listnodes(l2.info['id'])['nodes']
|
|
nodes2 = l2.rpc.listnodes(l2.info['id'])['nodes']
|
|
peer1 = l1.rpc.getpeer(l2.info['id'])
|
|
peer2 = l2.rpc.getpeer(l1.info['id'])
|
|
# peer features != to node features now because of keysend, which adds a node feature
|
|
assert only_one(nodes1)['features'] == nfeatures
|
|
assert only_one(nodes2)['features'] == nfeatures
|
|
assert peer1['features'] == lfeatures
|
|
assert peer2['features'] == lfeatures
|
|
|
|
# If it reconnects after db load, it should know features.
|
|
l1.restart()
|
|
wait_for(lambda: l1.rpc.getpeer(l2.info['id'])['connected'])
|
|
wait_for(lambda: l2.rpc.getpeer(l1.info['id'])['connected'])
|
|
assert l1.rpc.getpeer(l2.info['id'])['features'] == lfeatures
|
|
assert l2.rpc.getpeer(l1.info['id'])['features'] == lfeatures
|
|
|
|
# Close the channel to forget the peer
|
|
l1.rpc.close(chan)
|
|
|
|
# Make sure close tx hits mempool before we mine blocks.
|
|
bitcoind.generate_block(100, wait_for_mempool=1)
|
|
l1.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
l2.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
assert l1.rpc.listpeerchannels(l2.info['id'])['channels'] == []
|
|
assert l2.rpc.listpeerchannels(l1.info['id'])['channels'] == []
|
|
|
|
# The only channel was closed, everybody should have forgotten the nodes
|
|
assert l1.rpc.listnodes()['nodes'] == []
|
|
assert l2.rpc.listnodes()['nodes'] == []
|
|
|
|
|
|
def test_disconnectpeer(node_factory, bitcoind):
|
|
l1, l2, l3 = node_factory.get_nodes(3, opts={'may_reconnect': False})
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
|
|
# Gossiping
|
|
assert l1.rpc.getpeer(l2.info['id'])['connected']
|
|
assert len(l1.rpc.listpeerchannels(l2.info['id'])['channels']) == 0
|
|
assert l1.rpc.getpeer(l3.info['id'])['connected']
|
|
assert len(l1.rpc.listpeerchannels(l3.info['id'])['channels']) == 0
|
|
wait_for(lambda: l2.rpc.getpeer(l1.info['id']) is not None)
|
|
|
|
# Disconnect l2 from l1
|
|
l1.rpc.disconnect(l2.info['id'])
|
|
|
|
# Make sure listpeers no longer returns the disconnected node
|
|
assert l1.rpc.getpeer(l2.info['id']) is None
|
|
wait_for(lambda: l2.rpc.getpeer(l1.info['id']) is None)
|
|
|
|
# Make sure you cannot disconnect after disconnecting
|
|
with pytest.raises(RpcError, match=r'Unknown peer'):
|
|
l1.rpc.disconnect(l2.info['id'])
|
|
with pytest.raises(RpcError, match=r'Unknown peer'):
|
|
l2.rpc.disconnect(l1.info['id'])
|
|
|
|
# Fund channel l1 -> l3
|
|
l1.fundchannel(l3, 10**6)
|
|
mine_funding_to_announce(bitcoind, [l1, l2, l3])
|
|
|
|
# disconnecting a non gossiping peer results in error
|
|
with pytest.raises(RpcError, match=r'Peer has \(at least one\) channel in state CHANNELD_NORMAL'):
|
|
l1.rpc.disconnect(l3.info['id'])
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_fundee_forget_funding_tx_unconfirmed(node_factory, bitcoind):
|
|
"""Test that fundee will forget the channel if
|
|
the funding tx has been unconfirmed for too long.
|
|
"""
|
|
# Keep confirms low (default is 2016), since everything
|
|
# is much slower in VALGRIND mode and wait_for_log
|
|
# could time out before lightningd processes all the
|
|
# blocks. This also reduces the number of "slow confirm" peers
|
|
# from 100, to 1.
|
|
blocks = 10
|
|
l1, l2, l3 = node_factory.line_graph(3, fundchannel=False,
|
|
opts={"dev-max-funding-unconfirmed-blocks": blocks})
|
|
|
|
# Give openers some funds.
|
|
l1.fundwallet(10**7)
|
|
l3.fundwallet(10**7)
|
|
sync_blockheight(bitcoind, [l1, l2, l3])
|
|
|
|
def mock_sendrawtransaction(r):
|
|
return {'id': r['id'], 'error': {'code': 100, 'message': 'sendrawtransaction disabled'}}
|
|
|
|
def mock_donothing(r):
|
|
return {'id': r['id'], 'result': {'success': True}}
|
|
|
|
# Prevent opener from broadcasting funding tx (any tx really).
|
|
l1.daemon.rpcproxy.mock_rpc('sendrawtransaction', mock_sendrawtransaction)
|
|
# (for EXPERIMENTAL_DUAL_FUND=1, have to prevent l2 doing it too!)
|
|
l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', mock_donothing)
|
|
|
|
# l1 tries to open, fails.
|
|
with pytest.raises(RpcError, match=r'sendrawtransaction disabled'):
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6)
|
|
|
|
# One block later, l3 tries, fails silently.
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l1, l2, l3])
|
|
|
|
l3.daemon.rpcproxy.mock_rpc('sendrawtransaction', mock_donothing)
|
|
l3.rpc.fundchannel(l2.info['id'], 10**6)
|
|
|
|
# After 10 blocks, l1's is due to be forgotten, but doesn't since we let 1 linger.
|
|
bitcoind.generate_block(blocks - 1)
|
|
assert not l2.daemon.is_in_log(r'Forgetting channel')
|
|
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
state = 'DUALOPEND_AWAITING_LOCKIN'
|
|
else:
|
|
state = 'CHANNELD_AWAITING_LOCKIN'
|
|
assert [c['state'] for c in l2.rpc.listpeerchannels()['channels']] == [state] * 2
|
|
|
|
# But once l3 is also delayed, l1 gets kicked out.
|
|
bitcoind.generate_block(1)
|
|
|
|
# fundee will forget oldest channel: the one with l1!
|
|
l2.daemon.wait_for_log(rf'Forgetting channel: It has been {blocks + 1} blocks')
|
|
assert [c['state'] for c in l2.rpc.listpeerchannels()['channels']] == [state]
|
|
assert l2.rpc.listpeerchannels(l1.info['id']) == {'channels': []}
|
|
|
|
|
|
@pytest.mark.openchannel('v2')
|
|
def test_fundee_node_unconfirmed(node_factory, bitcoind):
|
|
"""Test that fundee will successfully broadcast and
|
|
funder still has correct UTXOs/correctly advances the channel
|
|
"""
|
|
# opener
|
|
l1, l2 = node_factory.line_graph(2, fundchannel=False)
|
|
|
|
# Give opener some funds.
|
|
l1.fundwallet(10**7)
|
|
|
|
start_amount = only_one(l1.rpc.listfunds()['outputs'])['amount_msat']
|
|
|
|
def mock_sendrawtransaction(r):
|
|
return {'id': r['id'], 'error': {'code': 100, 'message': 'sendrawtransaction disabled'}}
|
|
|
|
def mock_donothing(r):
|
|
time.sleep(10)
|
|
return bitcoind.rpc.sendrawtransaction(r['params'][0])
|
|
|
|
# Prevent both from broadcasting funding tx (any tx really).
|
|
l1.daemon.rpcproxy.mock_rpc('sendrawtransaction', mock_sendrawtransaction)
|
|
l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', mock_donothing)
|
|
|
|
# Fund the channel.
|
|
# The process will complete, but opener will be unable
|
|
# to broadcast and confirm funding tx.
|
|
with pytest.raises(RpcError, match=r'sendrawtransaction disabled'):
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6)
|
|
|
|
# Generate blocks until unconfirmed.
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
|
|
# Check that l1 opened the channel
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'CHANNELD_NORMAL')
|
|
end_amount = only_one(l1.rpc.listfunds()['outputs'])['amount_msat']
|
|
# We should be out the onchaind fees
|
|
assert start_amount > end_amount + Millisatoshi(10 ** 7 * 100)
|
|
|
|
|
|
def test_no_fee_estimate(node_factory, bitcoind, executor):
|
|
l1 = node_factory.get_node(start=False, options={'dev-no-fake-fees': True})
|
|
|
|
# Fail any fee estimation requests until we allow them further down
|
|
l1.daemon.rpcproxy.mock_rpc('estimatesmartfee', {
|
|
'error': {"errors": ["Insufficient data or no feerate found"], "blocks": 0}
|
|
})
|
|
l1.start()
|
|
|
|
l2 = node_factory.get_node()
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# Can't fund a channel.
|
|
l1.fundwallet(10**7)
|
|
with pytest.raises(RpcError, match=r'Cannot estimate fees'):
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6)
|
|
|
|
# Can't withdraw either.
|
|
with pytest.raises(RpcError, match=r'Cannot estimate fees'):
|
|
l1.rpc.withdraw(l2.rpc.newaddr()['bech32'], 'all')
|
|
|
|
# Can't use feerate names, either.
|
|
with pytest.raises(RpcError, match=r'Cannot estimate fees'):
|
|
l1.rpc.withdraw(l2.rpc.newaddr()['bech32'], 'all', 'urgent')
|
|
|
|
with pytest.raises(RpcError, match=r'Cannot estimate fees'):
|
|
l1.rpc.withdraw(l2.rpc.newaddr()['bech32'], 'all', 'normal')
|
|
|
|
with pytest.raises(RpcError, match=r'Cannot estimate fees'):
|
|
l1.rpc.withdraw(l2.rpc.newaddr()['bech32'], 'all', 'slow')
|
|
|
|
with pytest.raises(RpcError, match=r'Cannot estimate fees'):
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6, 'urgent')
|
|
|
|
with pytest.raises(RpcError, match=r'Cannot estimate fees'):
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6, 'normal')
|
|
|
|
with pytest.raises(RpcError, match=r'Cannot estimate fees'):
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6, 'slow')
|
|
|
|
# With anchors, not even with manual feerate!
|
|
l1.rpc.withdraw(l2.rpc.newaddr()['bech32'], 10000, '1500perkb')
|
|
if TEST_NETWORK == 'regtest':
|
|
with pytest.raises(RpcError, match=r'Cannot estimate fees'):
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6, '2000perkw', minconf=0)
|
|
|
|
# But can accept incoming connections.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l2.fundchannel(l1, 10**6)
|
|
|
|
# Can do HTLCs.
|
|
l2.pay(l1, 10**5)
|
|
|
|
# Can do mutual close.
|
|
l1.rpc.close(l2.info['id'])
|
|
wait_for(lambda: len(bitcoind.rpc.getrawmempool()) > 0)
|
|
bitcoind.generate_block(100)
|
|
sync_blockheight(bitcoind, [l1, l2])
|
|
|
|
# Can do unilateral close.
|
|
l2.rpc.connect(l1.info['id'], 'localhost', l1.port)
|
|
l2.fundchannel(l1, 10**6)
|
|
l2.pay(l1, 10**9 // 2)
|
|
l1.rpc.dev_fail(l2.info['id'])
|
|
l1.daemon.wait_for_log('Failing due to dev-fail command')
|
|
l1.wait_for_channel_onchain(l2.info['id'])
|
|
bitcoind.generate_block(5)
|
|
wait_for(lambda: len(bitcoind.rpc.getrawmempool()) > 0)
|
|
bitcoind.generate_block(100)
|
|
sync_blockheight(bitcoind, [l1, l2])
|
|
|
|
# Start estimatesmartfee.
|
|
l1.set_feerates((15000, 11000, 7500, 3750), True)
|
|
|
|
# Can now fund a channel (as a test, use slow feerate).
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
sync_blockheight(bitcoind, [l1])
|
|
l1.rpc.fundchannel(l2.info['id'], 10**6, 'slow')
|
|
|
|
# Can withdraw (use urgent feerate). `minconf` may be needed depending on
|
|
# the previous `fundchannel` selecting all confirmed outputs.
|
|
l1.rpc.withdraw(l2.rpc.newaddr()['bech32'], 'all', 'urgent', minconf=0)
|
|
|
|
|
|
def test_opener_feerate_reconnect(node_factory, bitcoind):
|
|
# l1 updates fees, then reconnect so l2 retransmits commitment_signed.
|
|
disconnects = ['-WIRE_COMMITMENT_SIGNED*3']
|
|
l1 = node_factory.get_node(may_reconnect=True,
|
|
feerates=(7500, 7500, 7500, 7500))
|
|
l2 = node_factory.get_node(disconnect=disconnects, may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundchannel(l2, 10**6)
|
|
|
|
# Need a payment otherwise it won't update fee.
|
|
l1.pay(l2, 10**9 // 2)
|
|
|
|
# create fee update, causing disconnect.
|
|
l1.set_feerates((15000, 11000, 7500, 3750))
|
|
l2.daemon.wait_for_log(r'dev_disconnect: \-WIRE_COMMITMENT_SIGNED')
|
|
|
|
# Wait until they reconnect.
|
|
l1.daemon.wait_for_logs(['Peer transient failure in CHANNELD_NORMAL',
|
|
'peer_disconnect_done'])
|
|
wait_for(lambda: l1.rpc.getpeer(l2.info['id'])['connected'])
|
|
|
|
# Should work normally.
|
|
l1.pay(l2, 200000000)
|
|
|
|
|
|
def test_opener_simple_reconnect(node_factory, bitcoind):
|
|
"""Sanity check that reconnection works with completely unused channels"""
|
|
# Set fees even so it doesn't send any commitments.
|
|
l1 = node_factory.get_node(may_reconnect=True,
|
|
feerates=(7500, 7500, 7500, 7500))
|
|
l2 = node_factory.get_node(may_reconnect=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundchannel(l2, 10**6)
|
|
|
|
l1.rpc.disconnect(l2.info['id'], True)
|
|
|
|
# Wait until they reconnect.
|
|
wait_for(lambda: l1.rpc.getpeer(l2.info['id'])['connected'])
|
|
|
|
# Should work normally.
|
|
l1.pay(l2, 200000000)
|
|
|
|
|
|
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "sqlite3-specific DB rollback")
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_dataloss_protection(node_factory, bitcoind):
|
|
l1 = node_factory.get_node(may_reconnect=True, options={'log-level': 'io'},
|
|
allow_warning=True,
|
|
feerates=(7500, 7500, 7500, 7500))
|
|
l2 = node_factory.get_node(may_reconnect=True, options={'log-level': 'io'},
|
|
broken_log='Cannot broadcast our commitment tx: they have a future one|Unknown commitment .*, recovering our funds',
|
|
feerates=(7500, 7500, 7500, 7500))
|
|
|
|
lf = expected_peer_features()
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
# l1 should send out WIRE_INIT (0010)
|
|
l1.daemon.wait_for_log(r"\[OUT\] 0010.*"
|
|
# lflen
|
|
+ format(len(lf) // 2, '04x')
|
|
+ lf)
|
|
|
|
l1.fundchannel(l2, 10**6)
|
|
l2.stop()
|
|
|
|
# Save copy of the db.
|
|
dbpath = os.path.join(l2.daemon.lightning_dir, TEST_NETWORK, "lightningd.sqlite3")
|
|
orig_db = open(dbpath, "rb").read()
|
|
l2.start()
|
|
|
|
# l1 should have sent WIRE_CHANNEL_REESTABLISH with extra fields.
|
|
l1.daemon.wait_for_log(r"\[OUT\] 0088"
|
|
# channel_id
|
|
"[0-9a-f]{64}"
|
|
# next_local_commitment_number
|
|
"0000000000000001"
|
|
# next_remote_revocation_number
|
|
"0000000000000000"
|
|
# your_last_per_commitment_secret (funding_depth may
|
|
# trigger a fee-update and commit, hence this may not
|
|
# be zero)
|
|
"[0-9a-f]{64}"
|
|
# my_current_per_commitment_point
|
|
"0[23][0-9a-f]{64}")
|
|
|
|
# After an htlc, we should get different results (two more commits)
|
|
l1.pay(l2, 200000000)
|
|
|
|
# Make sure both sides consider it completely settled (has received both
|
|
# REVOKE_AND_ACK)
|
|
l1.daemon.wait_for_logs([r"\[IN\] 0085"] * 2)
|
|
l2.daemon.wait_for_logs([r"\[IN\] 0085"] * 2)
|
|
|
|
l2.restart()
|
|
|
|
# l1 should have sent WIRE_CHANNEL_REESTABLISH with extra fields.
|
|
l1.daemon.wait_for_log(r"\[OUT\] 0088"
|
|
# channel_id
|
|
"[0-9a-f]{64}"
|
|
# next_local_commitment_number
|
|
"000000000000000[1-9]"
|
|
# next_remote_revocation_number
|
|
"000000000000000[1-9]"
|
|
# your_last_per_commitment_secret
|
|
"[0-9a-f]{64}"
|
|
# my_current_per_commitment_point
|
|
"0[23][0-9a-f]{64}")
|
|
|
|
# Now, move l2 back in time.
|
|
l2.stop()
|
|
# Overwrite with OLD db.
|
|
open(dbpath, "wb").write(orig_db)
|
|
l2.start()
|
|
|
|
# l2 should freak out!
|
|
l2.daemon.wait_for_log("Peer permanent failure in CHANNELD_NORMAL:.*Awaiting unilateral close")
|
|
|
|
# l2 must NOT drop to chain.
|
|
l2.daemon.wait_for_log("Cannot broadcast our commitment tx: they have a future one")
|
|
assert not l2.daemon.is_in_log('sendrawtx exit 0',
|
|
start=l2.daemon.logsearch_start)
|
|
|
|
# l1 should receive error and drop to chain
|
|
l1.daemon.wait_for_log("They sent ERROR.*Awaiting unilateral close")
|
|
l1.wait_for_channel_onchain(l2.info['id'])
|
|
|
|
closetxid = only_one(bitcoind.rpc.getrawmempool(False))
|
|
|
|
# l2 should still recover something!
|
|
bitcoind.generate_block(1)
|
|
|
|
l2.daemon.wait_for_log("ERROR: Unknown commitment #[0-9], recovering our funds!")
|
|
|
|
# Restarting l2, and it should remember from db.
|
|
l2.restart()
|
|
|
|
l2.daemon.wait_for_log("ERROR: Unknown commitment #[0-9], recovering our funds!")
|
|
bitcoind.generate_block(100)
|
|
l2.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
|
|
# l2 should have it in wallet.
|
|
assert (closetxid, "confirmed") in set([(o['txid'], o['status']) for o in l2.rpc.listfunds()['outputs']])
|
|
|
|
|
|
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "sqlite3-specific DB rollback")
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_dataloss_protection_no_broadcast(node_factory, bitcoind):
|
|
# If l2 sends an old version, but *doesn't* send an error, l1 should not broadcast tx.
|
|
# (https://github.com/lightning/bolts/issues/934)
|
|
l1 = node_factory.get_node(may_reconnect=True,
|
|
feerates=(7500, 7500, 7500, 7500),
|
|
allow_warning=True,
|
|
options={'dev-no-reconnect': None})
|
|
l2 = node_factory.get_node(may_reconnect=True,
|
|
feerates=(7500, 7500, 7500, 7500),
|
|
broken_log='Cannot broadcast our commitment tx: they have a future one',
|
|
disconnect=['-WIRE_ERROR'],
|
|
options={'dev-no-reconnect': None})
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundchannel(l2, 10**6)
|
|
l2.stop()
|
|
|
|
# Save copy of the db.
|
|
dbpath = os.path.join(l2.daemon.lightning_dir, TEST_NETWORK, "lightningd.sqlite3")
|
|
orig_db = open(dbpath, "rb").read()
|
|
l2.start()
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
# After an htlc, we should get different results (two more commits)
|
|
l1.pay(l2, 200000000)
|
|
|
|
# Make sure both sides consider it completely settled (has received both
|
|
# REVOKE_AND_ACK)
|
|
l1.daemon.wait_for_logs(["peer_in WIRE_REVOKE_AND_ACK"] * 2)
|
|
l2.daemon.wait_for_logs(["peer_in WIRE_REVOKE_AND_ACK"] * 2)
|
|
|
|
# Now, move l2 back in time.
|
|
l2.stop()
|
|
# Save new db
|
|
new_db = open(dbpath, "rb").read()
|
|
# Overwrite with OLD db.
|
|
open(dbpath, "wb").write(orig_db)
|
|
l2.start()
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
# l2 should freak out! But fail when trying to send error
|
|
l2.daemon.wait_for_logs(["Peer permanent failure in CHANNELD_NORMAL:.* Awaiting unilateral close",
|
|
'dev_disconnect: -WIRE_ERROR'])
|
|
|
|
# l1 should NOT drop to chain, since it didn't receive an error.
|
|
time.sleep(5)
|
|
assert bitcoind.rpc.getrawmempool(False) == []
|
|
|
|
# fix up l2.
|
|
l2.stop()
|
|
open(dbpath, "wb").write(new_db)
|
|
l2.start()
|
|
|
|
# All is forgiven
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.pay(l2, 200000000)
|
|
|
|
|
|
def test_restart_multi_htlc_rexmit(node_factory, bitcoind, executor):
|
|
# l1 disables commit timer once we send first htlc, dies on commit
|
|
l1, l2 = node_factory.line_graph(2, opts=[{'disconnect': ['-WIRE_COMMITMENT_SIGNED'],
|
|
'may_reconnect': True,
|
|
'dev-disable-commit-after': 0},
|
|
{'may_reconnect': True}])
|
|
|
|
executor.submit(l1.pay, l2, 20000)
|
|
executor.submit(l1.pay, l2, 30000)
|
|
|
|
l1.daemon.wait_for_logs(['peer_out WIRE_UPDATE_ADD_HTLC'] * 2)
|
|
l1.rpc.dev_reenable_commit(l2.info['id'])
|
|
l1.daemon.wait_for_log('dev_disconnect: -WIRE_COMMITMENT_SIGNED')
|
|
|
|
# This will make it reconnect
|
|
l1.stop()
|
|
# Clear the disconnect so we can proceed normally
|
|
l1.daemon.disconnect = None
|
|
l1.start()
|
|
|
|
# Payments will fail due to restart, but we can see results in listsendpays.
|
|
print(l1.rpc.listsendpays())
|
|
wait_for(lambda: [p['status'] for p in l1.rpc.listsendpays()['payments']] == ['complete', 'complete'])
|
|
|
|
|
|
def test_fulfill_incoming_first(node_factory, bitcoind):
|
|
"""Test that we handle the case where we completely resolve incoming htlc
|
|
before fulfilled outgoing htlc"""
|
|
|
|
# We agree on fee change first, then add HTLC, then remove; stop after remove.
|
|
disconnects = ['+WIRE_COMMITMENT_SIGNED*3']
|
|
# We manually reconnect l2 & l3, after 100 blocks; hence allowing manual
|
|
# reconnect, but disabling auto connect, and massive cltv so 2/3 doesn't
|
|
# time out.
|
|
l1, l2, l3 = node_factory.line_graph(3, opts=[{'disable-mpp': None},
|
|
{'may_reconnect': True,
|
|
'dev-no-reconnect': None},
|
|
{'may_reconnect': True,
|
|
'dev-no-reconnect': None,
|
|
'disconnect': disconnects,
|
|
'cltv-final': 200}],
|
|
wait_for_announce=True)
|
|
|
|
# This succeeds.
|
|
l1.rpc.pay(l3.rpc.invoice(200000000, 'test_fulfill_incoming_first', 'desc')['bolt11'])
|
|
|
|
# l1 can shutdown, fine.
|
|
l1.rpc.close(l2.info['id'])
|
|
l1.wait_for_channel_onchain(l2.info['id'])
|
|
bitcoind.generate_block(100)
|
|
l2.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
|
|
# Now, l2 should restore from DB fine, even though outgoing HTLC no longer
|
|
# has an incoming.
|
|
l2.restart()
|
|
|
|
# Manually reconnect l2->l3.
|
|
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
|
|
# Fulfill should be retransmitted OK (ignored result).
|
|
l2.rpc.close(l3.info['id'])
|
|
l2.wait_for_channel_onchain(l3.info['id'])
|
|
bitcoind.generate_block(100)
|
|
l2.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
l3.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
|
|
|
|
@pytest.mark.skip('needs blackhold support')
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_fail_unconfirmed(node_factory, bitcoind, executor):
|
|
"""Test that if we crash with an unconfirmed connection to a known
|
|
peer, we don't have a dangling peer in db"""
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
disconnect = ['=WIRE_OPEN_CHANNEL2']
|
|
else:
|
|
disconnect = ['=WIRE_OPEN_CHANNEL']
|
|
# = is a NOOP disconnect, but sets up file.
|
|
l1 = node_factory.get_node(disconnect=disconnect)
|
|
l2 = node_factory.get_node()
|
|
|
|
# First one, we close by mutual agreement.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundchannel(l2, 200000, wait_for_active=True)
|
|
l1.rpc.close(l2.info['id'])
|
|
|
|
# Make sure it's closed
|
|
l1.wait_for_channel_onchain(l2.info['id'])
|
|
bitcoind.generate_block(1)
|
|
l1.daemon.wait_for_log('State changed from CLOSINGD_COMPLETE to FUNDING_SPEND_SEEN')
|
|
|
|
l1.stop()
|
|
# Mangle disconnect file so this time it blackholes....
|
|
with open(l1.daemon.disconnect_file, "w") as f:
|
|
if EXPERIMENTAL_DUAL_FUND:
|
|
f.write("0WIRE_OPEN_CHANNEL2\n")
|
|
else:
|
|
f.write("0WIRE_OPEN_CHANNEL\n")
|
|
l1.start()
|
|
|
|
# Now we establish a new channel, which gets stuck.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundwallet(10**7)
|
|
executor.submit(l1.rpc.fundchannel, l2.info['id'], 100000)
|
|
|
|
l1.daemon.wait_for_log("dev_disconnect")
|
|
|
|
# Now complete old channel.
|
|
bitcoind.generate_block(100)
|
|
l1.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
|
|
# And crash l1, which is stuck.
|
|
l1.daemon.kill()
|
|
|
|
# Now, restart and see if it can connect OK.
|
|
l1.daemon.disconnect = None
|
|
l1.start()
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundchannel(l2, 200000, wait_for_active=True)
|
|
|
|
|
|
@pytest.mark.skip('needs blackhold support')
|
|
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_fail_unconfirmed_openchannel2(node_factory, bitcoind, executor):
|
|
"""Test that if we crash with an unconfirmed connection to a known
|
|
peer, we don't have a dangling peer in db"""
|
|
# = is a NOOP disconnect, but sets up file.
|
|
l1 = node_factory.get_node(disconnect=['=WIRE_OPEN_CHANNEL2'])
|
|
l2 = node_factory.get_node()
|
|
|
|
# First one, we close by mutual agreement.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundchannel(l2, 200000, wait_for_active=True)
|
|
l1.rpc.close(l2.info['id'])
|
|
|
|
# Make sure it's closed
|
|
l1.wait_for_channel_onchain(l2.info['id'])
|
|
bitcoind.generate_block(1)
|
|
l1.daemon.wait_for_log('State changed from CLOSINGD_COMPLETE to FUNDING_SPEND_SEEN')
|
|
|
|
l1.stop()
|
|
# Mangle disconnect file so this time it blackholes....
|
|
with open(l1.daemon.disconnect_file, "w") as f:
|
|
f.write("0WIRE_OPEN_CHANNEL2\n")
|
|
l1.start()
|
|
|
|
# Now we establish a new channel, which gets stuck.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundwallet(10**7)
|
|
executor.submit(l1.rpc.fundchannel, l2.info['id'], 100000)
|
|
|
|
l1.daemon.wait_for_log("dev_disconnect")
|
|
|
|
# Now complete old channel.
|
|
bitcoind.generate_block(100)
|
|
l1.daemon.wait_for_log('onchaind complete, forgetting peer')
|
|
|
|
# And crash l1, which is stuck.
|
|
l1.daemon.kill()
|
|
|
|
# Now, restart and see if it can connect OK.
|
|
l1.daemon.disconnect = None
|
|
l1.start()
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.fundchannel(l2, 200000, wait_for_active=True)
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_change_chaining(node_factory, bitcoind):
|
|
"""Test change chaining of unconfirmed fundings
|
|
|
|
Change chaining is the case where one transaction is broadcast but not
|
|
confirmed yet and we already build a followup on top of the change. If the
|
|
first transaction doesn't confirm we may end up creating a series of
|
|
unconfirmable transactions. This is why we generally disallow chaining.
|
|
|
|
"""
|
|
l1, l2, l3 = node_factory.get_nodes(3)
|
|
l1.fundwallet(10**8) # This will create an output with 1 confirmation
|
|
|
|
# Now fund a channel from l1 to l2, that should succeed, with minconf=1 but not before
|
|
l1.connect(l2)
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.fundchannel(l2.info['id'], 10**7, minconf=2)
|
|
l1.rpc.fundchannel(l2.info['id'], 10**7) # Defaults to minconf=1
|
|
|
|
# We don't have confirmed outputs anymore, so this should fail without minconf=0
|
|
l1.connect(l3)
|
|
with pytest.raises(RpcError):
|
|
l1.rpc.fundchannel(l3.info['id'], 10**7) # Defaults to minconf=1
|
|
l1.rpc.fundchannel(l3.info['id'], 10**7, minconf=0)
|
|
|
|
|
|
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', "Fees on elements are different")
|
|
def test_feerate_spam(node_factory, chainparams):
|
|
l1, l2 = node_factory.line_graph(2)
|
|
|
|
# We constrain the value the opener has at its disposal so we get the
|
|
# REMOTE feerate we are looking for below. This may be fragile and depends
|
|
# on the transactions we generate.
|
|
slack = 45000000
|
|
|
|
# Pay almost everything to l2.
|
|
l1.pay(l2, 10**9 - slack)
|
|
|
|
# It will send this once (may have happened before line_graph's wait)
|
|
if 'anchors/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
|
|
wait_for(lambda: l1.daemon.is_in_log('Setting REMOTE feerate to 3755'))
|
|
else:
|
|
wait_for(lambda: l1.daemon.is_in_log('Setting REMOTE feerate to 11005'))
|
|
wait_for(lambda: l1.daemon.is_in_log('peer_out WIRE_UPDATE_FEE'))
|
|
|
|
# Now change feerates to something l1 can't afford.
|
|
l1.set_feerates((200000, 200000, 200000, 200000))
|
|
|
|
# It will raise as far as it can (30551)
|
|
if 'anchors/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
|
|
maxfeerate = 30551
|
|
else:
|
|
maxfeerate = 48000
|
|
l1.daemon.wait_for_log('Setting REMOTE feerate to {}'.format(maxfeerate))
|
|
l1.daemon.wait_for_log('peer_out WIRE_UPDATE_FEE')
|
|
|
|
# But it won't do it again once it's at max.
|
|
with pytest.raises(TimeoutError):
|
|
l1.daemon.wait_for_log('peer_out WIRE_UPDATE_FEE', timeout=5)
|
|
|
|
|
|
def test_feerate_stress(node_factory, executor):
|
|
# Third node makes HTLC traffic less predictable.
|
|
l1, l2, l3 = node_factory.line_graph(3, opts={'commit-time': 100,
|
|
'may_reconnect': True,
|
|
'dev-fast-reconnect': None})
|
|
|
|
l1.pay(l2, 10**9 // 2)
|
|
scid12 = l1.get_channel_scid(l2)
|
|
scid23 = l2.get_channel_scid(l3)
|
|
|
|
routel1l3 = [{'amount_msat': '10002msat', 'id': l2.info['id'], 'delay': 11, 'channel': scid12},
|
|
{'amount_msat': '10000msat', 'id': l3.info['id'], 'delay': 5, 'channel': scid23}]
|
|
routel2l1 = [{'amount_msat': '10000msat', 'id': l1.info['id'], 'delay': 5, 'channel': scid12}]
|
|
|
|
rate = 1875
|
|
NUM_ATTEMPTS = 25
|
|
l1done = 0
|
|
l2done = 0
|
|
prev_log = 0
|
|
while l1done < NUM_ATTEMPTS and l2done < NUM_ATTEMPTS:
|
|
try:
|
|
r = random.randrange(6)
|
|
if r == 5:
|
|
l1.rpc.sendpay(routel1l3, "{:064x}".format(l1done))
|
|
l1done += 1
|
|
elif r == 4:
|
|
l2.rpc.sendpay(routel2l1, "{:064x}".format(l2done))
|
|
l2done += 1
|
|
elif r > 0:
|
|
l1.rpc.call('dev-feerate', [l2.info['id'], rate])
|
|
rate += 5
|
|
else:
|
|
l2.rpc.disconnect(l1.info['id'], True)
|
|
time.sleep(1)
|
|
except RpcError:
|
|
time.sleep(0.01)
|
|
assert not l1.daemon.is_in_log('Bad.*signature', start=prev_log)
|
|
prev_log = len(l1.daemon.logs)
|
|
|
|
# Wait for last payment
|
|
# We can get TEMPORARY_CHANNEL_FAILURE due to disconnect, too.
|
|
if l1done != 0:
|
|
with pytest.raises(RpcError, match='WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS|WIRE_TEMPORARY_CHANNEL_FAILURE'):
|
|
l1.rpc.waitsendpay("{:064x}".format(l1done - 1), timeout=TIMEOUT)
|
|
if l2done != 0:
|
|
with pytest.raises(RpcError, match='WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS|WIRE_TEMPORARY_CHANNEL_FAILURE'):
|
|
l2.rpc.waitsendpay("{:064x}".format(l2done - 1), timeout=TIMEOUT)
|
|
|
|
# Make sure it's reconnected, then try adjusting feerates
|
|
wait_for(lambda: l1.rpc.getpeer(l2.info['id'])['connected'] and l2.rpc.getpeer(l1.info['id'])['connected'])
|
|
|
|
l1.rpc.call('dev-feerate', [l2.info['id'], rate - 5])
|
|
time.sleep(1)
|
|
|
|
assert not l1.daemon.is_in_log('Bad.*signature')
|
|
assert not l2.daemon.is_in_log('Bad.*signature')
|
|
|
|
|
|
@pytest.mark.slow_test
|
|
def test_pay_disconnect_stress(node_factory, executor):
|
|
"""Expose race in htlc restoration in channeld: 50% chance of failure"""
|
|
if node_factory.valgrind:
|
|
NUM_RUNS = 2
|
|
else:
|
|
NUM_RUNS = 5
|
|
for i in range(NUM_RUNS):
|
|
l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True},
|
|
{'may_reconnect': True,
|
|
'disconnect': ['=WIRE_UPDATE_ADD_HTLC',
|
|
'-WIRE_COMMITMENT_SIGNED']}])
|
|
|
|
scid12 = l1.get_channel_scid(l2)
|
|
routel2l1 = [{'amount_msat': '10000msat', 'id': l1.info['id'], 'delay': 5, 'channel': scid12}]
|
|
|
|
# Get invoice from l1 to pay.
|
|
inv = l1.rpc.invoice(10000, "invoice", "invoice")
|
|
payhash1 = inv['payment_hash']
|
|
|
|
# Start balancing payment.
|
|
fut = executor.submit(l1.pay, l2, 10**9 // 2)
|
|
|
|
# As soon as reverse payment is accepted, reconnect.
|
|
while True:
|
|
l2.rpc.sendpay(routel2l1, payhash1, payment_secret=inv['payment_secret'])
|
|
try:
|
|
# This will usually fail with Capacity exceeded
|
|
l2.rpc.waitsendpay(payhash1, timeout=TIMEOUT)
|
|
break
|
|
except RpcError:
|
|
pass
|
|
|
|
fut.result()
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_wumbo_channels(node_factory, bitcoind):
|
|
# l3 is not wumbo.
|
|
l1, l2, l3 = node_factory.get_nodes(3, opts=[{}, {}, {'dev-force-features': '-19'}])
|
|
conn = l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
|
|
expected_features = expected_peer_features()
|
|
assert conn['features'] == expected_features
|
|
assert only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['features'] == expected_features
|
|
|
|
# Now, can we open a giant channel?
|
|
l1.fundwallet(1 << 26)
|
|
l1.rpc.fundchannel(l2.info['id'], 1 << 24)
|
|
|
|
# Get that mined, and announced.
|
|
bitcoind.generate_block(6, wait_for_mempool=1)
|
|
|
|
# Make sure l3 is ready to receive channel announcement!
|
|
sync_blockheight(bitcoind, [l1, l2, l3])
|
|
# Connect l3, get gossip.
|
|
l3.rpc.connect(l1.info['id'], 'localhost', port=l1.port)
|
|
|
|
# Make sure channel capacity is what we expected (might need to wait for
|
|
# both channel updates!
|
|
wait_for(lambda: [c['amount_msat'] for c in l3.rpc.listchannels()['channels']]
|
|
== [Millisatoshi(str(1 << 24) + "sat")] * 2)
|
|
|
|
# Make sure channel features are right from channel_announcement
|
|
assert ([c['features'] for c in l3.rpc.listchannels()['channels']]
|
|
== [expected_channel_features()] * 2)
|
|
|
|
# Make sure we can't open a wumbo channel if we don't agree.
|
|
with pytest.raises(RpcError, match='Amount exceeded'):
|
|
l1.rpc.fundchannel(l3.info['id'], 1 << 24)
|
|
|
|
# But we can open and announce a normal one.
|
|
l1.rpc.fundchannel(l3.info['id'], 'all')
|
|
bitcoind.generate_block(6, wait_for_mempool=1)
|
|
wait_for(lambda: l1.channel_state(l3) == 'CHANNELD_NORMAL')
|
|
|
|
# Make sure l2 sees correct size.
|
|
wait_for(lambda: [c['amount_msat'] for c in l2.rpc.listchannels(l1.get_channel_scid(l3))['channels']]
|
|
== [Millisatoshi(str((1 << 24) - 1) + "sat")] * 2)
|
|
|
|
# Make sure 'all' works with wumbo peers.
|
|
l1.rpc.close(l2.info['id'])
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
wait_for(lambda: l1.channel_state(l2) == 'ONCHAIN')
|
|
wait_for(lambda: l2.channel_state(l1) == 'ONCHAIN')
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], 'all')
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
wait_for(lambda: 'CHANNELD_NORMAL' in [c['state'] for c in l1.rpc.listpeerchannels(l2.info['id'])['channels']])
|
|
wait_for(lambda: 'CHANNELD_NORMAL' in [c['state'] for c in l2.rpc.listpeerchannels(l1.info['id'])['channels']])
|
|
|
|
# Exact amount depends on fees, but it will be wumbo!
|
|
chan = only_one([c for c in l1.rpc.listpeerchannels(l2.info['id'])['channels'] if c['state'] == 'CHANNELD_NORMAL'])
|
|
amount = chan['funding']['local_funds_msat']
|
|
assert amount > Millisatoshi(str((1 << 24) - 1) + "sat")
|
|
|
|
# We should know we can spend that much!
|
|
spendable = chan['spendable_msat']
|
|
assert spendable > Millisatoshi(str((1 << 24) - 1) + "sat")
|
|
|
|
# So should peer.
|
|
chan = only_one([c for c in l2.rpc.listpeerchannels(l1.info['id'])['channels'] if c['state'] == 'CHANNELD_NORMAL'])
|
|
assert chan['receivable_msat'] == spendable
|
|
|
|
# And we can wumbo pay, right?
|
|
inv = l2.rpc.invoice(str(1 << 24) + "sat", "test_wumbo_channels", "wumbo payment")
|
|
assert 'warning_mpp' not in inv
|
|
|
|
l1.rpc.pay(inv['bolt11'])
|
|
# Done in a single shot!
|
|
assert len(l1.rpc.listsendpays()['payments']) == 1
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
@pytest.mark.parametrize("anchors", [False, True])
|
|
def test_channel_features(node_factory, bitcoind, anchors):
|
|
if TEST_NETWORK == 'regtest':
|
|
if anchors is False:
|
|
opts = {'dev-force-features': "-23"}
|
|
else:
|
|
opts = {}
|
|
else:
|
|
# We have to force this ON for elements!
|
|
if anchors is False:
|
|
opts = {}
|
|
else:
|
|
opts = {'dev-force-features': "+23"}
|
|
l1, l2 = node_factory.line_graph(2, fundchannel=False, opts=opts)
|
|
|
|
bitcoind.rpc.sendtoaddress(l1.rpc.newaddr()['bech32'], 0.1)
|
|
bitcoind.generate_block(1)
|
|
wait_for(lambda: l1.rpc.listfunds()['outputs'] != [])
|
|
|
|
l1.rpc.fundchannel(l2.info['id'], 'all')
|
|
|
|
# We should see features in unconfirmed channels.
|
|
chan = only_one(l1.rpc.listpeerchannels()['channels'])
|
|
assert 'option_static_remotekey' in chan['features']
|
|
if anchors:
|
|
assert 'option_anchors' in chan['features']
|
|
|
|
# l2 should agree.
|
|
assert only_one(l2.rpc.listpeerchannels()['channels'])['features'] == chan['features']
|
|
|
|
# Confirm it.
|
|
bitcoind.generate_block(1)
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'CHANNELD_NORMAL')
|
|
wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['state'] == 'CHANNELD_NORMAL')
|
|
|
|
chan = only_one(l1.rpc.listpeerchannels()['channels'])
|
|
assert 'option_static_remotekey' in chan['features']
|
|
if anchors:
|
|
assert 'option_anchors' in chan['features']
|
|
|
|
# l2 should agree.
|
|
assert only_one(l2.rpc.listpeerchannels()['channels'])['features'] == chan['features']
|
|
|
|
|
|
def test_nonstatic_channel(node_factory, bitcoind):
|
|
"""Smoke test for a channel without option_static_remotekey"""
|
|
l1, l2 = node_factory.get_nodes(2,
|
|
# This forces us to allow send/recv of non-static-remotekey!
|
|
opts={'dev-any-channel-type': None})
|
|
l1.fundwallet(2000000)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], 'all', channel_type=[])
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
|
|
chan = only_one(l1.rpc.listpeerchannels()['channels'])
|
|
assert 'option_static_remotekey' not in chan['features']
|
|
assert 'option_anchor' not in chan['features']
|
|
assert 'option_anchors_zero_fee_htlc_tx' not in chan['features']
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'CHANNELD_NORMAL')
|
|
|
|
l1.pay(l2, 1000)
|
|
l1.rpc.close(l2.info['id'])
|
|
|
|
|
|
@pytest.mark.skip('needs blackhold support')
|
|
@pytest.mark.openchannel('v1')
|
|
def test_connection_timeout(node_factory):
|
|
# l1 hears nothing back after sending INIT, should time out.
|
|
l1, l2 = node_factory.get_nodes(2,
|
|
opts=[{'dev-timeout-secs': 1,
|
|
'disconnect': ['0WIRE_INIT', '0WIRE_INIT']},
|
|
{}])
|
|
|
|
with pytest.raises(RpcError, match='timed out'):
|
|
l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
l1.daemon.wait_for_log('conn timed out')
|
|
|
|
with pytest.raises(RpcError, match=r'(reset by peer|peer closed connection)'):
|
|
l2.rpc.connect(l1.info['id'], 'localhost', port=l1.port)
|
|
l1.daemon.wait_for_log('conn timed out')
|
|
|
|
|
|
def test_htlc_retransmit_order(node_factory, executor):
|
|
NUM_HTLCS = 10
|
|
l1, l2 = node_factory.line_graph(2,
|
|
opts=[{'may_reconnect': True,
|
|
'feerates': (7500, 7500, 7500, 7500),
|
|
'disconnect': ['=WIRE_UPDATE_ADD_HTLC*' + str(NUM_HTLCS),
|
|
'-WIRE_COMMITMENT_SIGNED'],
|
|
'dev-disable-commit-after': 0},
|
|
{'may_reconnect': True}])
|
|
invoices = [l2.rpc.invoice(1000, str(x), str(x)) for x in range(NUM_HTLCS)]
|
|
|
|
routestep = {
|
|
'amount_msat': 1000,
|
|
'id': l2.info['id'],
|
|
'delay': 5,
|
|
'channel': first_scid(l1, l2)
|
|
}
|
|
for inv in invoices:
|
|
executor.submit(l1.rpc.sendpay, [routestep], inv['payment_hash'], payment_secret=inv['payment_secret'])
|
|
|
|
l1.daemon.wait_for_log('dev_disconnect')
|
|
l1.rpc.call('dev-reenable-commit', [l2.info['id']])
|
|
l1.daemon.wait_for_log('dev_disconnect')
|
|
|
|
# Now reconnect.
|
|
l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
|
|
for inv in invoices:
|
|
result = l1.rpc.waitsendpay(inv['payment_hash'])
|
|
assert(result['status'] == 'complete')
|
|
|
|
# If order was wrong, we'll get a LOG_BROKEN and fixtures will complain.
|
|
|
|
|
|
@unittest.skipIf(True, "Currently failing, see tracking issue #4265")
|
|
@pytest.mark.openchannel('v1')
|
|
def test_fundchannel_start_alternate(node_factory, executor):
|
|
''' Test to see what happens if two nodes start channeling to
|
|
each other alternately.
|
|
Issue #4108
|
|
'''
|
|
l1, l2 = node_factory.get_nodes(2)
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.rpc.fundchannel_start(l2.info['id'], 100000)
|
|
|
|
fut = executor.submit(l2.rpc.fundchannel_start, l1.info['id'], 100000)
|
|
with pytest.raises(RpcError):
|
|
fut.result(10)
|
|
|
|
|
|
@pytest.mark.openchannel('v2')
|
|
def test_openchannel_init_alternate(node_factory, executor):
|
|
''' Test to see what happens if two nodes start channeling to
|
|
each other alternately.
|
|
'''
|
|
l1, l2 = node_factory.get_nodes(2)
|
|
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.fundwallet(2000000)
|
|
l2.fundwallet(2000000)
|
|
|
|
psbt1 = l1.rpc.fundpsbt('1000000msat', '253perkw', 250)['psbt']
|
|
psbt2 = l2.rpc.fundpsbt('1000000msat', '253perkw', 250)['psbt']
|
|
init = l1.rpc.openchannel_init(l2.info['id'], 100000, psbt1)
|
|
|
|
fut = executor.submit(l2.rpc.openchannel_init, l1.info['id'], '1000000msat', psbt2)
|
|
with pytest.raises(RpcError):
|
|
fut.result(10)
|
|
|
|
# FIXME: Clean up so it doesn't hang. Ok if these fail.
|
|
for node in [l1, l2]:
|
|
try:
|
|
node.rpc.openchannel_abort(init['channel_id'])
|
|
except RpcError:
|
|
# Ignoring all errors
|
|
print("nothing to do")
|
|
|
|
|
|
@unittest.skip("experimental-upgrade-protocol TLV fields conflict with splicing TLV fields")
|
|
def test_upgrade_statickey(node_factory, executor):
|
|
"""l1 doesn't have option_static_remotekey, l2 offers it."""
|
|
l1, l2 = node_factory.get_nodes(2, opts=[{'may_reconnect': True,
|
|
'experimental-upgrade-protocol': None,
|
|
# This forces us to allow sending non-static-remotekey!
|
|
'dev-any-channel-type': None},
|
|
{'may_reconnect': True,
|
|
# This forces us to accept non-static-remotekey!
|
|
'dev-any-channel-type': None,
|
|
'experimental-upgrade-protocol': None}])
|
|
|
|
l1.fundwallet(2000000)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], 'all', channel_type=[])
|
|
|
|
# Now reconnect.
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.daemon.wait_for_logs([r"They sent current_channel_type \[\]",
|
|
r"They offered upgrade to \[12\]"])
|
|
l2.daemon.wait_for_log(r"They sent desired_channel_type \[12\]")
|
|
|
|
l1.daemon.wait_for_log('option_static_remotekey enabled at 1/1')
|
|
l2.daemon.wait_for_log('option_static_remotekey enabled at 1/1')
|
|
|
|
# Make sure it's committed to db!
|
|
wait_for(lambda: l1.db_query('SELECT local_static_remotekey_start, remote_static_remotekey_start FROM channels;') == [{'local_static_remotekey_start': 1, 'remote_static_remotekey_start': 1}])
|
|
|
|
# They will consider themselves upgraded.
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
# They won't offer upgrade!
|
|
assert not l1.daemon.is_in_log("They offered upgrade",
|
|
start=l1.daemon.logsearch_start)
|
|
l1.daemon.wait_for_log(r"They sent current_channel_type \[12\]")
|
|
l2.daemon.wait_for_log(r"They sent desired_channel_type \[12\]")
|
|
|
|
|
|
@unittest.skip("experimental-upgrade-protocol TLV fields conflict with splicing TLV fields")
|
|
def test_upgrade_statickey_onchaind(node_factory, executor, bitcoind):
|
|
"""We test penalty before/after, and unilateral before/after"""
|
|
l1, l2 = node_factory.get_nodes(2, opts=[{'may_reconnect': True,
|
|
'experimental-upgrade-protocol': None,
|
|
# This forces us to allow sending non-static-remotekey!
|
|
'dev-any-channel-type': None,
|
|
# We try to cheat!
|
|
'broken_log': r"onchaind-chan#[0-9]*: Could not find resolution for output .*: did \*we\* cheat\?"},
|
|
{'may_reconnect': True,
|
|
# This forces us to allow non-static-remotekey!
|
|
'dev-any-channel-type': None,
|
|
'experimental-upgrade-protocol': None}])
|
|
|
|
l1.fundwallet(FUNDAMOUNT + 1000)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], 'all', channel_type=[])
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'CHANNELD_NORMAL')
|
|
|
|
# TEST 1: Cheat from pre-upgrade.
|
|
tx = l1.rpc.dev_sign_last_tx(l2.info['id'])['tx']
|
|
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.daemon.wait_for_log('option_static_remotekey enabled at 1/1')
|
|
|
|
# Make sure another commitment happens, sending failed payment.
|
|
routestep = {
|
|
'amount_msat': 1,
|
|
'id': l2.info['id'],
|
|
'delay': 5,
|
|
'channel': first_scid(l1, l2)
|
|
}
|
|
l1.rpc.sendpay([routestep], '00' * 32, payment_secret='00' * 32)
|
|
with pytest.raises(RpcError, match=r'WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS'):
|
|
l1.rpc.waitsendpay('00' * 32)
|
|
|
|
# Make sure l2 gets REVOKE_AND_ACK from previous.
|
|
l2.daemon.wait_for_log('peer_in WIRE_UPDATE_ADD_HTLC')
|
|
l2.daemon.wait_for_log('peer_out WIRE_REVOKE_AND_ACK')
|
|
l2.daemon.wait_for_log('peer_in WIRE_REVOKE_AND_ACK')
|
|
|
|
# Pre-statickey penalty works.
|
|
bitcoind.rpc.sendrawtransaction(tx)
|
|
bitcoind.generate_block(1)
|
|
|
|
_, txid, blocks = l2.wait_for_onchaind_tx('OUR_PENALTY_TX',
|
|
'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM')
|
|
assert blocks == 0
|
|
|
|
bitcoind.generate_block(100, wait_for_mempool=txid)
|
|
# This works even if they disconnect and listpeerchannels() is empty:
|
|
wait_for(lambda: l1.rpc.listpeerchannels()['channels'] == [])
|
|
wait_for(lambda: l2.rpc.listpeerchannels()['channels'] == [])
|
|
|
|
# TEST 2: Cheat from post-upgrade.
|
|
l1.fundwallet(FUNDAMOUNT + 1000)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], 'all', channel_type=[])
|
|
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
l1.daemon.wait_for_log('option_static_remotekey enabled at 1/1')
|
|
l2.daemon.wait_for_log('option_static_remotekey enabled at 1/1')
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'CHANNELD_NORMAL')
|
|
|
|
l1.pay(l2, 1000000)
|
|
|
|
# We will try to cheat later.
|
|
tx = l1.rpc.dev_sign_last_tx(l2.info['id'])['tx']
|
|
|
|
l1.pay(l2, 1000000)
|
|
|
|
# Pre-statickey penalty works.
|
|
bitcoind.rpc.sendrawtransaction(tx)
|
|
bitcoind.generate_block(1)
|
|
|
|
_, txid, blocks = l2.wait_for_onchaind_tx('OUR_PENALTY_TX',
|
|
'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM')
|
|
assert blocks == 0
|
|
|
|
bitcoind.generate_block(100, wait_for_mempool=txid)
|
|
# This works even if they disconnect and listpeers() is empty:
|
|
wait_for(lambda: len(l1.rpc.listpeerchannels()['channels']) == 0)
|
|
wait_for(lambda: len(l2.rpc.listpeerchannels()['channels']) == 0)
|
|
|
|
# TEST 3: Unilateral close from pre-upgrade
|
|
l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
l1.fundwallet(FUNDAMOUNT + 1000)
|
|
l1.rpc.fundchannel(l2.info['id'], 'all', channel_type=[])
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'CHANNELD_NORMAL')
|
|
|
|
# Give them both something for onchain close.
|
|
l1.pay(l2, 1000000)
|
|
|
|
# Make sure it's completely quiescent.
|
|
l1.daemon.wait_for_log("chan#3: Removing out HTLC 0 state RCVD_REMOVE_ACK_REVOCATION FULFILLED")
|
|
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.daemon.wait_for_log('option_static_remotekey enabled at 3/3')
|
|
|
|
# But this is the *pre*-update commit tx!
|
|
l2.stop()
|
|
l1.rpc.close(l2.info['id'], unilateraltimeout=1)
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
l2.start()
|
|
|
|
# They should both handle it fine.
|
|
_, txid, blocks = l1.wait_for_onchaind_tx('OUR_DELAYED_RETURN_TO_WALLET',
|
|
'OUR_UNILATERAL/DELAYED_OUTPUT_TO_US')
|
|
assert blocks == 4
|
|
l2.daemon.wait_for_logs(['Ignoring output .*: THEIR_UNILATERAL/OUTPUT_TO_US',
|
|
'Ignoring output .*: THEIR_UNILATERAL/DELAYED_OUTPUT_TO_THEM'])
|
|
bitcoind.generate_block(4)
|
|
bitcoind.generate_block(100, wait_for_mempool=txid)
|
|
|
|
# This works even if they disconnect and listpeerchannels() is empty:
|
|
wait_for(lambda: len(l1.rpc.listpeerchannels()['channels']) == 0)
|
|
wait_for(lambda: len(l2.rpc.listpeerchannels()['channels']) == 0)
|
|
|
|
# TEST 4: Unilateral close from post-upgrade
|
|
l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], 'all', channel_type=[])
|
|
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
l1.daemon.wait_for_log('option_static_remotekey enabled at 1/1')
|
|
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'CHANNELD_NORMAL')
|
|
|
|
# Move to static_remotekey.
|
|
l1.pay(l2, 1000000)
|
|
|
|
l2.stop()
|
|
l1.rpc.close(l2.info['id'], unilateraltimeout=1)
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
l2.start()
|
|
|
|
# They should both handle it fine.
|
|
_, txid, blocks = l1.wait_for_onchaind_tx('OUR_DELAYED_RETURN_TO_WALLET',
|
|
'OUR_UNILATERAL/DELAYED_OUTPUT_TO_US')
|
|
assert blocks == 4
|
|
l2.daemon.wait_for_logs(['Ignoring output .*: THEIR_UNILATERAL/OUTPUT_TO_US',
|
|
'Ignoring output .*: THEIR_UNILATERAL/DELAYED_OUTPUT_TO_THEM'])
|
|
|
|
bitcoind.generate_block(4)
|
|
bitcoind.generate_block(100, wait_for_mempool=txid)
|
|
|
|
# This works even if they disconnect and listpeerchannels() is empty:
|
|
wait_for(lambda: len(l2.rpc.listpeerchannels()['channels']) == 0)
|
|
|
|
|
|
@unittest.skip("experimental-upgrade-protocol TLV fields conflict with splicing TLV fields")
|
|
def test_upgrade_statickey_fail(node_factory, executor, bitcoind):
|
|
"""We reconnect at all points during retransmit, and we won't upgrade."""
|
|
l1_disconnects = ['-WIRE_COMMITMENT_SIGNED',
|
|
'-WIRE_REVOKE_AND_ACK']
|
|
l2_disconnects = ['-WIRE_REVOKE_AND_ACK',
|
|
'-WIRE_COMMITMENT_SIGNED']
|
|
|
|
l1, l2 = node_factory.get_nodes(2, opts=[{'may_reconnect': True,
|
|
'dev-no-reconnect': None,
|
|
'disconnect': l1_disconnects,
|
|
# This allows us to send non-static-remotekey!
|
|
'dev-any-channel-type': None,
|
|
'experimental-upgrade-protocol': None,
|
|
# Don't have feerate changes!
|
|
'feerates': (7500, 7500, 7500, 7500)},
|
|
{'may_reconnect': True,
|
|
'dev-no-reconnect': None,
|
|
'experimental-upgrade-protocol': None,
|
|
# This forces us to accept non-static-remotekey!
|
|
'dev-any-channel-type': None,
|
|
'disconnect': l2_disconnects,
|
|
'plugin': os.path.join(os.getcwd(), 'tests/plugins/hold_htlcs.py'),
|
|
'hold-time': 10000,
|
|
'hold-result': 'fail'}])
|
|
l1.fundwallet(FUNDAMOUNT + 1000)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
|
l1.rpc.fundchannel(l2.info['id'], 'all', channel_type=[])
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['state'] == 'CHANNELD_NORMAL')
|
|
|
|
# This HTLC will fail
|
|
l1.rpc.sendpay([{'amount_msat': 1000, 'id': l2.info['id'], 'delay': 5, 'channel': first_scid(l1, l2)}], '00' * 32, payment_secret='00' * 32)
|
|
|
|
# Each one should cause one disconnection, no upgrade.
|
|
for d in l1_disconnects + l2_disconnects:
|
|
l1.daemon.wait_for_log('Peer connection lost')
|
|
l2.daemon.wait_for_log('Peer connection lost')
|
|
assert not l1.daemon.is_in_log('option_static_remotekey enabled')
|
|
assert not l2.daemon.is_in_log('option_static_remotekey enabled')
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
line1 = l1.daemon.wait_for_log('No upgrade')
|
|
line2 = l2.daemon.wait_for_log('No upgrade')
|
|
|
|
# On the last reconnect, it retransmitted revoke_and_ack.
|
|
assert re.search('No upgrade: we retransmitted', line1)
|
|
assert re.search('No upgrade: pending changes', line2)
|
|
|
|
# Make sure we already skip the first of these.
|
|
l1.daemon.wait_for_log('billboard perm: Reconnected, and reestablished.')
|
|
assert 'option_static_remotekey' not in only_one(l1.rpc.listpeerchannels()['channels'])['features']
|
|
assert 'option_static_remotekey' not in only_one(l2.rpc.listpeerchannels()['channels'])['features']
|
|
|
|
sleeptime = 1
|
|
while True:
|
|
# Now when we reconnect, despite having an HTLC, we're quiescent.
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
oldstart = l1.daemon.logsearch_start
|
|
l1.daemon.wait_for_log('billboard perm: Reconnected, and reestablished.')
|
|
if not l1.daemon.is_in_log('No upgrade:', start=oldstart):
|
|
break
|
|
|
|
# Give it some processing time before reconnect...
|
|
time.sleep(sleeptime)
|
|
sleeptime += 1
|
|
|
|
l1.daemon.logsearch_start = oldstart
|
|
assert l1.daemon.wait_for_log('option_static_remotekey enabled at 2/2')
|
|
assert l2.daemon.wait_for_log('option_static_remotekey enabled at 2/2')
|
|
assert 'option_static_remotekey' in only_one(l1.rpc.listpeerchannels()['channels'])['features']
|
|
assert 'option_static_remotekey' in only_one(l2.rpc.listpeerchannels()['channels'])['features']
|
|
|
|
|
|
def test_quiescence(node_factory, executor):
|
|
l1, l2 = node_factory.line_graph(2)
|
|
|
|
# Works fine.
|
|
l1.pay(l2, 1000)
|
|
|
|
assert l1.rpc.call('dev-quiesce', [l2.info['id']]) == {}
|
|
|
|
# Both should consider themselves quiescent.
|
|
l1.daemon.wait_for_log("STFU complete: we are quiescent")
|
|
l2.daemon.wait_for_log("STFU complete: we are quiescent")
|
|
|
|
# Should not be able to increase fees.
|
|
l1.rpc.call('dev-feerate', [l2.info['id'], 9999])
|
|
|
|
try:
|
|
l1.daemon.wait_for_log('peer_out WIRE_UPDATE_FEE', 5)
|
|
assert False
|
|
except TimeoutError:
|
|
pass
|
|
|
|
|
|
def test_htlc_failed_noclose(node_factory):
|
|
"""Test a bug where the htlc timeout would kick in even if the HTLC failed"""
|
|
l1, l2 = node_factory.line_graph(2)
|
|
|
|
inv = l2.rpc.invoice(1000, "test", "test")
|
|
routestep = {
|
|
'amount_msat': FUNDAMOUNT * 1000,
|
|
'id': l2.info['id'],
|
|
'delay': 5,
|
|
'channel': first_scid(l1, l2)
|
|
}
|
|
|
|
# This fails at channeld
|
|
l1.rpc.sendpay([routestep], inv['payment_hash'], payment_secret=inv['payment_secret'])
|
|
with pytest.raises(RpcError, match="Capacity exceeded"):
|
|
l1.rpc.waitsendpay(inv['payment_hash'])
|
|
|
|
# Send a second one, too: make sure we don't crash.
|
|
l1.rpc.sendpay([routestep], inv['payment_hash'], payment_secret=inv['payment_secret'])
|
|
with pytest.raises(RpcError, match="Capacity exceeded"):
|
|
l1.rpc.waitsendpay(inv['payment_hash'])
|
|
|
|
time.sleep(35)
|
|
assert l1.rpc.getpeer(l2.info['id'])['connected']
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_multichan_stress(node_factory, executor, bitcoind):
|
|
"""Test multiple channels between same nodes"""
|
|
l1, l2, l3 = node_factory.line_graph(3, opts={'may_reconnect': True,
|
|
'dev-no-reconnect': None})
|
|
|
|
# Now fund *second* channel l2->l3 (slightly larger)
|
|
bitcoind.rpc.sendtoaddress(l2.rpc.newaddr()['bech32'], 0.1)
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l2])
|
|
l2.rpc.fundchannel(l3.info['id'], '0.01001btc')
|
|
assert(len(l2.rpc.listpeerchannels(l3.info['id'])['channels']) == 2)
|
|
assert(len(l3.rpc.listpeerchannels(l2.info['id'])['channels']) == 2)
|
|
|
|
# Make sure gossip works.
|
|
mine_funding_to_announce(bitcoind, [l1, l2, l3], num_blocks=6, wait_for_mempool=1)
|
|
wait_for(lambda: len(l1.rpc.listchannels(source=l3.info['id'])['channels']) == 2)
|
|
|
|
def send_many_payments():
|
|
for i in range(30):
|
|
inv = l3.rpc.invoice(100, "label-" + str(i), "desc")['bolt11']
|
|
try:
|
|
l1.rpc.pay(inv)
|
|
except RpcError:
|
|
pass
|
|
|
|
# Send a heap of payments, while reconnecting...
|
|
fut = executor.submit(send_many_payments)
|
|
|
|
for i in range(10):
|
|
l3.rpc.disconnect(l2.info['id'], force=True)
|
|
l3.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
fut.result(TIMEOUT)
|
|
|
|
wait_for(lambda: only_one(l3.rpc.listpeers(l2.info['id'])['peers'])['connected'])
|
|
inv = l3.rpc.invoice(50000000, "invoice4", "invoice4")
|
|
l1.rpc.xpay(inv['bolt11'])
|
|
|
|
|
|
def test_old_feerate(node_factory):
|
|
"""Test retransmission of old, now-unacceptable, feerate"""
|
|
l1, l2 = node_factory.line_graph(2, opts={'feerates': (75000, 75000, 75000, 75000),
|
|
'may_reconnect': True,
|
|
'dev-no-reconnect': None})
|
|
|
|
l1.pay(l2, 1000)
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
|
|
# Drop acceptable feerate by l2
|
|
l2.set_feerates((7000, 7000, 7000, 7000))
|
|
l2.restart()
|
|
|
|
# Minor change to l1, so it sends update_fee
|
|
l1.set_feerates((74900, 74900, 74900, 74900))
|
|
l1.restart()
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# This will timeout if l2 didn't accept fee.
|
|
l1.pay(l2, 1000)
|
|
|
|
|
|
def test_websocket(node_factory):
|
|
ws_port = node_factory.get_unused_port()
|
|
port = node_factory.get_unused_port()
|
|
l1, l2 = node_factory.line_graph(2,
|
|
opts=[{'addr': ':' + str(port),
|
|
'bind-addr': 'ws:127.0.0.1: ' + str(ws_port),
|
|
'dev-allow-localhost': None},
|
|
{'dev-allow-localhost': None}],
|
|
wait_for_announce=True)
|
|
# Some depend on ipv4 vs ipv6 behaviour...
|
|
for b in l1.rpc.getinfo()['binding']:
|
|
if b['type'] == 'ipv4':
|
|
assert b == {'type': 'ipv4', 'address': '0.0.0.0', 'port': port}
|
|
elif b['type'] == 'ipv6':
|
|
assert b == {'type': 'ipv6', 'address': '::', 'port': port}
|
|
else:
|
|
assert b == {'type': 'websocket',
|
|
'address': '127.0.0.1',
|
|
'subtype': 'ipv4',
|
|
'port': ws_port}
|
|
|
|
# Adapter to turn websocket into a stream "connection"
|
|
class BinWebSocket(object):
|
|
def __init__(self, hostname, port):
|
|
self.ws = websocket.WebSocket()
|
|
self.ws.connect("ws://" + hostname + ":" + str(port))
|
|
self.recvbuf = bytes()
|
|
|
|
def send(self, data):
|
|
self.ws.send(data, websocket.ABNF.OPCODE_BINARY)
|
|
|
|
def recv(self, maxlen):
|
|
while len(self.recvbuf) < maxlen:
|
|
self.recvbuf += self.ws.recv()
|
|
|
|
ret = self.recvbuf[:maxlen]
|
|
self.recvbuf = self.recvbuf[maxlen:]
|
|
return ret
|
|
|
|
ws = BinWebSocket('localhost', ws_port)
|
|
lconn = wire.LightningConnection(ws,
|
|
wire.PublicKey(bytes.fromhex(l1.info['id'])),
|
|
wire.PrivateKey(bytes([1] * 32)),
|
|
is_initiator=True)
|
|
|
|
l1.daemon.wait_for_log('Websocket connection in from')
|
|
|
|
# Perform handshake.
|
|
lconn.shake()
|
|
|
|
# Expect to receive init msg.
|
|
msg = lconn.read_message()
|
|
assert int.from_bytes(msg[0:2], 'big') == 16
|
|
|
|
# Echo same message back.
|
|
lconn.send_message(msg)
|
|
|
|
# Now try sending a ping, ask for 50 bytes
|
|
msg = bytes((0, 18, 0, 50, 0, 0))
|
|
lconn.send_message(msg)
|
|
|
|
# Could actually reply with some gossip msg!
|
|
while True:
|
|
msg = lconn.read_message()
|
|
if int.from_bytes(msg[0:2], 'big') == 19:
|
|
break
|
|
|
|
# Check node_announcement does NOT have websocket
|
|
assert not any([a['type'] == 'websocket'
|
|
for a in only_one(l2.rpc.listnodes(l1.info['id'])['nodes'])['addresses']])
|
|
|
|
|
|
def test_ping_timeout(node_factory):
|
|
# Disconnects after this, but doesn't know it.
|
|
l1_disconnects = ['xWIRE_PING']
|
|
|
|
# We remove the gossip_queries feature: otherwise the peer can try to do
|
|
# a gossip sync, and so we never get the period of no-traffic required to
|
|
# trigger a ping!
|
|
l1, l2 = node_factory.get_nodes(2, opts=[{'dev-no-reconnect': None,
|
|
'dev-force-features': -7,
|
|
'disconnect': l1_disconnects},
|
|
{'dev-no-ping-timer': None,
|
|
'dev-force-features': -7}])
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# Ping timers runs at 15-45 seconds, *but* only fires if also 60 seconds
|
|
# after previous traffic.
|
|
l1.daemon.wait_for_log('dev_disconnect: xWIRE_PING', timeout=60 + 45 + 5)
|
|
|
|
# Next pign will cause hangup
|
|
l1.daemon.wait_for_log('Last ping unreturned: hanging up', timeout=45 + 5)
|
|
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'] == [])
|
|
|
|
|
|
@pytest.mark.openchannel('v1')
|
|
@pytest.mark.openchannel('v2')
|
|
def test_multichan(node_factory, executor, bitcoind):
|
|
"""Test multiple channels between same nodes"""
|
|
l1, l2, l3 = node_factory.line_graph(3, opts={'may_reconnect': True})
|
|
|
|
scid12 = l1.get_channel_scid(l2)
|
|
scid23a = l2.get_channel_scid(l3)
|
|
|
|
# Now fund *second* channel l2->l3 (slightly larger)
|
|
bitcoind.rpc.sendtoaddress(l2.rpc.newaddr()['bech32'], 0.1)
|
|
bitcoind.generate_block(1)
|
|
sync_blockheight(bitcoind, [l1, l2, l3])
|
|
l2.rpc.fundchannel(l3.info['id'], '0.01001btc')
|
|
assert(len(l2.rpc.listpeerchannels(l3.info['id'])['channels']) == 2)
|
|
assert(len(l3.rpc.listpeerchannels(l2.info['id'])['channels']) == 2)
|
|
|
|
bitcoind.generate_block(1, wait_for_mempool=1)
|
|
sync_blockheight(bitcoind, [l1, l2, l3])
|
|
# Make sure new channel is also CHANNELD_NORMAL
|
|
wait_for(lambda: [c['state'] for c in l2.rpc.listpeerchannels(l3.info['id'])['channels']] == ["CHANNELD_NORMAL", "CHANNELD_NORMAL"])
|
|
|
|
# Dance around to get the *other* scid.
|
|
wait_for(lambda: all(['short_channel_id' in c for c in l3.rpc.listpeerchannels()['channels']]))
|
|
scids = [c['short_channel_id'] for c in l3.rpc.listpeerchannels()['channels']]
|
|
assert len(scids) == 2
|
|
|
|
if scids[0] == scid23a:
|
|
scid23b = scids[1]
|
|
else:
|
|
assert scids[1] == scid23a
|
|
scid23b = scids[0]
|
|
|
|
# Test paying by each,
|
|
route = [{'amount_msat': 100001001,
|
|
'id': l2.info['id'],
|
|
'delay': 11,
|
|
# Unneeded
|
|
'channel': scid12},
|
|
{'amount_msat': 100000000,
|
|
'id': l3.info['id'],
|
|
'delay': 5,
|
|
'channel': scid23a}]
|
|
|
|
before = l2.rpc.listpeerchannels(l3.info['id'])['channels']
|
|
inv1 = l3.rpc.invoice(100000000, "invoice", "invoice")
|
|
l1.rpc.sendpay(route, inv1['payment_hash'], payment_secret=inv1['payment_secret'])
|
|
l1.rpc.waitsendpay(inv1['payment_hash'])
|
|
|
|
# Wait until HTLCs fully settled
|
|
wait_for(lambda: [c['htlcs'] for c in l2.rpc.listpeerchannels(l3.info['id'])['channels']] == [[], []])
|
|
after = l2.rpc.listpeerchannels(l3.info['id'])['channels']
|
|
|
|
if before[0]['short_channel_id'] == scid23a:
|
|
chan23a_idx = 0
|
|
chan23b_idx = 1
|
|
else:
|
|
chan23a_idx = 1
|
|
chan23b_idx = 0
|
|
|
|
# Gratuitous reconnect
|
|
with pytest.raises(RpcError, match=r"Peer has \(at least one\) channel"):
|
|
l3.rpc.disconnect(l2.info['id'])
|
|
l3.rpc.disconnect(l2.info['id'], force=True)
|
|
l3.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# Check it used the larger channel!
|
|
assert before[chan23a_idx]['to_us_msat'] == after[chan23a_idx]['to_us_msat']
|
|
assert before[chan23b_idx]['to_us_msat'] != after[chan23b_idx]['to_us_msat']
|
|
|
|
before = l2.rpc.listpeerchannels(l3.info['id'])['channels']
|
|
route[1]['channel'] = scid23b
|
|
inv2 = l3.rpc.invoice(100000000, "invoice2", "invoice2")
|
|
l1.rpc.sendpay(route, inv2['payment_hash'], payment_secret=inv2['payment_secret'])
|
|
l1.rpc.waitsendpay(inv2['payment_hash'])
|
|
# Wait until HTLCs fully settled
|
|
wait_for(lambda: [c['htlcs'] for c in l2.rpc.listpeerchannels(l3.info['id'])['channels']] == [[], []])
|
|
after = l2.rpc.listpeerchannels(l3.info['id'])['channels']
|
|
|
|
# Now the first channel is larger!
|
|
assert before[chan23a_idx]['to_us_msat'] != after[chan23a_idx]['to_us_msat']
|
|
assert before[chan23b_idx]['to_us_msat'] == after[chan23b_idx]['to_us_msat']
|
|
|
|
# Make sure gossip works.
|
|
bitcoind.generate_block(5)
|
|
sync_blockheight(bitcoind, [l1, l2, l3])
|
|
|
|
wait_for(lambda: len(l1.rpc.listchannels(source=l3.info['id'])['channels']) == 2)
|
|
|
|
chans = l1.rpc.listchannels(source=l3.info['id'])['channels']
|
|
if chans[0]['short_channel_id'] == scid23a:
|
|
chan23a = chans[0]
|
|
chan23b = chans[1]
|
|
else:
|
|
chan23a = chans[1]
|
|
chan23b = chans[0]
|
|
|
|
assert chan23a['amount_msat'] == Millisatoshi(1000000000)
|
|
assert chan23a['short_channel_id'] == scid23a
|
|
assert chan23b['amount_msat'] == Millisatoshi(1001000000)
|
|
assert chan23b['short_channel_id'] == scid23b
|
|
|
|
# We can close one, other one is still fine.
|
|
with pytest.raises(RpcError, match="Peer has multiple channels"):
|
|
l2.rpc.close(l3.info['id'])
|
|
|
|
l2.rpc.close(scid23b)
|
|
bitcoind.generate_block(13, wait_for_mempool=1)
|
|
sync_blockheight(bitcoind, [l1, l2, l3])
|
|
|
|
# Gossip works as expected.
|
|
wait_for(lambda: len(l1.rpc.listchannels(source=l3.info['id'])['channels']) == 1)
|
|
assert only_one(l1.rpc.listchannels(source=l3.info['id'])['channels'])['short_channel_id'] == scid23a
|
|
|
|
# We can actually pay by *closed* scid (at least until it's completely forgotten)
|
|
route[1]['channel'] = scid23a
|
|
inv3 = l3.rpc.invoice(100000000, "invoice3", "invoice3")
|
|
l1.rpc.sendpay(route, inv3['payment_hash'], payment_secret=inv3['payment_secret'])
|
|
l1.rpc.waitsendpay(inv3['payment_hash'])
|
|
|
|
# Restart with multiple channels works.
|
|
l3.restart()
|
|
# FIXME: race against autoconnect can cause spurious failure (but we connect!)
|
|
try:
|
|
l3.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
except RpcError:
|
|
wait_for(lambda: only_one(l3.rpc.listpeers(l2.info['id'])['peers'])['connected'])
|
|
|
|
inv4 = l3.rpc.invoice(100000000, "invoice4", "invoice4")
|
|
l1.rpc.pay(inv4['bolt11'])
|
|
|
|
# A good place to test listhtlcs!
|
|
wait_for(lambda: all([h['state'] == 'RCVD_REMOVE_ACK_REVOCATION' for h in l1.rpc.listhtlcs()['htlcs']]))
|
|
|
|
l1htlcs = l1.rpc.listhtlcs()['htlcs']
|
|
assert l1htlcs == l1.rpc.listhtlcs(scid12)['htlcs']
|
|
assert l1htlcs == [{"short_channel_id": scid12,
|
|
"id": 0,
|
|
"created_index": 1,
|
|
"updated_index": 9,
|
|
"expiry": 117,
|
|
"direction": "out",
|
|
"amount_msat": Millisatoshi(100001001),
|
|
"payment_hash": inv1['payment_hash'],
|
|
"state": "RCVD_REMOVE_ACK_REVOCATION"},
|
|
{"short_channel_id": scid12,
|
|
"id": 1,
|
|
"created_index": 2,
|
|
"updated_index": 18,
|
|
"expiry": 117,
|
|
"direction": "out",
|
|
"amount_msat": Millisatoshi(100001001),
|
|
"payment_hash": inv2['payment_hash'],
|
|
"state": "RCVD_REMOVE_ACK_REVOCATION"},
|
|
{"short_channel_id": scid12,
|
|
"id": 2,
|
|
"created_index": 3,
|
|
"updated_index": 27,
|
|
"expiry": 135,
|
|
"direction": "out",
|
|
"amount_msat": Millisatoshi(100001001),
|
|
"payment_hash": inv3['payment_hash'],
|
|
"state": "RCVD_REMOVE_ACK_REVOCATION"},
|
|
{"short_channel_id": scid12,
|
|
"id": 3,
|
|
"created_index": 4,
|
|
"updated_index": 36,
|
|
"expiry": 135,
|
|
"direction": "out",
|
|
"amount_msat": Millisatoshi(100001001),
|
|
"payment_hash": inv4['payment_hash'],
|
|
"state": "RCVD_REMOVE_ACK_REVOCATION"}]
|
|
|
|
# Reverse direction, should match l2's view of channel.
|
|
for h in l1htlcs:
|
|
h['direction'] = 'in'
|
|
h['state'] = 'SENT_REMOVE_ACK_REVOCATION'
|
|
# These won't match!
|
|
del h['created_index']
|
|
del h['updated_index']
|
|
|
|
l2htlcs = l2.rpc.listhtlcs(scid12)['htlcs']
|
|
for h in l2htlcs:
|
|
del h['created_index']
|
|
del h['updated_index']
|
|
|
|
assert l2htlcs == l1htlcs
|
|
|
|
|
|
def test_mutual_reconnect_race(node_factory, executor, bitcoind):
|
|
"""Test simultaneous reconnect between nodes"""
|
|
l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True,
|
|
'dev-no-reconnect': None})
|
|
|
|
def send_many_payments():
|
|
for i in range(20):
|
|
time.sleep(0.5)
|
|
inv = l2.rpc.invoice(
|
|
100 - i, # Ensure prior chanhints don't block us
|
|
"label-" + str(i),
|
|
"desc"
|
|
)['bolt11']
|
|
try:
|
|
l1.rpc.pay(inv)
|
|
except RpcError:
|
|
pass
|
|
|
|
# Send a heap of payments, while reconnecting...
|
|
fut = executor.submit(send_many_payments)
|
|
|
|
for i in range(10):
|
|
try:
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
except RpcError:
|
|
pass
|
|
time.sleep(1)
|
|
# Aim for both at once!
|
|
executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.port)
|
|
executor.submit(l2.rpc.connect, l1.info['id'], 'localhost', l1.port)
|
|
|
|
# Wait for things to settle down, then make sure we're actually connected.
|
|
# Naively, you'd think we should be, but in fact, two connects which race
|
|
# can (do!) result in both disconnecting, thinking the other side is more
|
|
# recent.
|
|
time.sleep(1)
|
|
if not only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected']:
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# Now payments should finish!
|
|
fut.result(TIMEOUT)
|
|
|
|
wait_for(lambda: only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected'])
|
|
inv = l2.rpc.invoice(100000000, "invoice4", "invoice4")
|
|
l1.rpc.pay(inv['bolt11'])
|
|
|
|
|
|
def test_no_reconnect_awating_unilateral(node_factory, bitcoind):
|
|
l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True})
|
|
l2.stop()
|
|
|
|
# Close immediately.
|
|
l1.rpc.close(l2.info['id'], 1)
|
|
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['state'] == 'AWAITING_UNILATERAL')
|
|
|
|
# After switching to AWAITING_UNILATERAL it will *not* try to reconnect.
|
|
l1.daemon.wait_for_log("{}-connectd: peer_downgrade".format(l2.info['id']))
|
|
time.sleep(10)
|
|
|
|
assert not l1.daemon.is_in_log('Will try reconnect', start=l1.daemon.logsearch_start)
|
|
|
|
|
|
def test_peer_disconnected_reflected_in_channel_state(node_factory):
|
|
"""
|
|
Make sure that if a node is disconnected we have the value correct value
|
|
across listpeer and listpeerchannels.
|
|
"""
|
|
l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True})
|
|
l2.stop()
|
|
|
|
wait_for(lambda: only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected'] is False)
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['peer_connected'] is False)
|
|
|
|
|
|
def test_peer_disconnected_has_featurebits(node_factory):
|
|
"""
|
|
Make sure that if a node is restarted, it still remembers feature
|
|
bits from a peer it has a channel with but isn't connected to
|
|
"""
|
|
l1, l2 = node_factory.line_graph(2)
|
|
|
|
expected_features = expected_peer_features()
|
|
|
|
l1_features = only_one(l2.rpc.listpeers()['peers'])['features']
|
|
l2_features = only_one(l1.rpc.listpeers()['peers'])['features']
|
|
assert l1_features == expected_features
|
|
assert l2_features == expected_features
|
|
|
|
l1.stop()
|
|
l2.stop()
|
|
|
|
# Ensure we persisted feature bits and return them even when disconnected
|
|
l1.start()
|
|
|
|
wait_for(lambda: only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected'] is False)
|
|
wait_for(lambda: only_one(l1.rpc.listpeers()['peers'])['features'] == expected_features)
|
|
|
|
|
|
def test_reconnect_no_additional_transient_failure(node_factory, bitcoind):
|
|
l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True},
|
|
{'may_reconnect': True,
|
|
'dev-no-reconnect': None}])
|
|
l1id = l1.info['id']
|
|
l2id = l2.info['id']
|
|
# We wait until conenction is established and channel is NORMAL
|
|
l2.daemon.wait_for_logs([f"{l1id}-connectd: Handed peer, entering loop",
|
|
f"{l1id}-chan#1: State changed from CHANNELD_AWAITING_LOCKIN to CHANNELD_NORMAL"])
|
|
# We now stop l1
|
|
l1.stop()
|
|
# We wait for l2 to disconnect, ofc we also see an expected "Peer transient failure" here.
|
|
l2.daemon.wait_for_logs([f"{l1id}-channeld-chan#1: Peer connection lost",
|
|
f"{l1id}-lightningd: peer_disconnect_done",
|
|
f"{l1id}-chan#1: Peer transient failure in CHANNELD_NORMAL: channeld: Owning subdaemon channeld died"])
|
|
|
|
# When we restart l1 we should not see another Peer transient failure message.
|
|
offset1 = l1.daemon.logsearch_start
|
|
l1.start()
|
|
|
|
# We wait until l2 is fine again with l1
|
|
l2.daemon.wait_for_log(f"{l1id}-connectd: Handed peer, entering loop")
|
|
|
|
time.sleep(5)
|
|
|
|
# We should not see a "Peer transient failure" after restart of l1
|
|
assert not l1.daemon.is_in_log(f"{l2id}-chan#1: Peer transient failure in CHANNELD_NORMAL: Disconnected", start=offset1)
|
|
|
|
|
|
@pytest.mark.xfail(strict=True)
|
|
def test_offline(node_factory):
|
|
# if get_node starts it, it'll expect an address, so do it manually.
|
|
l1 = node_factory.get_node(options={"offline": None}, start=False)
|
|
l1.daemon.start()
|
|
|
|
# we expect it to log offline mode an not to create any listener
|
|
assert l1.daemon.is_in_log("Started in offline mode!")
|
|
assert not l1.daemon.is_in_log("connectd: Created listener on")
|
|
|
|
|
|
def test_last_stable_connection(node_factory):
|
|
l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True})
|
|
|
|
# We wait a minute to be stable.
|
|
STABLE_TIME = 60
|
|
assert 'last_stable_connection' not in only_one(l1.rpc.listpeerchannels()['channels'])
|
|
assert 'last_stable_connection' not in only_one(l2.rpc.listpeerchannels()['channels'])
|
|
|
|
recon_time = time.time()
|
|
|
|
# This take a minute, so don't fail if TIMEOUT is set to 10.
|
|
wait_for(lambda: 'last_stable_connection' in only_one(l1.rpc.listpeerchannels()['channels']), timeout=STABLE_TIME + 15)
|
|
l1stable = only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection']
|
|
wait_for(lambda: 'last_stable_connection' in only_one(l2.rpc.listpeerchannels()['channels']))
|
|
l2stable = only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection']
|
|
|
|
# Disconnect, and/or restart then reconnect.
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
recon_time = int(time.time())
|
|
l2.restart()
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
assert only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection'] == l1stable
|
|
assert only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection'] == l2stable
|
|
wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection'] != l1stable, timeout=STABLE_TIME + 15)
|
|
wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection'] != l2stable)
|
|
|
|
assert only_one(l1.rpc.listpeerchannels()['channels'])['last_stable_connection'] >= recon_time + STABLE_TIME
|
|
assert only_one(l2.rpc.listpeerchannels()['channels'])['last_stable_connection'] >= recon_time + STABLE_TIME
|
|
|
|
|
|
def test_wss_proxy(node_factory):
|
|
wss_port = node_factory.get_unused_port()
|
|
ws_port = node_factory.get_unused_port()
|
|
port = node_factory.get_unused_port()
|
|
wss_proxy_certs = node_factory.directory + '/wss-proxy-certs'
|
|
l1 = node_factory.get_node(options={'addr': ':' + str(port),
|
|
'bind-addr': 'ws:127.0.0.1:' + str(ws_port),
|
|
'wss-bind-addr': '127.0.0.1:' + str(wss_port),
|
|
'wss-certs': wss_proxy_certs,
|
|
'dev-allow-localhost': None})
|
|
|
|
# Some depend on ipv4 vs ipv6 behaviour...
|
|
for b in l1.rpc.getinfo()['binding']:
|
|
if b['type'] == 'ipv4':
|
|
assert b == {'type': 'ipv4', 'address': '0.0.0.0', 'port': port}
|
|
elif b['type'] == 'ipv6':
|
|
assert b == {'type': 'ipv6', 'address': '::', 'port': port}
|
|
else:
|
|
assert b == {'type': 'websocket',
|
|
'address': '127.0.0.1',
|
|
'subtype': 'ipv4',
|
|
'port': ws_port}
|
|
|
|
# Adapter to turn web secure socket into a stream "connection"
|
|
class BindWebSecureSocket(object):
|
|
def __init__(self, hostname, port):
|
|
certfile = f'{wss_proxy_certs}/client.pem'
|
|
keyfile = f'{wss_proxy_certs}/client-key.pem'
|
|
self.ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE, "ssl_version": ssl.PROTOCOL_TLS_CLIENT, "certfile": certfile, "keyfile": keyfile})
|
|
self.ws.connect("wss://" + hostname + ":" + str(port))
|
|
self.recvbuf = bytes()
|
|
|
|
def send(self, data):
|
|
self.ws.send(data, websocket.ABNF.OPCODE_BINARY)
|
|
|
|
def recv(self, maxlen):
|
|
while len(self.recvbuf) < maxlen:
|
|
self.recvbuf += self.ws.recv()
|
|
|
|
ret = self.recvbuf[:maxlen]
|
|
self.recvbuf = self.recvbuf[maxlen:]
|
|
return ret
|
|
|
|
# There can be a delay between the printing of "Websocket Secure Server Started"
|
|
# and actually binding the port. There's no obvious way to delay that message
|
|
# it's done. So we sleep here.
|
|
time.sleep(10)
|
|
|
|
wss = BindWebSecureSocket('localhost', wss_port)
|
|
|
|
lconn = wire.LightningConnection(wss,
|
|
wire.PublicKey(bytes.fromhex(l1.info['id'])),
|
|
wire.PrivateKey(bytes([1] * 32)),
|
|
is_initiator=True)
|
|
|
|
# This might happen really early!
|
|
l1.daemon.logsearch_start = 0
|
|
l1.daemon.wait_for_log(r'Websocket Secure Server Started')
|
|
|
|
# Perform handshake.
|
|
lconn.shake()
|
|
|
|
# Expect to receive init msg.
|
|
msg = lconn.read_message()
|
|
assert int.from_bytes(msg[0:2], 'big') == 16
|
|
|
|
# Echo same message back.
|
|
lconn.send_message(msg)
|
|
|
|
# Now try sending a ping, ask for 50 bytes
|
|
msg = bytes((0, 18, 0, 50, 0, 0))
|
|
lconn.send_message(msg)
|
|
|
|
# Could actually reply with some gossip msg!
|
|
while True:
|
|
msg = lconn.read_message()
|
|
if int.from_bytes(msg[0:2], 'big') == 19:
|
|
break
|
|
|
|
|
|
def test_connect_transient(node_factory):
|
|
l1, l2, l3, l4 = node_factory.get_nodes(4, opts={'may_reconnect': True})
|
|
|
|
# This is not transient, because they have a channel
|
|
node_factory.join_nodes([l1, l2])
|
|
|
|
# Make sure it reconnects once it has a channel.
|
|
l1.rpc.disconnect(l2.info['id'], force=True)
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
|
|
|
# This has no channel, and thus is a transient.
|
|
l1.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
|
|
|
l1.rpc.dev_connectd_exhaust_fds()
|
|
|
|
# Connecting to l4 will discard connection to l3!
|
|
l1.rpc.connect(l4.info['id'], 'localhost', l4.port)
|
|
assert l1.rpc.listpeers(l3.info['id'])['peers'] == []
|
|
assert l1.daemon.is_in_log(fr"due to stress, randomly closing peer {l3.info['id']} \(score 0\)")
|
|
|
|
|
|
def test_connect_transient_pending(node_factory, bitcoind, executor):
|
|
"""Test that we kick out in-connection transient connections"""
|
|
l1, l2, l3, l4 = node_factory.get_nodes(4, opts=[{},
|
|
{'dev-handshake-no-reply': None},
|
|
{'dev-handshake-no-reply': None},
|
|
{}])
|
|
|
|
# This will block...
|
|
fut1 = executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.port)
|
|
fut2 = executor.submit(l1.rpc.connect, l3.info['id'], 'localhost', l3.port)
|
|
|
|
assert not l1.daemon.is_in_log("due to stress, closing transient connect attempt")
|
|
|
|
# Wait until those connects in progress.
|
|
l2.daemon.wait_for_log("Connect IN")
|
|
l3.daemon.wait_for_log("Connect IN")
|
|
|
|
# Now force exhaustion.
|
|
l1.rpc.dev_connectd_exhaust_fds()
|
|
|
|
# This one will kick out one of the others.
|
|
l1.rpc.connect(l4.info['id'], 'localhost', l4.port)
|
|
line = l1.daemon.wait_for_log("due to stress, closing transient connect attempt")
|
|
peerid = re.search(r'due to stress, closing transient connect attempt to (.*)', line).groups()[0]
|
|
|
|
with pytest.raises(RpcError, match="Terminated due to too many connections"):
|
|
if peerid == l2.info['id']:
|
|
fut1.result(TIMEOUT)
|
|
else:
|
|
fut2.result(TIMEOUT)
|
|
|
|
|
|
def test_injectonionmessage(node_factory):
|
|
"""Test for injectonionmessage API"""
|
|
l1, l2 = node_factory.line_graph(2)
|
|
|
|
# This is deterministic, so the onion message created by fetchinvoice can be replayed here
|
|
# manually
|
|
l2.rpc.offer("any")
|
|
# We saved the output from `l1.rpc.fetchinvoice(offer['bolt12'], 200)` with some logging.
|
|
l1.rpc.injectonionmessage(message='0002cb7cd2001e3c670d64135542dcefdf4a3f590eb142cee9277b317848471906caeabe4afeae7f4e31f6ca9c119b643d5369c5e55f892f205469a185f750697124a2bb7ccea1245ec12d76340bcf7371ba6d1c9ddfe09b4153fce524417c14a594fdbb5e7c698a5daffe77db946727a38711be2ecdebdd347d2a9f990810f2795b3c39b871d7c72a11534bd388ca2517630263d96d8cc72d146bae800638066175c85a8e8665160ea332ed7d27efc31c960604d61c3f83801c25cbb69ae3962c2ef13b1fa9adc8dcbe3dc8d9a5e27ff5669e076b02cafef8f2c88fc548e03642180d57606386ad6ce27640339747d40f26eb5b9e93881fc8c16d5896122032b64bb5f1e4be6f41f5fa4dbd7851989aeccd80b2d5f6f25427f171964146185a8eaa57891d91e49a4d378743231e19edd5994c3118c9a415958a5d9524a6ecc78c0205f5c0059a7fbcf1abad706a189b712476d112521c9a4650d0ff09890536acae755a2b07d00811044df28b288d3dc2d5ae3f8bf3cf7a2950e2167105dfad0fb8398ef08f36abcdb1bfd6aca3241c33810f0750f35bdfb7c60b1759275b7704ab1bc8f3ea375b3588eab10e4f948f12fe0a3c77b67bebeedbcced1de0f0715f9959e5497cda5f8f6ab76c15b3dcc99956465de1bf2855338930650f8e8e8c391d9bb8950125dd60d8289dade0556d9dc443761983e26adcc223412b756e2fd9ad64022859b6cab20e8ffc3cf39ae6045b2c3338b1145ee3719a098e58c425db764d7f9a5034dbb730c20202f79bc3c53fab78ecd530aa0e8f7698c9ea53cb96dc9c639282c362d31177c5b81979f46f2db6090b8e171db47287523f28c462e35ef489b51426387f2709c342083968153b5f8a51cd5716b38106bb0f21c5ccfc28dd7c74b71c8367ae8ca348f66a7996bbc535076a1f65d9109658ec042257ca7523488fb1807dc8bec42739ccae066739cf58083b4e2c65e52e1747a6ec2aa26338bb6f2c3195a2b160e26dec70a2cfde269fa7c10c45d346a8bcc313bb618324edadc0291d15f4dc00ca3a7ad7131045fdf6978ba52178f4699525efcb8d96561630e2f28eaa97c66c38c66301b6c6f0124b550db620b09f35b9d45d1441cab7d93be5e3c39b9becfab7f8d05dd3a7a6e27a1d3f23f1dd01e967f5206600619f75439181848f7f4148216c11314b4eaf64c28c268ad4b33ea821d57728e9a9e9e1b6c4bcf35d14958295fc5f92bd6846f33c46f5fa20f569b25bc916b94e554f27a37448f873497e13baef8c740a7587828cc4136dd21b8584e6983e376e91663f8f91559637738b400fb49940fc2df299dfd448604b63c2f5d1f1ec023636f3baf2be5730364afd38191726a7c0d9477b1f231da4d707aabc6ad8036488181dbdb16b48500f2333036629004504d3524f87ece6afb04c4ba03ea6fce069e98b1ab7bf51f237d7c0f40756744dd703c6023b6461b90730f701404e8dddfaff40a9a60e670be7729556241fc9cc8727a586e38b71616bff8772c873b37d920d51a6ad31219a24b12f268545e2cfeb9e662236ab639fd4ecf865612678471ff7b320c934a13ca1f2587fc6a90f839c3c81c0ff84b51330820431418918e8501844893b53c1e0de46d51a64cb769974a996c58ff06683ebdc46fd4bb8e857cecebab785a351c64fd486fb648d25936cb09327b70d22c243035d4343fa3d2d148e2df5cd928010e34ae42b0333e698142050d9405b39f3aa69cecf8a388afbc7f199077b911cb829480f0952966956fe57d815f0d2467f7b28af11f8820645b601c0e1ad72a4684ebc60287d23ec3502f4c65ca44f5a4a0d79e3a5718cd23e7538cb35c57673fb9a1173e5526e767768117c7fefc2e3718f44f790b27e61995fecc6aef05107e75355be301ebe1500c147bb655a159f', path_key='03ccf3faa19e8d124f27d495e3359f4002a6622b9a02df9a51b609826d354cda52')
|
|
|
|
# We should get a reply!
|
|
l1.daemon.wait_for_log('lightningd: Got onionmsg with pathsecret')
|
|
|
|
|
|
def test_connect_ratelimit(node_factory, bitcoind):
|
|
"""l1 has 5 peers, restarts, make sure we limit"""
|
|
nodes = node_factory.get_nodes(6,
|
|
opts=[{'dev-limit-connections-inflight': None, 'may_reconnect': True}] + [{'may_reconnect': True}] * 5)
|
|
|
|
l1 = nodes[0]
|
|
nodes = nodes[1:]
|
|
|
|
addr = l1.rpc.newaddr()['bech32']
|
|
for n in nodes:
|
|
bitcoind.rpc.sendtoaddress(addr, (FUNDAMOUNT + 1000000) / 10**8)
|
|
bitcoind.generate_block(1, wait_for_mempool=len(nodes))
|
|
sync_blockheight(bitcoind, [l1])
|
|
|
|
for n in nodes:
|
|
l1.rpc.connect(n.info['id'], 'localhost', n.port)
|
|
l1.rpc.fundchannel(n.info['id'], FUNDAMOUNT)
|
|
|
|
# Make sure all channels are established and announced.
|
|
bitcoind.generate_block(6, wait_for_mempool=len(nodes))
|
|
wait_for(lambda: len(l1.rpc.listchannels()['channels']) == len(nodes) * 2)
|
|
|
|
assert not l1.daemon.is_in_log('Unblocking for')
|
|
|
|
l1.stop()
|
|
# Suspend the others, to make sure they cannot respond too fast.
|
|
for n in nodes:
|
|
os.kill(n.daemon.proc.pid, signal.SIGSTOP)
|
|
|
|
try:
|
|
l1.start()
|
|
|
|
# The first will be ok, but others should block and be unblocked.
|
|
l1.daemon.wait_for_logs((['Unblocking for ']
|
|
+ ['Too many connections, waiting'])
|
|
* (len(nodes) - 1))
|
|
except Exception as err:
|
|
# Resume, so pytest doesn't hang!
|
|
for n in nodes:
|
|
os.kill(n.daemon.proc.pid, signal.SIGCONT)
|
|
raise err
|
|
|
|
# Resume them
|
|
for n in nodes:
|
|
os.kill(n.daemon.proc.pid, signal.SIGCONT)
|
|
|
|
# And now they're all connected
|
|
wait_for(lambda: [p['connected'] for p in l1.rpc.listpeers()['peers']] == [True] * len(nodes))
|
|
|
|
|
|
def test_onionmessage_forward_fail(node_factory, bitcoind):
|
|
# The plugin will try to connect to l3, so it needs an advertized address.
|
|
l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True,
|
|
opts=[{},
|
|
{'dev-allow-localhost': None,
|
|
'may_reconnect': True,
|
|
'dev-no-reconnect': None,
|
|
'plugin': os.path.join(os.getcwd(), 'tests/plugins/onionmessage_forward_fail_notification.py'),
|
|
},
|
|
{'dev-allow-localhost': None,
|
|
'dev-no-reconnect': None,
|
|
'may_reconnect': True}])
|
|
|
|
offer = l3.rpc.offer(300, "test_onionmessage_forward_fail")
|
|
l2.rpc.disconnect(l3.info['id'], force=True)
|
|
|
|
# The plugin in l2 fixes up the connection, so this works!
|
|
l1.rpc.fetchinvoice(offer['bolt12'])
|
|
|
|
l2.daemon.is_in_log('plugin-onionmessage_forward_fail_notification.py: Received onionmessage_forward_fail')
|
|
|
|
|
|
def test_private_channel_no_reconnect(node_factory):
|
|
l1, l2 = node_factory.line_graph(2,
|
|
announce_channels=False,
|
|
wait_for_announce=False,
|
|
opts={'dev-no-reconnect-private': None,
|
|
'may_reconnect': True})
|
|
l3, l4 = node_factory.line_graph(2,
|
|
announce_channels=True,
|
|
wait_for_announce=False,
|
|
opts={'dev-no-reconnect-private': None,
|
|
'may_reconnect': True})
|
|
|
|
# test for 'private' flag in rpc output
|
|
assert only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['private']
|
|
|
|
# l1 won't even *try* to reconnect on restart.
|
|
l1.restart()
|
|
|
|
# l3 will.
|
|
l3.restart()
|
|
|
|
wait_for(lambda: only_one(l3.rpc.listpeers()['peers'])['connected'] is True)
|
|
|
|
assert only_one(l1.rpc.listpeers()['peers'])['connected'] is False
|
|
|
|
|
|
@unittest.skipIf(VALGRIND, "We assume machine is reasonably fast")
|
|
def test_no_delay(node_factory):
|
|
"""Is our Nagle disabling for critical messages working?"""
|
|
l1, l2 = node_factory.line_graph(2)
|
|
|
|
scid = only_one(l1.rpc.listpeerchannels()['channels'])['short_channel_id']
|
|
routestep = {
|
|
'amount_msat': 100,
|
|
'id': l2.info['id'],
|
|
'delay': 5,
|
|
'channel': scid
|
|
}
|
|
start = time.time()
|
|
# If we were stupid enough to leave Nagle enabled, this would add 200ms
|
|
# seconds delays each way!
|
|
for _ in range(100):
|
|
phash = random.randbytes(32).hex()
|
|
l1.rpc.sendpay([routestep], phash)
|
|
with pytest.raises(RpcError, match="WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS"):
|
|
l1.rpc.waitsendpay(phash)
|
|
end = time.time()
|
|
assert end < start + 100 * 0.5
|
|
|
|
|
|
@unittest.skipIf(os.getenv('TEST_BENCH', '0') == '0', "For profiling")
|
|
def test_bench(node_factory):
|
|
"""Is our Nagle disabling for critical messages working?"""
|
|
l1, l2 = node_factory.get_nodes(2, opts={'start': False,
|
|
'commit-time': 0})
|
|
|
|
# memleak detection plays havoc with profiles.
|
|
del l1.daemon.env["LIGHTNINGD_DEV_MEMLEAK"]
|
|
del l2.daemon.env["LIGHTNINGD_DEV_MEMLEAK"]
|
|
|
|
l1.start()
|
|
l2.start()
|
|
node_factory.join_nodes([l1, l2])
|
|
|
|
scid = only_one(l1.rpc.listpeerchannels()['channels'])['short_channel_id']
|
|
routestep = {
|
|
'amount_msat': 100,
|
|
'id': l2.info['id'],
|
|
'delay': 5,
|
|
'channel': scid
|
|
}
|
|
|
|
start = time.time()
|
|
# If we were stupid enough to leave Nagle enabled, this would add 200ms
|
|
# seconds delays each way!
|
|
for _ in range(1000):
|
|
phash = random.randbytes(32).hex()
|
|
l1.rpc.sendpay([routestep], phash)
|
|
with pytest.raises(RpcError, match="WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS"):
|
|
l1.rpc.waitsendpay(phash)
|
|
end = time.time()
|
|
duration = end - start
|
|
assert duration == 0
|
|
|
|
|
|
def test_listpeerchannels_by_scid(node_factory):
|
|
l1, l2, l3 = node_factory.line_graph(3, announce_channels=False)
|
|
|
|
chans = l2.rpc.listpeerchannels(l1.info['id'])
|
|
c = only_one(chans['channels'])
|
|
assert l2.rpc.listpeerchannels(short_channel_id=c['short_channel_id']) == chans
|
|
assert l2.rpc.listpeerchannels(short_channel_id=c['alias']['local']) == chans
|
|
assert l2.rpc.listpeerchannels(short_channel_id=c['alias']['remote']) == {'channels': []}
|
|
|
|
with pytest.raises(RpcError, match="Cannot specify both short_channel_id and id"):
|
|
l2.rpc.listpeerchannels(peer_id=l1.info['id'], short_channel_id='1x2x3')
|