Rusty Russell
8 years ago
10 changed files with 1158 additions and 0 deletions
@ -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 |
@ -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); |
||||
|
} |
@ -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 |
@ -0,0 +1 @@ |
|||||
|
run-wire |
@ -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/%) |
||||
|
|
@ -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; |
||||
|
} |
@ -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') |
@ -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); |
||||
|
} |
@ -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