mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-20 13:54:36 +01:00
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>
This commit is contained in:
parent
269dbe585c
commit
7fad7bccba
25 changed files with 780 additions and 5 deletions
|
@ -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 \
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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,4 +1,5 @@
|
|||
#include <assert.h>
|
||||
#include <common/amount.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
|
|
@ -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,4 +1,5 @@
|
|||
COMMON_SRC_NOGEN := \
|
||||
common/amount.c \
|
||||
common/base32.c \
|
||||
common/bech32.c \
|
||||
common/bech32_util.c \
|
||||
|
|
426
common/amount.c
Normal file
426
common/amount.c
Normal file
|
@ -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
Normal file
142
common/amount.h
Normal file
|
@ -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 */
|
|
@ -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
Normal file
152
common/test/run-amount.c
Normal file
|
@ -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);
|
||||
}
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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…
Add table
Reference in a new issue