liqudityhints: extend with mission control data

This commit is contained in:
bitromortac 2022-05-06 16:49:03 +02:00
parent 9eb115de5b
commit 9d758fc05e
No known key found for this signature in database
GPG key ID: 1965063FC13BEBE2
5 changed files with 123 additions and 8 deletions

View file

@ -146,15 +146,19 @@ class LiquidityHint:
else:
return self.cannot_send_backward
def update_can_send(self, is_forward_direction: bool, amount: int):
timestamp = int(time.time())
def update_can_send(self, is_forward_direction: bool, amount: int,
timestamp: int = None):
if not timestamp:
timestamp = int(time.time())
if is_forward_direction:
self.can_send_forward = AmountHistory(amount, timestamp)
else:
self.can_send_backward = AmountHistory(amount, timestamp)
def update_cannot_send(self, is_forward_direction: bool, amount: int):
timestamp = int(time.time())
def update_cannot_send(self, is_forward_direction: bool, amount: int,
timestamp: int = None):
if not timestamp:
timestamp = int(time.time())
if is_forward_direction:
self.cannot_send_forward = AmountHistory(amount, timestamp)
else:
@ -224,18 +228,20 @@ class LiquidityHintMgr:
self._liquidity_hints[node_pair] = hint
return hint
def update_can_send(self, node_from: NodeID, node_to: NodeID, amount_msat: int):
def update_can_send(self, node_from: NodeID, node_to: NodeID, amount_msat: int,
timestamp: int = None):
node_pair = NodePair((node_from, node_to))
logger.debug(f" report: can send {amount_msat // 1000} sat over channel {node_pair}")
hint = self._get_hint(node_pair)
hint.update_can_send(node_from > node_to, amount_msat)
hint.update_can_send(node_from > node_to, amount_msat, timestamp)
self._could_route[node_from] += 1
def update_cannot_send(self, node_from: NodeID, node_to: NodeID, amount: int):
def update_cannot_send(self, node_from: NodeID, node_to: NodeID, amount: int,
timestamp: int = None):
node_pair = NodePair((node_from, node_to))
logger.debug(f" report: cannot send {amount // 1000} sat over channel {node_pair}")
hint = self._get_hint(node_pair)
hint.update_cannot_send(node_from > node_to, amount)
hint.update_cannot_send(node_from > node_to, amount, timestamp)
self._could_not_route[node_from] += 1
def update_badness_hint(self, node: NodeID, badness: float):
@ -374,3 +380,20 @@ class LiquidityHintMgr:
for k, v in self._liquidity_hints.items():
string += f"{k}: {v}\n"
return string
def extend_with_mission_control(self, mc_pairs):
for pair in mc_pairs:
node_from = pair.node_from.hex()
node_to = pair.node_to.hex()
if pair.history.success_time:
self.update_can_send(
node_from, node_to, pair.history.success_amt_msat,
pair.history.success_time,
)
if pair.history.fail_time:
self.update_cannot_send(
node_from, node_to, pair.history.fail_amt_msat,
pair.history.fail_time,
)

View file

@ -90,6 +90,12 @@ class Network:
except Exception as e:
logger.exception(e)
# TODO: don't load if we loaded some time ago
# we extend our information with data from mission control
mc_pairs = self.node.query_mc()
self.liquidity_hints.extend_with_mission_control(mc_pairs)
self.save_liquidty_hints()
@profiled
def save_liquidty_hints(self):
cache_hints_filename = make_cache_filename('liquidity_hints.gpickle')

View file

@ -1039,3 +1039,9 @@ class LndNode:
node_to_channel_map[cv['remote_pubkey']].append(c)
return node_to_channel_map
def query_mc(self):
resp = self._routerrpc.QueryMissionControl(
lndrouter.QueryMissionControlRequest()
)
return resp.pairs

View file

@ -0,0 +1,79 @@
from dataclasses import dataclass
from unittest import TestCase, mock
from lndmanage.lib.data_types import NodePair
from lndmanage.lib.liquidityhints import LiquidityHintMgr, AmountHistory
@dataclass
class MCPairHistory:
fail_amt_msat: int
success_amt_msat: int
fail_time: int = 0
success_time: int = 0
@dataclass
class MCPair:
node_from: bytes
node_to: bytes
history: MCPairHistory
class LiquidityTest(TestCase):
@mock.patch('time.time', mock.MagicMock(return_value=100))
def test_load_mission_control(self):
mgr = LiquidityHintMgr("pubkey")
pairs = [
# valid pair
MCPair(
node_from=bytes.fromhex("aa"),
node_to=bytes.fromhex("bb"),
history=MCPairHistory(
success_amt_msat=10000,
success_time=1, # to be considered a valid hint
fail_amt_msat=30000,
fail_time=1, # to be considered a valid hint
)
),
# invalid pair (no timestamps)
MCPair(
node_from=bytes.fromhex("bb"),
node_to=bytes.fromhex("cc"),
history=MCPairHistory(
fail_amt_msat=30000,
success_amt_msat=10000,
)
)
]
mgr.extend_with_mission_control(pairs)
node_pair = NodePair(("aa", "bb"))
hint = mgr._liquidity_hints.get(node_pair)
# hint from mc:
self.assertEqual(
AmountHistory(amount=10000, timestamp=1),
hint.can_send("aa" > "bb"),
)
# hint from mc:
self.assertEqual(
AmountHistory(amount=30000, timestamp=1),
hint.cannot_send("aa" > "bb"),
)
# we conclude for the backward direction from the failure:
self.assertEqual(
AmountHistory(amount=30000, timestamp=1),
hint.can_send("bb" > "aa"),
)
# we can't say anything about the amount that cannot be sent in the backward
# direction
self.assertEqual(
AmountHistory(),
hint.cannot_send("bb" > "aa"),
)
node_pair = NodePair(("bb", "cc"))
hint = mgr._liquidity_hints.get(node_pair)
self.assertIsNone(hint)

View file

@ -19,6 +19,7 @@ def new_test_graph(graph: Dict):
# we need to init the node interface with a public key
class MockNode:
pub_key = 'A'
query_mc = lambda x: {}
# we disable cached graph reading
with mock.patch.object(Network, 'load_graph', return_value=None):