mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
wire: generate marshal/unmarshal from spec.
Including tests! Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
f85f2c6c2d
commit
36e018161f
1
Makefile
1
Makefile
@ -201,6 +201,7 @@ protocol-diagrams: $(patsubst %.script, doc/protocol-%.svg, $(notdir $(wildcard
|
||||
check: test-protocol bitcoin-tests
|
||||
|
||||
include bitcoin/Makefile
|
||||
include wire/Makefile
|
||||
|
||||
# Keep includes in alpha order.
|
||||
check-src-include-order/%: %
|
||||
|
33
wire/Makefile
Normal file
33
wire/Makefile
Normal file
@ -0,0 +1,33 @@
|
||||
#! /usr/bin/make
|
||||
|
||||
# Designed to be run one level up
|
||||
wire-wrongdir:
|
||||
$(MAKE) -C .. wire-all
|
||||
|
||||
WIRE_OBJS := wire/gen_wire.o \
|
||||
wire/fromwire.o \
|
||||
wire/towire.o
|
||||
|
||||
WIRE_HEADERS := wire/wire.h
|
||||
WIRE_GEN_HEADERS := wire/gen_wire.h
|
||||
WIRE_GEN_SRC := wire/gen_wire.c
|
||||
|
||||
# They may not have the bolts.
|
||||
BOLT_EXTRACT=$(BOLTDIR)/tools/extract-formats.py
|
||||
wire/gen_wire_csv: FORCE
|
||||
@set -e; if [ -f $(BOLT_EXTRACT) ]; then for f in $(BOLTDIR)/*.md $(BOLT_EXTRACT); do if [ $$f -nt $@ -o ! -f $@ ]; then $(BOLT_EXTRACT) --message-fields --message-types --check-alignment $(BOLTDIR)/*.md > $@; break; fi; done; fi
|
||||
|
||||
wire/gen_wire.h: wire/tools/generate-wire.py wire/gen_wire_csv
|
||||
wire/tools/generate-wire.py --header < wire/gen_wire_csv > $@
|
||||
|
||||
wire/gen_wire.c: wire/tools/generate-wire.py wire/gen_wire_csv
|
||||
wire/tools/generate-wire.py < wire/gen_wire_csv > $@
|
||||
|
||||
wire/gen_wire.o: wire/gen_wire.h
|
||||
|
||||
clean: wire-clean
|
||||
|
||||
wire-clean:
|
||||
$(RM) $(WIRE_OBJS) $(WIRE_GEN_SRC) $(WIRE_GEN_HEADERS)
|
||||
|
||||
include wire/test/Makefile
|
132
wire/fromwire.c
Normal file
132
wire/fromwire.c
Normal file
@ -0,0 +1,132 @@
|
||||
#include "wire.h"
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
|
||||
/* Sets *cursor to NULL and returns NULL when extraction fails. */
|
||||
static const void *fail_pull(const u8 **cursor, size_t *max)
|
||||
{
|
||||
*cursor = NULL;
|
||||
*max = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const u8 *fromwire(const u8 **cursor, size_t *max, void *copy, size_t n)
|
||||
{
|
||||
const u8 *p = *cursor;
|
||||
|
||||
if (*max < n) {
|
||||
/* Just make sure we don't leak uninitialized mem! */
|
||||
if (copy)
|
||||
memset(copy, 0, n);
|
||||
return fail_pull(cursor, max);
|
||||
}
|
||||
*cursor += n;
|
||||
*max -= n;
|
||||
if (copy)
|
||||
memcpy(copy, p, n);
|
||||
return memcheck(p, n);
|
||||
}
|
||||
|
||||
u8 fromwire_u8(const u8 **cursor, size_t *max)
|
||||
{
|
||||
u8 ret;
|
||||
|
||||
if (!fromwire(cursor, max, &ret, sizeof(ret)))
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
u16 fromwire_u16(const u8 **cursor, size_t *max)
|
||||
{
|
||||
be16 ret;
|
||||
|
||||
if (!fromwire(cursor, max, &ret, sizeof(ret)))
|
||||
return 0;
|
||||
return be16_to_cpu(ret);
|
||||
}
|
||||
|
||||
u32 fromwire_u32(const u8 **cursor, size_t *max)
|
||||
{
|
||||
be32 ret;
|
||||
|
||||
if (!fromwire(cursor, max, &ret, sizeof(ret)))
|
||||
return 0;
|
||||
return be32_to_cpu(ret);
|
||||
}
|
||||
|
||||
u64 fromwire_u64(const u8 **cursor, size_t *max)
|
||||
{
|
||||
be64 ret;
|
||||
|
||||
if (!fromwire(cursor, max, &ret, sizeof(ret)))
|
||||
return 0;
|
||||
return be64_to_cpu(ret);
|
||||
}
|
||||
|
||||
void fromwire_pubkey(const u8 **cursor, size_t *max, struct pubkey *pubkey)
|
||||
{
|
||||
u8 der[PUBKEY_DER_LEN];
|
||||
|
||||
if (!fromwire(cursor, max, der, sizeof(der)))
|
||||
return;
|
||||
|
||||
if (!pubkey_from_der(secp256k1_ctx, der, sizeof(der), pubkey))
|
||||
fail_pull(cursor, max);
|
||||
}
|
||||
|
||||
void fromwire_signature(const u8 **cursor, size_t *max, struct signature *sig)
|
||||
{
|
||||
u8 compact[64];
|
||||
|
||||
if (!fromwire(cursor, max, compact, sizeof(compact)))
|
||||
return;
|
||||
|
||||
if (secp256k1_ecdsa_signature_parse_compact(secp256k1_ctx,
|
||||
&sig->sig, compact)
|
||||
!= 1)
|
||||
fail_pull(cursor, max);
|
||||
}
|
||||
|
||||
void fromwire_channel_id(const u8 **cursor, size_t *max,
|
||||
struct channel_id *channel_id)
|
||||
{
|
||||
be32 txnum = 0;
|
||||
u8 outnum;
|
||||
|
||||
channel_id->blocknum = fromwire_u32(cursor, max);
|
||||
/* Pulling 3 bytes off wire is tricky; they're big-endian. */
|
||||
fromwire(cursor, max, (char *)&txnum + 1, 3);
|
||||
channel_id->txnum = be32_to_cpu(txnum);
|
||||
fromwire(cursor, max, &outnum, 1);
|
||||
channel_id->outnum = outnum;
|
||||
}
|
||||
|
||||
void fromwire_sha256(const u8 **cursor, size_t *max, struct sha256 *sha256)
|
||||
{
|
||||
fromwire(cursor, max, sha256, sizeof(*sha256));
|
||||
}
|
||||
|
||||
void fromwire_ipv6(const u8 **cursor, size_t *max, struct ipv6 *ipv6)
|
||||
{
|
||||
fromwire(cursor, max, ipv6, sizeof(*ipv6));
|
||||
}
|
||||
|
||||
void fromwire_u8_array(const u8 **cursor, size_t *max, u8 *arr, size_t num)
|
||||
{
|
||||
fromwire(cursor, max, arr, num);
|
||||
}
|
||||
|
||||
void fromwire_pad_array(const u8 **cursor, size_t *max, u8 *arr, size_t num)
|
||||
{
|
||||
fromwire(cursor, max, arr, num);
|
||||
}
|
||||
|
||||
void fromwire_signature_array(const u8 **cursor, size_t *max,
|
||||
struct signature *arr, size_t num)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
fromwire_signature(cursor, max, arr + i);
|
||||
}
|
119
wire/gen_wire_csv
Normal file
119
wire/gen_wire_csv
Normal file
@ -0,0 +1,119 @@
|
||||
init,16
|
||||
init,0,gflen,2
|
||||
init,2,globalfeatures,gflen
|
||||
init,2+gflen,lflen,2
|
||||
init,4+gflen,localfeatures,lflen
|
||||
error,17
|
||||
error,0,channel-id,8
|
||||
error,8,len,2
|
||||
error,10,data,len
|
||||
open_channel,32
|
||||
open_channel,0,temporary-channel-id,8
|
||||
open_channel,8,funding-satoshis,8
|
||||
open_channel,16,push-msat,8
|
||||
open_channel,24,dust-limit-satoshis,8
|
||||
open_channel,32,max-htlc-value-in-flight-msat,8
|
||||
open_channel,40,channel-reserve-satoshis,8
|
||||
open_channel,48,htlc-minimum-msat,4
|
||||
open_channel,52,feerate-per-kw,4
|
||||
open_channel,56,to-self-delay,2
|
||||
open_channel,58,max-accepted-htlcs,2
|
||||
open_channel,60,funding-pubkey,33
|
||||
open_channel,93,revocation-basepoint,33
|
||||
open_channel,126,payment-basepoint,33
|
||||
open_channel,159,delayed-payment-basepoint,33
|
||||
open_channel,192,first-per-commitment-point,33
|
||||
accept_channel,33
|
||||
accept_channel,0,temporary-channel-id,8
|
||||
accept_channel,8,dust-limit-satoshis,8
|
||||
accept_channel,16,max-htlc-value-in-flight-msat,8
|
||||
accept_channel,24,channel-reserve-satoshis,8
|
||||
accept_channel,32,minimum-depth,4
|
||||
accept_channel,36,htlc-minimum-msat,4
|
||||
accept_channel,40,to-self-delay,2
|
||||
accept_channel,42,max-accepted-htlcs,2
|
||||
accept_channel,44,funding-pubkey,33
|
||||
accept_channel,77,revocation-basepoint,33
|
||||
accept_channel,110,payment-basepoint,33
|
||||
accept_channel,143,delayed-payment-basepoint,33
|
||||
accept_channel,176,first-per-commitment-point,33
|
||||
funding_created,34
|
||||
funding_created,0,temporary-channel-id,8
|
||||
funding_created,8,txid,32
|
||||
funding_created,40,output-index,1
|
||||
funding_created,41,signature,64
|
||||
funding_signed,35
|
||||
funding_signed,0,temporary-channel-id,8
|
||||
funding_signed,8,signature,64
|
||||
funding_locked,36
|
||||
funding_locked,0,temporary-channel-id,8
|
||||
funding_locked,8,channel-id,8
|
||||
funding_locked,16,announcement-node-signature,64
|
||||
funding_locked,80,announcement-bitcoin-signature,64
|
||||
funding_locked,144,next-per-commitment-point,33
|
||||
update_fee,37
|
||||
update_fee,0,channel-id,8
|
||||
update_fee,8,feerate-per-kw,4
|
||||
shutdown,38
|
||||
shutdown,0,channel-id,8
|
||||
shutdown,8,len,2
|
||||
shutdown,10,scriptpubkey,len
|
||||
closing_signed,39
|
||||
closing_signed,0,channel-id,8
|
||||
closing_signed,8,fee-satoshis,8
|
||||
closing_signed,16,signature,64
|
||||
update_add_htlc,128
|
||||
update_add_htlc,0,channel-id,8
|
||||
update_add_htlc,8,id,8
|
||||
update_add_htlc,16,amount-msat,4
|
||||
update_add_htlc,20,expiry,4
|
||||
update_add_htlc,24,payment-hash,32
|
||||
update_add_htlc,56,onion-routing-packet,1254
|
||||
update_fulfill_htlc,130
|
||||
update_fulfill_htlc,0,channel-id,8
|
||||
update_fulfill_htlc,8,id,8
|
||||
update_fulfill_htlc,16,payment-preimage,32
|
||||
update_fail_htlc,131
|
||||
update_fail_htlc,0,channel-id,8
|
||||
update_fail_htlc,8,id,8
|
||||
update_fail_htlc,16,reason,154
|
||||
commit_sig,132
|
||||
commit_sig,0,channel-id,8
|
||||
commit_sig,8,signature,64
|
||||
commit_sig,72,num-htlcs,2
|
||||
commit_sig,74,htlc-signature,num-htlcs*64
|
||||
revoke_and_ack,133
|
||||
revoke_and_ack,0,channel-id,8
|
||||
revoke_and_ack,8,per-commitment-secret,32
|
||||
revoke_and_ack,40,next-per-commitment-point,33
|
||||
revoke_and_ack,73,padding,1
|
||||
revoke_and_ack,74,num-htlc-timeouts,2
|
||||
revoke_and_ack,76,htlc-timeout-signature,num-htlc-timeouts*64
|
||||
channel_announcement,256
|
||||
channel_announcement,0,node-signature-1,64
|
||||
channel_announcement,64,node-signature-2,64
|
||||
channel_announcement,128,channel-id,8
|
||||
channel_announcement,136,bitcoin-signature-1,64
|
||||
channel_announcement,200,bitcoin-signature-2,64
|
||||
channel_announcement,264,node-id-1,33
|
||||
channel_announcement,297,node-id-2,33
|
||||
channel_announcement,330,bitcoin-key-1,33
|
||||
channel_announcement,363,bitcoin-key-2,33
|
||||
node_announcement,257
|
||||
node_announcement,0,signature,64
|
||||
node_announcement,64,timestamp,4
|
||||
node_announcement,68,ipv6,16
|
||||
node_announcement,84,port,2
|
||||
node_announcement,86,node-id,33
|
||||
node_announcement,119,rgb-color,3
|
||||
node_announcement,122,pad,2
|
||||
node_announcement,124,alias,32
|
||||
channel_update,258
|
||||
channel_update,0,signature,64
|
||||
channel_update,64,channel-id,8
|
||||
channel_update,72,timestamp,4
|
||||
channel_update,76,flags,2
|
||||
channel_update,78,expiry,2
|
||||
channel_update,80,htlc-minimum-msat,4
|
||||
channel_update,84,fee-base-msat,4
|
||||
channel_update,88,fee-proportional-millionths,4
|
1
wire/test/.gitignore
vendored
Normal file
1
wire/test/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
run-wire
|
16
wire/test/Makefile
Normal file
16
wire/test/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
check: wire-tests
|
||||
|
||||
# Note that these actually #include everything they need, except ccan/ and bitcoin/.
|
||||
# That allows for unit testing of statics, and special effects.
|
||||
WIRE_TEST_SRC := $(wildcard wire/test/run-*.c)
|
||||
WIRE_TEST_OBJS := $(WIRE_TEST_SRC:.c=.o)
|
||||
WIRE_TEST_PROGRAMS := $(WIRE_TEST_OBJS:.o=)
|
||||
|
||||
update-mocks: $(WIRE_TEST_SRC:%=update-mocks/%)
|
||||
|
||||
$(WIRE_TEST_PROGRAMS): $(CCAN_OBJS) $(BITCOIN_OBJS) libsecp256k1.a utils.o
|
||||
|
||||
$(WIRE_TEST_OBJS): $(WIRE_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(GEN_HEADERS) $(WIRE_GEN_HEADERS) $(WIRE_GEN_SRC) $(CCAN_HEADERS)
|
||||
|
||||
wire-tests: $(WIRE_TEST_PROGRAMS:%=unittest/%)
|
||||
|
434
wire/test/run-wire.c
Normal file
434
wire/test/run-wire.c
Normal file
@ -0,0 +1,434 @@
|
||||
#include "../gen_wire.c"
|
||||
|
||||
void towire_pad_array_orig(u8 **pptr, const u8 *arr, size_t num);
|
||||
#define towire_pad_array towire_pad_array_orig
|
||||
#include "../towire.c"
|
||||
#undef towire_pad_array
|
||||
|
||||
#include "../fromwire.c"
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
secp256k1_context *secp256k1_ctx;
|
||||
|
||||
/* We allow non-zero padding for testing. */
|
||||
void towire_pad_array(u8 **pptr, const u8 *arr, size_t num)
|
||||
{
|
||||
towire_u8_array(pptr, arr, num);
|
||||
}
|
||||
|
||||
/* memsetting pubkeys doesn't work */
|
||||
static void set_pubkey(struct pubkey *key)
|
||||
{
|
||||
u8 der[PUBKEY_DER_LEN];
|
||||
memset(der, 2, sizeof(der));
|
||||
assert(pubkey_from_der(secp256k1_ctx, der, sizeof(der), key));
|
||||
}
|
||||
|
||||
/* Size up to field. */
|
||||
#define upto_field(p, field) \
|
||||
((char *)&(p)->field - (char *)(p))
|
||||
|
||||
/* Size including field. */
|
||||
#define with_field(p, field) \
|
||||
(upto_field((p), field) + sizeof((p)->field))
|
||||
|
||||
/* Equal upto this field */
|
||||
#define eq_upto(p1, p2, field) \
|
||||
(memcmp((p1), (p2), upto_field(p1, field)) == 0)
|
||||
|
||||
/* Equal upto and including this field */
|
||||
#define eq_with(p1, p2, field) \
|
||||
(memcmp((p1), (p2), with_field(p1, field)) == 0)
|
||||
|
||||
/* Equal from fields first to last inclusive. */
|
||||
#define eq_between(p1, p2, first, last) \
|
||||
(memcmp((char *)(p1) + upto_field((p1), first), \
|
||||
(char *)(p2) + upto_field((p1), first), \
|
||||
with_field(p1, last) - upto_field(p1, first)) == 0)
|
||||
|
||||
/* Equal in one field. */
|
||||
#define eq_field(p1, p2, field) \
|
||||
(memcmp((char *)(p1) + upto_field((p1), field), \
|
||||
(char *)(p2) + upto_field((p1), field), \
|
||||
sizeof((p1)->field)) == 0)
|
||||
|
||||
#define eq_var(p1, p2, lenfield, field) \
|
||||
(memcmp((p1)->field, (p2)->field, (p1)->lenfield * sizeof(*(p1)->field)) == 0)
|
||||
|
||||
static inline bool eq_skip_(const void *p1, const void *p2,
|
||||
size_t off, size_t skip, size_t total)
|
||||
{
|
||||
if (memcmp(p1, p2, off) != 0)
|
||||
return false;
|
||||
p1 = (char *)p1 + off + skip;
|
||||
p2 = (char *)p2 + off + skip;
|
||||
return memcmp(p1, p2, total - (off + skip)) == 0;
|
||||
}
|
||||
|
||||
static bool channel_announcement_eq(const struct msg_channel_announcement *a,
|
||||
const struct msg_channel_announcement *b)
|
||||
{
|
||||
return structeq(a, b);
|
||||
}
|
||||
|
||||
static bool funding_locked_eq(const struct msg_funding_locked *a,
|
||||
const struct msg_funding_locked *b)
|
||||
{
|
||||
return structeq(a, b);
|
||||
}
|
||||
|
||||
static bool update_fail_htlc_eq(const struct msg_update_fail_htlc *a,
|
||||
const struct msg_update_fail_htlc *b)
|
||||
{
|
||||
return eq_with(a, b, reason);
|
||||
}
|
||||
|
||||
static bool commit_sig_eq(const struct msg_commit_sig *a,
|
||||
const struct msg_commit_sig *b)
|
||||
{
|
||||
return eq_with(a, b, num_htlcs)
|
||||
&& eq_var(a, b, num_htlcs, htlc_signature);
|
||||
}
|
||||
|
||||
static bool funding_signed_eq(const struct msg_funding_signed *a,
|
||||
const struct msg_funding_signed *b)
|
||||
{
|
||||
return structeq(a, b);
|
||||
}
|
||||
|
||||
static bool closing_signed_eq(const struct msg_closing_signed *a,
|
||||
const struct msg_closing_signed *b)
|
||||
{
|
||||
return structeq(a, b);
|
||||
}
|
||||
|
||||
static bool update_fulfill_htlc_eq(const struct msg_update_fulfill_htlc *a,
|
||||
const struct msg_update_fulfill_htlc *b)
|
||||
{
|
||||
return structeq(a, b);
|
||||
}
|
||||
|
||||
static bool error_eq(const struct msg_error *a,
|
||||
const struct msg_error *b)
|
||||
{
|
||||
return eq_with(a, b, len)
|
||||
&& eq_var(a, b, len, data);
|
||||
}
|
||||
|
||||
static bool init_eq(const struct msg_init *a,
|
||||
const struct msg_init *b)
|
||||
{
|
||||
return eq_field(a, b, gflen)
|
||||
&& eq_var(a, b, gflen, globalfeatures)
|
||||
&& eq_field(a, b, lflen)
|
||||
&& eq_var(a, b, lflen, localfeatures);
|
||||
}
|
||||
|
||||
static bool update_fee_eq(const struct msg_update_fee *a,
|
||||
const struct msg_update_fee *b)
|
||||
{
|
||||
return structeq(a, b);
|
||||
}
|
||||
|
||||
static bool shutdown_eq(const struct msg_shutdown *a,
|
||||
const struct msg_shutdown *b)
|
||||
{
|
||||
return eq_with(a, b, len)
|
||||
&& eq_var(a, b, len, scriptpubkey);
|
||||
}
|
||||
|
||||
static bool funding_created_eq(const struct msg_funding_created *a,
|
||||
const struct msg_funding_created *b)
|
||||
{
|
||||
return eq_with(a, b, output_index)
|
||||
&& eq_field(a, b, signature);
|
||||
}
|
||||
|
||||
static bool revoke_and_ack_eq(const struct msg_revoke_and_ack *a,
|
||||
const struct msg_revoke_and_ack *b)
|
||||
{
|
||||
return eq_with(a, b, padding)
|
||||
&& eq_field(a, b, num_htlc_timeouts)
|
||||
&& eq_var(a, b, num_htlc_timeouts, htlc_timeout_signature);
|
||||
}
|
||||
|
||||
static bool open_channel_eq(const struct msg_open_channel *a,
|
||||
const struct msg_open_channel *b)
|
||||
{
|
||||
return eq_with(a, b, max_accepted_htlcs)
|
||||
&& eq_between(a, b, funding_pubkey, first_per_commitment_point);
|
||||
}
|
||||
|
||||
static bool channel_update_eq(const struct msg_channel_update *a,
|
||||
const struct msg_channel_update *b)
|
||||
{
|
||||
return structeq(a, b);
|
||||
}
|
||||
|
||||
static bool accept_channel_eq(const struct msg_accept_channel *a,
|
||||
const struct msg_accept_channel *b)
|
||||
{
|
||||
return eq_with(a, b, max_accepted_htlcs)
|
||||
&& eq_between(a, b, funding_pubkey, first_per_commitment_point);
|
||||
}
|
||||
|
||||
static bool update_add_htlc_eq(const struct msg_update_add_htlc *a,
|
||||
const struct msg_update_add_htlc *b)
|
||||
{
|
||||
return eq_with(a, b, onion_routing_packet);
|
||||
}
|
||||
|
||||
static bool node_announcement_eq(const struct msg_node_announcement *a,
|
||||
const struct msg_node_announcement *b)
|
||||
{
|
||||
return eq_with(a, b, port)
|
||||
&& eq_between(a, b, node_id, pad)
|
||||
&& eq_field(a, b, alias);
|
||||
}
|
||||
|
||||
/* Try flipping each bit, try running short. */
|
||||
#define test_corruption(a, b, type) \
|
||||
for (i = 0; i < tal_count(msg) * 8; i++) { \
|
||||
len = tal_count(msg); \
|
||||
msg[i / 8] ^= (1 << (i%8)); \
|
||||
b = fromwire_##type(ctx, msg, &len); \
|
||||
assert(!b || !type##_eq(a, b)); \
|
||||
msg[i / 8] ^= (1 << (i%8)); \
|
||||
} \
|
||||
for (i = 0; i < tal_count(msg); i++) { \
|
||||
len = i; \
|
||||
b = fromwire_##type(ctx, msg, &len); \
|
||||
assert(!b); \
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct msg_channel_announcement ca, *ca2;
|
||||
struct msg_funding_locked fl, *fl2;
|
||||
struct msg_update_fail_htlc ufh, *ufh2;
|
||||
struct msg_commit_sig cs, *cs2;
|
||||
struct msg_funding_signed fs, *fs2;
|
||||
struct msg_closing_signed cls, *cls2;
|
||||
struct msg_update_fulfill_htlc uflh, *uflh2;
|
||||
struct msg_error e, *e2;
|
||||
struct msg_init init, *init2;
|
||||
struct msg_update_fee uf, *uf2;
|
||||
struct msg_shutdown shutdown, *shutdown2;
|
||||
struct msg_funding_created fc, *fc2;
|
||||
struct msg_revoke_and_ack raa, *raa2;
|
||||
struct msg_open_channel oc, *oc2;
|
||||
struct msg_channel_update cu, *cu2;
|
||||
struct msg_accept_channel ac, *ac2;
|
||||
struct msg_update_add_htlc uah, *uah2;
|
||||
struct msg_node_announcement na, *na2;
|
||||
void *ctx = tal(NULL, char);
|
||||
size_t i, len;
|
||||
u8 *msg;
|
||||
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
||||
| SECP256K1_CONTEXT_SIGN);
|
||||
|
||||
memset(&ca, 2, sizeof(ca));
|
||||
set_pubkey(&ca.node_id_1);
|
||||
set_pubkey(&ca.node_id_2);
|
||||
set_pubkey(&ca.bitcoin_key_1);
|
||||
set_pubkey(&ca.bitcoin_key_2);
|
||||
|
||||
msg = towire_channel_announcement(ctx, &ca);
|
||||
len = tal_count(msg);
|
||||
ca2 = fromwire_channel_announcement(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(channel_announcement_eq(&ca, ca2));
|
||||
test_corruption(&ca, ca2, channel_announcement);
|
||||
|
||||
memset(&fl, 2, sizeof(fl));
|
||||
set_pubkey(&fl.next_per_commitment_point);
|
||||
|
||||
msg = towire_funding_locked(ctx, &fl);
|
||||
len = tal_count(msg);
|
||||
fl2 = fromwire_funding_locked(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(funding_locked_eq(&fl, fl2));
|
||||
test_corruption(&fl, fl2, funding_locked);
|
||||
|
||||
memset(&ufh, 2, sizeof(ufh));
|
||||
|
||||
msg = towire_update_fail_htlc(ctx, &ufh);
|
||||
len = tal_count(msg);
|
||||
ufh2 = fromwire_update_fail_htlc(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(update_fail_htlc_eq(&ufh, ufh2));
|
||||
test_corruption(&ufh, ufh2, update_fail_htlc);
|
||||
|
||||
memset(&cs, 2, sizeof(cs));
|
||||
cs.num_htlcs = 2;
|
||||
cs.htlc_signature = tal_arr(ctx, struct signature, 2);
|
||||
memset(cs.htlc_signature, 2, sizeof(struct signature)*2);
|
||||
|
||||
msg = towire_commit_sig(ctx, &cs);
|
||||
len = tal_count(msg);
|
||||
cs2 = fromwire_commit_sig(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(commit_sig_eq(&cs, cs2));
|
||||
test_corruption(&cs, cs2, commit_sig);
|
||||
|
||||
memset(&fs, 2, sizeof(fs));
|
||||
|
||||
msg = towire_funding_signed(ctx, &fs);
|
||||
len = tal_count(msg);
|
||||
fs2 = fromwire_funding_signed(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(funding_signed_eq(&fs, fs2));
|
||||
test_corruption(&fs, fs2, funding_signed);
|
||||
|
||||
memset(&cls, 2, sizeof(cls));
|
||||
|
||||
msg = towire_closing_signed(ctx, &cls);
|
||||
len = tal_count(msg);
|
||||
cls2 = fromwire_closing_signed(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(closing_signed_eq(&cls, cls2));
|
||||
test_corruption(&cls, cls2, closing_signed);
|
||||
|
||||
memset(&uflh, 2, sizeof(uflh));
|
||||
|
||||
msg = towire_update_fulfill_htlc(ctx, &uflh);
|
||||
len = tal_count(msg);
|
||||
uflh2 = fromwire_update_fulfill_htlc(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(update_fulfill_htlc_eq(&uflh, uflh2));
|
||||
test_corruption(&uflh, uflh2, update_fulfill_htlc);
|
||||
|
||||
memset(&e, 2, sizeof(e));
|
||||
e.len = 2;
|
||||
e.data = tal_arr(ctx, u8, 2);
|
||||
memset(e.data, 2, 2);
|
||||
|
||||
msg = towire_error(ctx, &e);
|
||||
len = tal_count(msg);
|
||||
e2 = fromwire_error(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(error_eq(&e, e2));
|
||||
test_corruption(&e, e2, error);
|
||||
|
||||
memset(&init, 2, sizeof(init));
|
||||
init.gflen = 2;
|
||||
init.globalfeatures = tal_arr(ctx, u8, 2);
|
||||
memset(init.globalfeatures, 2, 2);
|
||||
init.lflen = 2;
|
||||
init.localfeatures = tal_arr(ctx, u8, 2);
|
||||
memset(init.localfeatures, 2, 2);
|
||||
|
||||
msg = towire_init(ctx, &init);
|
||||
len = tal_count(msg);
|
||||
init2 = fromwire_init(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(init_eq(&init, init2));
|
||||
test_corruption(&init, init2, init);
|
||||
|
||||
memset(&uf, 2, sizeof(uf));
|
||||
|
||||
msg = towire_update_fee(ctx, &uf);
|
||||
len = tal_count(msg);
|
||||
uf2 = fromwire_update_fee(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(update_fee_eq(&uf, uf2));
|
||||
test_corruption(&uf, uf2, update_fee);
|
||||
|
||||
memset(&shutdown, 2, sizeof(shutdown));
|
||||
shutdown.len = 2;
|
||||
shutdown.scriptpubkey = tal_arr(ctx, u8, 2);
|
||||
memset(shutdown.scriptpubkey, 2, 2);
|
||||
|
||||
msg = towire_shutdown(ctx, &shutdown);
|
||||
len = tal_count(msg);
|
||||
shutdown2 = fromwire_shutdown(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(shutdown_eq(&shutdown, shutdown2));
|
||||
test_corruption(&shutdown, shutdown2, shutdown);
|
||||
|
||||
memset(&fc, 2, sizeof(fc));
|
||||
|
||||
msg = towire_funding_created(ctx, &fc);
|
||||
len = tal_count(msg);
|
||||
fc2 = fromwire_funding_created(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(funding_created_eq(&fc, fc2));
|
||||
test_corruption(&fc, fc2, funding_created);
|
||||
|
||||
memset(&raa, 2, sizeof(raa));
|
||||
set_pubkey(&raa.next_per_commitment_point);
|
||||
raa.num_htlc_timeouts = 2;
|
||||
raa.htlc_timeout_signature = tal_arr(ctx, struct signature, 2);
|
||||
memset(raa.htlc_timeout_signature, 2, sizeof(struct signature) * 2);
|
||||
|
||||
msg = towire_revoke_and_ack(ctx, &raa);
|
||||
len = tal_count(msg);
|
||||
raa2 = fromwire_revoke_and_ack(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(revoke_and_ack_eq(&raa, raa2));
|
||||
test_corruption(&raa, raa2, revoke_and_ack);
|
||||
|
||||
memset(&oc, 2, sizeof(oc));
|
||||
set_pubkey(&oc.funding_pubkey);
|
||||
set_pubkey(&oc.revocation_basepoint);
|
||||
set_pubkey(&oc.payment_basepoint);
|
||||
set_pubkey(&oc.delayed_payment_basepoint);
|
||||
set_pubkey(&oc.first_per_commitment_point);
|
||||
|
||||
msg = towire_open_channel(ctx, &oc);
|
||||
len = tal_count(msg);
|
||||
oc2 = fromwire_open_channel(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(open_channel_eq(&oc, oc2));
|
||||
test_corruption(&oc, oc2, open_channel);
|
||||
|
||||
memset(&cu, 2, sizeof(cu));
|
||||
|
||||
msg = towire_channel_update(ctx, &cu);
|
||||
len = tal_count(msg);
|
||||
cu2 = fromwire_channel_update(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(channel_update_eq(&cu, cu2));
|
||||
test_corruption(&cu, cu2, channel_update);
|
||||
|
||||
memset(&ac, 2, sizeof(ac));
|
||||
set_pubkey(&ac.funding_pubkey);
|
||||
set_pubkey(&ac.revocation_basepoint);
|
||||
set_pubkey(&ac.payment_basepoint);
|
||||
set_pubkey(&ac.delayed_payment_basepoint);
|
||||
set_pubkey(&ac.first_per_commitment_point);
|
||||
|
||||
msg = towire_accept_channel(ctx, &ac);
|
||||
len = tal_count(msg);
|
||||
ac2 = fromwire_accept_channel(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(accept_channel_eq(&ac, ac2));
|
||||
test_corruption(&ac, ac2, accept_channel);
|
||||
|
||||
memset(&uah, 2, sizeof(uah));
|
||||
|
||||
msg = towire_update_add_htlc(ctx, &uah);
|
||||
len = tal_count(msg);
|
||||
uah2 = fromwire_update_add_htlc(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(update_add_htlc_eq(&uah, uah2));
|
||||
test_corruption(&uah, uah2, update_add_htlc);
|
||||
|
||||
memset(&na, 2, sizeof(na));
|
||||
set_pubkey(&na.node_id);
|
||||
|
||||
msg = towire_node_announcement(ctx, &na);
|
||||
len = tal_count(msg);
|
||||
na2 = fromwire_node_announcement(ctx, msg, &len);
|
||||
assert(len == 0);
|
||||
assert(node_announcement_eq(&na, na2));
|
||||
test_corruption(&na, na2, node_announcement);
|
||||
|
||||
/* No memory leaks please */
|
||||
secp256k1_context_destroy(secp256k1_ctx);
|
||||
tal_free(ctx);
|
||||
return 0;
|
||||
}
|
265
wire/tools/generate-wire.py
Executable file
265
wire/tools/generate-wire.py
Executable file
@ -0,0 +1,265 @@
|
||||
#! /usr/bin/python3
|
||||
# Read from stdin, spit out C header or body.
|
||||
|
||||
from optparse import OptionParser
|
||||
from collections import namedtuple
|
||||
import fileinput
|
||||
import re
|
||||
|
||||
Enumtype = namedtuple('Enumtype', ['name', 'value'])
|
||||
|
||||
class Field(object):
|
||||
def __init__(self,message,name,size):
|
||||
self.message = message
|
||||
self.name = name.replace('-', '_')
|
||||
(self.typename, self.basesize) = Field._guess_type(message,self.name,size)
|
||||
|
||||
try:
|
||||
if int(size) % self.basesize != 0:
|
||||
raise ValueError('Invalid size {} for {}.{} not a multiple of {}'.format(size,self.message,self.name,self.basesize))
|
||||
self.num_elems = int(int(size) / self.basesize)
|
||||
except ValueError:
|
||||
self.num_elems = 0
|
||||
# If it's a multiplicitive expression, must end in basesize.
|
||||
if '*' in size:
|
||||
tail='*' + str(self.basesize)
|
||||
if not size.endswith(tail):
|
||||
raise ValueError('Invalid size {} for {}.{} not a multiple of {}'.format(size,self.message,self.name,self.basesize))
|
||||
size = size[:-len(tail)]
|
||||
else:
|
||||
if self.basesize != 1:
|
||||
raise ValueError('Invalid size {} for {}.{} not expressed as a multiple of {}'.format(size,self.message,self.name,self.basesize))
|
||||
|
||||
self.lenvar = size.replace('-','_')
|
||||
|
||||
def is_padding(self):
|
||||
return self.name.startswith('pad')
|
||||
|
||||
# Padding is always treated as an array.
|
||||
def is_array(self):
|
||||
return self.num_elems > 1 or self.is_padding()
|
||||
|
||||
def is_variable_size(self):
|
||||
return self.num_elems == 0
|
||||
|
||||
def is_assignable(self):
|
||||
if self.is_array() or self.is_variable_size():
|
||||
return False
|
||||
return self.typename == 'u8' or self.typename == 'u16' or self.typename == 'u32' or self.typename == 'u64'
|
||||
|
||||
# Returns typename and base size
|
||||
@staticmethod
|
||||
def _guess_type(message, fieldname, sizestr):
|
||||
if fieldname.startswith('pad'):
|
||||
return ('pad',1)
|
||||
|
||||
if fieldname.endswith('channel_id'):
|
||||
return ('struct channel_id',8)
|
||||
|
||||
if message == 'node_announcement' and fieldname == 'ipv6':
|
||||
return ('struct ipv6',16)
|
||||
|
||||
if fieldname.endswith('features'):
|
||||
return ('u8',1)
|
||||
|
||||
# We translate signatures and pubkeys.
|
||||
if 'signature' in fieldname:
|
||||
return ('struct signature',64)
|
||||
|
||||
# The remainder should be fixed sizes.
|
||||
if sizestr == '33':
|
||||
return ('struct pubkey',33)
|
||||
if sizestr == '32':
|
||||
return ('struct sha256',32)
|
||||
if sizestr == '8':
|
||||
return ('u64',8)
|
||||
if sizestr == '4':
|
||||
return ('u32',4)
|
||||
if sizestr == '2':
|
||||
return ('u16',2)
|
||||
if sizestr == '1':
|
||||
return ('u8',1)
|
||||
|
||||
# We whitelist specific things here, otherwise we'd treat everything
|
||||
# as a u8 array.
|
||||
if message == 'update_fail_htlc' and fieldname == 'reason':
|
||||
return ('u8', 1)
|
||||
if message == 'update_add_htlc' and fieldname == 'onion_routing_packet':
|
||||
return ('u8', 1)
|
||||
if message == 'node_announcement' and fieldname == 'alias':
|
||||
return ('u8',1)
|
||||
if message == 'error' and fieldname == 'data':
|
||||
return ('u8',1)
|
||||
if message == 'shutdown' and fieldname == 'scriptpubkey':
|
||||
return ('u8',1)
|
||||
if message == 'node_announcement' and fieldname == 'rgb_color':
|
||||
return ('u8',1)
|
||||
|
||||
raise ValueError('Unknown size {} for {}'.format(sizestr,fieldname))
|
||||
|
||||
class Message(object):
|
||||
def __init__(self,name,enum):
|
||||
self.name = name
|
||||
self.enum = enum
|
||||
self.fields = []
|
||||
|
||||
def checkLenField(self,field):
|
||||
for f in self.fields:
|
||||
if f.name == field.lenvar:
|
||||
if f.typename != 'u16':
|
||||
raise ValueError('Field {} has non-u16 length variable {}'
|
||||
.format(field.name, field.lenvar))
|
||||
|
||||
if f.is_array() or f.is_variable_size():
|
||||
raise ValueError('Field {} has non-simple length variable {}'
|
||||
.format(field.name, field.lenvar))
|
||||
return
|
||||
raise ValueError('Field {} unknown length variable {}'
|
||||
.format(field.name, field.lenvar))
|
||||
|
||||
def addField(self,field):
|
||||
# We assume field lengths are 16 bit, to avoid overflow issues and
|
||||
# massive allocations.
|
||||
if field.is_variable_size():
|
||||
self.checkLenField(field)
|
||||
self.fields.append(field)
|
||||
|
||||
def print_structure(self):
|
||||
print('struct msg_{} {{'.format(self.name));
|
||||
|
||||
for f in self.fields:
|
||||
# If size isn't known, it's a pointer.
|
||||
if f.is_array():
|
||||
print('\t{} {}[{}];'.format(f.typename, f.name, f.num_elems))
|
||||
elif f.is_variable_size():
|
||||
print('\t{} *{};'.format(f.typename, f.name))
|
||||
else:
|
||||
print('\t{} {};'.format(f.typename, f.name))
|
||||
|
||||
print('};')
|
||||
|
||||
def print_fromwire(self,is_header):
|
||||
print('struct msg_{} *fromwire_{}(const tal_t *ctx, const void *p, size_t *len)'.format(self.name,self.name), end='')
|
||||
|
||||
if is_header:
|
||||
print(';')
|
||||
return
|
||||
|
||||
print('\n'
|
||||
'{{\n'
|
||||
'\tconst u8 *cursor = p;\n'
|
||||
'\tstruct msg_{} *in = tal(ctx, struct msg_{});\n'
|
||||
''.format(self.name, self.name));
|
||||
|
||||
for f in self.fields:
|
||||
basetype=f.typename
|
||||
if f.typename.startswith('struct '):
|
||||
basetype=f.typename[7:]
|
||||
|
||||
if f.is_array():
|
||||
print('\tfromwire_{}_array(&cursor, len, in->{}, {});'
|
||||
.format(basetype, f.name, f.num_elems))
|
||||
elif f.is_variable_size():
|
||||
print('\tin->{} = tal_arr(in, {}, in->{});'
|
||||
.format(f.name, f.typename, f.lenvar))
|
||||
print('\tfromwire_{}_array(&cursor, len, in->{}, in->{});'
|
||||
.format(basetype, f.name, f.lenvar))
|
||||
elif f.is_assignable():
|
||||
print('\tin->{} = fromwire_{}(&cursor, len);'
|
||||
.format(f.name, basetype))
|
||||
else:
|
||||
print('\tfromwire_{}(&cursor, len, &in->{});'
|
||||
.format(basetype, f.name))
|
||||
|
||||
print('\n'
|
||||
'\tif (!cursor)\n'
|
||||
'\t\treturn tal_free(in);\n'
|
||||
'\treturn in;\n'
|
||||
'}\n')
|
||||
|
||||
def print_towire(self,is_header):
|
||||
print('u8 *towire_{}(const tal_t *ctx, const struct msg_{} *out)'.format(self.name,self.name), end='')
|
||||
|
||||
if is_header:
|
||||
print(';')
|
||||
return
|
||||
|
||||
print('\n'
|
||||
'{\n'
|
||||
'\tu8 *p = tal_arr(ctx, u8, 0);\n'
|
||||
'')
|
||||
|
||||
for f in self.fields:
|
||||
basetype=f.typename
|
||||
if f.typename.startswith('struct '):
|
||||
basetype=f.typename[7:]
|
||||
|
||||
if f.is_array():
|
||||
print('\ttowire_{}_array(&p, out->{}, {});'
|
||||
.format(basetype, f.name, f.num_elems))
|
||||
elif f.is_variable_size():
|
||||
print('\ttowire_{}_array(&p, out->{}, out->{});'
|
||||
.format(basetype, f.name, f.lenvar))
|
||||
elif f.is_assignable():
|
||||
print('\ttowire_{}(&p, out->{});'
|
||||
.format(basetype, f.name))
|
||||
else:
|
||||
print('\ttowire_{}(&p, &out->{});'
|
||||
.format(basetype, f.name))
|
||||
|
||||
print('\n'
|
||||
'\treturn p;\n'
|
||||
'}\n')
|
||||
|
||||
parser = OptionParser()
|
||||
parser.add_option("--header",
|
||||
action="store_true", dest="output_header", default=False,
|
||||
help="Create gen_wire.h")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.output_header:
|
||||
print('#ifndef LIGHTNING_WIRE_GEN_WIRE_H\n'
|
||||
'#define LIGHTNING_WIRE_GEN_WIRE_H\n'
|
||||
'#include <ccan/tal/tal.h>\n'
|
||||
'#include <wire/wire.h>\n'
|
||||
'\n'
|
||||
'typedef u8 pad;\n'
|
||||
'')
|
||||
else:
|
||||
print('#include "gen_wire.h"\n'
|
||||
'')
|
||||
|
||||
# Maps message names to messages
|
||||
messages = { }
|
||||
|
||||
# Read csv lines. Single comma is the message values, more is offset/len.
|
||||
for line in fileinput.input(args):
|
||||
parts = line.rstrip().split(',')
|
||||
|
||||
if len(parts) == 2:
|
||||
# eg commit_sig,132
|
||||
messages[parts[0]] = Message(parts[0],Enumtype("WIRE_" + parts[0].upper(), int(parts[1])))
|
||||
else:
|
||||
# eg commit_sig,0,channel-id,8
|
||||
messages[parts[0]].addField(Field(parts[0], parts[2], parts[3]))
|
||||
|
||||
if options.output_header:
|
||||
# Dump out enum, sorted by value order.
|
||||
print('enum wire_type {')
|
||||
for m in sorted(messages.values(),key=lambda x:x.enum.value):
|
||||
print('\t{} = {},'.format(m.enum.name, m.enum.value))
|
||||
print('};')
|
||||
|
||||
# Dump out structure definitions.
|
||||
for m in messages.values():
|
||||
m.print_structure()
|
||||
|
||||
for m in messages.values():
|
||||
m.print_fromwire(options.output_header)
|
||||
|
||||
for m in messages.values():
|
||||
m.print_towire(options.output_header)
|
||||
|
||||
if options.output_header:
|
||||
print('#endif /* LIGHTNING_WIRE_GEN_WIRE_H */\n')
|
97
wire/towire.c
Normal file
97
wire/towire.c
Normal file
@ -0,0 +1,97 @@
|
||||
#include "wire.h"
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
|
||||
void towire(u8 **pptr, const void *data, size_t len)
|
||||
{
|
||||
size_t oldsize = tal_count(*pptr);
|
||||
|
||||
tal_resize(pptr, oldsize + len);
|
||||
memcpy(*pptr + oldsize, memcheck(data, len), len);
|
||||
}
|
||||
|
||||
void towire_u8(u8 **pptr, u8 v)
|
||||
{
|
||||
towire(pptr, &v, sizeof(v));
|
||||
}
|
||||
|
||||
void towire_u16(u8 **pptr, u16 v)
|
||||
{
|
||||
be16 l = cpu_to_be16(v);
|
||||
towire(pptr, &l, sizeof(l));
|
||||
}
|
||||
|
||||
void towire_u32(u8 **pptr, u32 v)
|
||||
{
|
||||
be32 l = cpu_to_be32(v);
|
||||
towire(pptr, &l, sizeof(l));
|
||||
}
|
||||
|
||||
void towire_u64(u8 **pptr, u64 v)
|
||||
{
|
||||
be64 l = cpu_to_be64(v);
|
||||
towire(pptr, &l, sizeof(l));
|
||||
}
|
||||
|
||||
void towire_pubkey(u8 **pptr, const struct pubkey *pubkey)
|
||||
{
|
||||
u8 output[PUBKEY_DER_LEN];
|
||||
size_t outputlen = sizeof(output);
|
||||
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_ctx, output, &outputlen,
|
||||
&pubkey->pubkey,
|
||||
SECP256K1_EC_COMPRESSED);
|
||||
towire(pptr, output, outputlen);
|
||||
}
|
||||
|
||||
void towire_signature(u8 **pptr, const struct signature *sig)
|
||||
{
|
||||
u8 compact[64];
|
||||
|
||||
secp256k1_ecdsa_signature_serialize_compact(secp256k1_ctx,
|
||||
compact, &sig->sig);
|
||||
towire(pptr, compact, sizeof(compact));
|
||||
}
|
||||
|
||||
void towire_channel_id(u8 **pptr, const struct channel_id *channel_id)
|
||||
{
|
||||
be32 txnum = cpu_to_be32(channel_id->txnum);
|
||||
u8 outnum = channel_id->outnum;
|
||||
|
||||
towire_u32(pptr, channel_id->blocknum);
|
||||
towire(pptr, (char *)&txnum + 1, 3);
|
||||
towire(pptr, &outnum, 1);
|
||||
}
|
||||
|
||||
void towire_sha256(u8 **pptr, const struct sha256 *sha256)
|
||||
{
|
||||
towire(pptr, sha256, sizeof(*sha256));
|
||||
}
|
||||
|
||||
void towire_ipv6(u8 **pptr, const struct ipv6 *ipv6)
|
||||
{
|
||||
towire(pptr, ipv6, sizeof(*ipv6));
|
||||
}
|
||||
|
||||
void towire_u8_array(u8 **pptr, const u8 *arr, size_t num)
|
||||
{
|
||||
towire(pptr, arr, num);
|
||||
}
|
||||
|
||||
void towire_pad_array(u8 **pptr, const u8 *arr, size_t num)
|
||||
{
|
||||
/* Simply insert zeros. */
|
||||
size_t oldsize = tal_count(*pptr);
|
||||
|
||||
tal_resize(pptr, oldsize + num);
|
||||
memset(*pptr + oldsize, 0, num);
|
||||
}
|
||||
|
||||
void towire_signature_array(u8 **pptr, const struct signature *arr, size_t num)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
towire_signature(pptr, arr+i);
|
||||
}
|
60
wire/wire.h
Normal file
60
wire/wire.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef LIGHTNING_WIRE_WIRE_H
|
||||
#define LIGHTNING_WIRE_WIRE_H
|
||||
#include "config.h"
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <bitcoin/signature.h>
|
||||
#include <ccan/crypto/sha256/sha256.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FIXME: Move this declaration! */
|
||||
extern secp256k1_context *secp256k1_ctx;
|
||||
|
||||
struct pubkey;
|
||||
struct sha256;
|
||||
struct channel_id {
|
||||
u32 blocknum;
|
||||
u32 txnum : 24;
|
||||
u8 outnum : 8;
|
||||
};
|
||||
struct ipv6 {
|
||||
u8 addr[16];
|
||||
};
|
||||
|
||||
void towire(u8 **pptr, const void *data, size_t len);
|
||||
void towire_pubkey(u8 **pptr, const struct pubkey *pubkey);
|
||||
void towire_signature(u8 **pptr, const struct signature *signature);
|
||||
void towire_channel_id(u8 **pptr, const struct channel_id *channel_id);
|
||||
void towire_sha256(u8 **pptr, const struct sha256 *sha256);
|
||||
void towire_ipv6(u8 **pptr, const struct ipv6 *ipv6);
|
||||
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_u8_array(u8 **pptr, const u8 *arr, size_t num);
|
||||
void towire_pad_array(u8 **pptr, const u8 *arr, size_t num);
|
||||
void towire_signature_array(u8 **pptr, const struct signature *arr, size_t num);
|
||||
|
||||
|
||||
const u8 *fromwire(const u8 **cursor, size_t *max, void *copy, size_t n);
|
||||
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);
|
||||
void fromwire_pubkey(const u8 **cursor, size_t *max, struct pubkey *pubkey);
|
||||
void fromwire_signature(const u8 **cursor, size_t *max,
|
||||
struct signature *signature);
|
||||
void fromwire_channel_id(const u8 **cursor, size_t *max,
|
||||
struct channel_id *channel_id);
|
||||
void fromwire_sha256(const u8 **cursor, size_t *max, struct sha256 *sha256);
|
||||
void fromwire_ipv6(const u8 **cursor, size_t *max, struct ipv6 *ipv6);
|
||||
|
||||
void fromwire_u8_array(const u8 **cursor, size_t *max,
|
||||
u8 *arr, size_t num);
|
||||
void fromwire_pad_array(const u8 **cursor, size_t *max,
|
||||
u8 *arr, size_t num);
|
||||
void fromwire_signature_array(const u8 **cursor, size_t *max,
|
||||
struct signature *arr, size_t num);
|
||||
|
||||
#endif /* LIGHTNING_WIRE_WIRE_H */
|
Loading…
Reference in New Issue
Block a user