signed types: add handlers for signed types

We're adding signed types to the spec! This adds the support mechanisms
for them.
This commit is contained in:
Dustin Dettmer 2023-05-05 15:10:53 -04:00 committed by Rusty Russell
parent ad592d8b0d
commit aba4d18ed1
19 changed files with 266 additions and 77 deletions

View File

@ -23,30 +23,6 @@
#include <stdio.h>
#include <wire/onion_wire.h>
bool json_to_s64(const char *buffer, const jsmntok_t *tok, s64 *num)
{
char *end;
long long l;
l = strtoll(buffer + tok->start, &end, 0);
if (end != buffer + tok->end)
return false;
BUILD_ASSERT(sizeof(l) >= sizeof(*num));
*num = l;
/* Check for overflow/underflow */
if ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE)
return false;
/* Check if the number did not fit in `s64` (in case `long long`
is a bigger type). */
if (*num != l)
return false;
return true;
}
bool json_to_millionths(const char *buffer, const jsmntok_t *tok,
u64 *millionths)
{

View File

@ -88,6 +88,30 @@ bool json_to_u64(const char *buffer, const jsmntok_t *tok, u64 *num)
return true;
}
bool json_to_s64(const char *buffer, const jsmntok_t *tok, s64 *num)
{
char *end;
long long l;
l = strtoll(buffer + tok->start, &end, 0);
if (end != buffer + tok->end)
return false;
BUILD_ASSERT(sizeof(l) >= sizeof(*num));
*num = l;
/* Check for overflow/underflow */
if ((l == LONG_MAX || l == LONG_MIN) && errno == ERANGE)
return false;
/* Check if the number did not fit in `s64` (in case `long long`
is a bigger type). */
if (*num != l)
return false;
return true;
}
bool json_str_to_u64(const char *buffer, const jsmntok_t *tok, u64 *num)
{
jsmntok_t temp;

View File

@ -35,6 +35,9 @@ char *json_strdup(const tal_t *ctx, const char *buffer, const jsmntok_t *tok);
/* Extract number from this (may be a string, or a number literal) */
bool json_to_u64(const char *buffer, const jsmntok_t *tok, u64 *num);
/* Extract signed 64 bit integer from this (may be a string, or a number literal) */
bool json_to_s64(const char *buffer, const jsmntok_t *tok, s64 *num);
/* Extract number from string. The number must be the entirety of the
* string between the '"' */
bool json_str_to_u64(const char *buffer, const jsmntok_t *tok, u64 *num);

View File

@ -45,6 +45,9 @@ void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id U
/* Generated stub for towire_node_id */
void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED)
{ fprintf(stderr, "towire_node_id called!\n"); abort(); }
/* Generated stub for towire_s64 */
void towire_s64(u8 **pptr UNNEEDED, s64 v UNNEEDED)
{ fprintf(stderr, "towire_s64 called!\n"); abort(); }
/* Generated stub for towire_secp256k1_ecdsa_signature */
void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED,
const secp256k1_ecdsa_signature *signature UNNEEDED)

View File

