lnmsg: rewrite LN msg encoding/decoding

This commit is contained in:
SomberNight 2020-03-12 01:44:42 +01:00
parent 371f55a0f9
commit 4c10a830f3
No known key found for this signature in database
GPG key ID: B33B5F232C6271E9
8 changed files with 477 additions and 1036 deletions

View file

@ -321,11 +321,12 @@ class ChannelDB(SqlDB):
return ret return ret
# note: currently channel announcements are trusted by default (trusted=True); # note: currently channel announcements are trusted by default (trusted=True);
# they are not verified. Verifying them would make the gossip sync # they are not SPV-verified. Verifying them would make the gossip sync
# even slower; especially as servers will start throttling us. # even slower; especially as servers will start throttling us.
# It would probably put significant strain on servers if all clients # It would probably put significant strain on servers if all clients
# verified the complete gossip. # verified the complete gossip.
def add_channel_announcement(self, msg_payloads, *, trusted=True): def add_channel_announcement(self, msg_payloads, *, trusted=True):
# note: signatures have already been verified.
if type(msg_payloads) is dict: if type(msg_payloads) is dict:
msg_payloads = [msg_payloads] msg_payloads = [msg_payloads]
added = 0 added = 0
@ -499,6 +500,7 @@ class ChannelDB(SqlDB):
raise Exception(f'failed verifying channel update for {short_channel_id}') raise Exception(f'failed verifying channel update for {short_channel_id}')
def add_node_announcement(self, msg_payloads): def add_node_announcement(self, msg_payloads):
# note: signatures have already been verified.
if type(msg_payloads) is dict: if type(msg_payloads) is dict:
msg_payloads = [msg_payloads] msg_payloads = [msg_payloads]
new_nodes = {} new_nodes = {}

View file

