From a7df3500669ec309457ab63a830e0231533d6f9c Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sat, 9 May 2020 16:26:56 +0200 Subject: [PATCH 01/24] first version of data flow --- balancesharing/balancesharing.py | 48 ++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 14740e73e..c83470e3d 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -21,22 +21,35 @@ def foafbalance(plugin): """gets the balance of our friends channels""" reply = {} info = plugin.rpc.getinfo() - #addr = plugin.rpc.dev_rescan_outputs() - msg = r'ff' * 32 - #serialized = r'04070020' + msg + msg = r'105b126182746121' for peer in plugin.rpc.listpeers()["peers"]: res = plugin.rpc.dev_sendcustommsg(peer["id"], msg) plugin.log(str(res)) nid = info["id"] reply["id"] = nid - #reply["addr"] = addr reply["change"] = nid return reply -# @plugin.hook('peer_connected') -# def on_connected(plugin, **kwargs): -# plugin.log("GOT PEER CONNECTION HOOK") +def get_message_type(message): + assert len(message) > 4 + return message[:4] + + +def get_message_payload(message): + assert len(message) > 4 + return message[4:] + + +def handle_query_foaf_balances(payload, plugin): + plugin.rpc.listfunds()["channels"] + return + + +def send_reply_foaf_balances(peer, channels, plugin): + # TODO: CHECK if 107b is the correct little endian of 439 + plugin.rpc.dev_sendcustommsg(peer, "107b123412341234") + return @plugin.hook('custommsg') @@ -45,14 +58,21 @@ def on_custommsg(peer_id, message, plugin, **kwargs): msg=message, peer_id=peer_id )) + # message has to be at least 6 bytes. 4 bytes prefix and 2 bytes for the type + assert len(message) > 12 + # remove prefix: + message = message[8:] + message_type = get_message_type(message) + message_payload = get_message_payload(message) + + # query_foaf_balances message has type 437 which is 01b5 in hex + if message_type == "105b": + plugin.log("received query_foaf_balances message") + result = handle_query_foaf_balances(message_payload, plugin) + send_reply_foaf_balances(peer_id, result, plugin) -# @plugin.hook("custommsg") -# def on_custommsg(plugin, **kwargs): -# plugin.log('custommsg called') -# #res = {'result': {'id': peer_id, 'msg': message}} - # plugin.log(res) - # time.sleep(20) -# return {'result': 'continue'} + plugin.log(message) + plugin.log(str(type(message))) @plugin.init() From d6900b6db05ebccc144c74d7a8d3aa52431ef57a Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sat, 9 May 2020 16:31:29 +0200 Subject: [PATCH 02/24] fixed typo --- balancesharing/balancesharing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 52b67ce8c..891a55863 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -31,7 +31,6 @@ def foafbalance(plugin): return reply -<<<<<<< HEAD def get_message_type(message): assert len(message) > 4 return message[:4] From 894d7ccb918002fc65b4c246364eaf9ad1df2b65 Mon Sep 17 00:00:00 2001 From: qrest Date: Sat, 9 May 2020 20:26:48 +0200 Subject: [PATCH 03/24] add checks for peer and channels --- balancesharing/balancesharing.py | 62 ++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 891a55863..18568c85d 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -16,15 +16,71 @@ pass +# TODO: implement +def has_feature(feature): + """"check if XXX feature bit present""" + return True + + +def get_funds(plugin): + """"get output and channels""" + # TODO: switch to real data + # fund_list = plugin.rpc.listfunds() + fund_list = list_funds_mock() + outputs = fund_list["outputs"] + channels = fund_list["channels"] + + return outputs, channels + + +def list_funds_mock(): + """"read funds from file""" + # TODO: add dir + with open('/funds.json', 'r') as funds_file: + data = funds_file.read() + + return json.loads(data) + + +# TODO: we need to extend this, if we want to handle multiple channels per peer +def get_channel(channels, peer_id): + """"searches for ONE channel with the given peer_id""" + for ch in channels: + if ch["peer_id"] == peer_id: + return ch + + return None + + @plugin.method("foafbalance") def foafbalance(plugin): """gets the balance of our friends channels""" + flow_value = 1 + amt_to_rebalance = 10 reply = {} info = plugin.rpc.getinfo() msg = r'105b126182746121' + + outputs, channels = get_funds(plugin) + for peer in plugin.rpc.listpeers()["peers"]: - res = plugin.rpc.dev_sendcustommsg(peer["id"], msg) - plugin.log(str(res)) + # check if peer is the desired state + if not peer["connected"] or not has_feature(peer["features"]): + continue + peer_id = peer["id"] + peer_channel = get_channel(channels, peer_id) + + if peer_channel is None: + plugin.log("No channel found for {peer_id}".format(peer_id=peer_id)) + continue + else: + plugin.log("Found channel for {peer_id}: {channel}".format( + peer_id=peer_id, channel=peer_channel["short_channel_id"] + )) + + res = plugin.rpc.dev_sendcustommsg(peer_id, msg) + plugin.log("RPC response" + str(res)) + nid = info["id"] reply["id"] = nid reply["change"] = nid @@ -51,6 +107,7 @@ def send_reply_foaf_balances(peer, channels, plugin): plugin.rpc.dev_sendcustommsg(peer, "107b123412341234") return + @plugin.hook('peer_connected') def on_connected(plugin, **kwargs): plugin.log("GOT PEER CONNECTION HOOK") @@ -80,6 +137,7 @@ def on_custommsg(peer_id, message, plugin, **kwargs): plugin.log(str(type(message))) return {'result': 'continue'} + @plugin.init() def init(options, configuration, plugin): plugin.log("Plugin balancesharing.py initialized") From 1655925f23d88e86a49010c02e7d4d88a007877d Mon Sep 17 00:00:00 2001 From: qrest Date: Sat, 9 May 2020 21:05:23 +0200 Subject: [PATCH 04/24] remove channel checks in 'foafbalance' --- balancesharing/balancesharing.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 18568c85d..30aec9b5d 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -68,15 +68,6 @@ def foafbalance(plugin): if not peer["connected"] or not has_feature(peer["features"]): continue peer_id = peer["id"] - peer_channel = get_channel(channels, peer_id) - - if peer_channel is None: - plugin.log("No channel found for {peer_id}".format(peer_id=peer_id)) - continue - else: - plugin.log("Found channel for {peer_id}: {channel}".format( - peer_id=peer_id, channel=peer_channel["short_channel_id"] - )) res = plugin.rpc.dev_sendcustommsg(peer_id, msg) plugin.log("RPC response" + str(res)) From 2091b9278c470b8bd112ae37293b413f3075336a Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sat, 9 May 2020 21:11:11 +0200 Subject: [PATCH 05/24] wip for merging --- balancesharing/balancesharing.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 18568c85d..9408b4e0d 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -5,6 +5,8 @@ import pyln.client import json +import os + plugin = pyln.client.Plugin() @@ -35,8 +37,9 @@ def get_funds(plugin): def list_funds_mock(): """"read funds from file""" - # TODO: add dir - with open('/funds.json', 'r') as funds_file: + dir_path = os.path.dirname(os.path.realpath(__file__)) + file_name = os.path.join(dir_path, "funds.json") + with open(file_name, 'r') as funds_file: data = funds_file.read() return json.loads(data) @@ -60,6 +63,8 @@ def foafbalance(plugin): reply = {} info = plugin.rpc.getinfo() msg = r'105b126182746121' + dir_path = os.path.dirname(os.path.realpath(__file__)) + plugin.log(dir_path) outputs, channels = get_funds(plugin) @@ -71,7 +76,8 @@ def foafbalance(plugin): peer_channel = get_channel(channels, peer_id) if peer_channel is None: - plugin.log("No channel found for {peer_id}".format(peer_id=peer_id)) + plugin.log( + "No channel found for {peer_id}".format(peer_id=peer_id)) continue else: plugin.log("Found channel for {peer_id}: {channel}".format( @@ -98,7 +104,10 @@ def get_message_payload(message): def handle_query_foaf_balances(payload, plugin): - plugin.rpc.listfunds()["channels"] + _, channels = get_funds(plugin) + plugin.log("AAAAAA") + for channel in channels: + plugin.log(channel["short_channel_id"]) return From c99335d60c9cb0baad93a661701dbe9378212773 Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sat, 9 May 2020 21:54:31 +0200 Subject: [PATCH 06/24] added functionality to compute locally on which channels a node is willing to forward or receive a rebalancing operation --- balancesharing/balancesharing.py | 51 ++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 40a61518d..097eccf81 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -93,12 +93,57 @@ def get_message_payload(message): return message[4:] +def helper_compute_node_parameters(channels): + """ + computes the total funds (\tau) and the total capacity of a node (\kappa) + channels: is a list of local channels. Entries are formatted as in `listunfunds` API call + returns total capacity (\kappa) and total funds (\tau) of the node as integers in satoshis. + """ + kappa = sum(x["channel_total_sat"] for x in channels) + tau = sum(x["channel_sat"] for x in channels) + return kappa, tau + + +def helper_compute_channel_balance_coefficients(channels): + # assign zetas to channels: + for c in channels: + c["zeta"] = float(c["channel_sat"]) / c["channel_total_sat"] + return channels + + def handle_query_foaf_balances(payload, plugin): + # TODO: parse from payload + amt_to_rebalance = 150000 + # TODO: parse from payload but 1 means Outgoing forwarding + flow_value = 0 + + if flow_value == 0: + plugin.log("compute channels on which I want {} satoshis incoming while rebalancing".format( + amt_to_rebalance)) + elif flow_value == 1: + plugin.log("compute channels on which I want to forward {} satoshis while rebalancing".format( + amt_to_rebalance)) + _, channels = get_funds(plugin) - plugin.log("AAAAAA") + + kappa, tau = helper_compute_node_parameters(channels) + nu = float(tau)/kappa + channels = helper_compute_channel_balance_coefficients(channels) + + result = [] for channel in channels: - plugin.log(channel["short_channel_id"]) - return + reserve = int(int(channel["channel_total_sat"]) * 0.01) + 1 + if flow_value == 1: + if channel["zeta"] > nu: + if int(channel["channel_sat"]) > amt_to_rebalance + reserve: + result.append(channel["short_channel_id"]) + elif flow_value == 0: + if channel["zeta"] < nu: + if int(channel["channel_total_sat"])-int(channel["channel_sat"]) > amt_to_rebalance + reserve: + result.append(channel["short_channel_id"]) + plugin.log("{} of {} channels are good for rebalancing {} satoshis they are: {}".format( + len(result), len(channels), amt_to_rebalance, ", ".join(result))) + return result def send_reply_foaf_balances(peer, channels, plugin): From 919761918f338e370dbcb1f375d58d206ed0b020 Mon Sep 17 00:00:00 2001 From: qrest Date: Sat, 9 May 2020 21:57:12 +0200 Subject: [PATCH 07/24] add first encoding functions --- balancesharing/balancesharing.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 40a61518d..2f7f5adc7 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -6,7 +6,7 @@ import pyln.client import json import os - +import struct plugin = pyln.client.Plugin() @@ -55,11 +55,30 @@ def get_channel(channels, peer_id): return None +def encode_query_foaf_balances(flow_value, amt_to_rebalance): + """Encode flow_value (char) and amount (unsigend long long) """ + return struct.pack("!cQ", flow_value, amt_to_rebalance) + + +def decode_query_foaf_balances(data): + """Decode query_foaf_balances. Returns a byte and int""" + return struct.unpack("!cQ", data) + + @plugin.method("foafbalance") def foafbalance(plugin): """gets the balance of our friends channels""" - flow_value = 1 - amt_to_rebalance = 10 + flow_value = b'\x01' + amt_to_rebalance = int(123) + data = encode_query_foaf_balances(flow_value, amt_to_rebalance) + new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances(data) + + plugin.log(str(data)) + plugin.log("New values: {flow_value} {amt_to_rebalance}".format( + flow_value=new_flow_value, + amt_to_rebalance=new_amt_to_rebalance + )) + reply = {} info = plugin.rpc.getinfo() msg = r'105b126182746121' From 054c234e4c1c9fe266a65808b9542c5d23f12f8f Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sun, 10 May 2020 10:09:21 +0200 Subject: [PATCH 08/24] commit before merge --- balancesharing/balancesharing.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 097eccf81..e6144ad74 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -1,6 +1,12 @@ #!/usr/bin/env python3 """ - +author: Rene Pickhardt (rene.m.pickhardt@ntnu.no) & Michael Ziegler (michael.h.ziegler@ntnu.no) +Date: 9.5.2020 +License: MIT +This code computes an optimal split of a payment amount for the use of AMP. +The split is optimal in the sense that it reduces the imbalance of the funds of the node. +More theory about imbalances and the algorithm to decrease the imblance of a node was +suggested by this research: https://arxiv.org/abs/1912.09555 """ import pyln.client From 5a4a4bcb5fad527ee3b34b56ab8373600427487f Mon Sep 17 00:00:00 2001 From: qrest Date: Sun, 10 May 2020 10:30:42 +0200 Subject: [PATCH 09/24] parse input for 'foafbalance' --- balancesharing/balancesharing.py | 52 +++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 14758f72d..9f35194ee 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -35,6 +35,7 @@ def get_funds(plugin): return outputs, channels +# TODO: remove when finished, or keep for test cases def list_funds_mock(): """"read funds from file""" dir_path = os.path.dirname(os.path.realpath(__file__)) @@ -56,20 +57,57 @@ def get_channel(channels, peer_id): def encode_query_foaf_balances(flow_value, amt_to_rebalance): - """Encode flow_value (char) and amount (unsigend long long) """ + """Encode flow_value as 'char' and amount as 'unsigend long long'; C-Type data structure""" return struct.pack("!cQ", flow_value, amt_to_rebalance) def decode_query_foaf_balances(data): - """Decode query_foaf_balances. Returns a byte and int""" + """Decode query_foaf_balances. Returns a byte and int; Python-Type data structure""" return struct.unpack("!cQ", data) +def get_flow_value(flow): + if type(flow) is not int: + return None + + if flow == 1: + return b'\x01' + elif flow == 0: + return b'\x00' + return None + + +def get_amount(amt): + if type(amt) is not int or amt <= 0: + return None + return amt + + +def log_error(msg): + plugin.log("Error in balancesharing plugin: {msg}".format(msg=msg)) + + +# todo: add flow_value and amt_to_rebalance as arguments @plugin.method("foafbalance") -def foafbalance(plugin): +def foafbalance(plugin, flow, amount): """gets the balance of our friends channels""" - flow_value = b'\x01' - amt_to_rebalance = int(123) + + # Read input data + flow_value = get_flow_value(flow) + if flow_value is None: + log_error("argument 'flow_value' for function 'foafbalance' was not 0 or 1") + return + + amt_to_rebalance = get_amount(amount) + if amt_to_rebalance is None: + log_error("argument 'amt_to_rebalance' for function 'foafbalance' was not valid") + return + + plugin.log("Input data: {flow_value} and {amt_to_rebalance}".format( + flow_value=flow_value, + amt_to_rebalance=amt_to_rebalance + )) + data = encode_query_foaf_balances(flow_value, amt_to_rebalance) new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances(data) @@ -146,7 +184,7 @@ def handle_query_foaf_balances(payload, plugin): _, channels = get_funds(plugin) kappa, tau = helper_compute_node_parameters(channels) - nu = float(tau)/kappa + nu = float(tau) / kappa channels = helper_compute_channel_balance_coefficients(channels) result = [] @@ -158,7 +196,7 @@ def handle_query_foaf_balances(payload, plugin): result.append(channel["short_channel_id"]) elif flow_value == 0: if channel["zeta"] < nu: - if int(channel["channel_total_sat"])-int(channel["channel_sat"]) > amt_to_rebalance + reserve: + if int(channel["channel_total_sat"]) - int(channel["channel_sat"]) > amt_to_rebalance + reserve: result.append(channel["short_channel_id"]) plugin.log("{} of {} channels are good for rebalancing {} satoshis they are: {}".format( len(result), len(channels), amt_to_rebalance, ", ".join(result))) From 829ee0e7d98efed25f4afc05e02eef54039ed29c Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sun, 10 May 2020 10:56:58 +0200 Subject: [PATCH 10/24] worked on encoding --- balancesharing/balancesharing.py | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index e79d2e186..02835041a 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -9,13 +9,23 @@ suggested by this research: https://arxiv.org/abs/1912.09555 """ +import networkx as nx import pyln.client import json import os import struct +from binascii import hexlify, unhexlify + +hexlify(struct.pack(">H", 437)) + +QUERY_FOAF_BALANCES = 437 +REPLY_FOAF_BALANCES = 439 + +foaf_network = None plugin = pyln.client.Plugin() + # __version__ was introduced in 0.0.7.1, with utf8 passthrough support. try: if version.parse(lightning.__version__) >= version.parse("0.0.7.1"): @@ -52,6 +62,8 @@ def list_funds_mock(): # TODO: we need to extend this, if we want to handle multiple channels per peer + + def get_channel(channels, peer_id): """"searches for ONE channel with the given peer_id""" for ch in channels: @@ -74,6 +86,8 @@ def decode_query_foaf_balances(data): @plugin.method("foafbalance") def foafbalance(plugin): """gets the balance of our friends channels""" + global foaf_network + foaf_network = nx.DiGraph() flow_value = b'\x01' amt_to_rebalance = int(123) data = encode_query_foaf_balances(flow_value, amt_to_rebalance) @@ -87,7 +101,9 @@ def foafbalance(plugin): reply = {} info = plugin.rpc.getinfo() - msg = r'105b126182746121' + #msg = r'01b5' + str(hexlify(struct.pack(">H", 437))) + '126182746121' + msg = r'01b5126182746121' + dir_path = os.path.dirname(os.path.realpath(__file__)) plugin.log(dir_path) @@ -109,8 +125,16 @@ def foafbalance(plugin): def get_message_type(message): + """takes the 4 hex digits of a string and returns them as an integer + if they are a well known message type""" assert len(message) > 4 - return message[:4] + message_type = message[:4] + # >>> hexlify(pack(">H",437)) + # b'01b5' + # >>> unpack(">H",unhexlify(b'01b5')) + # (437,) + # >>> unpack(">H",unhexlify(b'01b5'))[0] + return struct.unpack(">H", unhexlify(message_type))[0] def get_message_payload(message): @@ -197,11 +221,13 @@ def on_custommsg(peer_id, message, plugin, **kwargs): message_payload = get_message_payload(message) # query_foaf_balances message has type 437 which is 01b5 in hex - if message_type == "105b": + if message_type == QUERY_FOAF_BALANCES: plugin.log("received query_foaf_balances message") result = handle_query_foaf_balances(message_payload, plugin) send_reply_foaf_balances(peer_id, result, plugin) + if message_type == REPLY_FOAF_BALANCES: + plugin.log("received a reply_foaf_balances message") plugin.log(message) plugin.log(str(type(message))) return {'result': 'continue'} From 8126229686bfeb641413ae41171d612d88705539 Mon Sep 17 00:00:00 2001 From: qrest Date: Sun, 10 May 2020 11:01:21 +0200 Subject: [PATCH 11/24] fix en- and decoding --- balancesharing/balancesharing.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index b32f28982..031352783 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -13,6 +13,7 @@ import json import os import struct +from binascii import hexlify, unhexlify plugin = pyln.client.Plugin() @@ -63,13 +64,14 @@ def get_channel(channels, peer_id): def encode_query_foaf_balances(flow_value, amt_to_rebalance): - """Encode flow_value as 'char' and amount as 'unsigend long long'; C-Type data structure""" - return struct.pack("!cQ", flow_value, amt_to_rebalance) + """Encode flow_value and amt_to_rebalance""" + """type: short, flow_value: char, amt_to_rebalance: unsigned long long""" + return hexlify(struct.pack("!hcQ", 437, flow_value, amt_to_rebalance)).decode('ASCII') def decode_query_foaf_balances(data): - """Decode query_foaf_balances. Returns a byte and int; Python-Type data structure""" - return struct.unpack("!cQ", data) + """Decode query_foaf_balances. Return type, flow_value and amt_to_rebalance""" + return struct.unpack("!hcQ", unhexlify(data.encode('ASCII'))) def get_flow_value(flow): @@ -115,20 +117,18 @@ def foafbalance(plugin, flow, amount): )) data = encode_query_foaf_balances(flow_value, amt_to_rebalance) - new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances(data) + msg_type, new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances(data) plugin.log(str(data)) - plugin.log("New values: {flow_value} {amt_to_rebalance}".format( + plugin.log("New values: {msg_type} -- {flow_value} -- {amt_to_rebalance}".format( + msg_type=msg_type, flow_value=new_flow_value, amt_to_rebalance=new_amt_to_rebalance )) - reply = {} info = plugin.rpc.getinfo() msg = r'105b126182746121' - dir_path = os.path.dirname(os.path.realpath(__file__)) - plugin.log(dir_path) - + reply = {} outputs, channels = get_funds(plugin) for peer in plugin.rpc.listpeers()["peers"]: @@ -137,7 +137,7 @@ def foafbalance(plugin, flow, amount): continue peer_id = peer["id"] - res = plugin.rpc.dev_sendcustommsg(peer_id, msg) + res = plugin.rpc.dev_sendcustommsg(peer_id, data) plugin.log("RPC response" + str(res)) nid = info["id"] From 6967d723912af11319d20b8cfda9768787816d39 Mon Sep 17 00:00:00 2001 From: qrest Date: Sun, 10 May 2020 11:35:47 +0200 Subject: [PATCH 12/24] plug in decoding on receiver side --- balancesharing/balancesharing.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 2e6a5e4fa..45a66dc7d 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -68,14 +68,14 @@ def get_channel(channels, peer_id): for ch in channels: if ch["peer_id"] == peer_id: return ch - return None def encode_query_foaf_balances(flow_value, amt_to_rebalance): """Encode flow_value and amt_to_rebalance""" """type: short, flow_value: char, amt_to_rebalance: unsigned long long""" - return hexlify(struct.pack("!hcQ", 437, flow_value, amt_to_rebalance)).decode('ASCII') + global QUERY_FOAF_BALANCES + return hexlify(struct.pack("!hcQ", QUERY_FOAF_BALANCES, flow_value, amt_to_rebalance)).decode('ASCII') def decode_query_foaf_balances(data): @@ -108,9 +108,6 @@ def log_error(msg): @plugin.method("foafbalance") def foafbalance(plugin, flow, amount): """gets the balance of our friends channels""" - global foaf_network - foaf_network = nx.DiGraph() - # Read input data flow_value = get_flow_value(flow) if flow_value is None: @@ -137,6 +134,9 @@ def foafbalance(plugin, flow, amount): amt_to_rebalance=new_amt_to_rebalance )) + global foaf_network + foaf_network = nx.DiGraph() + info = plugin.rpc.getinfo() msg = r'105b126182746121' reply = {} @@ -193,16 +193,11 @@ def helper_compute_channel_balance_coefficients(channels): return channels -def handle_query_foaf_balances(payload, plugin): - # TODO: parse from payload - amt_to_rebalance = 150000 - # TODO: parse from payload but 1 means Outgoing forwarding - flow_value = 0 - - if flow_value == 0: +def handle_query_foaf_balances(flow_value, amt_to_rebalance, plugin): + if flow_value == b'\x00': plugin.log("compute channels on which I want {} satoshis incoming while rebalancing".format( amt_to_rebalance)) - elif flow_value == 1: + elif flow_value == b'\x01': plugin.log("compute channels on which I want to forward {} satoshis while rebalancing".format( amt_to_rebalance)) @@ -251,12 +246,13 @@ def on_custommsg(peer_id, message, plugin, **kwargs): # remove prefix: message = message[8:] message_type = get_message_type(message) - message_payload = get_message_payload(message) + # message_payload = get_message_payload(message) # query_foaf_balances message has type 437 which is 01b5 in hex if message_type == QUERY_FOAF_BALANCES: plugin.log("received query_foaf_balances message") - result = handle_query_foaf_balances(message_payload, plugin) + _, flow, amt = decode_query_foaf_balances(message) + result = handle_query_foaf_balances(flow, amt, plugin) send_reply_foaf_balances(peer_id, result, plugin) if message_type == REPLY_FOAF_BALANCES: From 402decd0f68a1abe05e62bce42685e1264ca626b Mon Sep 17 00:00:00 2001 From: qrest Date: Sun, 10 May 2020 11:37:00 +0200 Subject: [PATCH 13/24] cleanup --- balancesharing/balancesharing.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 45a66dc7d..4e9081443 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -16,8 +16,6 @@ import struct from binascii import hexlify, unhexlify -hexlify(struct.pack(">H", 437)) - QUERY_FOAF_BALANCES = 437 REPLY_FOAF_BALANCES = 439 @@ -25,7 +23,6 @@ plugin = pyln.client.Plugin() - # __version__ was introduced in 0.0.7.1, with utf8 passthrough support. try: if version.parse(lightning.__version__) >= version.parse("0.0.7.1"): @@ -162,11 +159,6 @@ def get_message_type(message): if they are a well known message type""" assert len(message) > 4 message_type = message[:4] - # >>> hexlify(pack(">H",437)) - # b'01b5' - # >>> unpack(">H",unhexlify(b'01b5')) - # (437,) - # >>> unpack(">H",unhexlify(b'01b5'))[0] return struct.unpack(">H", unhexlify(message_type))[0] From 418019f11e9de27d802b5c06779cc77c44b3a39f Mon Sep 17 00:00:00 2001 From: qrest Date: Sun, 10 May 2020 11:59:41 +0200 Subject: [PATCH 14/24] more cleanup --- balancesharing/balancesharing.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 4e9081443..f28d519a5 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -72,12 +72,12 @@ def encode_query_foaf_balances(flow_value, amt_to_rebalance): """Encode flow_value and amt_to_rebalance""" """type: short, flow_value: char, amt_to_rebalance: unsigned long long""" global QUERY_FOAF_BALANCES - return hexlify(struct.pack("!hcQ", QUERY_FOAF_BALANCES, flow_value, amt_to_rebalance)).decode('ASCII') + return hexlify(struct.pack("!HcQ", QUERY_FOAF_BALANCES, flow_value, amt_to_rebalance)).decode('ASCII') def decode_query_foaf_balances(data): """Decode query_foaf_balances. Return type, flow_value and amt_to_rebalance""" - return struct.unpack("!hcQ", unhexlify(data.encode('ASCII'))) + return struct.unpack("!HcQ", unhexlify(data.encode('ASCII'))) def get_flow_value(flow): @@ -101,7 +101,6 @@ def log_error(msg): plugin.log("Error in balancesharing plugin: {msg}".format(msg=msg)) -# todo: add flow_value and amt_to_rebalance as arguments @plugin.method("foafbalance") def foafbalance(plugin, flow, amount): """gets the balance of our friends channels""" @@ -122,8 +121,9 @@ def foafbalance(plugin, flow, amount): )) data = encode_query_foaf_balances(flow_value, amt_to_rebalance) - msg_type, new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances(data) + # todo: remove. only for debugging + msg_type, new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances(data) plugin.log(str(data)) plugin.log("New values: {msg_type} -- {flow_value} -- {amt_to_rebalance}".format( msg_type=msg_type, @@ -134,11 +134,6 @@ def foafbalance(plugin, flow, amount): global foaf_network foaf_network = nx.DiGraph() - info = plugin.rpc.getinfo() - msg = r'105b126182746121' - reply = {} - outputs, channels = get_funds(plugin) - for peer in plugin.rpc.listpeers()["peers"]: # check if peer is the desired state if not peer["connected"] or not has_feature(peer["features"]): @@ -148,9 +143,8 @@ def foafbalance(plugin, flow, amount): res = plugin.rpc.dev_sendcustommsg(peer_id, data) plugin.log("RPC response" + str(res)) - nid = info["id"] - reply["id"] = nid - reply["change"] = nid + nid = plugin.rpc.getinfo()["id"] + reply = {"id": nid, "change": nid} return reply @@ -159,7 +153,7 @@ def get_message_type(message): if they are a well known message type""" assert len(message) > 4 message_type = message[:4] - return struct.unpack(">H", unhexlify(message_type))[0] + return struct.unpack(">H", unhexlify(message_type.encode('ASCII')))[0] def get_message_payload(message): @@ -246,9 +240,9 @@ def on_custommsg(peer_id, message, plugin, **kwargs): _, flow, amt = decode_query_foaf_balances(message) result = handle_query_foaf_balances(flow, amt, plugin) send_reply_foaf_balances(peer_id, result, plugin) - - if message_type == REPLY_FOAF_BALANCES: + elif message_type == REPLY_FOAF_BALANCES: plugin.log("received a reply_foaf_balances message") + plugin.log(message) plugin.log(str(type(message))) return {'result': 'continue'} From f98b83e8399fcfffcde3e66d180a07fdc9308a1a Mon Sep 17 00:00:00 2001 From: qrest Date: Sun, 10 May 2020 13:39:55 +0200 Subject: [PATCH 15/24] added chain_hash to query --- balancesharing/balancesharing.py | 38 +++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index f28d519a5..328252845 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -18,7 +18,8 @@ QUERY_FOAF_BALANCES = 437 REPLY_FOAF_BALANCES = 439 - +CHAIN_HASH = r'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +BTC_CHAIN_HASH = CHAIN_HASH foaf_network = None plugin = pyln.client.Plugin() @@ -70,14 +71,24 @@ def get_channel(channels, peer_id): def encode_query_foaf_balances(flow_value, amt_to_rebalance): """Encode flow_value and amt_to_rebalance""" - """type: short, flow_value: char, amt_to_rebalance: unsigned long long""" + """ + H -> type: short + 32s -> chain_hash: 32byte char + c -> flow_value: char + Q -> amt_to_rebalance: unsigned long long + """ global QUERY_FOAF_BALANCES - return hexlify(struct.pack("!HcQ", QUERY_FOAF_BALANCES, flow_value, amt_to_rebalance)).decode('ASCII') + global CHAIN_HASH + return hexlify( + struct.pack("!H32scQ", QUERY_FOAF_BALANCES, CHAIN_HASH.encode('ASCII'), flow_value, amt_to_rebalance)).decode( + 'ASCII') def decode_query_foaf_balances(data): - """Decode query_foaf_balances. Return type, flow_value and amt_to_rebalance""" - return struct.unpack("!HcQ", unhexlify(data.encode('ASCII'))) + """Decode query_foaf_balances. Return type, chain_hash, flow_value and amt_to_rebalance""" + msg_type, chain_hash, flow, amt = struct.unpack("!H32scQ", unhexlify(data.encode('ASCII'))) + chain_hash = chain_hash.decode('ASCII') + return msg_type, chain_hash, flow, amt def get_flow_value(flow): @@ -123,10 +134,11 @@ def foafbalance(plugin, flow, amount): data = encode_query_foaf_balances(flow_value, amt_to_rebalance) # todo: remove. only for debugging - msg_type, new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances(data) + msg_type, chain_hash, new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances(data) plugin.log(str(data)) - plugin.log("New values: {msg_type} -- {flow_value} -- {amt_to_rebalance}".format( + plugin.log("New values: {msg_type} -- {chain_hash} -- {flow_value} -- {amt_to_rebalance}".format( msg_type=msg_type, + chain_hash=chain_hash, flow_value=new_flow_value, amt_to_rebalance=new_amt_to_rebalance )) @@ -223,6 +235,7 @@ def on_connected(plugin, **kwargs): @plugin.hook('custommsg') def on_custommsg(peer_id, message, plugin, **kwargs): + global BTC_CHAIN_HASH plugin.log("Got a custom message {msg} from peer {peer_id}".format( msg=message, peer_id=peer_id @@ -237,9 +250,14 @@ def on_custommsg(peer_id, message, plugin, **kwargs): # query_foaf_balances message has type 437 which is 01b5 in hex if message_type == QUERY_FOAF_BALANCES: plugin.log("received query_foaf_balances message") - _, flow, amt = decode_query_foaf_balances(message) - result = handle_query_foaf_balances(flow, amt, plugin) - send_reply_foaf_balances(peer_id, result, plugin) + _, chain_hash, flow, amt = decode_query_foaf_balances(message) + + if chain_hash == BTC_CHAIN_HASH: + result = handle_query_foaf_balances(flow, amt, plugin) + send_reply_foaf_balances(peer_id, result, plugin) + else: + plugin.log("not handling non bitcoin chains for now") + elif message_type == REPLY_FOAF_BALANCES: plugin.log("received a reply_foaf_balances message") From 34fb2d08033137db1d328cfbca253a282030d5b4 Mon Sep 17 00:00:00 2001 From: qrest Date: Sun, 10 May 2020 15:31:47 +0200 Subject: [PATCH 16/24] add inital reply encoding --- balancesharing/balancesharing.py | 85 ++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 328252845..8b8f1c19d 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -14,6 +14,7 @@ import json import os import struct +import time from binascii import hexlify, unhexlify QUERY_FOAF_BALANCES = 437 @@ -69,6 +70,40 @@ def get_channel(channels, peer_id): return None +def encode_reply_foaf_balances(short_channels, amt_to_rebalance, plugin): + """Encode flow_value and amt_to_rebalance""" + """ + H -> type: short + 32s -> chain_hash: 32byte char + L -> timestamp: unsigned long + Q -> amt_to_rebalance: unsigned long long + H -> number_of_short_channels: unsigned short + {len*8}s -> short_channel_id + """ + global REPLY_FOAF_BALANCES + global CHAIN_HASH + + fund_list = list_funds_mock() + channels = fund_list["channels"] + + # TODO: remove mock + mock_short_channels = [] + for ch in channels: + mock_short_channels.append(ch["short_channel_id"]) + short_channels = mock_short_channels + + # time.time() returns a float with 4 decimal places + timestamp = int(time.time() * 1000) + number_of_short_channels = len(short_channels) + channel_array_sign = str(number_of_short_channels * 8) + 's' + plugin.log("Channel sign: {channel_array_sign}" + .format(channel_array_sign=channel_array_sign)) + return hexlify(struct.pack( + "!H32sLQH", REPLY_FOAF_BALANCES, CHAIN_HASH.encode('ASCII'), + timestamp, number_of_short_channels, amt_to_rebalance) + ).decode('ASCII') + + def encode_query_foaf_balances(flow_value, amt_to_rebalance): """Encode flow_value and amt_to_rebalance""" """ @@ -115,6 +150,7 @@ def log_error(msg): @plugin.method("foafbalance") def foafbalance(plugin, flow, amount): """gets the balance of our friends channels""" + plugin.log("Building query_foaf_balances message...") # Read input data flow_value = get_flow_value(flow) if flow_value is None: @@ -126,17 +162,11 @@ def foafbalance(plugin, flow, amount): log_error("argument 'amt_to_rebalance' for function 'foafbalance' was not valid") return - plugin.log("Input data: {flow_value} and {amt_to_rebalance}".format( - flow_value=flow_value, - amt_to_rebalance=amt_to_rebalance - )) - data = encode_query_foaf_balances(flow_value, amt_to_rebalance) # todo: remove. only for debugging msg_type, chain_hash, new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances(data) - plugin.log(str(data)) - plugin.log("New values: {msg_type} -- {chain_hash} -- {flow_value} -- {amt_to_rebalance}".format( + plugin.log("Test decoding: {msg_type} -- {chain_hash} -- {flow_value} -- {amt_to_rebalance}".format( msg_type=msg_type, chain_hash=chain_hash, flow_value=new_flow_value, @@ -146,6 +176,7 @@ def foafbalance(plugin, flow, amount): global foaf_network foaf_network = nx.DiGraph() + counter = 0 for peer in plugin.rpc.listpeers()["peers"]: # check if peer is the desired state if not peer["connected"] or not has_feature(peer["features"]): @@ -153,10 +184,15 @@ def foafbalance(plugin, flow, amount): peer_id = peer["id"] res = plugin.rpc.dev_sendcustommsg(peer_id, data) - plugin.log("RPC response" + str(res)) + plugin.log("Sent query_foaf_balances message to {peer_id}. Response: {res}".format( + peer_id=peer_id, + res=res + )) + + counter = counter + 1 nid = plugin.rpc.getinfo()["id"] - reply = {"id": nid, "change": nid} + reply = {"id": nid, "num_sent_queries": counter} return reply @@ -205,26 +241,33 @@ def handle_query_foaf_balances(flow_value, amt_to_rebalance, plugin): nu = float(tau) / kappa channels = helper_compute_channel_balance_coefficients(channels) - result = [] + channel_ids = [] for channel in channels: reserve = int(int(channel["channel_total_sat"]) * 0.01) + 1 if flow_value == 1: if channel["zeta"] > nu: if int(channel["channel_sat"]) > amt_to_rebalance + reserve: - result.append(channel["short_channel_id"]) + channel_ids.append(channel["short_channel_id"]) elif flow_value == 0: if channel["zeta"] < nu: if int(channel["channel_total_sat"]) - int(channel["channel_sat"]) > amt_to_rebalance + reserve: - result.append(channel["short_channel_id"]) + channel_ids.append(channel["short_channel_id"]) plugin.log("{} of {} channels are good for rebalancing {} satoshis they are: {}".format( - len(result), len(channels), amt_to_rebalance, ", ".join(result))) - return result + len(channel_ids), len(channels), amt_to_rebalance, ", ".join(channel_ids))) + return channel_ids -def send_reply_foaf_balances(peer, channels, plugin): +def send_reply_foaf_balances(peer, amt, channels, plugin): + encode_reply_foaf_balances(channels, amt, plugin) + # TODO: CHECK if 107b is the correct little endian of 439 - plugin.rpc.dev_sendcustommsg(peer, "107b123412341234") - return + res = plugin.rpc.dev_sendcustommsg(peer, "107b123412341234") + plugin.log("Sent query_foaf_balances message to {peer_id}. Response: {res}".format( + peer_id=peer, + res=res + )) + reply = {"peer_id": peer, "response": res} + return reply @plugin.hook('peer_connected') @@ -248,22 +291,22 @@ def on_custommsg(peer_id, message, plugin, **kwargs): # message_payload = get_message_payload(message) # query_foaf_balances message has type 437 which is 01b5 in hex + return_value = {} if message_type == QUERY_FOAF_BALANCES: plugin.log("received query_foaf_balances message") _, chain_hash, flow, amt = decode_query_foaf_balances(message) if chain_hash == BTC_CHAIN_HASH: result = handle_query_foaf_balances(flow, amt, plugin) - send_reply_foaf_balances(peer_id, result, plugin) + r = send_reply_foaf_balances(peer_id, amt, result, plugin) + return_value = {"result": r} else: plugin.log("not handling non bitcoin chains for now") elif message_type == REPLY_FOAF_BALANCES: plugin.log("received a reply_foaf_balances message") - plugin.log(message) - plugin.log(str(type(message))) - return {'result': 'continue'} + return return_value @plugin.init() From 2c1d6f603a1e4ce9e4d379b5502724cf03a96e92 Mon Sep 17 00:00:00 2001 From: qrest Date: Sun, 10 May 2020 15:52:48 +0200 Subject: [PATCH 17/24] change to unsigned long long for timestamp --- balancesharing/balancesharing.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 8b8f1c19d..1b319733c 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -75,7 +75,7 @@ def encode_reply_foaf_balances(short_channels, amt_to_rebalance, plugin): """ H -> type: short 32s -> chain_hash: 32byte char - L -> timestamp: unsigned long + Q -> timestamp: unsigned long Q -> amt_to_rebalance: unsigned long long H -> number_of_short_channels: unsigned short {len*8}s -> short_channel_id @@ -83,14 +83,14 @@ def encode_reply_foaf_balances(short_channels, amt_to_rebalance, plugin): global REPLY_FOAF_BALANCES global CHAIN_HASH - fund_list = list_funds_mock() - channels = fund_list["channels"] - - # TODO: remove mock - mock_short_channels = [] - for ch in channels: - mock_short_channels.append(ch["short_channel_id"]) - short_channels = mock_short_channels + # fund_list = list_funds_mock() + # channels = fund_list["channels"] + # + # # TODO: remove mock + # mock_short_channels = [] + # for ch in channels: + # mock_short_channels.append(ch["short_channel_id"]) + # short_channels = mock_short_channels # time.time() returns a float with 4 decimal places timestamp = int(time.time() * 1000) @@ -99,7 +99,7 @@ def encode_reply_foaf_balances(short_channels, amt_to_rebalance, plugin): plugin.log("Channel sign: {channel_array_sign}" .format(channel_array_sign=channel_array_sign)) return hexlify(struct.pack( - "!H32sLQH", REPLY_FOAF_BALANCES, CHAIN_HASH.encode('ASCII'), + "!H32sQQH", REPLY_FOAF_BALANCES, CHAIN_HASH.encode('ASCII'), timestamp, number_of_short_channels, amt_to_rebalance) ).decode('ASCII') From 5b5fdb64fcb4b0dcc09b1ff3e76ea0642cfb06c9 Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sun, 10 May 2020 17:19:37 +0200 Subject: [PATCH 18/24] WIP add path finding --- balancesharing/balancesharing.py | 75 ++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 1b319733c..714b856f7 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -21,6 +21,9 @@ REPLY_FOAF_BALANCES = 439 CHAIN_HASH = r'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' BTC_CHAIN_HASH = CHAIN_HASH +# TODO: replace with plugin.rpc.listchannels(short_channel_id) +CHANNEL_INDEX = {} + foaf_network = None plugin = pyln.client.Plugin() @@ -39,6 +42,17 @@ def has_feature(feature): return True +def get_other_node(node_id, short_channel_id): + channel = CHANNEL_INDEX[short_channel_id] + if channel == None: + return None + if channel["source"] == node_id: + return channel["destination"] + if channel["destination"] == node_id: + return channel["source"] + return None + + def get_funds(plugin): """"get output and channels""" # TODO: switch to real data @@ -121,7 +135,8 @@ def encode_query_foaf_balances(flow_value, amt_to_rebalance): def decode_query_foaf_balances(data): """Decode query_foaf_balances. Return type, chain_hash, flow_value and amt_to_rebalance""" - msg_type, chain_hash, flow, amt = struct.unpack("!H32scQ", unhexlify(data.encode('ASCII'))) + msg_type, chain_hash, flow, amt = struct.unpack( + "!H32scQ", unhexlify(data.encode('ASCII'))) chain_hash = chain_hash.decode('ASCII') return msg_type, chain_hash, flow, amt @@ -159,13 +174,15 @@ def foafbalance(plugin, flow, amount): amt_to_rebalance = get_amount(amount) if amt_to_rebalance is None: - log_error("argument 'amt_to_rebalance' for function 'foafbalance' was not valid") + log_error( + "argument 'amt_to_rebalance' for function 'foafbalance' was not valid") return data = encode_query_foaf_balances(flow_value, amt_to_rebalance) # todo: remove. only for debugging - msg_type, chain_hash, new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances(data) + msg_type, chain_hash, new_flow_value, new_amt_to_rebalance = decode_query_foaf_balances( + data) plugin.log("Test decoding: {msg_type} -- {chain_hash} -- {flow_value} -- {amt_to_rebalance}".format( msg_type=msg_type, chain_hash=chain_hash, @@ -270,6 +287,23 @@ def send_reply_foaf_balances(peer, amt, channels, plugin): return reply +def decode_reply_foaf_balances_mock(message): + """ + * [`chain_hash: chain_hash`] + * [`byte: flow_value`] + * [`u64: timestamp`] + * [`u64: amt_to_rebalance`] + * [`u16:len`] + * [`len*u64: short_channel_id`] + """ + chain_hash = CHAIN_HASH + flow_value = 1 + ts = int(time.time() * 1000) + amt_to_rebalance = 50000 + short_channel_ids = list(CHANNEL_INDEX.keys()) + return chain_hash, flow_value, ts, amt_to_rebalance, short_channel_ids + + @plugin.hook('peer_connected') def on_connected(plugin, **kwargs): plugin.log("GOT PEER CONNECTION HOOK") @@ -283,6 +317,9 @@ def on_custommsg(peer_id, message, plugin, **kwargs): msg=message, peer_id=peer_id )) + # TODO: Remove to stop mocking + peer_id = "03efccf2c383d7bf340da9a3f02e2c23104a0e4fe8ac1a880c8e2dc92fbdacd9df" + plugin.log("switched peer_id to {} for testing".format(peer_id)) # message has to be at least 6 bytes. 4 bytes prefix and 2 bytes for the type assert len(message) > 12 # remove prefix: @@ -304,14 +341,46 @@ def on_custommsg(peer_id, message, plugin, **kwargs): plugin.log("not handling non bitcoin chains for now") elif message_type == REPLY_FOAF_BALANCES: + chain_hash, flow_value, ts, amt_to_rebalance, short_channel_ids = decode_reply_foaf_balances_mock( + message) plugin.log("received a reply_foaf_balances message") + for short_channel_id in short_channel_ids: + partner = get_other_node(peer_id, short_channel_id) + if partner is None: + continue + # TODO: shall we include the timestamp the the edges? + # TODO: an edge MUST only exist in one direction + if flow_value == 1: + foaf_network.add_edge(peer_id, partner) + else: + foaf_network.add_edge(partner, peer_id) + # TODO invoke rebalance path finding logic (but with whome? need a peer to which an HTLC is stuck) + plugin.log("FOAF Graph now has {} channels".format( + len(foaf_network.edges()))) return return_value +def reindex_channels(plugin): + plugin.log("indexing payment channels by short channel id") + # TODO: REMOVE MOCK + # channels=plugin.rpc.listchannels()["channels"] + dir_path = os.path.dirname(os.path.realpath(__file__)) + file_name = os.path.join(dir_path, "channels.json") + with open(file_name, 'r') as funds_file: + data = funds_file.read() + + channels = json.loads(data)["channels"] + + for channel in channels: + short_channel_id = channel["short_channel_id"] + CHANNEL_INDEX[short_channel_id] = channel + + @plugin.init() def init(options, configuration, plugin): plugin.log("Plugin balancesharing.py initialized") + reindex_channels(plugin) plugin.run() From 0c459a9dd2c0bc11368660726113cd6dbfa1c0e8 Mon Sep 17 00:00:00 2001 From: qrest Date: Sun, 10 May 2020 17:20:15 +0200 Subject: [PATCH 19/24] add pack_channels function --- balancesharing/balancesharing.py | 33 +++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 1b319733c..5f741b4c7 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -70,11 +70,27 @@ def get_channel(channels, peer_id): return None -def encode_reply_foaf_balances(short_channels, amt_to_rebalance, plugin): +def pack_channels(channels, plugin): + # structure: blockheight 4 byte, index 2 byte, output 2 byte + channels_packed = [] + for ch in channels: + nums = ch.split('x') + if len(nums) != 3: + break + ch_packed = struct.pack("!LHH", int(nums[0]), + int(nums[1]), int(nums[2])) + channels_packed.append(ch_packed) + plugin.log("channel: " + ch + " " + str(ch_packed)) + + return channels_packed + + +def encode_reply_foaf_balances(short_channels, flow_value, amt_to_rebalance, plugin): """Encode flow_value and amt_to_rebalance""" """ H -> type: short 32s -> chain_hash: 32byte char + c -> flow_value: char Q -> timestamp: unsigned long Q -> amt_to_rebalance: unsigned long long H -> number_of_short_channels: unsigned short @@ -98,9 +114,10 @@ def encode_reply_foaf_balances(short_channels, amt_to_rebalance, plugin): channel_array_sign = str(number_of_short_channels * 8) + 's' plugin.log("Channel sign: {channel_array_sign}" .format(channel_array_sign=channel_array_sign)) + pack_channels(short_channels, plugin) return hexlify(struct.pack( - "!H32sQQH", REPLY_FOAF_BALANCES, CHAIN_HASH.encode('ASCII'), - timestamp, number_of_short_channels, amt_to_rebalance) + "!H32scQQH", REPLY_FOAF_BALANCES, CHAIN_HASH.encode('ASCII'), + flow_value, timestamp, number_of_short_channels, amt_to_rebalance) ).decode('ASCII') @@ -138,7 +155,7 @@ def get_flow_value(flow): def get_amount(amt): - if type(amt) is not int or amt <= 0: + if type(amt) is not int or amt == 0: return None return amt @@ -234,6 +251,8 @@ def handle_query_foaf_balances(flow_value, amt_to_rebalance, plugin): elif flow_value == b'\x01': plugin.log("compute channels on which I want to forward {} satoshis while rebalancing".format( amt_to_rebalance)) + else: + return [] _, channels = get_funds(plugin) @@ -257,8 +276,8 @@ def handle_query_foaf_balances(flow_value, amt_to_rebalance, plugin): return channel_ids -def send_reply_foaf_balances(peer, amt, channels, plugin): - encode_reply_foaf_balances(channels, amt, plugin) +def send_reply_foaf_balances(peer, amt, flow, channels, plugin): + encode_reply_foaf_balances(channels, flow, amt, plugin) # TODO: CHECK if 107b is the correct little endian of 439 res = plugin.rpc.dev_sendcustommsg(peer, "107b123412341234") @@ -298,7 +317,7 @@ def on_custommsg(peer_id, message, plugin, **kwargs): if chain_hash == BTC_CHAIN_HASH: result = handle_query_foaf_balances(flow, amt, plugin) - r = send_reply_foaf_balances(peer_id, amt, result, plugin) + r = send_reply_foaf_balances(peer_id, amt, flow, result, plugin) return_value = {"result": r} else: plugin.log("not handling non bitcoin chains for now") From 1f72d288a0fa8044ca70a62469502faf69f85c96 Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sun, 10 May 2020 17:34:59 +0200 Subject: [PATCH 20/24] current --- balancesharing/balancesharing.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 33debbe33..a81f6bfd1 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -180,7 +180,7 @@ def log_error(msg): @plugin.method("foafbalance") -def foafbalance(plugin, flow, amount): +def foafbalance(plugin, flow=1, amount=50000): """gets the balance of our friends channels""" plugin.log("Building query_foaf_balances message...") # Read input data @@ -332,12 +332,13 @@ def on_connected(plugin, **kwargs): @plugin.hook('custommsg') def on_custommsg(peer_id, message, plugin, **kwargs): global BTC_CHAIN_HASH + global foaf_network plugin.log("Got a custom message {msg} from peer {peer_id}".format( msg=message, peer_id=peer_id )) # TODO: Remove to stop mocking - peer_id = "03efccf2c383d7bf340da9a3f02e2c23104a0e4fe8ac1a880c8e2dc92fbdacd9df" + mock_peer_id = "03efccf2c383d7bf340da9a3f02e2c23104a0e4fe8ac1a880c8e2dc92fbdacd9df" plugin.log("switched peer_id to {} for testing".format(peer_id)) # message has to be at least 6 bytes. 4 bytes prefix and 2 bytes for the type assert len(message) > 12 @@ -364,7 +365,8 @@ def on_custommsg(peer_id, message, plugin, **kwargs): message) plugin.log("received a reply_foaf_balances message") for short_channel_id in short_channel_ids: - partner = get_other_node(peer_id, short_channel_id) + # TODO: remove mock + partner = get_other_node(mock_peer_id, short_channel_id) if partner is None: continue # TODO: shall we include the timestamp the the edges? From cdfeeb2a416a712c0bb5981d0e5c2aeb47ee5b6c Mon Sep 17 00:00:00 2001 From: qrest Date: Sun, 10 May 2020 19:06:38 +0200 Subject: [PATCH 21/24] fix error in encoding --- balancesharing/balancesharing.py | 66 ++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 5f741b4c7..c0997e0c4 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -85,6 +85,31 @@ def pack_channels(channels, plugin): return channels_packed +def decode_reply_foaf_balances(data, plugin): + """Decode query_foaf_balances. Return type, chain_hash, flow_value and amt_to_rebalance""" + # first part is 53 bytes big -> 106 characters + assert len(data) >= 106 + + first_part = data[:106] + second_part = data[106:] + plugin.log("Splitting data 1") + plugin.log(first_part) + msg_type, chain_hash, flow, timestamp, amt, num_channels \ + = struct.unpack("!H32scQQH", unhexlify(first_part.encode('ASCII'))) + # plugin.log("Msg type: " + str(msg_type)) + plugin.log("Splitting data 2") + chain_hash = chain_hash.decode('ASCII') + plugin.log("Splitting data 3") + + unpack_type = '!' + 'Q' * num_channels + plugin.log(unpack_type) + plugin.log(str(num_channels)) + plugin.log(str(len(second_part))) + short_channel_ids = struct.unpack(unpack_type, unhexlify(second_part.encode('ASCII'))) + + return msg_type, chain_hash, flow, timestamp, amt, short_channel_ids + + def encode_reply_foaf_balances(short_channels, flow_value, amt_to_rebalance, plugin): """Encode flow_value and amt_to_rebalance""" """ @@ -99,14 +124,14 @@ def encode_reply_foaf_balances(short_channels, flow_value, amt_to_rebalance, plu global REPLY_FOAF_BALANCES global CHAIN_HASH - # fund_list = list_funds_mock() - # channels = fund_list["channels"] - # - # # TODO: remove mock - # mock_short_channels = [] - # for ch in channels: - # mock_short_channels.append(ch["short_channel_id"]) - # short_channels = mock_short_channels + fund_list = list_funds_mock() + channels = fund_list["channels"] + + # TODO: remove mock + mock_short_channels = [] + for ch in channels: + mock_short_channels.append(ch["short_channel_id"]) + short_channels = mock_short_channels # time.time() returns a float with 4 decimal places timestamp = int(time.time() * 1000) @@ -114,11 +139,17 @@ def encode_reply_foaf_balances(short_channels, flow_value, amt_to_rebalance, plu channel_array_sign = str(number_of_short_channels * 8) + 's' plugin.log("Channel sign: {channel_array_sign}" .format(channel_array_sign=channel_array_sign)) - pack_channels(short_channels, plugin) - return hexlify(struct.pack( - "!H32scQQH", REPLY_FOAF_BALANCES, CHAIN_HASH.encode('ASCII'), - flow_value, timestamp, number_of_short_channels, amt_to_rebalance) - ).decode('ASCII') + + packed_first_part = struct.pack("!H32scQQH", REPLY_FOAF_BALANCES, CHAIN_HASH.encode('ASCII'), + flow_value, timestamp, amt_to_rebalance, number_of_short_channels) + + packed_second_part = b'' + packed_chs = pack_channels(short_channels, plugin) + for ch in packed_chs: + packed_second_part += ch + tmp = hexlify(packed_first_part + packed_second_part).decode('ASCII') + plugin.log(tmp) + return tmp def encode_query_foaf_balances(flow_value, amt_to_rebalance): @@ -199,7 +230,7 @@ def foafbalance(plugin, flow, amount): if not peer["connected"] or not has_feature(peer["features"]): continue peer_id = peer["id"] - + plugin.log(data) res = plugin.rpc.dev_sendcustommsg(peer_id, data) plugin.log("Sent query_foaf_balances message to {peer_id}. Response: {res}".format( peer_id=peer_id, @@ -277,7 +308,12 @@ def handle_query_foaf_balances(flow_value, amt_to_rebalance, plugin): def send_reply_foaf_balances(peer, amt, flow, channels, plugin): - encode_reply_foaf_balances(channels, flow, amt, plugin) + msg = encode_reply_foaf_balances(channels, flow, amt, plugin) + msg_type, chain_hash, flow, timestamp, amt, short_channel_ids \ + = decode_reply_foaf_balances(msg, plugin) + + for ids in short_channel_ids: + plugin.log(str(ids)) # TODO: CHECK if 107b is the correct little endian of 439 res = plugin.rpc.dev_sendcustommsg(peer, "107b123412341234") From c7c2a945836f0d70a7dab33ffc8bfd7f3a8232ac Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sun, 10 May 2020 20:00:57 +0200 Subject: [PATCH 22/24] more or less final version? --- balancesharing/balancesharing.py | 39 +++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index 51b9b0d93..f29798078 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -99,6 +99,17 @@ def pack_channels(channels, plugin): return channels_packed +def unpack_channels(channels, plugin): + res = [] + for channel in channels: + byte_channel = struct.pack("!Q", channel) + vals = struct.unpack("!LHH", byte_channel) + short_channel_id = "x".join([str(x) for x in vals]) + res.append(short_channel_id) + plugin.log(" ".join(res)) + return res + + def decode_reply_foaf_balances(data, plugin): """Decode query_foaf_balances. Return type, chain_hash, flow_value and amt_to_rebalance""" # first part is 53 bytes big -> 106 characters @@ -108,7 +119,7 @@ def decode_reply_foaf_balances(data, plugin): second_part = data[106:] plugin.log("Splitting data 1") plugin.log(first_part) - msg_type, chain_hash, flow, timestamp, amt, num_channels \ + msg_type, chain_hash, flow, timestamp, amt, num_channels\ = struct.unpack("!H32scQQH", unhexlify(first_part.encode('ASCII'))) # plugin.log("Msg type: " + str(msg_type)) plugin.log("Splitting data 2") @@ -119,7 +130,8 @@ def decode_reply_foaf_balances(data, plugin): plugin.log(unpack_type) plugin.log(str(num_channels)) plugin.log(str(len(second_part))) - short_channel_ids = struct.unpack(unpack_type, unhexlify(second_part.encode('ASCII'))) + short_channel_ids = struct.unpack( + unpack_type, unhexlify(second_part.encode('ASCII'))) return msg_type, chain_hash, flow, timestamp, amt, short_channel_ids @@ -138,6 +150,7 @@ def encode_reply_foaf_balances(short_channels, flow_value, amt_to_rebalance, plu global REPLY_FOAF_BALANCES global CHAIN_HASH + """ fund_list = list_funds_mock() channels = fund_list["channels"] @@ -146,6 +159,7 @@ def encode_reply_foaf_balances(short_channels, flow_value, amt_to_rebalance, plu for ch in channels: mock_short_channels.append(ch["short_channel_id"]) short_channels = mock_short_channels + """ # time.time() returns a float with 4 decimal places timestamp = int(time.time() * 1000) @@ -206,7 +220,7 @@ def get_amount(amt): return amt -def log_error(msg): +def log_error(msg, plugin): plugin.log("Error in balancesharing plugin: {msg}".format(msg=msg)) @@ -217,13 +231,14 @@ def foafbalance(plugin, flow=1, amount=50000): # Read input data flow_value = get_flow_value(flow) if flow_value is None: - log_error("argument 'flow_value' for function 'foafbalance' was not 0 or 1") + log_error( + "argument 'flow_value' for function 'foafbalance' was not 0 or 1", plugin) return amt_to_rebalance = get_amount(amount) if amt_to_rebalance is None: log_error( - "argument 'amt_to_rebalance' for function 'foafbalance' was not valid") + "argument 'amt_to_rebalance' for function 'foafbalance' was not valid", plugin) return data = encode_query_foaf_balances(flow_value, amt_to_rebalance) @@ -311,11 +326,11 @@ def handle_query_foaf_balances(flow_value, amt_to_rebalance, plugin): channel_ids = [] for channel in channels: reserve = int(int(channel["channel_total_sat"]) * 0.01) + 1 - if flow_value == 1: + if flow_value == b'\x01': if channel["zeta"] > nu: if int(channel["channel_sat"]) > amt_to_rebalance + reserve: channel_ids.append(channel["short_channel_id"]) - elif flow_value == 0: + elif flow_value == b'\x00': if channel["zeta"] < nu: if int(channel["channel_total_sat"]) - int(channel["channel_sat"]) > amt_to_rebalance + reserve: channel_ids.append(channel["short_channel_id"]) @@ -326,10 +341,10 @@ def handle_query_foaf_balances(flow_value, amt_to_rebalance, plugin): def send_reply_foaf_balances(peer, amt, flow, channels, plugin): msg = encode_reply_foaf_balances(channels, flow, amt, plugin) - msg_type, chain_hash, flow, timestamp, amt, short_channel_ids \ + msg_type, chain_hash, flow, timestamp, amt, short_channel_ids\ = decode_reply_foaf_balances(msg, plugin) - for ids in short_channel_ids: + for ids in unpack_channels(short_channel_ids, plugin): plugin.log(str(ids)) # TODO: CHECK if 107b is the correct little endian of 439 @@ -391,14 +406,16 @@ def on_custommsg(peer_id, message, plugin, **kwargs): if chain_hash == BTC_CHAIN_HASH: result = handle_query_foaf_balances(flow, amt, plugin) + plugin.log("HALLO" + str(result)) r = send_reply_foaf_balances(peer_id, amt, flow, result, plugin) return_value = {"result": r} else: plugin.log("not handling non bitcoin chains for now") elif message_type == REPLY_FOAF_BALANCES: - chain_hash, flow_value, ts, amt_to_rebalance, short_channel_ids = decode_reply_foaf_balances_mock( - message) + _, chain_hash, flow_value, ts, amt_to_rebalance, short_channel_ids = decode_reply_foaf_balances( + message, plugin) + # decode_reply_foaf_balances_mock(message) plugin.log("received a reply_foaf_balances message") for short_channel_id in short_channel_ids: # TODO: remove mock From d9225e11643d688db3ba40f91b7df73b5f4de633 Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sat, 23 May 2020 15:46:18 +0200 Subject: [PATCH 23/24] stable version without indexing the channels as a local graph --- balancesharing/balancesharing.py | 61 +++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/balancesharing/balancesharing.py b/balancesharing/balancesharing.py index f29798078..3ba97a9bc 100755 --- a/balancesharing/balancesharing.py +++ b/balancesharing/balancesharing.py @@ -3,10 +3,25 @@ author: Rene Pickhardt (rene.m.pickhardt@ntnu.no) & Michael Ziegler (michael.h.ziegler@ntnu.no) Date: 9.5.2020 License: MIT -This code computes an optimal split of a payment amount for the use of AMP. -The split is optimal in the sense that it reduces the imbalance of the funds of the node. -More theory about imbalances and the algorithm to decrease the imblance of a node was -suggested by this research: https://arxiv.org/abs/1912.09555 + +This is a reference example implementatation of the two new Lightning messages +`query_foaf_balances` and `reply_foaf_balances` introduced in BOLT 14 as a c-lightning plugin. +In order to run this plugin you need to compile c-lightning with developers=1 enabeled as it +makes use of `dev-sendcustommsg` api command. + +The tool also replies with channels that meet the rebalancing criteria from this research: +https://arxiv.org/abs/1912.09555 + +This plugin does not yet implement JIT routing / meaning it does not yet interrupt the +routing process if it cannot forward an HTLC due to a lack of liquidity on the requested +channel. +Thus the API forseing he query to all friends is currently exposed to the command line with: + +`lightning-cli foafalance {dirirction} {amount}` + +The messages have typ 437 (a prime number with checksum 14 and in the correct semantic range) + +The messages are currently not implemented in a TLV style. """ import networkx as nx @@ -21,6 +36,9 @@ REPLY_FOAF_BALANCES = 439 CHAIN_HASH = r'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' BTC_CHAIN_HASH = CHAIN_HASH + +MOCK_CALLS = True + # TODO: replace with plugin.rpc.listchannels(short_channel_id) CHANNEL_INDEX = {} @@ -56,8 +74,12 @@ def get_other_node(node_id, short_channel_id): def get_funds(plugin): """"get output and channels""" # TODO: switch to real data - # fund_list = plugin.rpc.listfunds() - fund_list = list_funds_mock() + fund_list = None + if MOCK_CALLS: + fund_list = list_funds_mock() + else: + fund_list = plugin.rpc.listfunds() + outputs = fund_list["outputs"] channels = fund_list["channels"] @@ -347,8 +369,11 @@ def send_reply_foaf_balances(peer, amt, flow, channels, plugin): for ids in unpack_channels(short_channel_ids, plugin): plugin.log(str(ids)) + plugin.log("attempting to send {} of type {}".format(msg, msg_type)) + # TODO: CHECK if 107b is the correct little endian of 439 - res = plugin.rpc.dev_sendcustommsg(peer, "107b123412341234") + # "107b"+msg[4:]) # "107b123412341234") + res = plugin.rpc.dev_sendcustommsg(peer, msg) plugin.log("Sent query_foaf_balances message to {peer_id}. Response: {res}".format( peer_id=peer, res=res @@ -388,8 +413,11 @@ def on_custommsg(peer_id, message, plugin, **kwargs): msg=message, peer_id=peer_id )) - # TODO: Remove to stop mocking - mock_peer_id = "03efccf2c383d7bf340da9a3f02e2c23104a0e4fe8ac1a880c8e2dc92fbdacd9df" + mock_peer_id = None + if MOCK_CALLS: + mock_peer_id = "03efccf2c383d7bf340da9a3f02e2c23104a0e4fe8ac1a880c8e2dc92fbdacd9df" + else: + mock_peer_id = peer_id plugin.log("switched peer_id to {} for testing".format(peer_id)) # message has to be at least 6 bytes. 4 bytes prefix and 2 bytes for the type assert len(message) > 12 @@ -400,6 +428,7 @@ def on_custommsg(peer_id, message, plugin, **kwargs): # query_foaf_balances message has type 437 which is 01b5 in hex return_value = {} + plugin.log("message type {}".format(message_type)) if message_type == QUERY_FOAF_BALANCES: plugin.log("received query_foaf_balances message") _, chain_hash, flow, amt = decode_query_foaf_balances(message) @@ -409,6 +438,7 @@ def on_custommsg(peer_id, message, plugin, **kwargs): plugin.log("HALLO" + str(result)) r = send_reply_foaf_balances(peer_id, amt, flow, result, plugin) return_value = {"result": r} + plugin.log("return value!!!! {}".format(return_value)) else: plugin.log("not handling non bitcoin chains for now") @@ -416,9 +446,14 @@ def on_custommsg(peer_id, message, plugin, **kwargs): _, chain_hash, flow_value, ts, amt_to_rebalance, short_channel_ids = decode_reply_foaf_balances( message, plugin) # decode_reply_foaf_balances_mock(message) - plugin.log("received a reply_foaf_balances message") - for short_channel_id in short_channel_ids: - # TODO: remove mock + plugin.log("received a reply_foaf_balances message {} with channels {} ".format( + message, short_channel_ids)) + # for short_channel_id in short_channel_ids: + # plugin.log("{}".format(short_channel_id)) + # return_value = {"result": {'peer_id': '03a0fe68c028d5779d999c08ebd91d23a735aa3fe94f7cc3e5c6f40a922033c531', 'response': { + # 'status': 'Message sent to subdaemon openingd for delivery'}}} + # TODO: remove mock + """ partner = get_other_node(mock_peer_id, short_channel_id) if partner is None: continue @@ -431,7 +466,7 @@ def on_custommsg(peer_id, message, plugin, **kwargs): # TODO invoke rebalance path finding logic (but with whome? need a peer to which an HTLC is stuck) plugin.log("FOAF Graph now has {} channels".format( len(foaf_network.edges()))) - +""" return return_value From c809e025ddddccd185ce7c189c81a9f9dfcd0fd8 Mon Sep 17 00:00:00 2001 From: Rene Pickhardt Date: Sat, 23 May 2020 15:53:18 +0200 Subject: [PATCH 24/24] addedmore info for the readme --- balancesharing/README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/balancesharing/README.md b/balancesharing/README.md index 612b62115..dc8eb10d7 100644 --- a/balancesharing/README.md +++ b/balancesharing/README.md @@ -1,7 +1,11 @@ -# Balance Sharin Plugin +# Balance Sharing Plugin This is Work in Progress by Michael Ziegler and Rene Pickhadt from NTNU to extend the Lightning Network Protocol with the ability of nodes sharing their balance information with neighbors. This is needed to provide JIT-Routing functionality. Read more on: https://wiki.fulmo.org/wiki/Challenges_May_2020#JIT_Routing_.2F_Sharing_balance_information +The current plugin is just able to encode and decode two new custom messages and send them out. The query message is exposed via the apicommand `lightning-cli foafbalance {direction} {amt}` + +Currently the results are writen to the logfile. in future they need to be cached and processed. In particular if the command line API should continue to exist (we recommend against this) there should be timeout of the queries. + ## Installation @@ -27,6 +31,12 @@ note that if you use the autoreload plugin you MUST pass the path the the balanc lightningd --network regtest --autoreload-plugin=/path/to/plugins/balancesharing/balancesharing.py ``` +if you want to run in regtest without setting up your own lightning cannels you can put 2 files in this directory which are the output from `listchannels` and `listfunds` command. by executing the following two commands on some lightning node and copy the two files. + +``` +lightning-cli listfunds > funds.json +lightning-cli listchannels > channels.json +``` For general plugin installation instructions see the repos main [README.md](https://github.com/lightningd/plugins/blob/master/README.md#Installation)