mirror of
https://github.com/lightning/bolts.git
synced 2025-01-19 05:33:37 +01:00
Merge pull request #14 from lightningnetwork/extraction-tools
tools/extract-formats.py: produce structure definitions and check alignment
This commit is contained in:
commit
2e0b7266d1
@ -710,8 +710,12 @@ features supported or required by this node. Odd features are
|
||||
optional, even features are compulsory ("it's OK to be odd!"). The
|
||||
meaning of these bits will be defined in future.
|
||||
|
||||
1. type: 16 (MSG_INIT)
|
||||
2. data: [4:len] [len:globalfeatures] [4:len] [len:localfeatures]
|
||||
1. type: 16 (`init`)
|
||||
2. data:
|
||||
* [4:gflen]
|
||||
* [gflen:globalfeatures]
|
||||
* [4:lflen]
|
||||
* [lflen:localfeatures]
|
||||
|
||||
The 4-byte len fields indicate the number of bytes in the immediately
|
||||
following field.
|
||||
@ -731,7 +735,7 @@ The receiving node MUST fail the channels if it receives a
|
||||
not understand.
|
||||
|
||||
|
||||
Each node MUST wait to receive MSG_INIT before sending any other
|
||||
Each node MUST wait to receive `init` before sending any other
|
||||
messages.
|
||||
|
||||
|
||||
@ -754,9 +758,11 @@ For simplicity of diagnosis, it is often useful to tell the peer that
|
||||
something is incorrect.
|
||||
|
||||
|
||||
1. type: 17 (`MSG_ERROR`)
|
||||
2. data: [8:channel-id] [4:len] [len:data]
|
||||
|
||||
1. type: 17 (`error`)
|
||||
2. data:
|
||||
* [8:channel-id]
|
||||
* [4:len]
|
||||
* [len:data]
|
||||
|
||||
The 4-byte len field indicates the number of bytes in the immediately
|
||||
following field.
|
||||
@ -765,15 +771,15 @@ following field.
|
||||
### Requirements
|
||||
|
||||
|
||||
A node SHOULD send `MSG_ERROR` for protocol violations or internal
|
||||
A node SHOULD send `error` for protocol violations or internal
|
||||
errors which make channels unusable or further communication unusable.
|
||||
A node MAY send an empty [data] field. A node sending `MSG_ERROR` MUST
|
||||
A node MAY send an empty [data] field. A node sending `error` MUST
|
||||
fail the channel referred to by the `channel-id`, or if `channel-id`
|
||||
is 0xFFFFFFFFFFFFFFFF it MUST fail all channels and MUST close the connection.
|
||||
A node MUST NOT set `len` to greater than the data length.
|
||||
|
||||
|
||||
A node receiving `MSG_ERROR` MUST fail the channel referred to by
|
||||
A node receiving `error` MUST fail the channel referred to by
|
||||
`channel-id`, or if `channel-id` is 0xFFFFFFFFFFFFFFFF it MUST fail
|
||||
all channels and MUST close the connection. A receiving node MUST truncate
|
||||
`len` to the remainder of the packet if it is larger.
|
||||
|
@ -68,7 +68,7 @@ fails.
|
||||
This message contains information about a node, and indicates its
|
||||
desire to set up a new channel.
|
||||
|
||||
1. type: 32 (`MSG_OPEN_CHANNEL`)
|
||||
1. type: 32 (`open_channel`)
|
||||
2. data:
|
||||
* [8:temporary-channel-id]
|
||||
* [8:funding-satoshis]
|
||||
@ -163,7 +163,7 @@ This message contains information about a node, and indicates its
|
||||
acceptance of the new channel.
|
||||
|
||||
|
||||
1. type: 33 (`MSG_ACCEPT_CHANNEL`)
|
||||
1. type: 33 (`accept_channel`)
|
||||
2. data:
|
||||
* [8:temporary-channel-id]
|
||||
* [8:dust-limit-satoshis]
|
||||
@ -194,7 +194,7 @@ This message describes the outpoint which the funder has created for
|
||||
the initial commitment transactions. After receiving the peer's
|
||||
signature, it will broadcast the funding transaction.
|
||||
|
||||
1. type: 34 (`MSG_FUNDING_CREATED`)
|
||||
1. type: 34 (`funding_created`)
|
||||
2. data:
|
||||
* [8:temporary-channel-id]
|
||||
* [32:txid]
|
||||
@ -218,7 +218,7 @@ This message gives the funder the signature they need for the first
|
||||
commitment transaction, so they can broadcast it knowing they can
|
||||
redeem their funds if they need to.
|
||||
|
||||
1. type: 35 (`MSG_FUNDING_SIGNED`)
|
||||
1. type: 35 (`funding_signed`)
|
||||
2. data:
|
||||
* [8:temporary-channel-id]
|
||||
* [64:signature]
|
||||
@ -233,7 +233,7 @@ The recipient MUST fail the channel if `signature` is incorrect.
|
||||
|
||||
This message indicates that the funding transaction has reached the `minimum-depth` asked for in `accept_channel`. Once both nodes have sent this, the channel enters normal operating mode.
|
||||
|
||||
1. type: 36 (`MSG_FUNDING_LOCKED`)
|
||||
1. type: 36 (`funding_locked`)
|
||||
2. data:
|
||||
* [8:temporary-channel-id]
|
||||
* [8:channel-id]
|
||||
@ -298,7 +298,7 @@ The exact calculation used for deriving the fee from the fee rate is
|
||||
given in [BOLT #3].
|
||||
|
||||
|
||||
1. type: 37 (`MSG_UPDATE_FEE`)
|
||||
1. type: 37 (`update_fee`)
|
||||
2. data:
|
||||
* [8:channel-id]
|
||||
* [4:feerate-per-kw]
|
||||
@ -374,7 +374,7 @@ Either node (or both) can send a `shutdown` message to initiate closing,
|
||||
and indicating the scriptpubkey it wants to be paid to.
|
||||
|
||||
|
||||
1. type: 38 (`MSG_SHUTDOWN`)
|
||||
1. type: 38 (`shutdown`)
|
||||
2. data:
|
||||
* [8:channel-id]
|
||||
* [4:len]
|
||||
@ -427,7 +427,7 @@ signs the close transaction with the `script_pubkey` fields from the
|
||||
process terminates when both agree on the same fee, or one side fails
|
||||
the channel.
|
||||
|
||||
1. type: 39 (`MSG_CLOSING_SIGNED`)
|
||||
1. type: 39 (`closing_signed`)
|
||||
2. data:
|
||||
* [8:channel-id]
|
||||
* [8:fee-satoshis]
|
||||
@ -557,7 +557,7 @@ The format of the `route` portion, which indicates where the payment
|
||||
is destined, is described in [BOLT #4].
|
||||
|
||||
|
||||
1. type: 128 (`MSG_UPDATE_ADD_HTLC`)
|
||||
1. type: 128 (`update_add_htlc`)
|
||||
2. data:
|
||||
* [8:channel-id]
|
||||
* [8:id]
|
||||
@ -624,7 +624,7 @@ failed to route, or the payment preimage is supplied.
|
||||
The `reason` field is an opaque encrypted blob for the benefit of the
|
||||
original HTLC initiator as defined in [BOLT #4].
|
||||
|
||||
1. type: 130 (`MSG_UPDATE_FULFILL_HTLC`)
|
||||
1. type: 130 (`update_fulfill_htlc`)
|
||||
2. data:
|
||||
* [8:channel-id]
|
||||
* [8:id]
|
||||
@ -632,7 +632,7 @@ original HTLC initiator as defined in [BOLT #4].
|
||||
|
||||
For a timed out or route-failed HTLC:
|
||||
|
||||
1. type: 131 (`MSG_UPDATE_FAIL_HTLC`)
|
||||
1. type: 131 (`update_fail_htlc`)
|
||||
2. data:
|
||||
* [8:channel-id]
|
||||
* [8:id]
|
||||
@ -671,7 +671,7 @@ sign the resulting transaction as defined in [BOLT #3] and send a
|
||||
`commitsig` message.
|
||||
|
||||
|
||||
1. type: 132 (`MSG_COMMIT_SIG`)
|
||||
1. type: 132 (`commit_sig`)
|
||||
2. data:
|
||||
* [8:channel-id]
|
||||
* [64:signature]
|
||||
@ -726,7 +726,7 @@ This message also supplies the signatures for the sender's HTLC-timeout transact
|
||||
The description of key derivation is in [BOLT #3](03-transactions.md#key-derivation).
|
||||
|
||||
|
||||
1. type: 133 (`MSG_REVOKE_AND_ACK`)
|
||||
1. type: 133 (`revoke_and_ack`)
|
||||
2. data:
|
||||
* [8:channel-id]
|
||||
* [32:per-commitment-secret]
|
||||
|
@ -21,7 +21,7 @@ on-chain bitcoin key to the lightning node key, and vice-versa.
|
||||
The channel is not really usable until at least one side has announced
|
||||
its fee levels and expiry using `channel_update`.
|
||||
|
||||
1. type: 256 (`MSG_CHANNEL_ANNOUNCEMENT`)
|
||||
1. type: 256 (`channel_announcement`)
|
||||
2. data:
|
||||
* [64:node-signature-1]
|
||||
* [64:node-signature-2]
|
||||
@ -100,7 +100,7 @@ This allows a node to indicate extra data associated with it, in
|
||||
addition to its public key. To avoid trivial denial of service attacks,
|
||||
nodes for which a channel is not already known are ignored.
|
||||
|
||||
1. type: 257 (`MSG_NODE_ANNOUNCEMENT`)
|
||||
1. type: 257 (`node_announcement`)
|
||||
2. data:
|
||||
* [64:signature]
|
||||
* [4:timestamp]
|
||||
@ -162,7 +162,7 @@ channel shortid which matches the `channel_announcement` and one byte
|
||||
to indicate which end this is. It can do this multiple times, if
|
||||
it wants to change fees.
|
||||
|
||||
1. type: 258 (`MSG_CHANNEL_UPDATE`)
|
||||
1. type: 258 (`channel_update`)
|
||||
2. data:
|
||||
* [64:signature]
|
||||
* [8:channel-id]
|
||||
|
115
tools/extract-formats.py
Executable file
115
tools/extract-formats.py
Executable file
@ -0,0 +1,115 @@
|
||||
#! /usr/bin/python3
|
||||
# Simple script to parse specs and produce CSV files.
|
||||
# Released by Rusty Russell under CC0: https://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
from optparse import OptionParser
|
||||
import sys
|
||||
import re
|
||||
import fileinput
|
||||
|
||||
# Figure out if we can determine type from size.
|
||||
def guess_alignment(message,name,sizestr):
|
||||
|
||||
# Exceptions:
|
||||
# - Padding has no alignment requirements.
|
||||
# - channel-id is size 8, but has alignment 4.
|
||||
# - node_announcement.ipv6 has size 16, but alignment 4 (to align IPv4 addr).
|
||||
# - node_announcement.alias is a string, so alignment 1
|
||||
# - signatures have alignment 4, because why not.
|
||||
if match.group('name').startswith('pad'):
|
||||
return 1
|
||||
|
||||
if match.group('name') == 'channel-id':
|
||||
return 4
|
||||
|
||||
if message == 'node_announcement' and match.group('name') == 'ipv6':
|
||||
return 4
|
||||
|
||||
if message == 'node_announcement' and match.group('name') == 'alias':
|
||||
return 1
|
||||
|
||||
if 'signature' in match.group('name'):
|
||||
return 4
|
||||
|
||||
# Size can be variable.
|
||||
try:
|
||||
size = int(match.group('size'))
|
||||
except ValueError:
|
||||
# If it contains a "*xxx" factor, that's our per-unit size.
|
||||
s = re.search('\*([0-9]*)$', match.group('size'))
|
||||
if s is None:
|
||||
size = 1
|
||||
else:
|
||||
size = int(s.group(1))
|
||||
|
||||
if size % 8 == 0:
|
||||
return 8
|
||||
elif size % 4 == 0:
|
||||
return 4
|
||||
elif size % 2 == 0:
|
||||
return 2
|
||||
|
||||
return 1
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option("--message-types",
|
||||
action="store_true", dest="output_types", default=False,
|
||||
help="Output MESSAGENAME,VALUE for every message")
|
||||
parser.add_option("--check-alignment",
|
||||
action="store_true", dest="check_alignment", default=False,
|
||||
help="Check alignment for every member of each message")
|
||||
parser.add_option("--message-fields",
|
||||
action="store_true", dest="output_fields", default=False,
|
||||
help="Output MESSAGENAME,OFFSET,FIELDNAME,SIZE for every message")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
# Example input:
|
||||
# 1. type: 17 (`MSG_ERROR`)
|
||||
# 2. data:
|
||||
# * [8:channel-id]
|
||||
# * [4:len]
|
||||
# * [len:data]
|
||||
message = None
|
||||
havedata = None
|
||||
typeline = re.compile('1\. type: (?P<value>[0-9]+) \(`(?P<name>[-A-Za-z_]+)`\)')
|
||||
dataline = re.compile('\s+\* \[(?P<size>[-a-z0-9*+]+):(?P<name>[-a-z0-9]+)\]')
|
||||
|
||||
for i,line in enumerate(fileinput.input(args)):
|
||||
line = line.rstrip()
|
||||
linenum = i+1
|
||||
|
||||
match = typeline.fullmatch(line)
|
||||
if match:
|
||||
if message is not None:
|
||||
raise ValueError('{}:Found a message while I was already in a message'.format(linenum))
|
||||
message = match.group('name')
|
||||
if options.output_types:
|
||||
print("{},{}".format(match.group('name'), match.group('value')))
|
||||
havedata = None
|
||||
elif message is not None and havedata is None:
|
||||
if line != '2. data:':
|
||||
raise ValueError('{}:Expected 2. data:'.format(linenum))
|
||||
havedata = True
|
||||
dataoff = 0
|
||||
off_extraterms = ""
|
||||
maxalign = 1
|
||||
elif message is not None and havedata is not None:
|
||||
match = dataline.fullmatch(line)
|
||||
if match:
|
||||
align = guess_alignment(message, match.group('name'), match.group('size'))
|
||||
|
||||
if options.check_alignment and dataoff % align != 0:
|
||||
raise ValueError('{}:message {} field {} Offset {} not aligned on {} boundary:'.format(linenum, message, match.group('name'), dataoff, align))
|
||||
|
||||
if options.output_fields:
|
||||
print("{},{}{},{},{}".format(message,dataoff,off_extraterms,match.group('name'),match.group('size')))
|
||||
|
||||
# Size can be variable.
|
||||
try:
|
||||
dataoff += int(match.group('size'))
|
||||
except ValueError:
|
||||
# Offset has variable component.
|
||||
off_extraterms = off_extraterms + "+" + match.group('size')
|
||||
else:
|
||||
message = None
|
Loading…
Reference in New Issue
Block a user