|
|
@ -4,6 +4,8 @@ |
|
|
|
Derived from https://gist.github.com/AdamISZ/046d05c156aaeb56cc897f85eecb3eb8 |
|
|
|
""" |
|
|
|
|
|
|
|
import json |
|
|
|
from collections import OrderedDict |
|
|
|
import asyncio |
|
|
|
import sys |
|
|
|
import binascii |
|
|
@ -17,6 +19,99 @@ from electrum.bitcoin import int_to_hex, bfh, rev_hex |
|
|
|
tcp_socket_timeout = 10 |
|
|
|
server_response_timeout = 60 |
|
|
|
|
|
|
|
############################### |
|
|
|
|
|
|
|
message_types = {} |
|
|
|
|
|
|
|
def handlesingle(x, ma): |
|
|
|
try: |
|
|
|
x = int(x) |
|
|
|
except ValueError: |
|
|
|
x = ma[x] |
|
|
|
try: |
|
|
|
x = int(x) |
|
|
|
except ValueError: |
|
|
|
x = int.from_bytes(x, byteorder="big") |
|
|
|
return x |
|
|
|
|
|
|
|
def calcexp(exp, ma): |
|
|
|
exp = str(exp) |
|
|
|
assert "*" not in exp |
|
|
|
return sum(handlesingle(x, ma) for x in exp.split("+")) |
|
|
|
|
|
|
|
def make_handler(k, v): |
|
|
|
def handler(data): |
|
|
|
nonlocal k, v |
|
|
|
print("msg type", k) |
|
|
|
ma = {} |
|
|
|
pos = 0 |
|
|
|
for fieldname in v["payload"]: |
|
|
|
poslenMap = v["payload"][fieldname] |
|
|
|
#print(poslenMap["position"], ma) |
|
|
|
assert pos == calcexp(poslenMap["position"], ma) |
|
|
|
length = poslenMap["length"] |
|
|
|
length = calcexp(length, ma) |
|
|
|
ma[fieldname] = data[pos:pos+length] |
|
|
|
pos += length |
|
|
|
assert pos == len(data), (k, pos, len(data)) |
|
|
|
return ma |
|
|
|
return handler |
|
|
|
|
|
|
|
with open("lightning.json") as f: |
|
|
|
structured = json.loads(f.read(), object_pairs_hook=OrderedDict) |
|
|
|
|
|
|
|
for k in structured: |
|
|
|
v = structured[k] |
|
|
|
if k in ["open_channel","final_incorrect_cltv_expiry", "final_incorrect_htlc_amount"]: |
|
|
|
continue |
|
|
|
if len(v["payload"]) == 0: |
|
|
|
continue |
|
|
|
try: |
|
|
|
num = int(v["type"]) |
|
|
|
except ValueError: |
|
|
|
#print("skipping", k) |
|
|
|
continue |
|
|
|
byts = num.to_bytes(byteorder="big",length=2) |
|
|
|
assert byts not in message_types, (byts, message_types[byts].__name__, k) |
|
|
|
names = [x.__name__ for x in message_types.values()] |
|
|
|
assert k + "_handler" not in names, (k, names) |
|
|
|
message_types[byts] = make_handler(k, v) |
|
|
|
message_types[byts].__name__ = k + "_handler" |
|
|
|
|
|
|
|
assert message_types[b"\x00\x10"].__name__ == "init_handler" |
|
|
|
|
|
|
|
def decode_msg(data): |
|
|
|
typ = data[:2] |
|
|
|
parsed = message_types[typ](data[2:]) |
|
|
|
return parsed |
|
|
|
|
|
|
|
|
|
|
|
def gen_msg(msg_type, **kwargs): |
|
|
|
typ = structured[msg_type] |
|
|
|
data = int(typ["type"]).to_bytes(byteorder="big", length=2) |
|
|
|
lengths = {} |
|
|
|
for k in typ["payload"]: |
|
|
|
poslenMap = typ["payload"][k] |
|
|
|
leng = calcexp(poslenMap["length"], lengths) |
|
|
|
try: |
|
|
|
leng = kwargs[poslenMap["length"]] |
|
|
|
except: |
|
|
|
pass |
|
|
|
try: |
|
|
|
param = kwargs[k] |
|
|
|
except KeyError: |
|
|
|
param = 0 |
|
|
|
try: |
|
|
|
param = param.to_bytes(length=leng, byteorder="big") |
|
|
|
except: |
|
|
|
raise Exception("{} does not fit in {} bytes".format(k, leng)) |
|
|
|
lengths[k] = len(param) |
|
|
|
data += param |
|
|
|
return data |
|
|
|
|
|
|
|
############################### |
|
|
|
|
|
|
|
|
|
|
|
def decode(string): |
|
|
|
"""Return the integer value of the |
|
|
|
bytestring b |
|
|
@ -198,7 +293,7 @@ async def main_loop(my_privkey, host, port, pubkey, loop): |
|
|
|
rn += 2 |
|
|
|
|
|
|
|
# send init |
|
|
|
init_msg = encode(16, 2) + encode(0, 2) +encode(0,2) |
|
|
|
init_msg = gen_msg("init", gflen=0, lflen=0) |
|
|
|
send_message(writer, init_msg, sk, sn) |
|
|
|
sn += 2 |
|
|
|
|
|
|
|