TLV parsing#2501
Conversation
c1a37c0 to
174e214
Compare
rustyrussell
left a comment
There was a problem hiding this comment.
Minor issues only. I'm happy if you want to keep the structs for now, since we can always change the API to open-code the fields if it proves a problem, and I don't want to create any roadblocks.
| funding_locked,36 | ||
| funding_locked,0,channel_id,32 | ||
| funding_locked,32,next_per_commitment_point,33 | ||
| open_channel2,56 |
There was a problem hiding this comment.
This is OK for now, but I think we're going to have to move to a system where we have experimental CSV files (which get compiled in if EXPERIMENTAL defined).
There was a problem hiding this comment.
I went back and forth on whether or not to include these. Really they're only here because I needed something to test with 🌵
| self.is_tlv = False | ||
|
|
||
| # field name appended with '+' means this field contains a tlv | ||
| if name.endswith('+'): |
There was a problem hiding this comment.
This isn't going to work well in the spec; let's use name.endswith('tlv')?
| """ prints fromwire function definition for a TLV message. | ||
| these are significantly different in that they take in a struct | ||
| to populate, instead of fields, as well as a length to read in | ||
| """ |
There was a problem hiding this comment.
This is an interesting choice, and I'm not sure it's the correct one (we changed from structs to individual parameters early on in our wire parsing).
We could parse TLVs just like we do a formatted field, except everything has to be a ptr-to-ptr so we can set it to NULL if it doesn't appear.
There was a problem hiding this comment.
right, i think either of these is a valid way to do this. i had the impression that most TLV messages would be rather involved field wise, but it's also possible they're mostly one-off fields...
| tlv__type_impl_towire_fields = """\tif ({tlv_name}->{name}) {{ | ||
| \t\ttlv_msg = tal_arr(ctx, u8, 0); | ||
| \t\ttowire_u16(p, {enum}); | ||
| \t\ttowire_u8(p, {enum}); |
There was a problem hiding this comment.
Except I was wrong and it (and type) should be varint :)
| \t\t}} | ||
| \t}} | ||
| \tif (!*p) {{ | ||
| \tif (!*p || start_len - *plen != *len) {{ |
There was a problem hiding this comment.
It's not entirely clear to me that this is correct. For onion, at least, we should on first type=0 and ignore any remaining. Seems consistent to do that elsewhere, too.
There was a problem hiding this comment.
hmm you're right. there's also the 'ordering' aspect of the proposed TLV spec that this implementation is missing at the moment. will update.
Version 1.1 of the lightning-rfc spec introduces TLVs for optional data fields. This starts the process of updating our auto-gen'd wireformat parsers to be able to understand TLV fields. The general way to declare a new TLV field is to add a '+' to the end of the fieldname. All field type declarations for that TLV set should be added to a file in the same directory by the name `gen_<field_name>_csv`. Note that the FIXME included in this commit is difficult to fix, as we currently pass in the csv files via stdin (so there's no easy way to ascertain the originating directory of file)
'.c' wire format files include case statements to print the names of enums. Include such methods for the enums pertaining to tlv's as well.
Add tlv-messages to the general messages set so that their parsing messages get printed out. FIXME: figure out how to account for partial message length processing?
Since messages in TLV's are optional, the ideal way to deal with them is to have a 'master struct' object for every defined tlv, where the presence or lack of a field can be determined via the presence (or lack thereof) of a struct for each of the optional message types. In order to do this, appropriately, we need a struct for every TLV message. The next commit will make use of these. Note that right now TLV message structs aren't namespaced to the TLV they belong to, so there's the potential for collision. This should be fixed when/where it occurs (should fail to compile).
construct structs for the TLV's. these will be the 'return type' for tlv fields in parent messages (so to speak)
clean up basetype parsing code a bit
much better than statically calculating the sizeof
Suggested-By: @rustyrussell
Suggested-By: @rustyrussell
let's let the fromwire__tlv methods allocate the tlv-objects and return them. we also want to initialize all of their underlying messages to NULL, and fail if we discover a duplicate mesage type. if parsing fails, instead of returning a struct we return NULL. Suggested-By: @rustyrussell
fail if a message type is even and it's not included. otherwise, continue with the next message type.
passing back a null TLV was crashing here, because we tried to dereference a null pointer. instead, we put it into a temporary struct that we can check for NULL-ness, before assigning to the passed in pointer.
need to pass in a pointer to the array so that when we advance the array in the subcalls, it advances in the parent. oops
otherwise they'll get cleaned up when the message is free'd. it's nbd either way, but this seems tighter.
include includes for TLV _csv files
Updated to match what the CSV generator in the RFC repo actually outputs, see lightning/bolts#597
so we can put and pull bitcoin 'var_int' length types from the wire. for more info on variable integers, see http://learnmeabitcoin.com/glossary/varint
TLV's use var_int's for messages sizes, both internally and in the top level (you should really stack a var_int inside a var_int!!) this updates our automagick generator code to understand 'var_ints'
8007a67 to
b58df84
Compare
|
@rustyrussell fixed up to exclude any and all references to 'dual funding' :) if you're happy with this, i think we're good to merge for now. here's a short list of things that need to be improved in a follow up PR:
|
I think at the moment it will break parsing, being considered even :)
I think this Just Works if the spec lists them in ascending order But probably good to check!
Naah, I think what will happen is we'll memcpy it in, so remainder will be zero.
Def. nice to have. |
| if (*max < 1) { | ||
| fromwire_fail(cursor, max); | ||
| return 0; | ||
| } |
There was a problem hiding this comment.
Note that this test is redundant!
Have the wire generators be TLV savvy. Adds parsers for nested structs etc.
Addition of a new TLV type requires adding a new filegen_{tlv_name}_csvto the wires. The parsers will identify TLV fields from the_csvfile, and then find the appropriate additional file to parse.Also generates the structs necessary to figure out whether or not these fields have been included. In general, you can check for a TLV type's inclusion via whether or not the returned tlv struct's message field is null.
A few notes:
capped at u8a varint.