Browse Source

common/amount: new types struct amount_msat and struct amount_sat.

They're generally used pass-by-copy (unusual for C structs, but
convenient they're basically u64) and all possibly problematic
operations return WARN_UNUSED_RESULT bool to make you handle the
over/underflow cases.

The new #include in json.h means we bolt11.c sees the amount.h definition
of MSAT_PER_BTC, so delete its local version.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
confirmed-only
Rusty Russell 6 years ago
parent
commit
7fad7bccba
  1. 3
      channeld/Makefile
  2. 1
      channeld/test/run-commit_tx.c
  3. 4
      channeld/test/run-full_channel.c
  4. 1
      cli/test/run-large-input.c
  5. 1
      closingd/Makefile
  6. 1
      common/Makefile
  7. 426
      common/amount.c
  8. 142
      common/amount.h
  9. 3
      common/bolt11.c
  10. 152
      common/test/run-amount.c
  11. 2
      common/type_to_string.h
  12. 1
      connectd/Makefile
  13. 1
      devtools/Makefile
  14. 1
      gossipd/Makefile
  15. 1
      hsmd/Makefile
  16. 1
      lightningd/test/run-find_my_abspath.c
  17. 1
      onchaind/Makefile
  18. 1
      openingd/Makefile
  19. 2
      tools/generate-wire.py
  20. 1
      wallet/test/run-db.c
  21. 1
      wallet/test/run-wallet.c
  22. 18
      wire/fromwire.c
  23. 4
      wire/test/run-peer-wire.c
  24. 11
      wire/towire.c
  25. 5
      wire/wire.h

3
channeld/Makefile

@ -33,8 +33,9 @@ ALL_GEN_HEADERS += $(LIGHTNINGD_CHANNEL_HEADERS_GEN)
# Common source we use.
CHANNELD_COMMON_OBJS := \
common/amount.o \
common/base32.o \
common/bip32.o \
common/bip32.o \
common/channel_config.o \
common/crypto_state.o \
common/crypto_sync.o \

1
channeld/test/run-commit_tx.c

@ -12,6 +12,7 @@ static bool print_superverbose;
#include <ccan/array_size/array_size.h>
#include <ccan/err/err.h>
#include <ccan/str/hex/hex.h>
#include <common/amount.h>
#include <common/key_derive.h>
#include <common/status.h>

4
channeld/test/run-full_channel.c