@ -1,903 +0,0 @@
{
"init": {
"type": "16",
"payload": {
"gflen": {
"position": "0",
"length": "2"
},
"globalfeatures": {
"position": "2",
"length": "gflen"
},
"lflen": {
"position": "2+gflen",
"length": "2"
},
"localfeatures": {
"position": "4+gflen",
"length": "lflen"
}
}
},
"error": {
"type": "17",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"len": {
"position": "32",
"length": "2"
},
"data": {
"position": "34",
"length": "len"
}
}
},
"ping": {
"type": "18",
"payload": {
"num_pong_bytes": {
"position": "0",
"length": "2"
},
"byteslen": {
"position": "2",
"length": "2"
},
"ignored": {
"position": "4",
"length": "byteslen"
}
}
},
"pong": {
"type": "19",
"payload": {
"byteslen": {
"position": "0",
"length": "2"
},
"ignored": {
"position": "2",
"length": "byteslen"
}
}
},
"open_channel": {
"type": "32",
"payload": {
"chain_hash": {
"position": "0",
"length": "32"
},
"temporary_channel_id": {
"position": "32",
"length": "32"
},
"funding_satoshis": {
"position": "64",
"length": "8"
},
"push_msat": {
"position": "72",
"length": "8"
},
"dust_limit_satoshis": {
"position": "80",
"length": "8"
},
"max_htlc_value_in_flight_msat": {
"position": "88",
"length": "8"
},
"channel_reserve_satoshis": {
"position": "96",
"length": "8"
},
"htlc_minimum_msat": {
"position": "104",
"length": "8"
},
"feerate_per_kw": {
"position": "112",
"length": "4"
},
"to_self_delay": {
"position": "116",
"length": "2"
},
"max_accepted_htlcs": {
"position": "118",
"length": "2"
},
"funding_pubkey": {
"position": "120",
"length": "33"
},
"revocation_basepoint": {
"position": "153",
"length": "33"
},
"payment_basepoint": {
"position": "186",
"length": "33"
},
"delayed_payment_basepoint": {
"position": "219",
"length": "33"
},
"htlc_basepoint": {
"position": "252",
"length": "33"
},
"first_per_commitment_point": {
"position": "285",
"length": "33"
},
"channel_flags": {
"position": "318",
"length": "1"
},
"shutdown_len": {
"position": "319",
"length": "2",
"feature": "option_upfront_shutdown_script"
},
"shutdown_scriptpubkey": {
"position": "321",
"length": "shutdown_len",
"feature": "option_upfront_shutdown_script"
}
}
},
"accept_channel": {
"type": "33",
"payload": {
"temporary_channel_id": {
"position": "0",
"length": "32"
},
"dust_limit_satoshis": {
"position": "32",
"length": "8"
},
"max_htlc_value_in_flight_msat": {
"position": "40",
"length": "8"
},
"channel_reserve_satoshis": {
"position": "48",
"length": "8"
},
"htlc_minimum_msat": {
"position": "56",
"length": "8"
},
"minimum_depth": {
"position": "64",
"length": "4"
},
"to_self_delay": {
"position": "68",
"length": "2"
},
"max_accepted_htlcs": {
"position": "70",
"length": "2"
},
"funding_pubkey": {
"position": "72",
"length": "33"
},
"revocation_basepoint": {
"position": "105",
"length": "33"
},
"payment_basepoint": {
"position": "138",
"length": "33"
},
"delayed_payment_basepoint": {
"position": "171",
"length": "33"
},
"htlc_basepoint": {
"position": "204",
"length": "33"
},
"first_per_commitment_point": {
"position": "237",
"length": "33"
},
"shutdown_len": {
"position": "270",
"length": "2",
"feature": "option_upfront_shutdown_script"
},
"shutdown_scriptpubkey": {
"position": "272",
"length": "shutdown_len",
"feature": "option_upfront_shutdown_script"
}
}
},
"funding_created": {
"type": "34",
"payload": {
"temporary_channel_id": {
"position": "0",
"length": "32"
},
"funding_txid": {
"position": "32",
"length": "32"
},
"funding_output_index": {
"position": "64",
"length": "2"
},
"signature": {
"position": "66",
"length": "64"
}
}
},
"funding_signed": {
"type": "35",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"signature": {
"position": "32",
"length": "64"
}
}
},
"funding_locked": {
"type": "36",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"next_per_commitment_point": {
"position": "32",
"length": "33"
}
}
},
"shutdown": {
"type": "38",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"len": {
"position": "32",
"length": "2"
},
"scriptpubkey": {
"position": "34",
"length": "len"
}
}
},
"closing_signed": {
"type": "39",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"fee_satoshis": {
"position": "32",
"length": "8"
},
"signature": {
"position": "40",
"length": "64"
}
}
},
"update_add_htlc": {
"type": "128",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"id": {
"position": "32",
"length": "8"
},
"amount_msat": {
"position": "40",
"length": "8"
},
"payment_hash": {
"position": "48",
"length": "32"
},
"cltv_expiry": {
"position": "80",
"length": "4"
},
"onion_routing_packet": {
"position": "84",
"length": "1366"
}
}
},
"update_fulfill_htlc": {
"type": "130",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"id": {
"position": "32",
"length": "8"
},
"payment_preimage": {
"position": "40",
"length": "32"
}
}
},
"update_fail_htlc": {
"type": "131",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"id": {
"position": "32",
"length": "8"
},
"len": {
"position": "40",
"length": "2"
},
"reason": {
"position": "42",
"length": "len"
}
}
},
"update_fail_malformed_htlc": {
"type": "135",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"id": {
"position": "32",
"length": "8"
},
"sha256_of_onion": {
"position": "40",
"length": "32"
},
"failure_code": {
"position": "72",
"length": "2"
}
}
},
"commitment_signed": {
"type": "132",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"signature": {
"position": "32",
"length": "64"
},
"num_htlcs": {
"position": "96",
"length": "2"
},
"htlc_signature": {
"position": "98",
"length": "num_htlcs*64"
}
}
},
"revoke_and_ack": {
"type": "133",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"per_commitment_secret": {
"position": "32",
"length": "32"
},
"next_per_commitment_point": {
"position": "64",
"length": "33"
}
}
},
"update_fee": {
"type": "134",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"feerate_per_kw": {
"position": "32",
"length": "4"
}
}
},
"channel_reestablish": {
"type": "136",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"next_local_commitment_number": {
"position": "32",
"length": "8"
},
"next_remote_revocation_number": {
"position": "40",
"length": "8"
},
"your_last_per_commitment_secret": {
"position": "48",
"length": "32",
"feature": "option_data_loss_protect"
},
"my_current_per_commitment_point": {
"position": "80",
"length": "33",
"feature": "option_data_loss_protect"
}
}
},
"invalid_realm": {
"type": "PERM|1",
"payload": {}
},
"temporary_node_failure": {
"type": "NODE|2",
"payload": {}
},
"permanent_node_failure": {
"type": "PERM|NODE|2",
"payload": {}
},
"required_node_feature_missing": {
"type": "PERM|NODE|3",
"payload": {}
},
"invalid_onion_version": {
"type": "BADONION|PERM|4",
"payload": {
"sha256_of_onion": {
"position": "0",
"length": "32"
}
}
},
"invalid_onion_hmac": {
"type": "BADONION|PERM|5",
"payload": {
"sha256_of_onion": {
"position": "0",
"length": "32"
}
}
},
"invalid_onion_key": {
"type": "BADONION|PERM|6",
"payload": {
"sha256_of_onion": {
"position": "0",
"length": "32"
}
}
},
"temporary_channel_failure": {
"type": "UPDATE|7",
"payload": {
"len": {
"position": "0",
"length": "2"
},
"channel_update": {
"position": "2",
"length": "len"
}
}
},
"permanent_channel_failure": {
"type": "PERM|8",
"payload": {}
},
"required_channel_feature_missing": {
"type": "PERM|9",
"payload": {}
},
"unknown_next_peer": {
"type": "PERM|10",
"payload": {}
},
"amount_below_minimum": {
"type": "UPDATE|11",
"payload": {
"htlc_msat": {
"position": "0",
"length": "8"
},
"len": {
"position": "8",
"length": "2"
},
"channel_update": {
"position": "10",
"length": "len"
}
}
},
"fee_insufficient": {
"type": "UPDATE|12",
"payload": {
"htlc_msat": {
"position": "0",
"length": "8"
},
"len": {
"position": "8",
"length": "2"
},
"channel_update": {
"position": "10",
"length": "len"
}
}
},
"incorrect_cltv_expiry": {
"type": "UPDATE|13",
"payload": {
"cltv_expiry": {
"position": "0",
"length": "4"
},
"len": {
"position": "4",
"length": "2"
},
"channel_update": {
"position": "6",
"length": "len"
}
}
},
"expiry_too_soon": {
"type": "UPDATE|14",
"payload": {
"len": {
"position": "0",
"length": "2"
},
"channel_update": {
"position": "2",
"length": "len"
}
}
},
"unknown_payment_hash": {
"type": "PERM|15",
"payload": {}
},
"incorrect_payment_amount": {
"type": "PERM|16",
"payload": {}
},
"final_expiry_too_soon": {
"type": "17",
"payload": {}
},
"final_incorrect_cltv_expiry": {
"type": "18",
"payload": {
"cltv_expiry": {
"position": "0",
"length": "4"
}
}
},
"final_incorrect_htlc_amount": {
"type": "19",
"payload": {
"incoming_htlc_amt": {
"position": "0",
"length": "8"
}
}
},
"channel_disabled": {
"type": "UPDATE|20",
"payload": {}
},
"expiry_too_far": {
"type": "21",
"payload": {}
},
"announcement_signatures": {
"type": "259",
"payload": {
"channel_id": {
"position": "0",
"length": "32"
},
"short_channel_id": {
"position": "32",
"length": "8"
},
"node_signature": {
"position": "40",
"length": "64"
},
"bitcoin_signature": {
"position": "104",
"length": "64"
}
}
},
"channel_announcement": {
"type": "256",
"payload": {
"node_signature_1": {
"position": "0",
"length": "64"
},
"node_signature_2": {
"position": "64",
"length": "64"
},
"bitcoin_signature_1": {
"position": "128",
"length": "64"
},
"bitcoin_signature_2": {
"position": "192",
"length": "64"
},
"len": {
"position": "256",
"length": "2"
},
"features": {
"position": "258",
"length": "len"
},
"chain_hash": {
"position": "258+len",
"length": "32"
},
"short_channel_id": {
"position": "290+len",
"length": "8"
},
"node_id_1": {
"position": "298+len",
"length": "33"
},
"node_id_2": {
"position": "331+len",
"length": "33"
},
"bitcoin_key_1": {
"position": "364+len",
"length": "33"
},
"bitcoin_key_2": {
"position": "397+len",
"length": "33"
}
}
},
"node_announcement": {
"type": "257",
"payload": {
"signature": {
"position": "0",
"length": "64"
},
"flen": {
"position": "64",
"length": "2"
},
"features": {
"position": "66",
"length": "flen"
},
"timestamp": {
"position": "66+flen",
"length": "4"
},
"node_id": {
"position": "70+flen",
"length": "33"
},
"rgb_color": {
"position": "103+flen",
"length": "3"
},
"alias": {
"position": "106+flen",
"length": "32"
},
"addrlen": {
"position": "138+flen",
"length": "2"
},
"addresses": {
"position": "140+flen",
"length": "addrlen"
}
}
},
"channel_update": {
"type": "258",
"payload": {
"signature": {
"position": "0",
"length": "64"
},
"chain_hash": {
"position": "64",
"length": "32"
},
"short_channel_id": {
"position": "96",
"length": "8"
},
"timestamp": {
"position": "104",
"length": "4"
},
"message_flags": {
"position": "108",
"length": "1"
},
"channel_flags": {
"position": "109",
"length": "1"
},
"cltv_expiry_delta": {
"position": "110",
"length": "2"
},
"htlc_minimum_msat": {
"position": "112",
"length": "8"
},
"fee_base_msat": {
"position": "120",
"length": "4"
},
"fee_proportional_millionths": {
"position": "124",
"length": "4"
},
"htlc_maximum_msat": {
"position": "128",
"length": "8",
"feature": "option_channel_htlc_max"
}
}
},
"query_short_channel_ids": {
"type": "261",
"payload": {
"chain_hash": {
"position": "0",
"length": "32"
},
"len": {
"position": "32",
"length": "2"
},
"encoded_short_ids": {
"position": "34",
"length": "len"
}
}
},
"reply_short_channel_ids_end": {
"type": "262",
"payload": {
"chain_hash": {
"position": "0",
"length": "32"
},
"complete": {
"position": "32",
"length": "1"
}
}
},
"query_channel_range": {
"type": "263",
"payload": {
"chain_hash": {
"position": "0",
"length": "32"
},
"first_blocknum": {
"position": "32",
"length": "4"
},
"number_of_blocks": {
"position": "36",
"length": "4"
}
}
},
"reply_channel_range": {
"type": "264",
"payload": {
"chain_hash": {
"position": "0",
"length": "32"
},
"first_blocknum": {
"position": "32",
"length": "4"
},
"number_of_blocks": {
"position": "36",
"length": "4"
},
"complete": {
"position": "40",
"length": "1"
},
"len": {
"position": "41",
"length": "2"
},
"encoded_short_ids": {
"position": "43",
"length": "len"
}
}
},
"gossip_timestamp_filter": {
"type": "265",
"payload": {
"chain_hash": {
"position": "0",
"length": "32"
},
"first_timestamp": {
"position": "32",
"length": "4"
},
"timestamp_range": {
"position": "36",
"length": "4"
}
}
}
}

View file

@ -249,7 +249,8 @@ class Channel(Logger):
node_ids = sorted_node_ids node_ids = sorted_node_ids
bitcoin_keys.reverse() bitcoin_keys.reverse()
chan_ann = encode_msg("channel_announcement", chan_ann = encode_msg(
"channel_announcement",
len=0, len=0,
features=b'', features=b'',
chain_hash=constants.net.rev_genesis_bytes(), chain_hash=constants.net.rev_genesis_bytes(),
@ -257,7 +258,7 @@ class Channel(Logger):
node_id_1=node_ids[0], node_id_1=node_ids[0],
node_id_2=node_ids[1], node_id_2=node_ids[1],
bitcoin_key_1=bitcoin_keys[0], bitcoin_key_1=bitcoin_keys[0],
bitcoin_key_2=bitcoin_keys[1] bitcoin_key_2=bitcoin_keys[1],
) )
self._chan_ann_without_sigs = chan_ann self._chan_ann_without_sigs = chan_ann