@ -22,6 +22,10 @@ typemap = {
'u8': 'uint32', # Yep, this is the smallest integer type in grpc...
'u32': 'uint32',
'u64': 'uint64',
's8': 'int32',
's16': 'int32',
's32': 'int32',
's64': 'int64',
'u16': 'uint32', # Yeah, I know...
'f32': 'float',
'integer': 'sint64',

View File

@ -40,6 +40,10 @@ class Grpc2PyGenerator(IGenerator):
'u16': "m.{name}",
'u32': "m.{name}",
'u64': "m.{name}",
's8': "m.{name}",
's16': "m.{name}",
's32': "m.{name}",
's64': "m.{name}",
'boolean': "m.{name}",
'short_channel_id': "m.{name}",
'msat': "amount2msat(m.{name})",

View File

@ -22,6 +22,10 @@ __all__ = [
'u16',
'u32',
'u64',
's8',
's16',
's32',
's64',
'tu16',
'tu32',
'tu64',

View File

@ -257,6 +257,10 @@ def fundamental_types() -> List[FieldType]:
# * `u16`: a 2 byte unsigned integer
# * `u32`: a 4 byte unsigned integer
# * `u64`: an 8 byte unsigned integer
# * `s8`: an 8-bit signed integer
# * `s16`: a 2 byte signed integer
# * `s32`: a 4 byte signed integer
# * `s64`: an 8 byte signed integer
#
# Inside TLV records which contain a single value, leading zeros in
# integers can be omitted:
@ -284,6 +288,10 @@ def fundamental_types() -> List[FieldType]:
IntegerType('u16', 2, '>H'),
IntegerType('u32', 4, '>I'),
IntegerType('u64', 8, '>Q'),
IntegerType('s8', 1, 'b'),
IntegerType('s16', 2, '>h'),
IntegerType('s32', 4, '>i'),
IntegerType('s64', 8, '>q'),
TruncatedIntType('tu16', 2),
TruncatedIntType('tu32', 4),
TruncatedIntType('tu64', 8),

View File

@ -13,6 +13,29 @@ def test_fundamental_types():
'u64': [['18446744073709551615',
b'\xff\xff\xff\xff\xff\xff\xff\xff'],
['0', b'\x00\x00\x00\x00\x00\x00\x00\x00']],
's8': [['0', b'\x00'],
['42', b'\x2a'],
['-42', b'\xd6'],
['127', b'\x7f'],
['-128', b'\x80']],
's16': [['128', b'\x00\x80'],
['-129', b'\xff\x7f'],
['15000', b'\x3a\x98'],
['-15000', b'\xc5\x68'],
['32767', b'\x7f\xff'],
['-32768', b'\x80\x00']],
's32': [['32768', b'\x00\x00\x80\x00'],
['-32769', b'\xff\xff\x7f\xff'],
['21000000', b'\x01\x40\x6f\x40'],
['-21000000', b'\xfe\xbf\x90\xc0'],
['2147483647', b'\x7f\xff\xff\xff'],
['-2147483648', b'\x80\x00\x00\x00']],
's64': [['2147483648', b'\x00\x00\x00\x00\x80\x00\x00\x00'],
['-2147483649', b'\xff\xff\xff\xff\x7f\xff\xff\xff'],
['500000000000', b'\x00\x00\x00\x74\x6a\x52\x88\x00'],
['-500000000000', b'\xff\xff\xff\x8b\x95\xad\x78\x00'],
['9223372036854775807', b'\x7f\xff\xff\xff\xff\xff\xff\xff'],
['-9223372036854775808', b'\x80\x00\x00\x00\x00\x00\x00\x00']],
'tu16': [['65535', b'\xff\xff'],
['256', b'\x01\x00'],
['255', b'\xff'],

View File

@ -8,7 +8,7 @@ DEVTOOLS_TOOL_OBJS := $(DEVTOOLS_TOOL_SRC:.c=.o)
# Make sure these depend on everything.
ALL_C_SOURCES += $(DEVTOOLS_TOOL_SRC)
ALL_C_HEADERS +=
ALL_C_HEADERS +=
ALL_PROGRAMS += $(DEVTOOLS)
DEVTOOLS_COMMON_OBJS := \

View File

@ -51,6 +51,50 @@ bool printwire_u64(const char *fieldname, const u8 **cursor, size_t *plen)
return true;
}
bool printwire_s8(const char *fieldname, const u8 **cursor, size_t *plen)
{
s8 v = fromwire_s8(cursor, plen);
if (!*cursor) {
printf("**TRUNCATED s64 %s**\n", fieldname);
return false;
}
printf("%d\n", v);
return true;
}
bool printwire_s16(const char *fieldname, const u8 **cursor, size_t *plen)
{
s16 v = fromwire_s16(cursor, plen);
if (!*cursor) {
printf("**TRUNCATED s64 %s**\n", fieldname);
return false;
}
printf("%d\n", v);
return true;
}
bool printwire_s32(const char *fieldname, const u8 **cursor, size_t *plen)
{
s32 v = fromwire_s32(cursor, plen);
if (!*cursor) {
printf("**TRUNCATED s64 %s**\n", fieldname);
return false;
}
printf("%d\n", v);
return true;
}
bool printwire_s64(const char *fieldname, const u8 **cursor, size_t *plen)
{
s64 v = fromwire_s64(cursor, plen);
if (!*cursor) {
printf("**TRUNCATED s64 %s**\n", fieldname);
return false;
}
printf("%ld\n", v);
return true;
}
bool printwire_tu16(const char *fieldname, const u8 **cursor, size_t *plen)
{
u16 v = fromwire_tu16(cursor, plen);

View File

@ -20,6 +20,10 @@ bool printwire_u8(const char *fieldname, const u8 **cursor, size_t *plen);
bool printwire_u16(const char *fieldname, const u8 **cursor, size_t *plen);
bool printwire_u32(const char *fieldname, const u8 **cursor, size_t *plen);
bool printwire_u64(const char *fieldname, const u8 **cursor, size_t *plen);
bool printwire_s8(const char *fieldname, const u8 **cursor, size_t *plen);
bool printwire_s16(const char *fieldname, const u8 **cursor, size_t *plen);
bool printwire_s32(const char *fieldname, const u8 **cursor, size_t *plen);
bool printwire_s64(const char *fieldname, const u8 **cursor, size_t *plen);
bool printwire_tu16(const char *fieldname, const u8 **cursor, size_t *plen);
bool printwire_tu32(const char *fieldname, const u8 **cursor, size_t *plen);
bool printwire_tu64(const char *fieldname, const u8 **cursor, size_t *plen);

View File

@ -184,6 +184,10 @@ class Type(FieldSet):
'u16',
'u32',
'u64',
's8',
's16',
's32',
's64',
'tu16',
'tu32',
'tu64',
@ -199,6 +203,10 @@ class Type(FieldSet):
'u16',
'u32',
'u64',
's8',
's16',
's32',
's64',
'bool',
'secp256k1_ecdsa_signature',
'secp256k1_ecdsa_recoverable_signature',

View File

@ -28,7 +28,9 @@ ALL_C_SOURCES += $(TOOL_GEN_SRC) $(TOOL_TEST_SRC)
ALL_C_HEADERS += $(TOOL_GEN_HEADER)
TOOL_TEST_COMMON_OBJS := \
common/utils.o
common/utils.o \
wire/fromwire.o \
wire/towire.o
TOOLS_WIRE_DEPS := $(BOLT_DEPS) tools/test/test_cases $(wildcard tools/gen/*_template)

View File

@ -3,49 +3,37 @@
#include "print_gen.h"
#include <assert.h>
#include <ccan/array_size/array_size.h>
#include <ccan/mem/mem.h>
#include <stdio.h>
#include <wire/wire.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for fromwire_amount_msat */
struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_amount_msat called!\n"); abort(); }
/* Generated stub for fromwire_bool */
bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_bool called!\n"); abort(); }
/* Generated stub for fromwire_peektype */
int fromwire_peektype(const u8 *cursor UNNEEDED)
{ fprintf(stderr, "fromwire_peektype called!\n"); abort(); }
/* Generated stub for fromwire_tlv */
bool fromwire_tlv(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED,
void *record UNNEEDED, struct tlv_field **fields UNNEEDED,
const u64 *extra_types UNNEEDED, size_t *err_off UNNEEDED, u64 *err_type UNNEEDED)
{ fprintf(stderr, "fromwire_tlv called!\n"); abort(); }
/* Generated stub for fromwire_tu32 */
u32 fromwire_tu32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_tu32 called!\n"); abort(); }
/* Generated stub for fromwire_tu64 */
u64 fromwire_tu64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_tu64 called!\n"); abort(); }
/* Generated stub for fromwire_u16 */
u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); }
/* Generated stub for fromwire_u32 */
u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); }
/* Generated stub for fromwire_u64 */
u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); }
/* Generated stub for fromwire_u8 */
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
/* Generated stub for fromwire_u8_array */
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); }
/* Generated stub for printwire_amount_msat */
bool printwire_amount_msat(const char *fieldname UNNEEDED, const u8 **cursor UNNEEDED, size_t *plen UNNEEDED)
{ fprintf(stderr, "printwire_amount_msat called!\n"); abort(); }
/* Generated stub for printwire_s16 */
bool printwire_s16(const char *fieldname UNNEEDED, const u8 **cursor UNNEEDED, size_t *plen UNNEEDED)
{ fprintf(stderr, "printwire_s16 called!\n"); abort(); }
/* Generated stub for printwire_s32 */
bool printwire_s32(const char *fieldname UNNEEDED, const u8 **cursor UNNEEDED, size_t *plen UNNEEDED)
{ fprintf(stderr, "printwire_s32 called!\n"); abort(); }
/* Generated stub for printwire_s64 */
bool printwire_s64(const char *fieldname UNNEEDED, const u8 **cursor UNNEEDED, size_t *plen UNNEEDED)
{ fprintf(stderr, "printwire_s64 called!\n"); abort(); }
/* Generated stub for printwire_s8 */
bool printwire_s8(const char *fieldname UNNEEDED, const u8 **cursor UNNEEDED, size_t *plen UNNEEDED)
{ fprintf(stderr, "printwire_s8 called!\n"); abort(); }
/* Generated stub for printwire_tlvs */
bool printwire_tlvs(const char *tlv_name UNNEEDED, const u8 **cursor UNNEEDED, size_t *plen UNNEEDED,
const struct tlv_print_record_type types[] UNNEEDED, size_t num_types UNNEEDED)
@ -71,37 +59,76 @@ bool printwire_u8_array(const char *fieldname UNNEEDED, const u8 **cursor UNNEED
/* Generated stub for towire_amount_msat */
void towire_amount_msat(u8 **pptr UNNEEDED, const struct amount_msat msat UNNEEDED)
{ fprintf(stderr, "towire_amount_msat called!\n"); abort(); }
/* Generated stub for towire_bool */
void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED)
{ fprintf(stderr, "towire_bool called!\n"); abort(); }
/* Generated stub for towire_tlv */
void towire_tlv(u8 **pptr UNNEEDED,
const struct tlv_record_type *types UNNEEDED, size_t num_types UNNEEDED,
const void *record UNNEEDED)
{ fprintf(stderr, "towire_tlv called!\n"); abort(); }
/* Generated stub for towire_tu32 */
void towire_tu32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
{ fprintf(stderr, "towire_tu32 called!\n"); abort(); }
/* Generated stub for towire_tu64 */
void towire_tu64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
{ fprintf(stderr, "towire_tu64 called!\n"); abort(); }
/* Generated stub for towire_u16 */
void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED)
{ fprintf(stderr, "towire_u16 called!\n"); abort(); }
/* Generated stub for towire_u32 */
void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
{ fprintf(stderr, "towire_u32 called!\n"); abort(); }
/* Generated stub for towire_u64 */
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
/* Generated stub for towire_u8 */
void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
{ fprintf(stderr, "towire_u8 called!\n"); abort(); }
/* Generated stub for towire_u8_array */
void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "towire_u8_array called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
#define COMPARE_VALS(type, len) \
for (size_t i = 0; i < ARRAY_SIZE(type##s); i++) { \
const u8 *ptr, *data = \
tal_hexdata(ctx, type##s[i].hexstr, \
strlen(type##s[i].hexstr)); \
size_t max, size = tal_bytelen(data); \
assert(size == (len)); \
max = size; \
ptr = data; \
type val = fromwire_##type(&ptr, &max); \
assert(max == 0); \
assert(val == type##s[i].val); \
\
/* Check towire */ \
u8 *wired = tal_arr(ctx, u8, 0); \
towire_##type(&wired, (type)type##s[i].val); \
assert(memeq(data, size, wired, tal_bytelen(wired))); \
}
static void test_signed_ints(void)
{
/* Let's test some serializations */
void *ctx = tal(NULL, char);
struct test_case {
s64 val;
char *hexstr;
} s8s[] = {
{ .val = 0, .hexstr = "00" },
{ .val = 42, .hexstr = "2a" },
{ .val = -42, .hexstr = "d6" },
{ .val = 127, .hexstr = "7f" },
{ .val = -128, .hexstr = "80" },
}, s16s[] = {
{ .val = 128, .hexstr = "0080" },
{ .val = -129, .hexstr = "ff7f" },
{ .val = 15000, .hexstr = "3a98" },
{ .val = -15000, .hexstr = "c568" },
{ .val = 32767, .hexstr = "7fff" },
{ .val = -32768, .hexstr = "8000" },
}, s32s[] = {
{ .val = 32768, .hexstr = "00008000" },
{ .val = -32769, .hexstr = "ffff7fff" },
{ .val = 21000000, .hexstr = "01406f40" },
{ .val = -21000000, .hexstr = "febf90c0" },
{ .val = 2147483647, .hexstr = "7fffffff" },
{ .val = -2147483648, .hexstr = "80000000" },
}, s64s[] = {
{ .val = 2147483648, .hexstr = "0000000080000000" },
{ .val = -2147483649, .hexstr = "ffffffff7fffffff" },
{ .val = 500000000000, .hexstr = "000000746a528800" },
{ .val = -500000000000, .hexstr = "ffffff8b95ad7800" },
{ .val = 9223372036854775807, .hexstr = "7fffffffffffffff" },
{ .val = -9223372036854775808ULL, .hexstr = "8000000000000000" },
};
COMPARE_VALS(s8, 1);
COMPARE_VALS(s16, 2);
COMPARE_VALS(s32, 4);
COMPARE_VALS(s64, 8);
tal_free(ctx);
}
int main(void)
{
setup_locale();
@ -115,5 +142,7 @@ int main(void)
assert(n2);
assert(n3);
test_signed_ints();
tal_free(ctx);
}

View File

@ -30,6 +30,11 @@ msgdata,test_msg,test_varsize_struct_varlen,test_features,len_varsize_struct
msgdata,test_msg,test_assignable,u16,
# enum
msgdata,test_msg,test_enum,enum test_enum,
# test signed int fields
msgdata,test_msg,test_s8,s8,
msgdata,test_msg,test_s16,s16,
msgdata,test_msg,test_s32,s32,
msgdata,test_msg,test_s64,s64,
# test struct
msgdata,test_msg,test_struct,test_short_id,
# test var-size struct

View File

@ -88,6 +88,26 @@ u64 fromwire_u64(const u8 **cursor, size_t *max)
return be64_to_cpu(ret);
}
s8 fromwire_s8(const u8 **cursor, size_t *max)
{
return (s8)fromwire_u8(cursor, max);
}
s16 fromwire_s16(const u8 **cursor, size_t *max)
{
return (s16)fromwire_u16(cursor, max);
}
s32 fromwire_s32(const u8 **cursor, size_t *max)
{
return (s32)fromwire_u32(cursor, max);
}
s64 fromwire_s64(const u8 **cursor, size_t *max)
{
return (s64)fromwire_u64(cursor, max);
}
static u64 fromwire_tlv_uint(const u8 **cursor, size_t *max, size_t maxlen)
{
u8 bytes[8];

View File

@ -39,6 +39,26 @@ void towire_u64(u8 **pptr, u64 v)
towire(pptr, &l, sizeof(l));
}
void towire_s8(u8 **pptr, s8 v)
{
towire_u8(pptr, (u8)v);
}
void towire_s32(u8 **pptr, s32 v)
{
towire_u32(pptr, (u32)v);
}
void towire_s16(u8 **pptr, s16 v)
{
towire_u16(pptr, (u16)v);
}
void towire_s64(u8 **pptr, s64 v)
{
towire_u64(pptr, (u64)v);
}
static void towire_tlv_uint(u8 **pptr, u64 v)
{
u8 bytes[8];

View File

@ -31,6 +31,10 @@ void towire_u8(u8 **pptr, u8 v);
void towire_u16(u8 **pptr, u16 v);
void towire_u32(u8 **pptr, u32 v);
void towire_u64(u8 **pptr, u64 v);
void towire_s8(u8 **pptr, s8 v);
void towire_s16(u8 **pptr, s16 v);
void towire_s32(u8 **pptr, s32 v);
void towire_s64(u8 **pptr, s64 v);
void towire_tu16(u8 **pptr, u16 v);
void towire_tu32(u8 **pptr, u32 v);
void towire_tu64(u8 **pptr, u64 v);
@ -49,6 +53,10 @@ u8 fromwire_u8(const u8 **cursor, size_t *max);
u16 fromwire_u16(const u8 **cursor, size_t *max);
u32 fromwire_u32(const u8 **cursor, size_t *max);
u64 fromwire_u64(const u8 **cursor, size_t *max);
s8 fromwire_s8(const u8 **cursor, size_t *max);
s16 fromwire_s16(const u8 **cursor, size_t *max);
s32 fromwire_s32(const u8 **cursor, size_t *max);
s64 fromwire_s64(const u8 **cursor, size_t *max);
u16 fromwire_tu16(const u8 **cursor, size_t *max);
u32 fromwire_tu32(const u8 **cursor, size_t *max);
u64 fromwire_tu64(const u8 **cursor, size_t *max);