@ -7,11 +7,15 @@
#include <bitcoin/pubkey.h>
#include <ccan/err/err.h>
#include <ccan/str/hex/hex.h>
#include <common/amount.h>
#include <common/sphinx.h>
#include <common/type_to_string.h>
#include <stdio.h>
#include <wally_core.h>
/* AUTOGENERATED MOCKS START */
/* AUTOGENERATED MOCKS END */
void status_fmt(enum log_level level UNUSED, const char *fmt, ...)
{
va_list ap;

1
cli/test/run-large-input.c

@ -1,4 +1,5 @@
#include <assert.h>
#include <common/amount.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/stat.h>

1
closingd/Makefile

@ -42,6 +42,7 @@ $(LIGHTNINGD_CLOSING_OBJS): $(LIGHTNINGD_HEADERS)
# Common source we use.
CLOSINGD_COMMON_OBJS := \
common/amount.o \
common/base32.o \
common/bip32.o \
common/close_tx.o \

1
common/Makefile

@ -1,4 +1,5 @@
COMMON_SRC_NOGEN := \
common/amount.c \
common/base32.c \
common/bech32.c \
common/bech32_util.c \

426
common/amount.c

@ -0,0 +1,426 @@
#include <assert.h>
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/overflows.h>
#include <common/type_to_string.h>
#include <inttypes.h>
bool amount_sat_to_msat(struct amount_msat *msat,
struct amount_sat sat)
{
if (mul_overflows_u64(sat.satoshis, MSAT_PER_SAT))
return false;
msat->millisatoshis = sat.satoshis * MSAT_PER_SAT;
return true;
}
/* You can always truncate millisatoshis->satoshis. */
struct amount_sat amount_msat_to_sat_round_down(struct amount_msat msat)
{
struct amount_sat sat;
sat.satoshis = msat.millisatoshis / MSAT_PER_SAT;
return sat;
}
/* You may not be able to do this. */
bool amount_msat_to_sat_exact(struct amount_sat *sat,
const struct amount_msat *msat)
{
if (msat->millisatoshis % MSAT_PER_SAT != 0)
return false;
sat->satoshis = msat->millisatoshis / MSAT_PER_SAT;
return true;
}
/* Different formatting by amounts: btc, sat and msat */
const char *fmt_amount_msat_btc(const tal_t *ctx,
const struct amount_msat *msat,
bool append_unit)
{
return tal_fmt(ctx, "%"PRIu64".%011"PRIu64"%s",
msat->millisatoshis / MSAT_PER_BTC,
msat->millisatoshis % MSAT_PER_BTC,
append_unit ? "btc" : "");
}
const char *fmt_amount_msat(const tal_t *ctx, const struct amount_msat *msat)
{
return tal_fmt(ctx, "%"PRIu64"msat", msat->millisatoshis);
}
REGISTER_TYPE_TO_STRING(amount_msat, fmt_amount_msat);
const char *fmt_amount_sat_btc(const tal_t *ctx,
const struct amount_sat *sat,
bool append_unit)
{
return tal_fmt(ctx, "%"PRIu64".%08"PRIu64"%s",
sat->satoshis / SAT_PER_BTC,
sat->satoshis % SAT_PER_BTC,
append_unit ? "btc" : "");
}
const char *fmt_amount_sat(const tal_t *ctx, const struct amount_sat *sat)
{
return tal_fmt(ctx, "%"PRIu64"sat", sat->satoshis);
}
REGISTER_TYPE_TO_STRING(amount_sat, fmt_amount_sat);
static bool breakup(const char *str, size_t slen,
/* Length of first numeric part. */
size_t *whole_number_len,
/* Pointer to post-decimal part, or NULL */
const char **post_decimal_ptr,
size_t *post_decimal_len,
/* Pointer to suffix, or NULL */
const char **suffix_ptr,
size_t *suffix_len)
{
size_t i;
*whole_number_len = 0;
*post_decimal_len = 0;
*post_decimal_ptr = NULL;
*suffix_ptr = NULL;
*suffix_len = 0;
for (i = 0;; i++) {
if (i >= slen)
return i != 0;
if (cisdigit(str[i]))
(*whole_number_len)++;
else
break;
}
if (str[i] == '.') {
i++;
*post_decimal_ptr = str + i;
for (;; i++) {
/* True if > 0 decimals. */
if (i >= slen)
return str + i != *post_decimal_ptr;
if (cisdigit(str[i]))
(*post_decimal_len)++;
else
break;
}
}
*suffix_ptr = str + i;
*suffix_len = slen - i;
return true;
}
static bool from_number(u64 *res, const char *s, size_t len, u64 multipler)
{
if (len == 0)
return false;
*res = 0;
for (size_t i = 0; i < len; i++) {
if (mul_overflows_u64(*res, 10))
return false;
*res *= 10;
assert(cisdigit(s[i]));
if (add_overflows_u64(*res, s[i] - '0'))
return false;
*res += s[i] - '0';
}
if (mul_overflows_u64(*res, multipler))
return false;
*res *= multipler;
return true;
}
static bool from_numbers(u64 *res,
const char *s1, size_t len1, u64 multipler1,
const char *s2, size_t len2, u64 multipler2)
{
u64 p1, p2;
if (!from_number(&p1, s1, len1, multipler1)
|| !from_number(&p2, s2, len2, multipler2))
return false;
if (add_overflows_u64(p1, p2))
return false;
*res = p1 + p2;
return true;
}
/* Valid strings:
* [0-9]+ => millisatoshi.
* [0-9]+msat => millisatoshi.
* [0-9]+sat => *1000 -> millisatopshi.
* [0-9]+.[0-9]{8}btc => *1000 -> millisatoshi.
* [0-9]+.[0-9]{11}btc => millisatoshi.
*/
bool parse_amount_msat(struct amount_msat *msat, const char *s, size_t slen)
{
size_t whole_number_len, post_decimal_len, suffix_len;
const char *post_decimal_ptr, *suffix_ptr;
if (!breakup(s, slen, &whole_number_len,
&post_decimal_ptr, &post_decimal_len,
&suffix_ptr, &suffix_len))
return false;
if (!post_decimal_ptr && !suffix_ptr)
return from_number(&msat->millisatoshis, s, whole_number_len, 1);
if (!post_decimal_ptr && memeqstr(suffix_ptr, suffix_len, "msat"))
return from_number(&msat->millisatoshis, s, whole_number_len, 1);
if (!post_decimal_ptr && memeqstr(suffix_ptr, suffix_len, "sat"))
return from_number(&msat->millisatoshis, s, whole_number_len,
MSAT_PER_SAT);
if (post_decimal_ptr && post_decimal_len == 8
&& memeqstr(suffix_ptr, suffix_len, "btc"))
return from_numbers(&msat->millisatoshis,
s, whole_number_len,
MSAT_PER_BTC,
post_decimal_ptr, post_decimal_len,
MSAT_PER_SAT);
if (post_decimal_ptr && post_decimal_len == 11
&& memeqstr(suffix_ptr, suffix_len, "btc"))
return from_numbers(&msat->millisatoshis,
s, whole_number_len,
MSAT_PER_BTC,
post_decimal_ptr, post_decimal_len, 1);
return false;
}
/* Valid strings:
* [0-9]+ => satoshi.
* [0-9]+sat => satoshi.
* [0-9]+000msat => satoshi.
* [0-9]+.[0-9]{8}btc => satoshi.
*/
bool parse_amount_sat(struct amount_sat *sat, const char *s, size_t slen)
{
size_t whole_number_len, post_decimal_len, suffix_len;
const char *post_decimal_ptr, *suffix_ptr;
if (!breakup(s, slen, &whole_number_len,
&post_decimal_ptr, &post_decimal_len,
&suffix_ptr, &suffix_len))
return false;
if (!post_decimal_ptr && !suffix_ptr)
return from_number(&sat->satoshis, s, whole_number_len, 1);
if (!post_decimal_ptr && memeqstr(suffix_ptr, suffix_len, "sat"))
return from_number(&sat->satoshis, s, whole_number_len, 1);
if (!post_decimal_ptr && memeqstr(suffix_ptr, suffix_len, "msat")) {
if (!memends(s, whole_number_len, "000", strlen("000")))
return false;
return from_number(&sat->satoshis, s, whole_number_len - 3, 1);
}
if (post_decimal_ptr && post_decimal_len == 8
&& memeqstr(suffix_ptr, suffix_len, "btc"))
return from_numbers(&sat->satoshis,
s, whole_number_len,
SAT_PER_BTC,
post_decimal_ptr, post_decimal_len,
1);
return false;
}
WARN_UNUSED_RESULT bool amount_msat_add(struct amount_msat *val,
struct amount_msat a,
struct amount_msat b)
{
if (add_overflows_u64(a.millisatoshis, b.millisatoshis))
return false;
val->millisatoshis = a.millisatoshis + b.millisatoshis;
return true;
}
WARN_UNUSED_RESULT bool amount_msat_sub(struct amount_msat *val,
struct amount_msat a,
struct amount_msat b)
{
if (a.millisatoshis < b.millisatoshis)
return false;
val->millisatoshis = a.millisatoshis - b.millisatoshis;
return true;
}
WARN_UNUSED_RESULT bool amount_sat_add(struct amount_sat *val,
struct amount_sat a,
struct amount_sat b)
{
if (add_overflows_u64(a.satoshis, b.satoshis))
return false;
val->satoshis = a.satoshis + b.satoshis;
return true;
}
WARN_UNUSED_RESULT bool amount_sat_sub(struct amount_sat *val,
struct amount_sat a,
struct amount_sat b)
{
if (a.satoshis < b.satoshis)
return false;
val->satoshis = a.satoshis - b.satoshis;
return true;
}
WARN_UNUSED_RESULT bool amount_msat_sub_sat(struct amount_msat *val,
struct amount_msat a,
struct amount_sat b)
{
struct amount_msat msatb;
if (!amount_sat_to_msat(&msatb, b))
return false;
return amount_msat_sub(val, a, msatb);
}
WARN_UNUSED_RESULT bool amount_sat_sub_msat(struct amount_msat *val,
struct amount_sat a,
struct amount_msat b)
{
struct amount_msat msata;
if (!amount_sat_to_msat(&msata, a))
return false;
return amount_msat_sub(val, msata, b);
}
bool amount_sat_eq(struct amount_sat a, struct amount_sat b)
{
return a.satoshis == b.satoshis;
}
bool amount_msat_eq(struct amount_msat a, struct amount_msat b)
{
return a.millisatoshis == b.millisatoshis;
}
bool amount_sat_greater(struct amount_sat a, struct amount_sat b)
{
return a.satoshis > b.satoshis;
}
bool amount_msat_greater(struct amount_msat a, struct amount_msat b)
{
return a.millisatoshis > b.millisatoshis;
}
bool amount_sat_greater_eq(struct amount_sat a, struct amount_sat b)
{
return a.satoshis >= b.satoshis;
}
bool amount_msat_greater_eq(struct amount_msat a, struct amount_msat b)
{
return a.millisatoshis >= b.millisatoshis;
}
bool amount_sat_less(struct amount_sat a, struct amount_sat b)
{
return a.satoshis < b.satoshis;
}
bool amount_msat_less(struct amount_msat a, struct amount_msat b)
{
return a.millisatoshis < b.millisatoshis;
}
bool amount_sat_less_eq(struct amount_sat a, struct amount_sat b)
{
return a.satoshis <= b.satoshis;
}
bool amount_msat_less_eq(struct amount_msat a, struct amount_msat b)
{
return a.millisatoshis <= b.millisatoshis;
}
bool amount_msat_greater_sat(struct amount_msat msat, struct amount_sat sat)
{
struct amount_msat msat_from_sat;
if (!amount_sat_to_msat(&msat_from_sat, sat))
return false;
return msat.millisatoshis > msat_from_sat.millisatoshis;
}
bool amount_msat_greater_eq_sat(struct amount_msat msat, struct amount_sat sat)
{
struct amount_msat msat_from_sat;
if (!amount_sat_to_msat(&msat_from_sat, sat))
return false;
return msat.millisatoshis >= msat_from_sat.millisatoshis;
}
bool amount_msat_less_sat(struct amount_msat msat, struct amount_sat sat)
{
struct amount_msat msat_from_sat;
if (!amount_sat_to_msat(&msat_from_sat, sat))
return false;
return msat.millisatoshis < msat_from_sat.millisatoshis;
}
bool amount_msat_less_eq_sat(struct amount_msat msat, struct amount_sat sat)
{
struct amount_msat msat_from_sat;
if (!amount_sat_to_msat(&msat_from_sat, sat))
return false;
return msat.millisatoshis <= msat_from_sat.millisatoshis;
}
bool amount_msat_fee(struct amount_msat *fee,
struct amount_msat amt,
u32 fee_base_msat,
u32 fee_proportional_millionths)
{
struct amount_msat fee_base, fee_prop;
/* BOLT #7:
*
* - SHOULD accept HTLCs that pay a fee equal to or greater than:
* - fee_base_msat + ( amount_to_forward * fee_proportional_millionths / 1000000 )
*/
fee_base.millisatoshis = fee_base_msat;
if (mul_overflows_u64(amt.millisatoshis, fee_proportional_millionths))
return false;
fee_prop.millisatoshis = amt.millisatoshis * fee_proportional_millionths
/ 1000000;
return amount_msat_add(fee, fee_base, fee_prop);
}
bool amount_msat_add_fee(struct amount_msat *amt,
u32 fee_base_msat,
u32 fee_proportional_millionths)
{
struct amount_msat fee;
if (!amount_msat_fee(&fee, *amt,
fee_base_msat, fee_proportional_millionths))
return false;
return amount_msat_add(amt, *amt, fee);
}
struct amount_sat amount_tx_fee(u32 fee_per_kw, size_t weight)
{
struct amount_sat fee;
/* If this overflows, weight must be > 2^32, which is not a real tx */
assert(!mul_overflows_u64(fee_per_kw, weight));
fee.satoshis = fee_per_kw * weight / 1000;
return fee;
}

142
common/amount.h

@ -0,0 +1,142 @@
#ifndef LIGHTNING_COMMON_AMOUNT_H
#define LIGHTNING_COMMON_AMOUNT_H
#include "config.h"
#include <ccan/build_assert/build_assert.h>
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
#include <stdbool.h>
#define MSAT_PER_SAT ((u64)1000)
#define SAT_PER_BTC ((u64)100000000)
#define MSAT_PER_BTC (MSAT_PER_SAT * SAT_PER_BTC)
/* Use these to wrap amounts, for typesafety. Please use ops where possible,
* rather than accessing the members directly. */
struct amount_sat {
/* Amount in satoshis. */
u64 satoshis;
};
struct amount_msat {
/* Amount in millisatoshis. */
u64 millisatoshis;
};
/* For constants only: others must be built from primitives! */
#if HAVE_BUILTIN_CONSTANT_P
#define AMOUNT_MUST_BE_CONST(c) BUILD_ASSERT_OR_ZERO(IS_COMPILE_CONSTANT(c))
#else
#define AMOUNT_MUST_BE_CONST(c) 0
#endif
#define AMOUNT_MSAT(constant) \
((struct amount_msat){(constant) + AMOUNT_MUST_BE_CONST(constant)})
#define AMOUNT_SAT(constant) \
((struct amount_sat){(constant) + AMOUNT_MUST_BE_CONST(constant)})
/* You may not always be able to convert satoshis->millisatoshis. */
WARN_UNUSED_RESULT bool amount_sat_to_msat(struct amount_msat *msat,
struct amount_sat sat);
/* This may require rounding. */
WARN_UNUSED_RESULT bool amount_msat_to_sat_exact(struct amount_sat *,
const struct amount_msat *);
/* You can always truncate millisatoshis->satoshis. */
struct amount_sat amount_msat_to_sat_round_down(struct amount_msat msat);
/* Simple operations: val = a + b, val = a - b. */
WARN_UNUSED_RESULT bool amount_msat_add(struct amount_msat *val,
struct amount_msat a,
struct amount_msat b);
WARN_UNUSED_RESULT bool amount_msat_sub(struct amount_msat *val,
struct amount_msat a,
struct amount_msat b);
WARN_UNUSED_RESULT bool amount_sat_add(struct amount_sat *val,
struct amount_sat a,
struct amount_sat b);
WARN_UNUSED_RESULT bool amount_sat_sub(struct amount_sat *val,
struct amount_sat a,
struct amount_sat b);
WARN_UNUSED_RESULT bool amount_msat_sub_sat(struct amount_msat *val,
struct amount_msat a,
struct amount_sat b);
WARN_UNUSED_RESULT bool amount_sat_sub_msat(struct amount_msat *val,
struct amount_sat a,
struct amount_msat b);
/* Is a == b? */
bool amount_sat_eq(struct amount_sat a, struct amount_sat b);
bool amount_msat_eq(struct amount_msat a, struct amount_msat b);
/* Is a > b? */
bool amount_sat_greater(struct amount_sat a, struct amount_sat b);
bool amount_msat_greater(struct amount_msat a, struct amount_msat b);
/* Is a >= b */
bool amount_sat_greater_eq(struct amount_sat a, struct amount_sat b);
bool amount_msat_greater_eq(struct amount_msat a, struct amount_msat b);
/* Is a < b? */
bool amount_sat_less(struct amount_sat a, struct amount_sat b);
bool amount_msat_less(struct amount_msat a, struct amount_msat b);
/* Is a <= b? */
bool amount_sat_less_eq(struct amount_sat a, struct amount_sat b);
bool amount_msat_less_eq(struct amount_msat a, struct amount_msat b);
/* Is msat > sat? */
bool amount_msat_greater_sat(struct amount_msat msat, struct amount_sat sat);
/* Is msat >= sat? */
bool amount_msat_greater_eq_sat(struct amount_msat msat, struct amount_sat sat);
/* Is msat < sat? */
bool amount_msat_less_sat(struct amount_msat msat, struct amount_sat sat);
/* Is msat <= sat? */
bool amount_msat_less_eq_sat(struct amount_msat msat, struct amount_sat sat);
/* Common operation: what is the HTLC fee for given feerate? Can overflow! */
WARN_UNUSED_RESULT bool amount_msat_fee(struct amount_msat *fee,
struct amount_msat amt,
u32 fee_base_msat,
u32 fee_proportional_millionths);
/* Same, but add into amt. */
WARN_UNUSED_RESULT bool amount_msat_add_fee(struct amount_msat *amt,
u32 fee_base_msat,
u32 fee_proportional_millionths);
/* What is the fee for this tx weight? */
struct amount_sat amount_tx_fee(u32 fee_per_kw, size_t weight);
/* Different formatting by amounts: btc, sat and msat */
const char *fmt_amount_msat_btc(const tal_t *ctx,
const struct amount_msat *msat,
bool append_unit);
/* 1234msat */
const char *fmt_amount_msat(const tal_t *ctx, const struct amount_msat *msat);
const char *fmt_amount_sat_btc(const tal_t *ctx,
const struct amount_sat *sat,
bool append_unit);
/* 1234sat */
const char *fmt_amount_sat(const tal_t *ctx, const struct amount_sat *sat);
/* Valid strings:
* [0-9]+ => millisatoshi.
* [0-9]+msat => millisatoshi.
* [0-9]+sat => *1000 -> millisatopshi.
* [0-9]+.[0-9]{8}btc => *1000 -> millisatoshi.
* [0-9]+.[0-9]{11}btc => millisatoshi.
*/
bool parse_amount_msat(struct amount_msat *msat, const char *s, size_t slen);
/* Valid strings:
* [0-9]+ => satoshi.
* [0-9]+sat => satoshi.
* [0-9]+000msat => satoshi.
* [0-9]+.[0-9]{8}btc => satoshi.
*/
bool parse_amount_sat(struct amount_sat *sat, const char *s, size_t slen);
#endif /* LIGHTNING_COMMON_AMOUNT_H */

3
common/bolt11.c

@ -22,9 +22,6 @@
#include <wire/wire.h>
#include <wire/wire_sync.h>
/* 1000 * 10^8 millisatoshi == 1 bitcoin */
#define MSAT_PER_BTC 100000000000ULL
struct multiplier {
const char letter;
/* We can't represent p postfix to msat, so we multiply this by 10 */

152
common/test/run-amount.c

@ -0,0 +1,152 @@
#include "../amount.c"
#include <common/utils.h>
#define FAIL_MSAT(msatp, str) \
assert(!parse_amount_msat((msatp), (str), strlen(str)))
#define PASS_MSAT(msatp, str, val) \
do { \
assert(parse_amount_msat((msatp), (str), strlen(str))); \
assert((msatp)->millisatoshis == val); \
} while (0)
#define FAIL_SAT(satp, str) \
assert(!parse_amount_sat((satp), (str), strlen(str)))
#define PASS_SAT(satp, str, val) \
do { \
assert(parse_amount_sat((satp), (str), strlen(str))); \
assert((satp)->satoshis == val); \
} while (0)
int main(void)
{
struct amount_msat msat;
struct amount_sat sat;
setup_locale();
setup_tmpctx();
/* Grossly malformed */
FAIL_MSAT(&msat, "x");
FAIL_MSAT(&msat, "x100");
PASS_MSAT(&msat, "0", 0);
PASS_MSAT(&msat, "1", 1);
PASS_MSAT(&msat, "2100000000000000000", 2100000000000000000ULL);
FAIL_MSAT(&msat, "0.0");
FAIL_MSAT(&msat, "0.00000000");
FAIL_MSAT(&msat, "0.00000000000");
FAIL_MSAT(&msat, "0.00000000msat");
FAIL_MSAT(&msat, "0.00000000000msat");
PASS_MSAT(&msat, "0msat", 0);
PASS_MSAT(&msat, "1msat", 1);
PASS_MSAT(&msat, "2100000000000000000msat", 2100000000000000000ULL);
PASS_MSAT(&msat, "0sat", 0);
PASS_MSAT(&msat, "1sat", 1000);
PASS_MSAT(&msat, "2100000000000000sat", 2100000000000000000ULL);
PASS_MSAT(&msat, "0.00000000btc", 0);
PASS_MSAT(&msat, "0.00000000000btc", 0);
PASS_MSAT(&msat, "0.00000001btc", 1000);
PASS_MSAT(&msat, "0.00000000001btc", 1);
PASS_MSAT(&msat, "1.23456789btc", 123456789000);
PASS_MSAT(&msat, "1.23456789012btc", 123456789012);
FAIL_MSAT(&msat, "1btc");
FAIL_MSAT(&msat, "1.0000000btc");
FAIL_MSAT(&msat, "1.000000000btc");
/* Overflowingly big. */
FAIL_MSAT(&msat, "21000000000000000000000000.00000000btc");
/* Grossly malformed */
FAIL_SAT(&sat, "x");
FAIL_SAT(&sat, "x100");
PASS_SAT(&sat, "0", 0);
PASS_SAT(&sat, "1", 1);
PASS_SAT(&sat, "2100000000000000", 2100000000000000ULL);
FAIL_SAT(&sat, "0.0");
FAIL_SAT(&sat, "0.00000000");
FAIL_SAT(&sat, "0.00000000000");
FAIL_SAT(&sat, "0.00000000sat");
FAIL_SAT(&sat, "0.00000000000msat");
PASS_SAT(&sat, "0sat", 0);
PASS_SAT(&sat, "1sat", 1);
PASS_SAT(&sat, "2100000000000000sat", 2100000000000000ULL);
PASS_SAT(&sat, "1000msat", 1);
PASS_SAT(&sat, "1000000msat", 1000);
PASS_SAT(&sat, "2100000000000000000msat", 2100000000000000ULL);
FAIL_SAT(&sat, "0msat");
FAIL_SAT(&sat, "100msat");
FAIL_SAT(&sat, "2000000000000000999msat");
PASS_SAT(&sat, "0.00000000btc", 0);
FAIL_SAT(&sat, "0.00000000000btc");
PASS_SAT(&sat, "0.00000001btc", 1);
FAIL_SAT(&sat, "0.00000000001btc");
PASS_SAT(&sat, "1.23456789btc", 123456789);
FAIL_SAT(&sat, "1.23456789012btc");
FAIL_SAT(&sat, "1btc");
FAIL_SAT(&sat, "1.0000000btc");
FAIL_SAT(&sat, "1.000000000btc");
/* Overflowingly big. */
FAIL_SAT(&sat, "21000000000000000000000000.00000000btc");
/* Test fmt_amount_msat_btc, fmt_amount_msat */
for (u64 i = 0; i <= UINT64_MAX / 10; i = i ? i * 10 : 1) {
const char *with, *without;
msat.millisatoshis = i;
with = fmt_amount_msat_btc(tmpctx, &msat, true);
without = fmt_amount_msat_btc(tmpctx, &msat, false);
assert(strends(with, "btc"));
assert(strlen(with) == strlen(without) + 3);
assert(strncmp(with, without, strlen(without)) == 0);
/* Make sure it overwrites. */
msat.millisatoshis++;
assert(parse_amount_msat(&msat, with, strlen(with)));
assert(msat.millisatoshis == i);
with = fmt_amount_msat(tmpctx, &msat);
without = tal_fmt(tmpctx, "%"PRIu64, msat.millisatoshis);
assert(strends(with, "msat"));
assert(strlen(with) == strlen(without) + 4);
assert(strncmp(with, without, strlen(without)) == 0);
/* Make sure it overwrites. */
msat.millisatoshis++;
assert(parse_amount_msat(&msat, with, strlen(with)));
assert(msat.millisatoshis == i);
}
/* Test fmt_amount_sat_btc, fmt_amount_sat */
for (u64 i = 0; i <= UINT64_MAX / 10; i = i ? i * 10 : 1) {
const char *with, *without;
sat.satoshis = i;
with = fmt_amount_sat_btc(tmpctx, &sat, true);
without = fmt_amount_sat_btc(tmpctx, &sat, false);
assert(strends(with, "btc"));
assert(strlen(with) == strlen(without) + 3);
assert(strncmp(with, without, strlen(without)) == 0);
/* Make sure it overwrites. */
sat.satoshis++;
assert(parse_amount_sat(&sat, with, strlen(with)));
assert(sat.satoshis == i);
with = fmt_amount_sat(tmpctx, &sat);
without = tal_fmt(tmpctx, "%"PRIu64, sat.satoshis);
assert(strends(with, "sat"));
assert(strlen(with) == strlen(without) + 3);
assert(strncmp(with, without, strlen(without)) == 0);
/* Make sure it overwrites. */
sat.satoshis++;
assert(parse_amount_sat(&sat, with, strlen(with)));
assert(sat.satoshis == i);
}
tal_free(tmpctx);
}

2
common/type_to_string.h

@ -30,6 +30,8 @@ union printable_types {
const secp256k1_ecdsa_signature *secp256k1_ecdsa_signature;
const struct bitcoin_signature *bitcoin_signature;
const struct channel *channel;
const struct amount_msat *amount_msat;
const struct amount_sat *amount_sat;
const char *charp_;
};

1
connectd/Makefile

@ -37,6 +37,7 @@ LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_CONNECT_HEADERS)
# Common source we use.
CONNECTD_COMMON_OBJS := \
common/amount.o \
common/base32.o \
common/bech32.o \
common/bech32_util.o \

1
devtools/Makefile

@ -5,6 +5,7 @@ DEVTOOLS_TOOL_SRC := $(DEVTOOLS:=.c)
DEVTOOLS_TOOL_OBJS := $(DEVTOOLS_TOOL_SRC:.c=.o)
DEVTOOLS_COMMON_OBJS := \
common/amount.o \
common/base32.o \
common/bech32.o \
common/bech32_util.o \

1
gossipd/Makefile

@ -36,6 +36,7 @@ LIGHTNINGD_HEADERS_GEN += $(LIGHTNINGD_GOSSIP_HEADERS)
# Common source we use.
GOSSIPD_COMMON_OBJS := \
bitcoin/chainparams.o \
common/amount.o \
common/base32.o \
common/bech32.o \
common/bech32_util.o \

1
hsmd/Makefile

@ -13,6 +13,7 @@ LIGHTNINGD_HSM_OBJS := $(LIGHTNINGD_HSM_SRC:.c=.o)
# Common source we use.
HSMD_COMMON_OBJS := \
common/amount.o \
common/bip32.o \
common/daemon.o \
common/daemon_conn.o \

1
lightningd/test/run-find_my_abspath.c

@ -4,6 +4,7 @@ int unused_main(int argc, char *argv[]);
#include "../../common/wireaddr.c"
#include "../lightningd.c"
#include "../subd.c"
#include <common/amount.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for activate_peers */

1
onchaind/Makefile

@ -47,6 +47,7 @@ $(LIGHTNINGD_ONCHAIN_OBJS): $(LIGHTNINGD_HEADERS)
# Common source we use.
ONCHAIND_COMMON_OBJS := \
common/amount.o \
common/bip32.o \
common/daemon.o \
common/daemon_conn.o \

1
openingd/Makefile

@ -35,6 +35,7 @@ LIGHTNINGD_HEADERS_NOGEN += $(LIGHTNINGD_OPENING_HEADERS_NOGEN)
# Common source we use.
OPENINGD_COMMON_OBJS := \
common/amount.o \
common/base32.o \
common/bip32.o \
common/channel_config.o \

2
tools/generate-wire.py

@ -45,7 +45,7 @@ class FieldType(object):
self.name = name
def is_assignable(self):
return self.name in ['u8', 'u16', 'u32', 'u64', 'bool'] or self.name.startswith('enum ')
return self.name in ['u8', 'u16', 'u32', 'u64', 'bool', 'struct amount_msat', 'struct amount_sat'] or self.name.startswith('enum ')
# We only accelerate the u8 case: it's common and trivial.
def has_array_helper(self):

1
wallet/test/run-db.c

@ -12,6 +12,7 @@ static void db_log_(struct log *log UNUSED, enum log_level level UNUSED, const c
#include "test_utils.h"
#include <common/amount.h>
#include <common/memleak.h>
#include <stdio.h>
#include <unistd.h>

1
wallet/test/run-wallet.c

@ -19,6 +19,7 @@ static void db_log_(struct log *log UNUSED, enum log_level level UNUSED, const c
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/memleak.h>
#include <stdarg.h>
#include <stddef.h>

18
wire/fromwire.c

@ -8,6 +8,7 @@
#include <ccan/endian/endian.h>
#include <ccan/mem/mem.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/type_to_string.h>
#include <common/utils.h>
@ -270,3 +271,20 @@ void fromwire_siphash_seed(const u8 **cursor, size_t *max,
{
fromwire(cursor, max, seed, sizeof(*seed));
}
struct amount_msat fromwire_amount_msat(const u8 **cursor, size_t *max)
{
struct amount_msat msat;
msat.millisatoshis = fromwire_u64(cursor, max);
return msat;
}
struct amount_sat fromwire_amount_sat(const u8 **cursor, size_t *max)
{
struct amount_sat sat;
sat.satoshis = fromwire_u64(cursor, max);
return sat;
}

4
wire/test/run-peer-wire.c

@ -13,10 +13,14 @@ void fromwire_pad_orig(const u8 **cursor, size_t *max, size_t num);
#include <assert.h>
#include <stdio.h>
#include <common/amount.h>
#include <common/sphinx.h>
secp256k1_context *secp256k1_ctx;
/* AUTOGENERATED MOCKS START */
/* AUTOGENERATED MOCKS END */
/* We allow non-zero padding for testing. */
static const void *towire_pad_arr;
void towire_pad(u8 **pptr, size_t num)

11
wire/towire.c

@ -8,6 +8,7 @@
#include <ccan/endian/endian.h>
#include <ccan/mem/mem.h>
#include <ccan/tal/tal.h>
#include <common/amount.h>
#include <common/utils.h>
void towire(u8 **pptr, const void *data, size_t len)
@ -182,3 +183,13 @@ void towire_siphash_seed(u8 **pptr, const struct siphash_seed *seed)
{
towire(pptr, seed, sizeof(*seed));
}
void towire_amount_msat(u8 **pptr, const struct amount_msat msat)
{
towire_u64(pptr, msat.millisatoshis);
}
void towire_amount_sat(u8 **pptr, const struct amount_sat sat)
{
towire_u64(pptr, sat.satoshis);
}

5
wire/wire.h

@ -10,6 +10,7 @@
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/short_types/short_types.h>
#include <ccan/structeq/structeq.h>
#include <common/amount.h>
#include <secp256k1_recovery.h>
#include <stdlib.h>
@ -56,6 +57,8 @@ void towire_bitcoin_signature(u8 **pptr, const struct bitcoin_signature *sig);
void towire_bitcoin_blkid(u8 **pptr, const struct bitcoin_blkid *blkid);
void towire_preimage(u8 **pptr, const struct preimage *preimage);
void towire_ripemd160(u8 **pptr, const struct ripemd160 *ripemd);
void towire_amount_msat(u8 **pptr, const struct amount_msat msat);
void towire_amount_sat(u8 **pptr, const struct amount_sat sat);
void towire_u8(u8 **pptr, u8 v);
void towire_u16(u8 **pptr, u16 v);
void towire_u32(u8 **pptr, u32 v);
@ -102,6 +105,8 @@ void fromwire_bitcoin_blkid(const u8 **cursor, size_t *max,
struct bitcoin_blkid *blkid);
void fromwire_preimage(const u8 **cursor, size_t *max, struct preimage *preimage);
void fromwire_ripemd160(const u8 **cursor, size_t *max, struct ripemd160 *ripemd);
struct amount_msat fromwire_amount_msat(const u8 **cursor, size_t *max);
struct amount_sat fromwire_amount_sat(const u8 **cursor, size_t *max);
void fromwire_pad(const u8 **cursor, size_t *max, size_t num);
void fromwire_u8_array(const u8 **cursor, size_t *max, u8 *arr, size_t num);

Loading…
Cancel
Save