diff --git a/Makefile b/Makefile index c054b05aa..61d364bd7 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,8 @@ BITCOIN_SRC := \ bitcoin/script.c \ bitcoin/shadouble.c \ bitcoin/signature.c \ - bitcoin/tx.c + bitcoin/tx.c \ + bitcoin/varint.c BITCOIN_OBJS := $(BITCOIN_SRC:.c=.o) CORE_SRC := \ @@ -135,7 +136,8 @@ BITCOIN_HEADERS := bitcoin/address.h \ bitcoin/script.h \ bitcoin/shadouble.h \ bitcoin/signature.h \ - bitcoin/tx.h + bitcoin/tx.h \ + bitcoin/varint.h CORE_HEADERS := close_tx.h \ commit_tx.h \ diff --git a/bitcoin/test/run-tx-encode.c b/bitcoin/test/run-tx-encode.c index dea5f735e..f8048b011 100644 --- a/bitcoin/test/run-tx-encode.c +++ b/bitcoin/test/run-tx-encode.c @@ -1,5 +1,6 @@ #include "bitcoin/tx.c" #include "bitcoin/shadouble.c" +#include "bitcoin/varint.c" #include #include diff --git a/bitcoin/tx.c b/bitcoin/tx.c index bace90079..8a1d7e60c 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -13,32 +13,9 @@ static void add_varint(varint_t v, void (*add)(const void *, size_t, void *), void *addp) { - u8 buf[9], *p = buf; + u8 buf[VARINT_MAX_LEN]; - if (v < 0xfd) { - *(p++) = v; - } else if (v <= 0xffff) { - (*p++) = 0xfd; - (*p++) = v; - (*p++) = v >> 8; - } else if (v <= 0xffffffff) { - (*p++) = 0xfe; - (*p++) = v; - (*p++) = v >> 8; - (*p++) = v >> 16; - (*p++) = v >> 24; - } else { - (*p++) = 0xff; - (*p++) = v; - (*p++) = v >> 8; - (*p++) = v >> 16; - (*p++) = v >> 24; - (*p++) = v >> 32; - (*p++) = v >> 40; - (*p++) = v >> 48; - (*p++) = v >> 56; - } - add(buf, p - buf, addp); + add(buf, varint_put(buf, v), addp); } static void add_le32(u32 v, @@ -376,34 +353,15 @@ static const u8 *pull(const u8 **cursor, size_t *max, void *copy, size_t n) static u64 pull_varint(const u8 **cursor, size_t *max) { u64 ret; - const u8 *p; + size_t len; - p = pull(cursor, max, NULL, 1); - if (!p) + len = varint_get(*cursor, *max, &ret); + if (len == 0) { + *cursor = NULL; + *max = 0; return 0; - - if (*p < 0xfd) { - ret = *p; - } else if (*p == 0xfd) { - p = pull(cursor, max, NULL, 2); - if (!p) - return 0; - ret = ((u64)p[1] << 8) + p[0]; - } else if (*p == 0xfe) { - p = pull(cursor, max, NULL, 4); - if (!p) - return 0; - ret = ((u64)p[3] << 24) + ((u64)p[2] << 16) - + ((u64)p[1] << 8) + p[0]; - } else { - p = pull(cursor, max, NULL, 8); - if (!p) - return 0; - ret = ((u64)p[7] << 56) + ((u64)p[6] << 48) - + ((u64)p[5] << 40) + ((u64)p[4] << 32) - + ((u64)p[3] << 24) + ((u64)p[2] << 16) - + ((u64)p[1] << 8) + p[0]; } + pull(cursor, max, NULL, len); return ret; } diff --git a/bitcoin/tx.h b/bitcoin/tx.h index 31f5ae059..b4b75712a 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -3,12 +3,10 @@ #include "config.h" #include "shadouble.h" #include "signature.h" +#include "varint.h" #include #include -/* We unpack varints for our in-memory representation */ -#define varint_t u64 - struct bitcoin_tx { u32 version; varint_t input_count; diff --git a/bitcoin/varint.c b/bitcoin/varint.c new file mode 100644 index 000000000..e041f422e --- /dev/null +++ b/bitcoin/varint.c @@ -0,0 +1,62 @@ +#include "varint.h" + +size_t varint_put(u8 buf[VARINT_MAX_LEN], varint_t v) +{ + u8 *p = buf; + + if (v < 0xfd) { + *(p++) = v; + } else if (v <= 0xffff) { + (*p++) = 0xfd; + (*p++) = v; + (*p++) = v >> 8; + } else if (v <= 0xffffffff) { + (*p++) = 0xfe; + (*p++) = v; + (*p++) = v >> 8; + (*p++) = v >> 16; + (*p++) = v >> 24; + } else { + (*p++) = 0xff; + (*p++) = v; + (*p++) = v >> 8; + (*p++) = v >> 16; + (*p++) = v >> 24; + (*p++) = v >> 32; + (*p++) = v >> 40; + (*p++) = v >> 48; + (*p++) = v >> 56; + } + return p - buf; +} + +size_t varint_get(const u8 *p, size_t max, varint_t *val) +{ + if (max < 1) + return 0; + + switch (*p) { + case 0xfd: + if (max < 3) + return 0; + *val = ((u64)p[1] << 8) + p[0]; + return 3; + case 0xfe: + if (max < 5) + return 0; + *val = ((u64)p[3] << 24) + ((u64)p[2] << 16) + + ((u64)p[1] << 8) + p[0]; + return 5; + case 0xff: + if (max < 9) + return 0; + *val = ((u64)p[7] << 56) + ((u64)p[6] << 48) + + ((u64)p[5] << 40) + ((u64)p[4] << 32) + + ((u64)p[3] << 24) + ((u64)p[2] << 16) + + ((u64)p[1] << 8) + p[0]; + return 9; + default: + *val = *p; + return 1; + } +} diff --git a/bitcoin/varint.h b/bitcoin/varint.h new file mode 100644 index 000000000..e8e99827e --- /dev/null +++ b/bitcoin/varint.h @@ -0,0 +1,17 @@ +#ifndef LIGHTNING_BITCOIN_VARINT_H +#define LIGHTNING_BITCOIN_VARINT_H +#include "config.h" +#include +#include + +/* We unpack varints for our in-memory representation */ +#define varint_t u64 + +#define VARINT_MAX_LEN 9 + +/* Returns bytes used (up to 9) */ +size_t varint_put(u8 buf[VARINT_MAX_LEN], varint_t v); + +/* Returns bytes used: 0 if max_len too small. */ +size_t varint_get(const u8 *p, size_t max_len, varint_t *val); +#endif /* LIGHTNING_BITCOIN_VARINT_H */