View file

@ -1,152 +1,225 @@
import json
import os import os
from typing import Callable, Tuple import csv
from collections import OrderedDict import io
from typing import Callable, Tuple, Any, Dict, List, Sequence, Union
def _eval_length_term(x, ma: dict) -> int:
"""
Evaluate a term of the simple language used
to specify lightning message field lengths.
If `x` is an integer, it is returned as is, class MalformedMsg(Exception):
otherwise it is treated as a variable and pass
looked up in `ma`.
If the value in `ma` was no integer, it is
assumed big-endian bytes and decoded.
Returns evaluated result as int class UnknownMsgFieldType(MalformedMsg):
""" pass
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 _eval_exp_with_ctx(exp, ctx: dict) -> int:
"""
Evaluate simple mathematical expression given
in `exp` with context (variables assigned)
from the dict `ctx`.
Returns evaluated result as int class UnexpectedEndOfStream(MalformedMsg):
""" pass
exp = str(exp)
if "*" in exp:
assert "+" not in exp
result = 1
for term in exp.split("*"):
result *= _eval_length_term(term, ctx)
return result
return sum(_eval_length_term(x, ctx) for x in exp.split("+"))
def _make_handler(msg_name: str, v: dict) -> Callable[[bytes], Tuple[str, dict]]:
"""
Generate a message handler function (taking bytes)
for message type `msg_name` with specification `v`
Check lib/lightning.json, `msg_name` could be 'init', def _assert_can_read_at_least_n_bytes(fd: io.BytesIO, n: int) -> None:
and `v` could be cur_pos = fd.tell()
end_pos = fd.seek(0, io.SEEK_END)
fd.seek(cur_pos)
if end_pos - cur_pos < n:
raise UnexpectedEndOfStream(f"cur_pos={cur_pos}. end_pos={end_pos}. wants to read: {n}")
{ type: 16, payload: { 'gflen': ..., ... }, ... }
Returns function taking bytes # TODO return int when it makes sense
""" def _read_field(*, fd: io.BytesIO, field_type: str, count: int) -> bytes:
def handler(data: bytes) -> Tuple[str, dict]: if not fd: raise Exception()
ma = {} # map of field name -> field data; after parsing msg assert isinstance(count, int) and count >= 0, f"{count!r} must be non-neg int"
pos = 0 if count == 0:
for fieldname in v["payload"]: return b""
poslenMap = v["payload"][fieldname] type_len = None
if "feature" in poslenMap and pos == len(data): if field_type == 'byte':
continue type_len = 1
#assert pos == _eval_exp_with_ctx(poslenMap["position"], ma) # this assert is expensive... elif field_type == 'u16':
length = poslenMap["length"] type_len = 2
length = _eval_exp_with_ctx(length, ma) elif field_type == 'u32':
ma[fieldname] = data[pos:pos+length] type_len = 4
pos += length elif field_type == 'u64':
# BOLT-01: "MUST ignore any additional data within a message beyond the length that it expects for that type." type_len = 8
assert pos <= len(data), (msg_name, pos, len(data)) # TODO tu16/tu32/tu64
return msg_name, ma elif field_type == 'chain_hash':
return handler type_len = 32
elif field_type == 'channel_id':
type_len = 32
elif field_type == 'sha256':
type_len = 32
elif field_type == 'signature':
type_len = 64
elif field_type == 'point':
type_len = 33
elif field_type == 'short_channel_id':
type_len = 8
if type_len is None:
raise UnknownMsgFieldType(f"unexpected field type: {field_type!r}")
total_len = count * type_len
_assert_can_read_at_least_n_bytes(fd, total_len)
return fd.read(total_len)
def _write_field(*, fd: io.BytesIO, field_type: str, count: int,
value: Union[bytes, int]) -> None:
if not fd: raise Exception()
assert isinstance(count, int) and count >= 0, f"{count!r} must be non-neg int"
if count == 0:
return
type_len = None
if field_type == 'byte':
type_len = 1
elif field_type == 'u16':
type_len = 2
elif field_type == 'u32':
type_len = 4
elif field_type == 'u64':
type_len = 8
# TODO tu16/tu32/tu64
elif field_type == 'chain_hash':
type_len = 32
elif field_type == 'channel_id':
type_len = 32
elif field_type == 'sha256':
type_len = 32
elif field_type == 'signature':
type_len = 64
elif field_type == 'point':
type_len = 33
elif field_type == 'short_channel_id':
type_len = 8
if type_len is None:
raise UnknownMsgFieldType(f"unexpected fundamental type: {field_type!r}")
total_len = count * type_len
if isinstance(value, int) and (count == 1 or field_type == 'byte'):
value = int.to_bytes(value, length=total_len, byteorder="big", signed=False)
if not isinstance(value, (bytes, bytearray)):
raise Exception(f"can only write bytes into fd. got: {value!r}")
if total_len != len(value):
raise Exception(f"unexpected field size. expected: {total_len}, got {len(value)}")
nbytes_written = fd.write(value)
if nbytes_written != len(value):
raise Exception(f"tried to write {len(value)} bytes, but only wrote {nbytes_written}!?")
class LNSerializer: class LNSerializer:
def __init__(self): def __init__(self):
message_types = {} self.msg_scheme_from_type = {} # type: Dict[bytes, List[Sequence[str]]]
path = os.path.join(os.path.dirname(__file__), 'lightning.json') self.msg_type_from_name = {} # type: Dict[str, bytes]
with open(path) as f: path = os.path.join(os.path.dirname(__file__), "lnwire", "peer_wire.csv")
structured = json.loads(f.read(), object_pairs_hook=OrderedDict) with open(path, newline='') as f:
csvreader = csv.reader(f)
for row in csvreader:
#print(f">>> {row!r}")
if row[0] == "msgtype":
msg_type_name = row[1]
msg_type_int = int(row[2])
msg_type_bytes = msg_type_int.to_bytes(2, 'big')
assert msg_type_bytes not in self.msg_scheme_from_type, f"type collision? for {msg_type_name}"
assert msg_type_name not in self.msg_type_from_name, f"type collision? for {msg_type_name}"
row[2] = msg_type_int
self.msg_scheme_from_type[msg_type_bytes] = [tuple(row)]
self.msg_type_from_name[msg_type_name] = msg_type_bytes
elif row[0] == "msgdata":
assert msg_type_name == row[1]
self.msg_scheme_from_type[msg_type_bytes].append(tuple(row))
else:
pass # TODO
for msg_name in structured: def encode_msg(self, msg_type: str, **kwargs) -> bytes:
v = structured[msg_name]
# these message types are skipped since their types collide
# (for example with pong, which also uses type=19)
# we don't need them yet
if msg_name in ["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(2, 'big')
assert byts not in message_types, (byts, message_types[byts].__name__, msg_name)
names = [x.__name__ for x in message_types.values()]
assert msg_name + "_handler" not in names, (msg_name, names)
message_types[byts] = _make_handler(msg_name, v)
message_types[byts].__name__ = msg_name + "_handler"
assert message_types[b"\x00\x10"].__name__ == "init_handler"
self.structured = structured
self.message_types = message_types
def encode_msg(self, msg_type : str, **kwargs) -> bytes:
""" """
Encode kwargs into a Lightning message (bytes) Encode kwargs into a Lightning message (bytes)
of the type given in the msg_type string of the type given in the msg_type string
""" """
typ = self.structured[msg_type] #print(f">>> encode_msg. msg_type={msg_type}, payload={kwargs!r}")
data = int(typ["type"]).to_bytes(2, 'big') msg_type_bytes = self.msg_type_from_name[msg_type]
lengths = {} scheme = self.msg_scheme_from_type[msg_type_bytes]
for k in typ["payload"]: with io.BytesIO() as fd:
poslenMap = typ["payload"][k] fd.write(msg_type_bytes)
if k not in kwargs and "feature" in poslenMap: for row in scheme:
continue if row[0] == "msgtype":
param = kwargs.get(k, 0) pass
leng = _eval_exp_with_ctx(poslenMap["length"], lengths) elif row[0] == "msgdata":
try: field_name = row[2]
clone = dict(lengths) field_type = row[3]
clone.update(kwargs) field_count_str = row[4]
leng = _eval_exp_with_ctx(poslenMap["length"], clone) #print(f">>> encode_msg. msgdata. field_name={field_name!r}. field_type={field_type!r}. field_count_str={field_count_str!r}")
except KeyError: if field_count_str == "":
pass field_count = 1
try: else:
if not isinstance(param, bytes): try:
assert isinstance(param, int), "field {} is neither bytes or int".format(k) field_count = int(field_count_str)
param = param.to_bytes(leng, 'big') except ValueError:
except ValueError: field_count = kwargs[field_count_str]
raise Exception("{} does not fit in {} bytes".format(k, leng)) if isinstance(field_count, (bytes, bytearray)):
lengths[k] = len(param) field_count = int.from_bytes(field_count, byteorder="big")
if lengths[k] != leng: assert isinstance(field_count, int)
raise Exception("field {} is {} bytes long, should be {} bytes long".format(k, lengths[k], leng)) try:
data += param field_value = kwargs[field_name]
return data except KeyError:
if len(row) > 5:
break # optional feature field not present
else:
field_value = 0 # default mandatory fields to zero
#print(f">>> encode_msg. writing field: {field_name}. value={field_value!r}. field_type={field_type!r}. count={field_count!r}")
try:
_write_field(fd=fd,
field_type=field_type,
count=field_count,
value=field_value)
#print(f">>> encode_msg. so far: {fd.getvalue().hex()}")
except UnknownMsgFieldType as e:
pass # TODO
else:
pass # TODO
return fd.getvalue()
def decode_msg(self, data : bytes) -> Tuple[str, dict]: def decode_msg(self, data: bytes) -> Tuple[str, dict]:
""" """
Decode Lightning message by reading the first Decode Lightning message by reading the first
two bytes to determine message type. two bytes to determine message type.
Returns message type string and parsed message contents dict Returns message type string and parsed message contents dict
""" """
typ = data[:2] #print(f"decode_msg >>> {data.hex()}")
k, parsed = self.message_types[typ](data[2:]) assert len(data) >= 2
return k, parsed msg_type_bytes = data[:2]
msg_type_int = int.from_bytes(msg_type_bytes, byteorder="big", signed=False)
scheme = self.msg_scheme_from_type[msg_type_bytes]
assert scheme[0][2] == msg_type_int
msg_type_name = scheme[0][1]
parsed = {}
with io.BytesIO(data[2:]) as fd:
for row in scheme:
#print(f"row: {row!r}")
if row[0] == "msgtype":
pass
elif row[0] == "msgdata":
field_name = row[2]
field_type = row[3]
field_count_str = row[4]
if field_count_str == "":
field_count = 1
else:
try:
field_count = int(field_count_str)
except ValueError:
field_count = int.from_bytes(parsed[field_count_str], byteorder="big")
#print(f">> count={field_count}. parsed={parsed}")
try:
parsed[field_name] = _read_field(fd=fd,
field_type=field_type,
count=field_count)
except UnknownMsgFieldType as e:
pass # TODO
except UnexpectedEndOfStream as e:
if len(row) > 5:
break # optional feature field not present
else:
raise
else:
pass # TODO
return msg_type_name, parsed
_inst = LNSerializer() _inst = LNSerializer()
encode_msg = _inst.encode_msg encode_msg = _inst.encode_msg

View file

@ -131,7 +131,7 @@ class Peer(Logger):
async def initialize(self): async def initialize(self):
if isinstance(self.transport, LNTransport): if isinstance(self.transport, LNTransport):
await self.transport.handshake() await self.transport.handshake()
self.send_message("init", gflen=0, lflen=2, localfeatures=self.localfeatures) self.send_message("init", gflen=0, flen=2, features=self.localfeatures)
self._sent_init = True self._sent_init = True
self.maybe_set_initialized() self.maybe_set_initialized()
@ -201,7 +201,7 @@ class Peer(Logger):
return return
# if they required some even flag we don't have, they will close themselves # if they required some even flag we don't have, they will close themselves
# but if we require an even flag they don't have, we close # but if we require an even flag they don't have, we close
their_localfeatures = int.from_bytes(payload['localfeatures'], byteorder="big") their_localfeatures = int.from_bytes(payload['features'], byteorder="big") # TODO feature bit unification
try: try:
self.localfeatures = ln_compare_features(self.localfeatures, their_localfeatures) self.localfeatures = ln_compare_features(self.localfeatures, their_localfeatures)
except IncompatibleLightningFeatures as e: except IncompatibleLightningFeatures as e:
@ -760,16 +760,16 @@ class Peer(Logger):
self.send_message( self.send_message(
"channel_reestablish", "channel_reestablish",
channel_id=chan_id, channel_id=chan_id,
next_local_commitment_number=next_local_ctn, next_commitment_number=next_local_ctn,
next_remote_revocation_number=oldest_unrevoked_remote_ctn, next_revocation_number=oldest_unrevoked_remote_ctn,
your_last_per_commitment_secret=last_rev_secret, your_last_per_commitment_secret=last_rev_secret,
my_current_per_commitment_point=latest_point) my_current_per_commitment_point=latest_point)
self.logger.info(f'channel_reestablish ({chan.get_id_for_log()}): sent channel_reestablish with ' self.logger.info(f'channel_reestablish ({chan.get_id_for_log()}): sent channel_reestablish with '
f'(next_local_ctn={next_local_ctn}, ' f'(next_local_ctn={next_local_ctn}, '
f'oldest_unrevoked_remote_ctn={oldest_unrevoked_remote_ctn})') f'oldest_unrevoked_remote_ctn={oldest_unrevoked_remote_ctn})')
msg = await self.wait_for_message('channel_reestablish', chan_id) msg = await self.wait_for_message('channel_reestablish', chan_id)
their_next_local_ctn = int.from_bytes(msg["next_local_commitment_number"], 'big') their_next_local_ctn = int.from_bytes(msg["next_commitment_number"], 'big')
their_oldest_unrevoked_remote_ctn = int.from_bytes(msg["next_remote_revocation_number"], 'big') their_oldest_unrevoked_remote_ctn = int.from_bytes(msg["next_revocation_number"], 'big')
their_local_pcp = msg.get("my_current_per_commitment_point") their_local_pcp = msg.get("my_current_per_commitment_point")
their_claim_of_our_last_per_commitment_secret = msg.get("your_last_per_commitment_secret") their_claim_of_our_last_per_commitment_secret = msg.get("your_last_per_commitment_secret")
self.logger.info(f'channel_reestablish ({chan.get_id_for_log()}): received channel_reestablish with ' self.logger.info(f'channel_reestablish ({chan.get_id_for_log()}): received channel_reestablish with '
@ -818,7 +818,7 @@ class Peer(Logger):
if oldest_unrevoked_local_ctn != their_oldest_unrevoked_remote_ctn: if oldest_unrevoked_local_ctn != their_oldest_unrevoked_remote_ctn:
if oldest_unrevoked_local_ctn - 1 == their_oldest_unrevoked_remote_ctn: if oldest_unrevoked_local_ctn - 1 == their_oldest_unrevoked_remote_ctn:
# A node: # A node:
# if next_remote_revocation_number is equal to the commitment number of the last revoke_and_ack # if next_revocation_number is equal to the commitment number of the last revoke_and_ack
# the receiving node sent, AND the receiving node hasn't already received a closing_signed: # the receiving node sent, AND the receiving node hasn't already received a closing_signed:
# MUST re-send the revoke_and_ack. # MUST re-send the revoke_and_ack.
last_secret, last_point = chan.get_secret_and_point(LOCAL, oldest_unrevoked_local_ctn - 1) last_secret, last_point = chan.get_secret_and_point(LOCAL, oldest_unrevoked_local_ctn - 1)

View file

@ -0,0 +1,5 @@
These files are generated from the BOLT repository:
```
$ python3 tools/extract-formats.py 01-*.md 02-*.md 07-*.md > peer_wire.csv
$ python3 tools/extract-formats.py 04-*.md > onion_wire.csv
```

View file

@ -0,0 +1,53 @@
tlvtype,tlv_payload,amt_to_forward,2
tlvdata,tlv_payload,amt_to_forward,amt_to_forward,tu64,
tlvtype,tlv_payload,outgoing_cltv_value,4
tlvdata,tlv_payload,outgoing_cltv_value,outgoing_cltv_value,tu32,
tlvtype,tlv_payload,short_channel_id,6
tlvdata,tlv_payload,short_channel_id,short_channel_id,short_channel_id,
tlvtype,tlv_payload,payment_data,8
tlvdata,tlv_payload,payment_data,payment_secret,byte,32
tlvdata,tlv_payload,payment_data,total_msat,tu64,
msgtype,invalid_realm,PERM|1
msgtype,temporary_node_failure,NODE|2
msgtype,permanent_node_failure,PERM|NODE|2
msgtype,required_node_feature_missing,PERM|NODE|3
msgtype,invalid_onion_version,BADONION|PERM|4
msgdata,invalid_onion_version,sha256_of_onion,sha256,
msgtype,invalid_onion_hmac,BADONION|PERM|5
msgdata,invalid_onion_hmac,sha256_of_onion,sha256,
msgtype,invalid_onion_key,BADONION|PERM|6
msgdata,invalid_onion_key,sha256_of_onion,sha256,
msgtype,temporary_channel_failure,UPDATE|7
msgdata,temporary_channel_failure,len,u16,
msgdata,temporary_channel_failure,channel_update,byte,len
msgtype,permanent_channel_failure,PERM|8
msgtype,required_channel_feature_missing,PERM|9
msgtype,unknown_next_peer,PERM|10
msgtype,amount_below_minimum,UPDATE|11
msgdata,amount_below_minimum,htlc_msat,u64,
msgdata,amount_below_minimum,len,u16,
msgdata,amount_below_minimum,channel_update,byte,len
msgtype,fee_insufficient,UPDATE|12
msgdata,fee_insufficient,htlc_msat,u64,
msgdata,fee_insufficient,len,u16,
msgdata,fee_insufficient,channel_update,byte,len
msgtype,incorrect_cltv_expiry,UPDATE|13
msgdata,incorrect_cltv_expiry,cltv_expiry,u32,
msgdata,incorrect_cltv_expiry,len,u16,
msgdata,incorrect_cltv_expiry,channel_update,byte,len
msgtype,expiry_too_soon,UPDATE|14
msgdata,expiry_too_soon,len,u16,
msgdata,expiry_too_soon,channel_update,byte,len
msgtype,incorrect_or_unknown_payment_details,PERM|15
msgdata,incorrect_or_unknown_payment_details,htlc_msat,u64,
msgdata,incorrect_or_unknown_payment_details,height,u32,
msgtype,final_incorrect_cltv_expiry,18
msgdata,final_incorrect_cltv_expiry,cltv_expiry,u32,
msgtype,final_incorrect_htlc_amount,19
msgdata,final_incorrect_htlc_amount,incoming_htlc_amt,u64,
msgtype,channel_disabled,UPDATE|20
msgtype,expiry_too_far,21
msgtype,invalid_onion_payload,PERM|22
msgdata,invalid_onion_payload,type,varint,
msgdata,invalid_onion_payload,offset,u16,
msgtype,mpp_timeout,23
1 tlvtype,tlv_payload,amt_to_forward,2
2 tlvdata,tlv_payload,amt_to_forward,amt_to_forward,tu64,
3 tlvtype,tlv_payload,outgoing_cltv_value,4
4 tlvdata,tlv_payload,outgoing_cltv_value,outgoing_cltv_value,tu32,
5 tlvtype,tlv_payload,short_channel_id,6
6 tlvdata,tlv_payload,short_channel_id,short_channel_id,short_channel_id,
7 tlvtype,tlv_payload,payment_data,8
8 tlvdata,tlv_payload,payment_data,payment_secret,byte,32
9 tlvdata,tlv_payload,payment_data,total_msat,tu64,
10 msgtype,invalid_realm,PERM|1
11 msgtype,temporary_node_failure,NODE|2
12 msgtype,permanent_node_failure,PERM|NODE|2
13 msgtype,required_node_feature_missing,PERM|NODE|3
14 msgtype,invalid_onion_version,BADONION|PERM|4
15 msgdata,invalid_onion_version,sha256_of_onion,sha256,
16 msgtype,invalid_onion_hmac,BADONION|PERM|5
17 msgdata,invalid_onion_hmac,sha256_of_onion,sha256,
18 msgtype,invalid_onion_key,BADONION|PERM|6
19 msgdata,invalid_onion_key,sha256_of_onion,sha256,
20 msgtype,temporary_channel_failure,UPDATE|7
21 msgdata,temporary_channel_failure,len,u16,
22 msgdata,temporary_channel_failure,channel_update,byte,len
23 msgtype,permanent_channel_failure,PERM|8
24 msgtype,required_channel_feature_missing,PERM|9
25 msgtype,unknown_next_peer,PERM|10
26 msgtype,amount_below_minimum,UPDATE|11
27 msgdata,amount_below_minimum,htlc_msat,u64,
28 msgdata,amount_below_minimum,len,u16,
29 msgdata,amount_below_minimum,channel_update,byte,len
30 msgtype,fee_insufficient,UPDATE|12
31 msgdata,fee_insufficient,htlc_msat,u64,
32 msgdata,fee_insufficient,len,u16,
33 msgdata,fee_insufficient,channel_update,byte,len
34 msgtype,incorrect_cltv_expiry,UPDATE|13
35 msgdata,incorrect_cltv_expiry,cltv_expiry,u32,
36 msgdata,incorrect_cltv_expiry,len,u16,
37 msgdata,incorrect_cltv_expiry,channel_update,byte,len
38 msgtype,expiry_too_soon,UPDATE|14
39 msgdata,expiry_too_soon,len,u16,
40 msgdata,expiry_too_soon,channel_update,byte,len
41 msgtype,incorrect_or_unknown_payment_details,PERM|15
42 msgdata,incorrect_or_unknown_payment_details,htlc_msat,u64,
43 msgdata,incorrect_or_unknown_payment_details,height,u32,
44 msgtype,final_incorrect_cltv_expiry,18
45 msgdata,final_incorrect_cltv_expiry,cltv_expiry,u32,
46 msgtype,final_incorrect_htlc_amount,19
47 msgdata,final_incorrect_htlc_amount,incoming_htlc_amt,u64,
48 msgtype,channel_disabled,UPDATE|20
49 msgtype,expiry_too_far,21
50 msgtype,invalid_onion_payload,PERM|22
51 msgdata,invalid_onion_payload,type,varint,
52 msgdata,invalid_onion_payload,offset,u16,
53 msgtype,mpp_timeout,23

View file

@ -0,0 +1,210 @@
msgtype,init,16
msgdata,init,gflen,u16,
msgdata,init,globalfeatures,byte,gflen
msgdata,init,flen,u16,
msgdata,init,features,byte,flen
msgdata,init,tlvs,init_tlvs,
tlvtype,init_tlvs,networks,1
tlvdata,init_tlvs,networks,chains,chain_hash,...
msgtype,error,17
msgdata,error,channel_id,channel_id,
msgdata,error,len,u16,
msgdata,error,data,byte,len
msgtype,ping,18
msgdata,ping,num_pong_bytes,u16,
msgdata,ping,byteslen,u16,
msgdata,ping,ignored,byte,byteslen
msgtype,pong,19
msgdata,pong,byteslen,u16,
msgdata,pong,ignored,byte,byteslen
tlvtype,n1,tlv1,1
tlvdata,n1,tlv1,amount_msat,tu64,
tlvtype,n1,tlv2,2
tlvdata,n1,tlv2,scid,short_channel_id,
tlvtype,n1,tlv3,3
tlvdata,n1,tlv3,node_id,point,
tlvdata,n1,tlv3,amount_msat_1,u64,
tlvdata,n1,tlv3,amount_msat_2,u64,
tlvtype,n1,tlv4,254
tlvdata,n1,tlv4,cltv_delta,u16,
tlvtype,n2,tlv1,0
tlvdata,n2,tlv1,amount_msat,tu64,
tlvtype,n2,tlv2,11
tlvdata,n2,tlv2,cltv_expiry,tu32,
msgtype,open_channel,32
msgdata,open_channel,chain_hash,chain_hash,
msgdata,open_channel,temporary_channel_id,byte,32
msgdata,open_channel,funding_satoshis,u64,
msgdata,open_channel,push_msat,u64,
msgdata,open_channel,dust_limit_satoshis,u64,
msgdata,open_channel,max_htlc_value_in_flight_msat,u64,
msgdata,open_channel,channel_reserve_satoshis,u64,
msgdata,open_channel,htlc_minimum_msat,u64,
msgdata,open_channel,feerate_per_kw,u32,
msgdata,open_channel,to_self_delay,u16,
msgdata,open_channel,max_accepted_htlcs,u16,
msgdata,open_channel,funding_pubkey,point,
msgdata,open_channel,revocation_basepoint,point,
msgdata,open_channel,payment_basepoint,point,
msgdata,open_channel,delayed_payment_basepoint,point,
msgdata,open_channel,htlc_basepoint,point,
msgdata,open_channel,first_per_commitment_point,point,
msgdata,open_channel,channel_flags,byte,
msgdata,open_channel,shutdown_len,u16,,option_upfront_shutdown_script
msgdata,open_channel,shutdown_scriptpubkey,byte,shutdown_len,option_upfront_shutdown_script
msgtype,accept_channel,33
msgdata,accept_channel,temporary_channel_id,byte,32
msgdata,accept_channel,dust_limit_satoshis,u64,
msgdata,accept_channel,max_htlc_value_in_flight_msat,u64,
msgdata,accept_channel,channel_reserve_satoshis,u64,
msgdata,accept_channel,htlc_minimum_msat,u64,
msgdata,accept_channel,minimum_depth,u32,
msgdata,accept_channel,to_self_delay,u16,
msgdata,accept_channel,max_accepted_htlcs,u16,
msgdata,accept_channel,funding_pubkey,point,
msgdata,accept_channel,revocation_basepoint,point,
msgdata,accept_channel,payment_basepoint,point,
msgdata,accept_channel,delayed_payment_basepoint,point,
msgdata,accept_channel,htlc_basepoint,point,
msgdata,accept_channel,first_per_commitment_point,point,
msgdata,accept_channel,shutdown_len,u16,,option_upfront_shutdown_script
msgdata,accept_channel,shutdown_scriptpubkey,byte,shutdown_len,option_upfront_shutdown_script
msgtype,funding_created,34
msgdata,funding_created,temporary_channel_id,byte,32
msgdata,funding_created,funding_txid,sha256,
msgdata,funding_created,funding_output_index,u16,
msgdata,funding_created,signature,signature,
msgtype,funding_signed,35
msgdata,funding_signed,channel_id,channel_id,
msgdata,funding_signed,signature,signature,
msgtype,funding_locked,36
msgdata,funding_locked,channel_id,channel_id,
msgdata,funding_locked,next_per_commitment_point,point,
msgtype,shutdown,38
msgdata,shutdown,channel_id,channel_id,
msgdata,shutdown,len,u16,
msgdata,shutdown,scriptpubkey,byte,len
msgtype,closing_signed,39
msgdata,closing_signed,channel_id,channel_id,
msgdata,closing_signed,fee_satoshis,u64,
msgdata,closing_signed,signature,signature,
msgtype,update_add_htlc,128
msgdata,update_add_htlc,channel_id,channel_id,
msgdata,update_add_htlc,id,u64,
msgdata,update_add_htlc,amount_msat,u64,
msgdata,update_add_htlc,payment_hash,sha256,
msgdata,update_add_htlc,cltv_expiry,u32,
msgdata,update_add_htlc,onion_routing_packet,byte,1366
msgtype,update_fulfill_htlc,130
msgdata,update_fulfill_htlc,channel_id,channel_id,
msgdata,update_fulfill_htlc,id,u64,
msgdata,update_fulfill_htlc,payment_preimage,byte,32
msgtype,update_fail_htlc,131
msgdata,update_fail_htlc,channel_id,channel_id,
msgdata,update_fail_htlc,id,u64,
msgdata,update_fail_htlc,len,u16,
msgdata,update_fail_htlc,reason,byte,len
msgtype,update_fail_malformed_htlc,135
msgdata,update_fail_malformed_htlc,channel_id,channel_id,
msgdata,update_fail_malformed_htlc,id,u64,
msgdata,update_fail_malformed_htlc,sha256_of_onion,sha256,
msgdata,update_fail_malformed_htlc,failure_code,u16,
msgtype,commitment_signed,132
msgdata,commitment_signed,channel_id,channel_id,
msgdata,commitment_signed,signature,signature,
msgdata,commitment_signed,num_htlcs,u16,
msgdata,commitment_signed,htlc_signature,signature,num_htlcs
msgtype,revoke_and_ack,133
msgdata,revoke_and_ack,channel_id,channel_id,
msgdata,revoke_and_ack,per_commitment_secret,byte,32
msgdata,revoke_and_ack,next_per_commitment_point,point,
msgtype,update_fee,134
msgdata,update_fee,channel_id,channel_id,
msgdata,update_fee,feerate_per_kw,u32,
msgtype,channel_reestablish,136
msgdata,channel_reestablish,channel_id,channel_id,
msgdata,channel_reestablish,next_commitment_number,u64,
msgdata,channel_reestablish,next_revocation_number,u64,
msgdata,channel_reestablish,your_last_per_commitment_secret,byte,32,option_data_loss_protect,option_static_remotekey
msgdata,channel_reestablish,my_current_per_commitment_point,point,,option_data_loss_protect,option_static_remotekey
msgtype,announcement_signatures,259
msgdata,announcement_signatures,channel_id,channel_id,
msgdata,announcement_signatures,short_channel_id,short_channel_id,
msgdata,announcement_signatures,node_signature,signature,
msgdata,announcement_signatures,bitcoin_signature,signature,
msgtype,channel_announcement,256
msgdata,channel_announcement,node_signature_1,signature,
msgdata,channel_announcement,node_signature_2,signature,
msgdata,channel_announcement,bitcoin_signature_1,signature,
msgdata,channel_announcement,bitcoin_signature_2,signature,
msgdata,channel_announcement,len,u16,
msgdata,channel_announcement,features,byte,len
msgdata,channel_announcement,chain_hash,chain_hash,
msgdata,channel_announcement,short_channel_id,short_channel_id,
msgdata,channel_announcement,node_id_1,point,
msgdata,channel_announcement,node_id_2,point,
msgdata,channel_announcement,bitcoin_key_1,point,
msgdata,channel_announcement,bitcoin_key_2,point,
msgtype,node_announcement,257
msgdata,node_announcement,signature,signature,
msgdata,node_announcement,flen,u16,
msgdata,node_announcement,features,byte,flen
msgdata,node_announcement,timestamp,u32,
msgdata,node_announcement,node_id,point,
msgdata,node_announcement,rgb_color,byte,3
msgdata,node_announcement,alias,byte,32
msgdata,node_announcement,addrlen,u16,
msgdata,node_announcement,addresses,byte,addrlen
msgtype,channel_update,258
msgdata,channel_update,signature,signature,
msgdata,channel_update,chain_hash,chain_hash,
msgdata,channel_update,short_channel_id,short_channel_id,
msgdata,channel_update,timestamp,u32,
msgdata,channel_update,message_flags,byte,
msgdata,channel_update,channel_flags,byte,
msgdata,channel_update,cltv_expiry_delta,u16,
msgdata,channel_update,htlc_minimum_msat,u64,
msgdata,channel_update,fee_base_msat,u32,
msgdata,channel_update,fee_proportional_millionths,u32,
msgdata,channel_update,htlc_maximum_msat,u64,,option_channel_htlc_max
msgtype,query_short_channel_ids,261,gossip_queries
msgdata,query_short_channel_ids,chain_hash,chain_hash,
msgdata,query_short_channel_ids,len,u16,
msgdata,query_short_channel_ids,encoded_short_ids,byte,len
msgdata,query_short_channel_ids,tlvs,query_short_channel_ids_tlvs,
tlvtype,query_short_channel_ids_tlvs,query_flags,1
tlvdata,query_short_channel_ids_tlvs,query_flags,encoding_type,u8,
tlvdata,query_short_channel_ids_tlvs,query_flags,encoded_query_flags,byte,...
msgtype,reply_short_channel_ids_end,262,gossip_queries
msgdata,reply_short_channel_ids_end,chain_hash,chain_hash,
msgdata,reply_short_channel_ids_end,complete,byte,
msgtype,query_channel_range,263,gossip_queries
msgdata,query_channel_range,chain_hash,chain_hash,
msgdata,query_channel_range,first_blocknum,u32,
msgdata,query_channel_range,number_of_blocks,u32,
msgdata,query_channel_range,tlvs,query_channel_range_tlvs,
tlvtype,query_channel_range_tlvs,query_option,1
tlvdata,query_channel_range_tlvs,query_option,query_option_flags,varint,
msgtype,reply_channel_range,264,gossip_queries
msgdata,reply_channel_range,chain_hash,chain_hash,
msgdata,reply_channel_range,first_blocknum,u32,
msgdata,reply_channel_range,number_of_blocks,u32,
msgdata,reply_channel_range,complete,byte,
msgdata,reply_channel_range,len,u16,
msgdata,reply_channel_range,encoded_short_ids,byte,len
msgdata,reply_channel_range,tlvs,reply_channel_range_tlvs,
tlvtype,reply_channel_range_tlvs,timestamps_tlv,1
tlvdata,reply_channel_range_tlvs,timestamps_tlv,encoding_type,u8,
tlvdata,reply_channel_range_tlvs,timestamps_tlv,encoded_timestamps,byte,...
tlvtype,reply_channel_range_tlvs,checksums_tlv,3
tlvdata,reply_channel_range_tlvs,checksums_tlv,checksums,channel_update_checksums,...
subtype,channel_update_timestamps
subtypedata,channel_update_timestamps,timestamp_node_id_1,u32,
subtypedata,channel_update_timestamps,timestamp_node_id_2,u32,
subtype,channel_update_checksums
subtypedata,channel_update_checksums,checksum_node_id_1,u32,
subtypedata,channel_update_checksums,checksum_node_id_2,u32,
msgtype,gossip_timestamp_filter,265,gossip_queries
msgdata,gossip_timestamp_filter,chain_hash,chain_hash,
msgdata,gossip_timestamp_filter,first_timestamp,u32,
msgdata,gossip_timestamp_filter,timestamp_range,u32,
1 msgtype,init,16
2 msgdata,init,gflen,u16,
3 msgdata,init,globalfeatures,byte,gflen
4 msgdata,init,flen,u16,
5 msgdata,init,features,byte,flen
6 msgdata,init,tlvs,init_tlvs,
7 tlvtype,init_tlvs,networks,1
8 tlvdata,init_tlvs,networks,chains,chain_hash,...
9 msgtype,error,17
10 msgdata,error,channel_id,channel_id,
11 msgdata,error,len,u16,
12 msgdata,error,data,byte,len
13 msgtype,ping,18
14 msgdata,ping,num_pong_bytes,u16,
15 msgdata,ping,byteslen,u16,
16 msgdata,ping,ignored,byte,byteslen
17 msgtype,pong,19
18 msgdata,pong,byteslen,u16,
19 msgdata,pong,ignored,byte,byteslen
20 tlvtype,n1,tlv1,1
21 tlvdata,n1,tlv1,amount_msat,tu64,
22 tlvtype,n1,tlv2,2
23 tlvdata,n1,tlv2,scid,short_channel_id,
24 tlvtype,n1,tlv3,3
25 tlvdata,n1,tlv3,node_id,point,
26 tlvdata,n1,tlv3,amount_msat_1,u64,
27 tlvdata,n1,tlv3,amount_msat_2,u64,
28 tlvtype,n1,tlv4,254
29 tlvdata,n1,tlv4,cltv_delta,u16,
30 tlvtype,n2,tlv1,0
31 tlvdata,n2,tlv1,amount_msat,tu64,
32 tlvtype,n2,tlv2,11
33 tlvdata,n2,tlv2,cltv_expiry,tu32,
34 msgtype,open_channel,32
35 msgdata,open_channel,chain_hash,chain_hash,
36 msgdata,open_channel,temporary_channel_id,byte,32
37 msgdata,open_channel,funding_satoshis,u64,
38 msgdata,open_channel,push_msat,u64,
39 msgdata,open_channel,dust_limit_satoshis,u64,
40 msgdata,open_channel,max_htlc_value_in_flight_msat,u64,
41 msgdata,open_channel,channel_reserve_satoshis,u64,
42 msgdata,open_channel,htlc_minimum_msat,u64,
43 msgdata,open_channel,feerate_per_kw,u32,
44 msgdata,open_channel,to_self_delay,u16,
45 msgdata,open_channel,max_accepted_htlcs,u16,
46 msgdata,open_channel,funding_pubkey,point,
47 msgdata,open_channel,revocation_basepoint,point,
48 msgdata,open_channel,payment_basepoint,point,
49 msgdata,open_channel,delayed_payment_basepoint,point,
50 msgdata,open_channel,htlc_basepoint,point,
51 msgdata,open_channel,first_per_commitment_point,point,
52 msgdata,open_channel,channel_flags,byte,
53 msgdata,open_channel,shutdown_len,u16,,option_upfront_shutdown_script
54 msgdata,open_channel,shutdown_scriptpubkey,byte,shutdown_len,option_upfront_shutdown_script
55 msgtype,accept_channel,33
56 msgdata,accept_channel,temporary_channel_id,byte,32
57 msgdata,accept_channel,dust_limit_satoshis,u64,
58 msgdata,accept_channel,max_htlc_value_in_flight_msat,u64,
59 msgdata,accept_channel,channel_reserve_satoshis,u64,
60 msgdata,accept_channel,htlc_minimum_msat,u64,
61 msgdata,accept_channel,minimum_depth,u32,
62 msgdata,accept_channel,to_self_delay,u16,
63 msgdata,accept_channel,max_accepted_htlcs,u16,
64 msgdata,accept_channel,funding_pubkey,point,
65 msgdata,accept_channel,revocation_basepoint,point,
66 msgdata,accept_channel,payment_basepoint,point,
67 msgdata,accept_channel,delayed_payment_basepoint,point,
68 msgdata,accept_channel,htlc_basepoint,point,
69 msgdata,accept_channel,first_per_commitment_point,point,
70 msgdata,accept_channel,shutdown_len,u16,,option_upfront_shutdown_script
71 msgdata,accept_channel,shutdown_scriptpubkey,byte,shutdown_len,option_upfront_shutdown_script
72 msgtype,funding_created,34
73 msgdata,funding_created,temporary_channel_id,byte,32
74 msgdata,funding_created,funding_txid,sha256,
75 msgdata,funding_created,funding_output_index,u16,
76 msgdata,funding_created,signature,signature,
77 msgtype,funding_signed,35
78 msgdata,funding_signed,channel_id,channel_id,
79 msgdata,funding_signed,signature,signature,
80 msgtype,funding_locked,36
81 msgdata,funding_locked,channel_id,channel_id,
82 msgdata,funding_locked,next_per_commitment_point,point,
83 msgtype,shutdown,38
84 msgdata,shutdown,channel_id,channel_id,
85 msgdata,shutdown,len,u16,
86 msgdata,shutdown,scriptpubkey,byte,len
87 msgtype,closing_signed,39
88 msgdata,closing_signed,channel_id,channel_id,
89 msgdata,closing_signed,fee_satoshis,u64,
90 msgdata,closing_signed,signature,signature,
91 msgtype,update_add_htlc,128
92 msgdata,update_add_htlc,channel_id,channel_id,
93 msgdata,update_add_htlc,id,u64,
94 msgdata,update_add_htlc,amount_msat,u64,
95 msgdata,update_add_htlc,payment_hash,sha256,
96 msgdata,update_add_htlc,cltv_expiry,u32,
97 msgdata,update_add_htlc,onion_routing_packet,byte,1366
98 msgtype,update_fulfill_htlc,130
99 msgdata,update_fulfill_htlc,channel_id,channel_id,
100 msgdata,update_fulfill_htlc,id,u64,
101 msgdata,update_fulfill_htlc,payment_preimage,byte,32
102 msgtype,update_fail_htlc,131
103 msgdata,update_fail_htlc,channel_id,channel_id,
104 msgdata,update_fail_htlc,id,u64,
105 msgdata,update_fail_htlc,len,u16,
106 msgdata,update_fail_htlc,reason,byte,len
107 msgtype,update_fail_malformed_htlc,135
108 msgdata,update_fail_malformed_htlc,channel_id,channel_id,
109 msgdata,update_fail_malformed_htlc,id,u64,
110 msgdata,update_fail_malformed_htlc,sha256_of_onion,sha256,
111 msgdata,update_fail_malformed_htlc,failure_code,u16,
112 msgtype,commitment_signed,132
113 msgdata,commitment_signed,channel_id,channel_id,
114 msgdata,commitment_signed,signature,signature,
115 msgdata,commitment_signed,num_htlcs,u16,
116 msgdata,commitment_signed,htlc_signature,signature,num_htlcs
117 msgtype,revoke_and_ack,133
118 msgdata,revoke_and_ack,channel_id,channel_id,
119 msgdata,revoke_and_ack,per_commitment_secret,byte,32
120 msgdata,revoke_and_ack,next_per_commitment_point,point,
121 msgtype,update_fee,134
122 msgdata,update_fee,channel_id,channel_id,
123 msgdata,update_fee,feerate_per_kw,u32,
124 msgtype,channel_reestablish,136
125 msgdata,channel_reestablish,channel_id,channel_id,
126 msgdata,channel_reestablish,next_commitment_number,u64,
127 msgdata,channel_reestablish,next_revocation_number,u64,
128 msgdata,channel_reestablish,your_last_per_commitment_secret,byte,32,option_data_loss_protect,option_static_remotekey
129 msgdata,channel_reestablish,my_current_per_commitment_point,point,,option_data_loss_protect,option_static_remotekey
130 msgtype,announcement_signatures,259
131 msgdata,announcement_signatures,channel_id,channel_id,
132 msgdata,announcement_signatures,short_channel_id,short_channel_id,
133 msgdata,announcement_signatures,node_signature,signature,
134 msgdata,announcement_signatures,bitcoin_signature,signature,
135 msgtype,channel_announcement,256
136 msgdata,channel_announcement,node_signature_1,signature,
137 msgdata,channel_announcement,node_signature_2,signature,
138 msgdata,channel_announcement,bitcoin_signature_1,signature,
139 msgdata,channel_announcement,bitcoin_signature_2,signature,
140 msgdata,channel_announcement,len,u16,
141 msgdata,channel_announcement,features,byte,len
142 msgdata,channel_announcement,chain_hash,chain_hash,
143 msgdata,channel_announcement,short_channel_id,short_channel_id,
144 msgdata,channel_announcement,node_id_1,point,
145 msgdata,channel_announcement,node_id_2,point,
146 msgdata,channel_announcement,bitcoin_key_1,point,
147 msgdata,channel_announcement,bitcoin_key_2,point,
148 msgtype,node_announcement,257
149 msgdata,node_announcement,signature,signature,
150 msgdata,node_announcement,flen,u16,
151 msgdata,node_announcement,features,byte,flen
152 msgdata,node_announcement,timestamp,u32,
153 msgdata,node_announcement,node_id,point,
154 msgdata,node_announcement,rgb_color,byte,3
155 msgdata,node_announcement,alias,byte,32
156 msgdata,node_announcement,addrlen,u16,
157 msgdata,node_announcement,addresses,byte,addrlen
158 msgtype,channel_update,258
159 msgdata,channel_update,signature,signature,
160 msgdata,channel_update,chain_hash,chain_hash,
161 msgdata,channel_update,short_channel_id,short_channel_id,
162 msgdata,channel_update,timestamp,u32,
163 msgdata,channel_update,message_flags,byte,
164 msgdata,channel_update,channel_flags,byte,
165 msgdata,channel_update,cltv_expiry_delta,u16,
166 msgdata,channel_update,htlc_minimum_msat,u64,
167 msgdata,channel_update,fee_base_msat,u32,
168 msgdata,channel_update,fee_proportional_millionths,u32,
169 msgdata,channel_update,htlc_maximum_msat,u64,,option_channel_htlc_max
170 msgtype,query_short_channel_ids,261,gossip_queries
171 msgdata,query_short_channel_ids,chain_hash,chain_hash,
172 msgdata,query_short_channel_ids,len,u16,
173 msgdata,query_short_channel_ids,encoded_short_ids,byte,len
174 msgdata,query_short_channel_ids,tlvs,query_short_channel_ids_tlvs,
175 tlvtype,query_short_channel_ids_tlvs,query_flags,1
176 tlvdata,query_short_channel_ids_tlvs,query_flags,encoding_type,u8,
177 tlvdata,query_short_channel_ids_tlvs,query_flags,encoded_query_flags,byte,...
178 msgtype,reply_short_channel_ids_end,262,gossip_queries
179 msgdata,reply_short_channel_ids_end,chain_hash,chain_hash,
180 msgdata,reply_short_channel_ids_end,complete,byte,
181 msgtype,query_channel_range,263,gossip_queries
182 msgdata,query_channel_range,chain_hash,chain_hash,
183 msgdata,query_channel_range,first_blocknum,u32,
184 msgdata,query_channel_range,number_of_blocks,u32,
185 msgdata,query_channel_range,tlvs,query_channel_range_tlvs,
186 tlvtype,query_channel_range_tlvs,query_option,1
187 tlvdata,query_channel_range_tlvs,query_option,query_option_flags,varint,
188 msgtype,reply_channel_range,264,gossip_queries
189 msgdata,reply_channel_range,chain_hash,chain_hash,
190 msgdata,reply_channel_range,first_blocknum,u32,
191 msgdata,reply_channel_range,number_of_blocks,u32,
192 msgdata,reply_channel_range,complete,byte,
193 msgdata,reply_channel_range,len,u16,
194 msgdata,reply_channel_range,encoded_short_ids,byte,len
195 msgdata,reply_channel_range,tlvs,reply_channel_range_tlvs,
196 tlvtype,reply_channel_range_tlvs,timestamps_tlv,1
197 tlvdata,reply_channel_range_tlvs,timestamps_tlv,encoding_type,u8,
198 tlvdata,reply_channel_range_tlvs,timestamps_tlv,encoded_timestamps,byte,...
199 tlvtype,reply_channel_range_tlvs,checksums_tlv,3
200 tlvdata,reply_channel_range_tlvs,checksums_tlv,checksums,channel_update_checksums,...
201 subtype,channel_update_timestamps
202 subtypedata,channel_update_timestamps,timestamp_node_id_1,u32,
203 subtypedata,channel_update_timestamps,timestamp_node_id_2,u32,
204 subtype,channel_update_checksums
205 subtypedata,channel_update_checksums,checksum_node_id_1,u32,
206 subtypedata,channel_update_checksums,checksum_node_id_2,u32,
207 msgtype,gossip_timestamp_filter,265,gossip_queries
208 msgdata,gossip_timestamp_filter,chain_hash,chain_hash,
209 msgdata,gossip_timestamp_filter,first_timestamp,u32,
210 msgdata,gossip_timestamp_filter,timestamp_range,u32,