commit dbe1260b542029edd37beb46459050f7312f50dc
parent c4206883f2dfc3a431909953fc9f3f0346d01444
Author: William Casarin <jb55@jb55.com>
Date: Wed, 19 Oct 2022 07:45:06 -0700
damus-c: add bolt11 parser from CLN
We'll need this for our lightning invoice view
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
A | damus-c/alignof.h | | | 20 | ++++++++++++++++++++ |
A | damus-c/amount.c | | | 566 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/amount.h | | | 203 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/array_size.h | | | 26 | ++++++++++++++++++++++++++ |
A | damus-c/bech32.c | | | 210 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/bech32.h | | | 134 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/bech32_util.c | | | 127 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/bech32_util.h | | | 28 | ++++++++++++++++++++++++++++ |
A | damus-c/bolt11.c | | | 676 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/bolt11.h | | | 104 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/build_assert.h | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/check_type.h | | | 64 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/compiler.h | | | 317 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/config.h | | | 18 | ++++++++++++++++++ |
A | damus-c/container_of.h | | | 145 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/cppmagic.h | | | 191 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/endian.h | | | 363 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/hash_u5.c | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/hash_u5.h | | | 20 | ++++++++++++++++++++ |
A | damus-c/hex.c | | | 66 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/hex.h | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/likely.h | | | 111 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/list.c | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/list.h | | | 842 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/mem.c | | | 128 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/mem.h | | | 295 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/node_id.c | | | 64 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/node_id.h | | | 38 | ++++++++++++++++++++++++++++++++++++++ |
A | damus-c/overflows.h | | | 43 | +++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/sha256.c | | | 308 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/sha256.h | | | 147 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/short_types.h | | | 35 | +++++++++++++++++++++++++++++++++++ |
A | damus-c/str.h | | | 228 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/str_debug.h | | | 30 | ++++++++++++++++++++++++++++++ |
A | damus-c/structeq.h | | | 46 | ++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/take.c | | | 126 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/take.h | | | 136 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/tal.c | | | 972 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/tal.h | | | 553 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/talstr.c | | | 315 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/talstr.h | | | 225 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | damus-c/typesafe_cb.h | | | 134 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | damus-c/utf8.c | | | 19 | +++++++++++++++++++ |
M | damus-c/utf8.h | | | 3 | +++ |
44 files changed, 8280 insertions(+), 0 deletions(-)
diff --git a/damus-c/alignof.h b/damus-c/alignof.h
@@ -0,0 +1,20 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_ALIGNOF_H
+#define CCAN_ALIGNOF_H
+#include "config.h"
+
+/**
+ * ALIGNOF - get the alignment of a type
+ * @t: the type to test
+ *
+ * This returns a safe alignment for the given type.
+ */
+#if HAVE_ALIGNOF
+/* A GCC extension. */
+#define ALIGNOF(t) __alignof__(t)
+#else
+/* Alignment by measuring structure padding. */
+#define ALIGNOF(t) ((char *)(&((struct { char c; t _h; } *)0)->_h) - (char *)0)
+#endif
+
+#endif /* CCAN_ALIGNOF_H */
diff --git a/damus-c/amount.c b/damus-c/amount.c
@@ -0,0 +1,566 @@
+#include "config.h"
+#include <assert.h>
+#include "mem.h"
+#include "talstr.h"
+#include "amount.h"
+#include "overflows.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;
+}
+
+bool amount_msat_to_sat(struct amount_sat *sat,
+ struct amount_msat msat)
+{
+ if (msat.millisatoshis % MSAT_PER_SAT)
+ return false;
+ sat->satoshis = msat.millisatoshis / 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;
+}
+
+/* Different formatting by amounts: btc, sat and msat */
+const char *fmt_amount_msat_btc(const tal_t *ctx,
+ struct amount_msat msat,
+ bool append_unit)
+{
+ if (msat.millisatoshis == 0)
+ return tal_fmt(ctx, append_unit ? "0btc" : "0");
+
+ 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, struct amount_msat msat)
+{
+ return tal_fmt(ctx, "%"PRIu64"msat", msat.millisatoshis);
+}
+
+const char *fmt_amount_sat_btc(const tal_t *ctx,
+ struct amount_sat sat,
+ bool append_unit)
+{
+ if (sat.satoshis == 0)
+ return tal_fmt(ctx, append_unit ? "0btc" : "0");
+
+ 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, struct amount_sat sat)
+{
+ return tal_fmt(ctx, "%"PRIu64"sat", sat.satoshis);
+}
+
+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++) {
+ /* The string may be null-terminated. */
+ if (i >= slen || str[i] == '\0')
+ 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 || str[i] == '\0')
+ 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, int tens_factor)
+{
+ 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';
+ }
+ while (tens_factor > 0) {
+ if (mul_overflows_u64(*res, 10))
+ return false;
+ *res *= 10;
+ tens_factor--;
+ }
+ return true;
+}
+
+static bool from_numbers(u64 *res,
+ const char *s1, size_t len1, int tens_factor,
+ const char *s2, size_t len2)
+{
+ u64 p1, p2;
+ if (len2 > tens_factor)
+ return false;
+
+ if (!from_number(&p1, s1, len1, tens_factor)
+ || !from_number(&p2, s2, len2, tens_factor - len2))
+ 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 -> millisatoshi.
+ * [0-9]+.[0-9]{1,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, 0);
+ if (!post_decimal_ptr && memstarts_str(suffix_ptr, suffix_len, "msat"))
+ return from_number(&msat->millisatoshis, s, whole_number_len, 0);
+ if (!post_decimal_ptr && memstarts_str(suffix_ptr, suffix_len, "sat"))
+ return from_number(&msat->millisatoshis, s, whole_number_len, 3);
+ if (memstarts_str(suffix_ptr, suffix_len, "btc")) {
+ if (post_decimal_len > 0)
+ return from_numbers(&msat->millisatoshis,
+ s, whole_number_len, 11,
+ post_decimal_ptr, post_decimal_len);
+ return from_number(&msat->millisatoshis, s, whole_number_len, 11);
+ }
+
+ return false;
+}
+
+/* Valid strings:
+ * [0-9]+ => satoshi.
+ * [0-9]+sat => satoshi.
+ * [0-9]+000msat => satoshi.
+ * 0msat => 0 satoshi
+ * [0-9]+.[0-9]{1,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, 0);
+ if (!post_decimal_ptr && memstarts_str(suffix_ptr, suffix_len, "sat"))
+ return from_number(&sat->satoshis, s, whole_number_len, 0);
+ if (!post_decimal_ptr && memstarts_str(suffix_ptr, suffix_len, "msat")) {
+ if (!memends(s, whole_number_len, "000", strlen("000"))) {
+ if (memstarts_str(s, whole_number_len, "0"))
+ return from_number(&sat->satoshis, s,
+ whole_number_len, 0);
+ return false;
+ }
+ return from_number(&sat->satoshis, s, whole_number_len - 3, 0);
+ }
+ if (memstarts_str(suffix_ptr, suffix_len, "btc")) {
+ if (post_decimal_len > 0)
+ return from_numbers(&sat->satoshis,
+ s, whole_number_len, 8,
+ post_decimal_ptr, post_decimal_len);
+ return from_number(&sat->satoshis, s, whole_number_len, 8);
+ }
+
+ 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);
+}
+
+WARN_UNUSED_RESULT bool amount_msat_add_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_add(val, a, msatb);
+}
+
+WARN_UNUSED_RESULT bool amount_msat_scale(struct amount_msat *val,
+ struct amount_msat msat,
+ double scale)
+{
+ double scaled = msat.millisatoshis * scale;
+
+ /* If mantissa is < 64 bits, a naive "if (scaled >
+ * UINT64_MAX)" doesn't work. Stick to powers of 2. */
+ if (scaled >= (double)((u64)1 << 63) * 2)
+ return false;
+ val->millisatoshis = scaled;
+ return true;
+}
+
+WARN_UNUSED_RESULT bool amount_sat_scale(struct amount_sat *val,
+ struct amount_sat sat,
+ double scale)
+{
+ double scaled = sat.satoshis * scale;
+
+ /* If mantissa is < 64 bits, a naive "if (scaled >
+ * UINT64_MAX)" doesn't work. Stick to powers of 2. */
+ if (scaled >= (double)((u64)1 << 63) * 2)
+ return false;
+ val->satoshis = scaled;
+ return true;
+}
+
+bool amount_sat_eq(struct amount_sat a, struct amount_sat b)
+{
+ return a.satoshis == b.satoshis;
+}
+
+bool amount_sat_zero(struct amount_sat a)
+{
+ return a.satoshis == 0;
+}
+
+bool amount_msat_zero(struct amount_msat a)
+{
+ return a.millisatoshis == 0;
+}
+
+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_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_to_u32(struct amount_msat msat, u32 *millisatoshis)
+{
+ if (amount_msat_greater_eq(msat, AMOUNT_MSAT(0x100000000)))
+ return false;
+ *millisatoshis = msat.millisatoshis;
+ return true;
+}
+
+struct amount_msat amount_msat(u64 millisatoshis)
+{
+ struct amount_msat msat;
+
+ msat.millisatoshis = millisatoshis;
+ return msat;
+}
+
+struct amount_sat amount_sat(u64 satoshis)
+{
+ struct amount_sat sat;
+
+ sat.satoshis = satoshis;
+ return sat;
+}
+
+double amount_msat_ratio(struct amount_msat a, struct amount_msat b)
+{
+ return (double)a.millisatoshis / b.millisatoshis;
+}
+
+struct amount_msat amount_msat_div(struct amount_msat msat, u64 div)
+{
+ msat.millisatoshis /= div;
+ return msat;
+}
+
+struct amount_sat amount_sat_div(struct amount_sat sat, u64 div)
+{
+ sat.satoshis /= div;
+ return sat;
+}
+
+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 = (u64)fee_per_kw * weight / 1000;
+
+ return fee;
+}
+
+/*
+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;
+}
+
+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);
+}
+
+
+*/
diff --git a/damus-c/amount.h b/damus-c/amount.h
@@ -0,0 +1,203 @@
+#ifndef LIGHTNING_COMMON_AMOUNT_H
+#define LIGHTNING_COMMON_AMOUNT_H
+#include "config.h"
+#include "short_types.h"
+#include "tal.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;
+};
+
+struct amount_asset {
+ u64 value;
+ u8 asset[33]; /* 1 version byte + 32 byte asset_tag */
+};
+
+/* 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
+
+/* GCC 4.8.5 (Centos 7.6!) thinks struct casts are not constants, so we
+ * need to not use a cast for static initializations. */
+#define AMOUNT_MSAT_INIT(msat) \
+ { .millisatoshis = (msat) }
+#define AMOUNT_SAT_INIT(sat) \
+ { .satoshis = (sat) }
+
+#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)})
+
+/* We do sometimes need to import from raw types, eg. wally or wire fmt */
+struct amount_msat amount_msat(u64 millisatoshis);
+struct amount_sat amount_sat(u64 satoshis);
+
+/* 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);
+
+/* You may not always be able to convert millisatoshis->satoshis without rounding. */
+WARN_UNUSED_RESULT bool amount_msat_to_sat(struct amount_sat *sat,
+ struct amount_msat 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_msat_add_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);
+WARN_UNUSED_RESULT bool amount_msat_scale(struct amount_msat *val,
+ struct amount_msat msat,
+ double scale);
+WARN_UNUSED_RESULT bool amount_sat_scale(struct amount_sat *val,
+ struct amount_sat sat,
+ double scale);
+
+struct amount_msat amount_msat_div(struct amount_msat msat, u64 div);
+struct amount_sat amount_sat_div(struct amount_sat sat, u64 div);
+
+/* 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 zero? */
+bool amount_sat_zero(struct amount_sat a);
+bool amount_msat_zero(struct amount_msat a);
+
+/* 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);
+/* Is msat == sat? */
+bool amount_msat_eq_sat(struct amount_msat msat, struct amount_sat sat);
+
+/* a / b */
+double amount_msat_ratio(struct amount_msat a, struct amount_msat b);
+
+/* Check whether this asset is actually the main / fee-paying asset of the
+ * current chain. */
+bool amount_asset_is_main(struct amount_asset *asset);
+
+/* Convert an amount_sat to an amount_asset */
+struct amount_asset amount_sat_to_asset(struct amount_sat *sat, const u8 *asset);
+
+/* amount_asset_extract_value -Prefix the amount_asset's value
+ * to have the 'explicit' marker. Returns NULL if the
+ * asset was originally blinded.
+ * FIXME: pass through blinded amounts */
+u8 *amount_asset_extract_value(const tal_t *ctx, struct amount_asset *asset);
+
+/* Convert from a generic asset to the fee-paying asset if possible. */
+struct amount_sat amount_asset_to_sat(struct amount_asset *asset);
+
+/* Returns true if msat fits in a u32 value. */
+WARN_UNUSED_RESULT bool amount_msat_to_u32(struct amount_msat msat,
+ u32 *millisatoshis);
+
+/* 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 */
+/* => 1.23456789012btc (11 decimals!) */
+const char *fmt_amount_msat_btc(const tal_t *ctx,
+ struct amount_msat msat,
+ bool append_unit);
+/* => 1234msat */
+const char *fmt_amount_msat(const tal_t *ctx, struct amount_msat msat);
+
+/* => 1.23456789btc (8 decimals!) */
+const char *fmt_amount_sat_btc(const tal_t *ctx,
+ struct amount_sat sat,
+ bool append_unit);
+/* => 1234sat */
+const char *fmt_amount_sat(const tal_t *ctx, struct amount_sat sat);
+
+/* Valid strings:
+ * [0-9]+ => millisatoshi.
+ * [0-9]+msat => millisatoshi.
+ * [0-9]+sat => *1000 -> millisatopshi.
+ * [0-9]+.[0-9]{1,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]{1,8}btc => satoshi.
+ */
+bool parse_amount_sat(struct amount_sat *sat, const char *s, size_t slen);
+
+/* Marshal/unmarshal functions */
+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 towire_amount_msat(u8 **pptr, const struct amount_msat msat);
+void towire_amount_sat(u8 **pptr, const struct amount_sat sat);
+#endif /* LIGHTNING_COMMON_AMOUNT_H */
diff --git a/damus-c/array_size.h b/damus-c/array_size.h
@@ -0,0 +1,26 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_ARRAY_SIZE_H
+#define CCAN_ARRAY_SIZE_H
+#include "config.h"
+#include "build_assert.h"
+
+/**
+ * ARRAY_SIZE - get the number of elements in a visible array
+ * @arr: the array whose size you want.
+ *
+ * This does not work on pointers, or arrays declared as [], or
+ * function parameters. With correct compiler support, such usage
+ * will cause a build error (see build_assert).
+ */
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + _array_size_chk(arr))
+
+#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
+/* Two gcc extensions.
+ * &a[0] degrades to a pointer: a different type from an array */
+#define _array_size_chk(arr) \
+ BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(arr), \
+ typeof(&(arr)[0])))
+#else
+#define _array_size_chk(arr) 0
+#endif
+#endif /* CCAN_ALIGNOF_H */
diff --git a/damus-c/bech32.c b/damus-c/bech32.c
@@ -0,0 +1,210 @@
+/* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.c,
+ * with only the two ' > 90' checks hoisted, and more internals exposed */
+
+/* Copyright (c) 2017, 2021 Pieter Wuille
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "config.h"
+#include <assert.h>
+#include "bech32.h"
+#include <string.h>
+
+static uint32_t bech32_polymod_step(uint32_t pre) {
+ uint8_t b = pre >> 25;
+ return ((pre & 0x1FFFFFF) << 5) ^
+ (-((b >> 0) & 1) & 0x3b6a57b2UL) ^
+ (-((b >> 1) & 1) & 0x26508e6dUL) ^
+ (-((b >> 2) & 1) & 0x1ea119faUL) ^
+ (-((b >> 3) & 1) & 0x3d4233ddUL) ^
+ (-((b >> 4) & 1) & 0x2a1462b3UL);
+}
+
+static uint32_t bech32_final_constant(bech32_encoding enc) {
+ if (enc == BECH32_ENCODING_BECH32) return 1;
+ if (enc == BECH32_ENCODING_BECH32M) return 0x2bc830a3;
+ assert(0);
+}
+
+const char bech32_charset[] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
+
+const int8_t bech32_charset_rev[128] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
+ -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
+ 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
+ -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
+ 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
+};
+
+int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len, size_t max_input_len, bech32_encoding enc) {
+ uint32_t chk = 1;
+ size_t i = 0;
+ while (hrp[i] != 0) {
+ int ch = hrp[i];
+ if (ch < 33 || ch > 126) {
+ return 0;
+ }
+
+ if (ch >= 'A' && ch <= 'Z') return 0;
+ chk = bech32_polymod_step(chk) ^ (ch >> 5);
+ ++i;
+ }
+ if (i + 7 + data_len > max_input_len) return 0;
+ chk = bech32_polymod_step(chk);
+ while (*hrp != 0) {
+ chk = bech32_polymod_step(chk) ^ (*hrp & 0x1f);
+ *(output++) = *(hrp++);
+ }
+ *(output++) = '1';
+ for (i = 0; i < data_len; ++i) {
+ if (*data >> 5) return 0;
+ chk = bech32_polymod_step(chk) ^ (*data);
+ *(output++) = bech32_charset[*(data++)];
+ }
+ for (i = 0; i < 6; ++i) {
+ chk = bech32_polymod_step(chk);
+ }
+ chk ^= bech32_final_constant(enc);
+ for (i = 0; i < 6; ++i) {
+ *(output++) = bech32_charset[(chk >> ((5 - i) * 5)) & 0x1f];
+ }
+ *output = 0;
+ return 1;
+}
+
+bech32_encoding bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const char *input, size_t max_input_len) {
+ uint32_t chk = 1;
+ size_t i;
+ size_t input_len = strlen(input);
+ size_t hrp_len;
+ int have_lower = 0, have_upper = 0;
+ if (input_len < 8 || input_len > max_input_len) {
+ return BECH32_ENCODING_NONE;
+ }
+ *data_len = 0;
+ while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') {
+ ++(*data_len);
+ }
+ hrp_len = input_len - (1 + *data_len);
+ if (1 + *data_len >= input_len || *data_len < 6) {
+ return BECH32_ENCODING_NONE;
+ }
+ *(data_len) -= 6;
+ for (i = 0; i < hrp_len; ++i) {
+ int ch = input[i];
+ if (ch < 33 || ch > 126) {
+ return BECH32_ENCODING_NONE;
+ }
+ if (ch >= 'a' && ch <= 'z') {
+ have_lower = 1;
+ } else if (ch >= 'A' && ch <= 'Z') {
+ have_upper = 1;
+ ch = (ch - 'A') + 'a';
+ }
+ hrp[i] = ch;
+ chk = bech32_polymod_step(chk) ^ (ch >> 5);
+ }
+ hrp[i] = 0;
+ chk = bech32_polymod_step(chk);
+ for (i = 0; i < hrp_len; ++i) {
+ chk = bech32_polymod_step(chk) ^ (input[i] & 0x1f);
+ }
+ ++i;
+ while (i < input_len) {
+ int v = (input[i] & 0x80) ? -1 : bech32_charset_rev[(int)input[i]];
+ if (input[i] >= 'a' && input[i] <= 'z') have_lower = 1;
+ if (input[i] >= 'A' && input[i] <= 'Z') have_upper = 1;
+ if (v == -1) {
+ return BECH32_ENCODING_NONE;
+ }
+ chk = bech32_polymod_step(chk) ^ v;
+ if (i + 6 < input_len) {
+ data[i - (1 + hrp_len)] = v;
+ }
+ ++i;
+ }
+ if (have_lower && have_upper) {
+ return BECH32_ENCODING_NONE;
+ }
+ if (chk == bech32_final_constant(BECH32_ENCODING_BECH32)) {
+ return BECH32_ENCODING_BECH32;
+ } else if (chk == bech32_final_constant(BECH32_ENCODING_BECH32M)) {
+ return BECH32_ENCODING_BECH32M;
+ } else {
+ return BECH32_ENCODING_NONE;
+ }
+}
+
+int bech32_convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) {
+ uint32_t val = 0;
+ int bits = 0;
+ uint32_t maxv = (((uint32_t)1) << outbits) - 1;
+ while (inlen--) {
+ val = (val << inbits) | *(in++);
+ bits += inbits;
+ while (bits >= outbits) {
+ bits -= outbits;
+ out[(*outlen)++] = (val >> bits) & maxv;
+ }
+ }
+ if (pad) {
+ if (bits) {
+ out[(*outlen)++] = (val << (outbits - bits)) & maxv;
+ }
+ } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) {
+ return 0;
+ }
+ return 1;
+}
+
+int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) {
+ uint8_t data[65];
+ size_t datalen = 0;
+ bech32_encoding enc = BECH32_ENCODING_BECH32;
+ if (witver > 16) return 0;
+ if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0;
+ if (witprog_len < 2 || witprog_len > 40) return 0;
+ if (witver > 0) enc = BECH32_ENCODING_BECH32M;
+ data[0] = witver;
+ bech32_convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1);
+ ++datalen;
+ return bech32_encode(output, hrp, data, datalen, 90, enc);
+}
+
+int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) {
+ uint8_t data[84];
+ char hrp_actual[84];
+ size_t data_len;
+ bech32_encoding enc = bech32_decode(hrp_actual, data, &data_len, addr, 90);
+ if (enc == BECH32_ENCODING_NONE) return 0;
+ if (data_len == 0 || data_len > 65) return 0;
+ if (strncmp(hrp, hrp_actual, 84) != 0) return 0;
+ if (data[0] > 16) return 0;
+ if (data[0] == 0 && enc != BECH32_ENCODING_BECH32) return 0;
+ if (data[0] > 0 && enc != BECH32_ENCODING_BECH32M) return 0;
+ *witdata_len = 0;
+ if (!bech32_convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0;
+ if (*witdata_len < 2 || *witdata_len > 40) return 0;
+ if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) return 0;
+ *witver = data[0];
+ return 1;
+}
diff --git a/damus-c/bech32.h b/damus-c/bech32.h
@@ -0,0 +1,134 @@
+/* Stolen from https://github.com/sipa/bech32/blob/master/ref/c/segwit_addr.h,
+ * with only the two ' > 90' checks hoisted */
+
+/* Copyright (c) 2017, 2021 Pieter Wuille
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef LIGHTNING_COMMON_BECH32_H
+#define LIGHTNING_COMMON_BECH32_H
+#include "config.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/** Encode a SegWit address
+ *
+ * Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be
+ * updated to contain the null-terminated address.
+ * In: hrp: Pointer to the null-terminated human readable part to use
+ * (chain/network specific).
+ * ver: Version of the witness program (between 0 and 16 inclusive).
+ * prog: Data bytes for the witness program (between 2 and 40 bytes).
+ * prog_len: Number of data bytes in prog.
+ * Returns 1 if successful.
+ */
+int segwit_addr_encode(
+ char *output,
+ const char *hrp,
+ int ver,
+ const uint8_t *prog,
+ size_t prog_len
+);
+
+/** Decode a SegWit address
+ *
+ * Out: ver: Pointer to an int that will be updated to contain the witness
+ * program version (between 0 and 16 inclusive).
+ * prog: Pointer to a buffer of size 40 that will be updated to
+ * contain the witness program bytes.
+ * prog_len: Pointer to a size_t that will be updated to contain the length
+ * of bytes in prog.
+ * hrp: Pointer to the null-terminated human readable part that is
+ * expected (chain/network specific).
+ * addr: Pointer to the null-terminated address.
+ * Returns 1 if successful.
+ */
+int segwit_addr_decode(
+ int* ver,
+ uint8_t* prog,
+ size_t* prog_len,
+ const char* hrp,
+ const char* addr
+);
+
+/** Supported encodings. */
+typedef enum {
+ BECH32_ENCODING_NONE,
+ BECH32_ENCODING_BECH32,
+ BECH32_ENCODING_BECH32M
+} bech32_encoding;
+
+/** Encode a Bech32 or Bech32m string
+ *
+ * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that
+ * will be updated to contain the null-terminated Bech32 string.
+ * In: hrp : Pointer to the null-terminated human readable part.
+ * data : Pointer to an array of 5-bit values.
+ * data_len: Length of the data array.
+ * max_input_len: Maximum valid length of input (90 for segwit usage).
+ * enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}).
+ * Returns 1 if successful.
+ */
+int bech32_encode(
+ char *output,
+ const char *hrp,
+ const uint8_t *data,
+ size_t data_len,
+ size_t max_input_len,
+ bech32_encoding enc
+);
+
+/** Decode a Bech32 or Bech32m string
+ *
+ * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be
+ * updated to contain the null-terminated human readable part.
+ * data: Pointer to a buffer of size strlen(input) - 8 that will
+ * hold the encoded 5-bit data values.
+ * data_len: Pointer to a size_t that will be updated to be the number
+ * of entries in data.
+ * In: input: Pointer to a null-terminated Bech32 string.
+ * max_input_len: Maximum valid length of input (90 for segwit usage).
+ * Returns BECH32_ENCODING_BECH32{,M} to indicate decoding was successful
+ * with the specified encoding standard. BECH32_ENCODING_NONE is returned if
+ * decoding failed.
+ */
+bech32_encoding bech32_decode(
+ char *hrp,
+ uint8_t *data,
+ size_t *data_len,
+ const char *input,
+ size_t max_input_len
+);
+
+/* Helper from bech32: translates inbits-bit bytes to outbits-bit bytes.
+ * @outlen is incremented as bytes are added.
+ * @pad is true if we're to pad, otherwise truncate last byte if necessary
+ */
+int bech32_convert_bits(uint8_t* out, size_t* outlen, int outbits,
+ const uint8_t* in, size_t inlen, int inbits,
+ int pad);
+
+/* The charset, and reverse mapping */
+extern const char bech32_charset[32];
+extern const int8_t bech32_charset_rev[128];
+
+#endif /* LIGHTNING_COMMON_BECH32_H */
+
diff --git a/damus-c/bech32_util.c b/damus-c/bech32_util.c
@@ -0,0 +1,127 @@
+#include "config.h"
+#include "bech32.h"
+#include "bech32_util.h"
+#include "hash_u5.h"
+#include "talstr.h"
+#include "tal.h"
+#include "short_types.h"
+#include <stdbool.h>
+
+static u8 get_bit(const u8 *src, size_t bitoff)
+{
+ return ((src[bitoff / 8] >> (7 - (bitoff % 8))) & 1);
+}
+
+void bech32_push_bits(u5 **data, const void *src, size_t nbits)
+{
+ size_t i, b;
+ size_t data_len = tal_count(*data);
+
+ for (i = 0; i < nbits; i += b) {
+ tal_resize(data, data_len+1);
+ (*data)[data_len] = 0;
+ for (b = 0; b < 5; b++) {
+ (*data)[data_len] <<= 1;
+ /* If we need bits we don't have, zero */
+ if (i+b < nbits)
+ (*data)[data_len] |= get_bit(src, i+b);
+ }
+ data_len++;
+ }
+}
+
+static u8 get_u5_bit(const u5 *src, size_t bitoff)
+{
+ return ((src[bitoff / 5] >> (4 - (bitoff % 5))) & 1);
+}
+
+void bech32_pull_bits(u8 **data, const u5 *src, size_t nbits)
+{
+ size_t i;
+ size_t data_len = tal_count(*data);
+
+ /* We discard trailing bits. */
+ for (i = 0; i + 8 <= nbits; i += 8) {
+ tal_resize(data, data_len+1);
+ (*data)[data_len] = 0;
+ for (size_t b = 0; b < 8; b++) {
+ (*data)[data_len] <<= 1;
+ (*data)[data_len] |= get_u5_bit(src, i+b);
+ }
+ data_len++;
+ }
+}
+
+/* Returns a char, tracks case. */
+static int fixup_char(int c, bool *upper, bool *lower)
+{
+ if (c >= 'A' && c <= 'Z') {
+ *upper = true;
+ return c + ('a' - 'A');
+ } else if (c >= 'a' && c <= 'z') {
+ *lower = true;
+ }
+ return c;
+}
+
+bool from_bech32_charset(const tal_t *ctx,
+ const char *bech32,
+ size_t bech32_len,
+ char **hrp, u8 **data)
+{
+ u5 *u5data;
+ const char *sep;
+ bool upper = false, lower = false;
+ size_t datalen;
+
+ sep = memchr(bech32, '1', bech32_len);
+ if (!sep)
+ return false;
+
+ *hrp = tal_strndup(ctx, bech32, sep - bech32);
+ for (size_t i = 0; i < strlen(*hrp); i++)
+ (*hrp)[i] = fixup_char((*hrp)[i], &upper, &lower);
+
+ datalen = bech32_len - (sep + 1 - bech32);
+ u5data = tal_arr(NULL, u5, datalen);
+ for (size_t i = 0; i < datalen; i++) {
+ int c = sep[1+i];
+ if (c < 0 || c > 128)
+ goto fail;
+ c = fixup_char(c, &upper, &lower);
+ if (bech32_charset_rev[c] == -1)
+ goto fail;
+ u5data[i] = bech32_charset_rev[c];
+ }
+
+ /* Check case consistency */
+ if (upper && lower)
+ goto fail;
+
+ *data = tal_arr(ctx, u8, 0);
+ bech32_pull_bits(data, u5data, tal_bytelen(u5data) * 5);
+ tal_free(u5data);
+ return true;
+
+fail:
+ *hrp = tal_free(*hrp);
+ tal_free(u5data);
+ return false;
+}
+
+char *to_bech32_charset(const tal_t *ctx,
+ const char *hrp, const u8 *data)
+{
+ u5 *u5data = tal_arr(NULL, u5, 0);
+ char *ret;
+
+ bech32_push_bits(&u5data, data, tal_bytelen(data) * 8);
+ ret = tal_dup_arr(ctx, char, hrp, strlen(hrp),
+ 1 + tal_bytelen(u5data) + 1);
+ ret[strlen(hrp)] = '1';
+ for (size_t i = 0; i < tal_bytelen(u5data); i++)
+ ret[strlen(hrp) + 1 + i] = bech32_charset[u5data[i]];
+ ret[strlen(hrp) + 1 + tal_bytelen(u5data)] = '\0';
+ tal_free(u5data);
+ return ret;
+}
diff --git a/damus-c/bech32_util.h b/damus-c/bech32_util.h
@@ -0,0 +1,28 @@
+#ifndef LIGHTNING_COMMON_BECH32_UTIL_H
+#define LIGHTNING_COMMON_BECH32_UTIL_H
+#include "config.h"
+
+#include "tal.h"
+#include "hash_u5.h"
+
+/**
+ * Push the bytes in src in 5 bit format onto the end of data.
+ */
+void bech32_push_bits(u5 **data, const void *src, size_t nbits);
+
+/**
+ * Push the bytes in src in 8 bit format onto the end of data.
+ */
+void bech32_pull_bits(u8 **data, const u5 *src, size_t nbits);
+
+/**
+ * Checksumless bech32 routines.
+ */
+bool from_bech32_charset(const tal_t *ctx,
+ const char *bech32, size_t bech32_len,
+ char **hrp, u8 **data);
+
+char *to_bech32_charset(const tal_t *ctx,
+ const char *hrp, const u8 *data);
+
+#endif /* LIGHTNING_COMMON_BECH32_UTIL_H */
diff --git a/damus-c/bolt11.c b/damus-c/bolt11.c
@@ -0,0 +1,676 @@
+//
+// bolt11.c
+// damus
+//
+// Created by William Casarin on 2022-10-18.
+//
+
+#include "bolt11.h"
+
+//#include "address.h"
+//#include "script.h"
+#include "bech32.h"
+#include "utf8.h"
+#include "compiler.h"
+#include "endian.h"
+#include "list.h"
+#include "talstr.h"
+#include "tal.h"
+#include "node_id.h"
+#include "bech32_util.h"
+#include "bolt11.h"
+#include "amount.h"
+#include "array_size.h"
+#include "structeq.h"
+
+//#include "features.h"
+#include <errno.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#define MSAT_PER_SAT ((u64)1000)
+#define SAT_PER_BTC ((u64)100000000)
+#define MSAT_PER_BTC (MSAT_PER_SAT * SAT_PER_BTC)
+
+struct multiplier {
+ const char letter;
+ /* We can't represent p postfix to msat, so we multiply this by 10 */
+ u64 m10;
+};
+
+/* BOLT #11:
+ *
+ * The following `multiplier` letters are defined:
+ *
+ * * `m` (milli): multiply by 0.001
+ * * `u` (micro): multiply by 0.000001
+ * * `n` (nano): multiply by 0.000000001
+ * * `p` (pico): multiply by 0.000000000001
+ */
+static struct multiplier multipliers[] = {
+ { 'm', 10 * MSAT_PER_BTC / 1000 },
+ { 'u', 10 * MSAT_PER_BTC / 1000000 },
+ { 'n', 10 * MSAT_PER_BTC / 1000000000 },
+ { 'p', 10 * MSAT_PER_BTC / 1000000000000ULL }
+};
+
+/* If pad is false, we discard any bits which don't fit in the last byte.
+ * Otherwise we add an extra byte */
+static bool pull_bits(struct hash_u5 *hu5,
+ u5 **data, size_t *data_len, void *dst, size_t nbits,
+ bool pad)
+{
+ size_t n5 = nbits / 5;
+ size_t len = 0;
+
+ if (nbits % 5)
+ n5++;
+
+ if (*data_len < n5)
+ return false;
+ if (!bech32_convert_bits(dst, &len, 8, *data, n5, 5, pad))
+ return false;
+ if (hu5)
+ hash_u5(hu5, *data, n5);
+ *data += n5;
+ *data_len -= n5;
+
+ return true;
+}
+
+/* For pulling fields where we should have checked it will succeed already. */
+#ifndef NDEBUG
+#define pull_bits_certain(hu5, data, data_len, dst, nbits, pad) \
+ assert(pull_bits((hu5), (data), (data_len), (dst), (nbits), (pad)))
+#else
+#define pull_bits_certain pull_bits
+#endif
+
+/* Helper for pulling a variable-length big-endian int. */
+static bool pull_uint(struct hash_u5 *hu5,
+ u5 **data, size_t *data_len,
+ u64 *val, size_t databits)
+{
+ be64 be_val;
+
+ /* Too big. */
+ if (databits > sizeof(be_val) * CHAR_BIT)
+ return false;
+ if (!pull_bits(hu5, data, data_len, &be_val, databits, true))
+ return false;
+ *val = be64_to_cpu(be_val) >> (sizeof(be_val) * CHAR_BIT - databits);
+ return true;
+}
+
+static size_t num_u8(size_t num_u5)
+{
+ return (num_u5 * 5 + 4) / 8;
+}
+
+/* Frees bolt11, returns NULL. */
+static struct bolt11 *decode_fail(struct bolt11 *b11, char **fail,
+ const char *fmt, ...)
+ PRINTF_FMT(3,4);
+
+static struct bolt11 *decode_fail(struct bolt11 *b11, char **fail,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ *fail = tal_vfmt(tal_parent(b11), fmt, ap);
+ va_end(ap);
+ return tal_free(b11);
+}
+
+/*
+ * These handle specific fields in the payment request; returning the problem
+ * if any, or NULL.
+ */
+static char *unknown_field(struct bolt11 *b11,
+ struct hash_u5 *hu5,
+ u5 **data, size_t *data_len,
+ u5 type, size_t length)
+{
+ struct bolt11_field *extra = tal(b11, struct bolt11_field);
+ u8 u8data[num_u8(length)];
+
+ extra->tag = type;
+ extra->data = tal_dup_arr(extra, u5, *data, length, 0);
+ list_add_tail(&b11->extra_fields, &extra->list);
+
+ pull_bits_certain(hu5, data, data_len, u8data, length * 5, true);
+ return NULL;
+}
+
+/* BOLT #11:
+ *
+ * `p` (1): `data_length` 52. 256-bit SHA256 payment_hash. Preimage of this
+ * provides proof of payment
+ */
+static void decode_p(struct bolt11 *b11,
+ struct hash_u5 *hu5,
+ u5 **data, size_t *data_len,
+ size_t data_length, bool *have_p)
+{
+ /* BOLT #11:
+ *
+ * A payer... SHOULD use the first `p` field that it did NOT
+ * skip as the payment hash.
+ */
+ if (*have_p) {
+ unknown_field(b11, hu5, data, data_len, 'p', data_length);
+ return;
+ }
+
+ /* BOLT #11:
+ *
+ * A reader... MUST skip over unknown fields, OR an `f` field
+ * with unknown `version`, OR `p`, `h`, `s` or `n` fields that do
+ * NOT have `data_length`s of 52, 52, 52 or 53, respectively.
+ */
+ if (data_length != 52) {
+ unknown_field(b11, hu5, data, data_len, 'p', data_length);
+ return;
+ }
+
+ pull_bits_certain(hu5, data, data_len, &b11->payment_hash, 256, false);
+ *have_p = true;
+}
+
+
+static char *utf8_str(const tal_t *ctx, const u8 *buf TAKES, size_t buflen)
+{
+ char *ret;
+
+ if (!utf8_check(buf, buflen)) {
+ if (taken(buf))
+ tal_free(buf);
+ return NULL;
+ }
+
+ /* Add one for nul term */
+ ret = tal_dup_arr(ctx, char, (const char *)buf, buflen, 1);
+ ret[buflen] = '\0';
+ return ret;
+}
+
+
+/* BOLT #11:
+ *
+ * `d` (13): `data_length` variable. Short description of purpose of payment
+ * (UTF-8), e.g. '1 cup of coffee' or 'ナンセンス 1杯'
+ */
+static char *decode_d(struct bolt11 *b11,
+ struct hash_u5 *hu5,
+ u5 **data, size_t *data_len,
+ size_t data_length, bool *have_d)
+{
+ u8 *desc;
+ if (*have_d)
+ return unknown_field(b11, hu5, data, data_len, 'd', data_length);
+
+ desc = tal_arr(NULL, u8, data_length * 5 / 8);
+ pull_bits_certain(hu5, data, data_len, desc, data_length*5, false);
+
+ *have_d = true;
+ b11->description = utf8_str(b11, take(desc), tal_bytelen(desc));
+ if (b11->description)
+ return NULL;
+
+ return tal_fmt(b11, "d: invalid utf8");
+}
+
+/* BOLT #11:
+ *
+ * `h` (23): `data_length` 52. 256-bit description of purpose of payment
+ * (SHA256). This is used to commit to an associated description that is over
+ * 639 bytes, but the transport mechanism for the description in that case is
+ * transport specific and not defined here.
+ */
+static void decode_h(struct bolt11 *b11,
+ struct hash_u5 *hu5,
+ u5 **data, size_t *data_len,
+ size_t data_length, bool *have_h)
+{
+ if (*have_h) {
+ unknown_field(b11, hu5, data, data_len, 'h', data_length);
+ return;
+ }
+
+ /* BOLT #11:
+ *
+ * A reader... MUST skip over unknown fields, OR an `f` field
+ * with unknown `version`, OR `p`, `h`, `s` or `n` fields that do
+ * NOT have `data_length`s of 52, 52, 52 or 53, respectively. */
+ if (data_length != 52) {
+ unknown_field(b11, hu5, data, data_len, 'h', data_length);
+ return;
+ }
+
+ b11->description_hash = tal(b11, struct sha256);
+ pull_bits_certain(hu5, data, data_len, b11->description_hash, 256,
+ false);
+ *have_h = true;
+}
+
+/* BOLT #11:
+ *
+ * `x` (6): `data_length` variable. `expiry` time in seconds
+ * (big-endian). Default is 3600 (1 hour) if not specified.
+ */
+#define DEFAULT_X 3600
+static char *decode_x(struct bolt11 *b11,
+ struct hash_u5 *hu5,
+ u5 **data, size_t *data_len,
+ size_t data_length, bool *have_x)
+{
+ if (*have_x)
+ return unknown_field(b11, hu5, data, data_len, 'x',
+ data_length);
+
+ /* FIXME: Put upper limit in bolt 11 */
+ if (!pull_uint(hu5, data, data_len, &b11->expiry, data_length * 5))
+ return tal_fmt(b11, "x: length %zu chars is excessive",
+ *data_len);
+
+ *have_x = true;
+ return NULL;
+}
+
+/* BOLT #11:
+ *
+ * `c` (24): `data_length` variable. `min_final_cltv_expiry` to use for the
+ * last HTLC in the route. Default is 18 if not specified.
+ */
+static char *decode_c(struct bolt11 *b11,
+ struct hash_u5 *hu5,
+ u5 **data, size_t *data_len,
+ size_t data_length, bool *have_c)
+{
+ u64 c;
+ if (*have_c)
+ return unknown_field(b11, hu5, data, data_len, 'c',
+ data_length);
+
+ /* FIXME: Put upper limit in bolt 11 */
+ if (!pull_uint(hu5, data, data_len, &c, data_length * 5))
+ return tal_fmt(b11, "c: length %zu chars is excessive",
+ *data_len);
+ b11->min_final_cltv_expiry = c;
+ /* Can overflow, since c is 64 bits but value must be < 32 bits */
+ if (b11->min_final_cltv_expiry != c)
+ return tal_fmt(b11, "c: %"PRIu64" is too large", c);
+
+ *have_c = true;
+ return NULL;
+}
+
+static char *decode_n(struct bolt11 *b11,
+ struct hash_u5 *hu5,
+ u5 **data, size_t *data_len,
+ size_t data_length, bool *have_n)
+{
+ if (*have_n)
+ return unknown_field(b11, hu5, data, data_len, 'n',
+ data_length);
+
+ /* BOLT #11:
+ *
+ * A reader... MUST skip over unknown fields, OR an `f` field
+ * with unknown `version`, OR `p`, `h`, `s` or `n` fields that do
+ * NOT have `data_length`s of 52, 52, 52 or 53, respectively. */
+ if (data_length != 53)
+ return unknown_field(b11, hu5, data, data_len, 'n',
+ data_length);
+
+ pull_bits_certain(hu5, data, data_len, &b11->receiver_id.k,
+ data_length * 5, false);
+ /*
+ if (!node_id_valid(&b11->receiver_id))
+ return tal_fmt(b11, "n: invalid pubkey %s",
+ node_id_to_hexstr(b11, &b11->receiver_id));
+ */
+
+ *have_n = true;
+ return NULL;
+}
+
+/* BOLT #11:
+ *
+ * `m` (27): `data_length` variable. Additional metadata to attach to
+ * the payment. Note that the size of this field is limited by the
+ * maximum hop payload size. Long metadata fields reduce the maximum
+ * route length.
+ */
+static char *decode_m(struct bolt11 *b11,
+ struct hash_u5 *hu5,
+ u5 **data, size_t *data_len,
+ size_t data_length,
+ bool *have_m)
+{
+ size_t mlen = (data_length * 5) / 8;
+
+ if (*have_m)
+ return unknown_field(b11, hu5, data, data_len, 'm',
+ data_length);
+
+ b11->metadata = tal_arr(b11, u8, mlen);
+ pull_bits_certain(hu5, data, data_len, b11->metadata,
+ data_length * 5, false);
+
+ *have_m = true;
+ return NULL;
+}
+
+struct bolt11 *new_bolt11(const tal_t *ctx)
+{
+ struct bolt11 *b11 = tal(ctx, struct bolt11);
+
+ list_head_init(&b11->extra_fields);
+ b11->description = NULL;
+ b11->description_hash = NULL;
+ b11->fallbacks = NULL;
+ b11->msat = NULL;
+ b11->expiry = DEFAULT_X;
+ b11->features = tal_arr(b11, u8, 0);
+ /* BOLT #11:
+ * - if the `c` field (`min_final_cltv_expiry`) is not provided:
+ * - MUST use an expiry delta of at least 18 when making the payment
+ */
+ b11->min_final_cltv_expiry = 18;
+ //b11->payment_secret = NULL;
+ b11->metadata = NULL;
+
+ //if (msat)
+ //b11->msat = tal_dup(b11, struct amount_msat, msat);
+ return b11;
+}
+
+/* Define sha256_eq. */
+//STRUCTEQ_DEF(sha256, 0, u);
+
+/* Extracts signature but does not check it. */
+struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, u5 **sig, char **fail)
+{
+ char *hrp, *amountstr, *prefix;
+ u5 *data;
+ size_t data_len;
+ struct bolt11 *b11 = new_bolt11(ctx);
+ struct hash_u5 hu5;
+ bool have_p = false, have_d = false, have_h = false, have_n = false,
+ have_x = false, have_c = false, have_m = false;
+
+ /* BOLT #11:
+ *
+ * If a URI scheme is desired, the current recommendation is to either
+ * use 'lightning:' as a prefix before the BOLT-11 encoding
+ */
+ if (strstarts(str, "lightning:") || strstarts(str, "LIGHTNING:"))
+ str += strlen("lightning:");
+
+ if (strlen(str) < 8)
+ return decode_fail(b11, fail, "Bad bech32 string");
+
+ hrp = tal_arr(b11, char, strlen(str) - 6);
+ data = tal_arr(b11, u5, strlen(str) - 8);
+
+ if (bech32_decode(hrp, data, &data_len, str, (size_t)-1)
+ != BECH32_ENCODING_BECH32)
+ return decode_fail(b11, fail, "Bad bech32 string");
+
+ /* For signature checking at the end. */
+ hash_u5_init(&hu5, hrp);
+
+ /* BOLT #11:
+ *
+ * The human-readable part of a Lightning invoice consists of two sections:
+ * 1. `prefix`: `ln` + BIP-0173 currency prefix (e.g. `lnbc` for Bitcoin mainnet,
+ * `lntb` for Bitcoin testnet, `lntbs` for Bitcoin signet, and `lnbcrt` for Bitcoin regtest)
+ * 1. `amount`: optional number in that currency, followed by an optional
+ * `multiplier` letter. The unit encoded here is the 'social' convention of a payment unit -- in the case of Bitcoin the unit is 'bitcoin' NOT satoshis.
+ */
+ prefix = tal_strndup(b11, hrp, strcspn(hrp, "0123456789"));
+
+ /* BOLT #11:
+ *
+ * A reader...if it does NOT understand the `prefix`... MUST fail the payment.
+ */
+ if (!strstarts(prefix, "ln"))
+ return decode_fail(b11, fail,
+ "Prefix '%s' does not start with ln", prefix);
+
+ /* BOLT #11:
+ *
+ * - if the `amount` is empty:
+ * */
+ amountstr = tal_strdup(b11, hrp + strlen(prefix));
+ if (streq(amountstr, "")) {
+ /* BOLT #11:
+ *
+ * - SHOULD indicate to the payer that amount is unspecified.
+ */
+ b11->msat = NULL;
+ } else {
+ u64 m10 = 10 * MSAT_PER_BTC; /* Pico satoshis in a Bitcoin */
+ u64 amount;
+ char *end;
+
+ /* Gather and trim multiplier */
+ end = amountstr + strlen(amountstr)-1;
+ for (size_t i = 0; i < ARRAY_SIZE(multipliers); i++) {
+ if (*end == multipliers[i].letter) {
+ m10 = multipliers[i].m10;
+ *end = '\0';
+ break;
+ }
+ }
+
+ /* BOLT #11:
+ *
+ * if `amount` contains a non-digit OR is followed by
+ * anything except a `multiplier` (see table above)... MUST fail the
+ * payment.
+ **/
+ amount = strtoull(amountstr, &end, 10);
+ if (amount == ULLONG_MAX && errno == ERANGE)
+ return decode_fail(b11, fail,
+ "Invalid amount '%s'", amountstr);
+ if (!*amountstr || *end)
+ return decode_fail(b11, fail,
+ "Invalid amount postfix '%s'", end);
+
+ /* BOLT #11:
+ *
+ * if the `multiplier` is present... MUST multiply
+ * `amount` by the `multiplier` value to derive the
+ * amount required for payment.
+ */
+ b11->msat = tal(b11, struct amount_msat);
+ /* BOLT #11:
+ *
+ * - if multiplier is `p` and the last decimal of `amount` is
+ * not 0:
+ * - MUST fail the payment.
+ */
+ if (amount * m10 % 10 != 0)
+ return decode_fail(b11, fail,
+ "Invalid sub-millisatoshi amount"
+ " '%sp'", amountstr);
+
+ *b11->msat = amount_msat(amount * m10 / 10);
+ }
+
+ /* BOLT #11:
+ *
+ * The data part of a Lightning invoice consists of multiple sections:
+ *
+ * 1. `timestamp`: seconds-since-1970 (35 bits, big-endian)
+ * 1. zero or more tagged parts
+ * 1. `signature`: Bitcoin-style signature of above (520 bits)
+ */
+ if (!pull_uint(&hu5, &data, &data_len, &b11->timestamp, 35))
+ return decode_fail(b11, fail, "Can't get 35-bit timestamp");
+
+ while (data_len > 520 / 5) {
+ const char *problem = NULL;
+ u64 type, data_length;
+
+ /* BOLT #11:
+ *
+ * Each Tagged Field is of the form:
+ *
+ * 1. `type` (5 bits)
+ * 1. `data_length` (10 bits, big-endian)
+ * 1. `data` (`data_length` x 5 bits)
+ */
+ if (!pull_uint(&hu5, &data, &data_len, &type, 5)
+ || !pull_uint(&hu5, &data, &data_len, &data_length, 10))
+ return decode_fail(b11, fail,
+ "Can't get tag and length");
+
+ /* Can't exceed total data remaining. */
+ if (data_length > data_len)
+ return decode_fail(b11, fail, "%c: truncated",
+ bech32_charset[type]);
+
+ switch (bech32_charset[type]) {
+ case 'p':
+ decode_p(b11, &hu5, &data, &data_len, data_length,
+ &have_p);
+ break;
+
+ case 'd':
+ problem = decode_d(b11, &hu5, &data, &data_len,
+ data_length, &have_d);
+ break;
+
+ case 'h':
+ decode_h(b11, &hu5, &data, &data_len, data_length,
+ &have_h);
+ break;
+
+ case 'n':
+ problem = decode_n(b11, &hu5, &data,
+ &data_len, data_length,
+ have_n);
+ break;
+
+ case 'x':
+ problem = decode_x(b11, &hu5, &data,
+ &data_len, data_length,
+ &have_x);
+ break;
+
+ case 'c':
+ problem = decode_c(b11, &hu5, &data,
+ &data_len, data_length,
+ &have_c);
+ break;
+
+ /*
+ case 'f':
+ problem = decode_f(b11, &hu5, &data,
+ &data_len, data_length);
+ break;
+ case 'r':
+ problem = decode_r(b11, &hu5, &data, &data_len,
+ data_length);
+ break;
+ case '9':
+ problem = decode_9(b11, our_features, &hu5,
+ &data, &data_len,
+ data_length);
+ break;
+ case 's':
+ problem = decode_s(b11, &hu5, &data, &data_len,
+ data_length, &have_s);
+ break;
+ */
+ case 'm':
+ problem = decode_m(b11, &hu5, &data, &data_len,
+ data_length, &have_m);
+ break;
+ default:
+ unknown_field(b11, &hu5, &data, &data_len,
+ bech32_charset[type], data_length);
+ }
+ if (problem)
+ return decode_fail(b11, fail, "%s", problem);
+ }
+
+ if (!have_p)
+ return decode_fail(b11, fail, "No valid 'p' field found");
+
+ *sig = tal_dup_arr(ctx, u5, data, data_len, 0);
+ return b11;
+}
+
+/* Decodes and checks signature; returns NULL on error. */
+struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str, char **fail)
+{
+ u5 *sigdata;
+ size_t data_len;
+ u8 sig_and_recid[65];
+ //secp256k1_ecdsa_recoverable_signature sig;
+ struct bolt11 *b11;
+
+ b11 = bolt11_decode_nosig(ctx, str, &sigdata, fail);
+ if (!b11)
+ return NULL;
+
+ /* BOLT #11:
+ *
+ * A writer...MUST set `signature` to a valid 512-bit
+ * secp256k1 signature of the SHA2 256-bit hash of the
+ * human-readable part, represented as UTF-8 bytes,
+ * concatenated with the data part (excluding the signature)
+ * with 0 bits appended to pad the data to the next byte
+ * boundary, with a trailing byte containing the recovery ID
+ * (0, 1, 2, or 3).
+ */
+ data_len = tal_count(sigdata);
+ if (!pull_bits(NULL, &sigdata, &data_len, sig_and_recid, 520, false))
+ return decode_fail(b11, fail, "signature truncated");
+
+ assert(data_len == 0);
+
+ /*
+ if (!secp256k1_ecdsa_recoverable_signature_parse_compact
+ (secp256k1_ctx, &sig, sig_and_recid, sig_and_recid[64]))
+ return decode_fail(b11, fail, "signature invalid");
+
+ secp256k1_ecdsa_recoverable_signature_convert(secp256k1_ctx,
+ &b11->sig, &sig);
+ */
+
+ /* BOLT #11:
+ *
+ * A reader... MUST check that the `signature` is valid (see
+ * the `n` tagged field specified below). ... A reader...
+ * MUST use the `n` field to validate the signature instead of
+ * performing signature recovery.
+ */
+ /*
+ if (!have_n) {
+ struct pubkey k;
+ if (!secp256k1_ecdsa_recover(secp256k1_ctx,
+ &k.pubkey,
+ &sig,
+ (const u8 *)&hash))
+ return decode_fail(b11, fail,
+ "signature recovery failed");
+ node_id_from_pubkey(&b11->receiver_id, &k);
+ } else {
+ struct pubkey k;
+ if (!pubkey_from_node_id(&k, &b11->receiver_id))
+ abort();
+ if (!secp256k1_ecdsa_verify(secp256k1_ctx, &b11->sig,
+ (const u8 *)&hash,
+ &k.pubkey))
+ return decode_fail(b11, fail, "invalid signature");
+ }
+ */
+
+ return b11;
+}
diff --git a/damus-c/bolt11.h b/damus-c/bolt11.h
@@ -0,0 +1,104 @@
+#ifndef LIGHTNING_COMMON_BOLT11_H
+#define LIGHTNING_COMMON_BOLT11_H
+
+#include "short_types.h"
+#include "hash_u5.h"
+#include "list.h"
+#include "node_id.h"
+//#include <secp256k1_recovery.h>
+
+/* We only have 10 bits for the field length, meaning < 640 bytes */
+#define BOLT11_FIELD_BYTE_LIMIT ((1 << 10) * 5 / 8)
+
+/* BOLT #11:
+ * * `c` (24): `data_length` variable.
+ * `min_final_cltv_expiry` to use for the last HTLC in the route.
+ * Default is 18 if not specified.
+ */
+#define DEFAULT_FINAL_CLTV_DELTA 18
+
+struct feature_set;
+
+struct bolt11_field {
+ struct list_node list;
+
+ char tag;
+ u5 *data;
+};
+
+/* BOLT #11:
+ * * `pubkey` (264 bits)
+ * * `short_channel_id` (64 bits)
+ * * `fee_base_msat` (32 bits, big-endian)
+ * * `fee_proportional_millionths` (32 bits, big-endian)
+ * * `cltv_expiry_delta` (16 bits, big-endian)
+ */
+
+/*
+struct route_info {
+ struct node_id pubkey;
+ u16 cltv_expiry_delta;
+ struct short_channel_id short_channel_id;
+ u32 fee_base_msat, fee_proportional_millionths;
+};
+ */
+
+struct bolt11 {
+ const struct chainparams *chain;
+ u64 timestamp;
+ struct amount_msat *msat; /* NULL if not specified. */
+
+ struct sha256 payment_hash;
+ struct node_id receiver_id;
+
+ /* description_hash valid if and only if description is NULL. */
+ const char *description;
+ struct sha256 *description_hash;
+
+ /* How many seconds to pay from @timestamp above. */
+ u64 expiry;
+
+ /* How many blocks final hop requires. */
+ u32 min_final_cltv_expiry;
+
+ /* If non-NULL, indicates fallback addresses to pay to. */
+ const u8 **fallbacks;
+
+ /* If non-NULL: array of route arrays */
+ //struct route_info **routes;
+
+ /* signature of sha256 of entire thing. */
+ //secp256k1_ecdsa_signature sig;
+
+ /* payment secret, if any. */
+ //struct secret *payment_secret;
+
+ /* Features bitmap, if any. */
+ u8 *features;
+
+ /* Optional metadata to send with payment. */
+ u8 *metadata;
+
+ struct list_head extra_fields;
+};
+
+/* Decodes and checks signature; returns NULL on error; description is
+ * (optional) out-of-band description of payment, for `h` field.
+ * fset is NULL to accept any features (usually not desirable!).
+ *
+ * if @must_be_chain is not NULL, fails unless it's this chain.
+ */
+struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str, char **fail);
+
+/* Extracts signature but does not check it. */
+struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, u5 **sigdata, char **fail);
+
+/* Initialize an empty bolt11 struct with optional amount */
+struct bolt11 *new_bolt11(const tal_t *ctx);
+
+#if DEVELOPER
+/* Flag for tests to suppress `min_final_cltv_expiry` field generation, to match test vectors */
+extern bool dev_bolt11_no_c_generation;
+#endif
+
+#endif /* LIGHTNING_COMMON_BOLT11_H */
diff --git a/damus-c/build_assert.h b/damus-c/build_assert.h
@@ -0,0 +1,40 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_BUILD_ASSERT_H
+#define CCAN_BUILD_ASSERT_H
+
+/**
+ * BUILD_ASSERT - assert a build-time dependency.
+ * @cond: the compile-time condition which must be true.
+ *
+ * Your compile will fail if the condition isn't true, or can't be evaluated
+ * by the compiler. This can only be used within a function.
+ *
+ * Example:
+ * #include <stddef.h>
+ * ...
+ * static char *foo_to_char(struct foo *foo)
+ * {
+ * // This code needs string to be at start of foo.
+ * BUILD_ASSERT(offsetof(struct foo, string) == 0);
+ * return (char *)foo;
+ * }
+ */
+#define BUILD_ASSERT(cond) \
+ do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
+
+/**
+ * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
+ * @cond: the compile-time condition which must be true.
+ *
+ * Your compile will fail if the condition isn't true, or can't be evaluated
+ * by the compiler. This can be used in an expression: its value is "0".
+ *
+ * Example:
+ * #define foo_to_char(foo) \
+ * ((char *)(foo) \
+ * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
+ */
+#define BUILD_ASSERT_OR_ZERO(cond) \
+ (sizeof(char [1 - 2*!(cond)]) - 1)
+
+#endif /* CCAN_BUILD_ASSERT_H */
diff --git a/damus-c/check_type.h b/damus-c/check_type.h
@@ -0,0 +1,64 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_CHECK_TYPE_H
+#define CCAN_CHECK_TYPE_H
+#include "config.h"
+
+/**
+ * check_type - issue a warning or build failure if type is not correct.
+ * @expr: the expression whose type we should check (not evaluated).
+ * @type: the exact type we expect the expression to be.
+ *
+ * This macro is usually used within other macros to try to ensure that a macro
+ * argument is of the expected type. No type promotion of the expression is
+ * done: an unsigned int is not the same as an int!
+ *
+ * check_type() always evaluates to 0.
+ *
+ * If your compiler does not support typeof, then the best we can do is fail
+ * to compile if the sizes of the types are unequal (a less complete check).
+ *
+ * Example:
+ * // They should always pass a 64-bit value to _set_some_value!
+ * #define set_some_value(expr) \
+ * _set_some_value((check_type((expr), uint64_t), (expr)))
+ */
+
+/**
+ * check_types_match - issue a warning or build failure if types are not same.
+ * @expr1: the first expression (not evaluated).
+ * @expr2: the second expression (not evaluated).
+ *
+ * This macro is usually used within other macros to try to ensure that
+ * arguments are of identical types. No type promotion of the expressions is
+ * done: an unsigned int is not the same as an int!
+ *
+ * check_types_match() always evaluates to 0.
+ *
+ * If your compiler does not support typeof, then the best we can do is fail
+ * to compile if the sizes of the types are unequal (a less complete check).
+ *
+ * Example:
+ * // Do subtraction to get to enclosing type, but make sure that
+ * // pointer is of correct type for that member.
+ * #define container_of(mbr_ptr, encl_type, mbr) \
+ * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
+ * ((encl_type *) \
+ * ((char *)(mbr_ptr) - offsetof(encl_type, mbr))))
+ */
+#if HAVE_TYPEOF
+#define check_type(expr, type) \
+ ((typeof(expr) *)0 != (type *)0)
+
+#define check_types_match(expr1, expr2) \
+ ((typeof(expr1) *)0 != (typeof(expr2) *)0)
+#else
+#include <ccan/build_assert/build_assert.h>
+/* Without typeof, we can only test the sizes. */
+#define check_type(expr, type) \
+ BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type))
+
+#define check_types_match(expr1, expr2) \
+ BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2))
+#endif /* HAVE_TYPEOF */
+
+#endif /* CCAN_CHECK_TYPE_H */
diff --git a/damus-c/compiler.h b/damus-c/compiler.h
@@ -0,0 +1,317 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_COMPILER_H
+#define CCAN_COMPILER_H
+#include "config.h"
+
+#ifndef COLD
+#if HAVE_ATTRIBUTE_COLD
+/**
+ * COLD - a function is unlikely to be called.
+ *
+ * Used to mark an unlikely code path and optimize appropriately.
+ * It is usually used on logging or error routines.
+ *
+ * Example:
+ * static void COLD moan(const char *reason)
+ * {
+ * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
+ * }
+ */
+#define COLD __attribute__((__cold__))
+#else
+#define COLD
+#endif
+#endif
+
+#ifndef NORETURN
+#if HAVE_ATTRIBUTE_NORETURN
+/**
+ * NORETURN - a function does not return
+ *
+ * Used to mark a function which exits; useful for suppressing warnings.
+ *
+ * Example:
+ * static void NORETURN fail(const char *reason)
+ * {
+ * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
+ * exit(1);
+ * }
+ */
+#define NORETURN __attribute__((__noreturn__))
+#else
+#define NORETURN
+#endif
+#endif
+
+#ifndef PRINTF_FMT
+#if HAVE_ATTRIBUTE_PRINTF
+/**
+ * PRINTF_FMT - a function takes printf-style arguments
+ * @nfmt: the 1-based number of the function's format argument.
+ * @narg: the 1-based number of the function's first variable argument.
+ *
+ * This allows the compiler to check your parameters as it does for printf().
+ *
+ * Example:
+ * void PRINTF_FMT(2,3) my_printf(const char *prefix, const char *fmt, ...);
+ */
+#define PRINTF_FMT(nfmt, narg) \
+ __attribute__((format(__printf__, nfmt, narg)))
+#else
+#define PRINTF_FMT(nfmt, narg)
+#endif
+#endif
+
+#ifndef CONST_FUNCTION
+#if HAVE_ATTRIBUTE_CONST
+/**
+ * CONST_FUNCTION - a function's return depends only on its argument
+ *
+ * This allows the compiler to assume that the function will return the exact
+ * same value for the exact same arguments. This implies that the function
+ * must not use global variables, or dereference pointer arguments.
+ */
+#define CONST_FUNCTION __attribute__((__const__))
+#else
+#define CONST_FUNCTION
+#endif
+
+#ifndef PURE_FUNCTION
+#if HAVE_ATTRIBUTE_PURE
+/**
+ * PURE_FUNCTION - a function is pure
+ *
+ * A pure function is one that has no side effects other than it's return value
+ * and uses no inputs other than it's arguments and global variables.
+ */
+#define PURE_FUNCTION __attribute__((__pure__))
+#else
+#define PURE_FUNCTION
+#endif
+#endif
+#endif
+
+#if HAVE_ATTRIBUTE_UNUSED
+#ifndef UNNEEDED
+/**
+ * UNNEEDED - a variable/function may not be needed
+ *
+ * This suppresses warnings about unused variables or functions, but tells
+ * the compiler that if it is unused it need not emit it into the source code.
+ *
+ * Example:
+ * // With some preprocessor options, this is unnecessary.
+ * static UNNEEDED int counter;
+ *
+ * // With some preprocessor options, this is unnecessary.
+ * static UNNEEDED void add_to_counter(int add)
+ * {
+ * counter += add;
+ * }
+ */
+#define UNNEEDED __attribute__((__unused__))
+#endif
+
+#ifndef NEEDED
+#if HAVE_ATTRIBUTE_USED
+/**
+ * NEEDED - a variable/function is needed
+ *
+ * This suppresses warnings about unused variables or functions, but tells
+ * the compiler that it must exist even if it (seems) unused.
+ *
+ * Example:
+ * // Even if this is unused, these are vital for debugging.
+ * static NEEDED int counter;
+ * static NEEDED void dump_counter(void)
+ * {
+ * printf("Counter is %i\n", counter);
+ * }
+ */
+#define NEEDED __attribute__((__used__))
+#else
+/* Before used, unused functions and vars were always emitted. */
+#define NEEDED __attribute__((__unused__))
+#endif
+#endif
+
+#ifndef UNUSED
+/**
+ * UNUSED - a parameter is unused
+ *
+ * Some compilers (eg. gcc with -W or -Wunused) warn about unused
+ * function parameters. This suppresses such warnings and indicates
+ * to the reader that it's deliberate.
+ *
+ * Example:
+ * // This is used as a callback, so needs to have this prototype.
+ * static int some_callback(void *unused UNUSED)
+ * {
+ * return 0;
+ * }
+ */
+#define UNUSED __attribute__((__unused__))
+#endif
+#else
+#ifndef UNNEEDED
+#define UNNEEDED
+#endif
+#ifndef NEEDED
+#define NEEDED
+#endif
+#ifndef UNUSED
+#define UNUSED
+#endif
+#endif
+
+#ifndef IS_COMPILE_CONSTANT
+#if HAVE_BUILTIN_CONSTANT_P
+/**
+ * IS_COMPILE_CONSTANT - does the compiler know the value of this expression?
+ * @expr: the expression to evaluate
+ *
+ * When an expression manipulation is complicated, it is usually better to
+ * implement it in a function. However, if the expression being manipulated is
+ * known at compile time, it is better to have the compiler see the entire
+ * expression so it can simply substitute the result.
+ *
+ * This can be done using the IS_COMPILE_CONSTANT() macro.
+ *
+ * Example:
+ * enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON };
+ *
+ * // Out-of-line version.
+ * const char *greek_name(enum greek greek);
+ *
+ * // Inline version.
+ * static inline const char *_greek_name(enum greek greek)
+ * {
+ * switch (greek) {
+ * case ALPHA: return "alpha";
+ * case BETA: return "beta";
+ * case GAMMA: return "gamma";
+ * case DELTA: return "delta";
+ * case EPSILON: return "epsilon";
+ * default: return "**INVALID**";
+ * }
+ * }
+ *
+ * // Use inline if compiler knows answer. Otherwise call function
+ * // to avoid copies of the same code everywhere.
+ * #define greek_name(g) \
+ * (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g))
+ */
+#define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr)
+#else
+/* If we don't know, assume it's not. */
+#define IS_COMPILE_CONSTANT(expr) 0
+#endif
+#endif
+
+#ifndef WARN_UNUSED_RESULT
+#if HAVE_WARN_UNUSED_RESULT
+/**
+ * WARN_UNUSED_RESULT - warn if a function return value is unused.
+ *
+ * Used to mark a function where it is extremely unlikely that the caller
+ * can ignore the result, eg realloc().
+ *
+ * Example:
+ * // buf param may be freed by this; need return value!
+ * static char *WARN_UNUSED_RESULT enlarge(char *buf, unsigned *size)
+ * {
+ * return realloc(buf, (*size) *= 2);
+ * }
+ */
+#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+#else
+#define WARN_UNUSED_RESULT
+#endif
+#endif
+
+
+#if HAVE_ATTRIBUTE_DEPRECATED
+/**
+ * WARN_DEPRECATED - warn that a function/type/variable is deprecated when used.
+ *
+ * Used to mark a function, type or variable should not be used.
+ *
+ * Example:
+ * WARN_DEPRECATED char *oldfunc(char *buf);
+ */
+#define WARN_DEPRECATED __attribute__((__deprecated__))
+#else
+#define WARN_DEPRECATED
+#endif
+
+
+#if HAVE_ATTRIBUTE_NONNULL
+/**
+ * NO_NULL_ARGS - specify that no arguments to this function can be NULL.
+ *
+ * The compiler will warn if any pointer args are NULL.
+ *
+ * Example:
+ * NO_NULL_ARGS char *my_copy(char *buf);
+ */
+#define NO_NULL_ARGS __attribute__((__nonnull__))
+
+/**
+ * NON_NULL_ARGS - specify that some arguments to this function can't be NULL.
+ * @...: 1-based argument numbers for which args can't be NULL.
+ *
+ * The compiler will warn if any of the specified pointer args are NULL.
+ *
+ * Example:
+ * char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1);
+ */
+#define NON_NULL_ARGS(...) __attribute__((__nonnull__(__VA_ARGS__)))
+#else
+#define NO_NULL_ARGS
+#define NON_NULL_ARGS(...)
+#endif
+
+#if HAVE_ATTRIBUTE_RETURNS_NONNULL
+/**
+ * RETURNS_NONNULL - specify that this function cannot return NULL.
+ *
+ * Mainly an optimization opportunity, but can also suppress warnings.
+ *
+ * Example:
+ * RETURNS_NONNULL char *my_copy(char *buf);
+ */
+#define RETURNS_NONNULL __attribute__((__returns_nonnull__))
+#else
+#define RETURNS_NONNULL
+#endif
+
+#if HAVE_ATTRIBUTE_SENTINEL
+/**
+ * LAST_ARG_NULL - specify the last argument of a variadic function must be NULL.
+ *
+ * The compiler will warn if the last argument isn't NULL.
+ *
+ * Example:
+ * char *join_string(char *buf, ...) LAST_ARG_NULL;
+ */
+#define LAST_ARG_NULL __attribute__((__sentinel__))
+#else
+#define LAST_ARG_NULL
+#endif
+
+#if HAVE_BUILTIN_CPU_SUPPORTS
+/**
+ * cpu_supports - test if current CPU supports the named feature.
+ *
+ * This takes a literal string, and currently only works on glibc platforms.
+ *
+ * Example:
+ * if (cpu_supports("mmx"))
+ * printf("MMX support engaged!\n");
+ */
+#define cpu_supports(x) __builtin_cpu_supports(x)
+#else
+#define cpu_supports(x) 0
+#endif /* HAVE_BUILTIN_CPU_SUPPORTS */
+
+#endif /* CCAN_COMPILER_H */
diff --git a/damus-c/config.h b/damus-c/config.h
@@ -0,0 +1,18 @@
+/* Generated by CCAN configurator */
+#ifndef CCAN_CONFIG_H
+#define CCAN_CONFIG_H
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE /* Always use GNU extensions. */
+#endif
+#define CCAN_COMPILER "cc"
+#define CCAN_CFLAGS "-g3 -ggdb -Wall -Wundef -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes -Wold-style-definition"
+#define CCAN_OUTPUT_EXE_CFLAG "-o"
+
+#define HAVE_CCAN 1
+#define HAVE_UNALIGNED_ACCESS 1
+#define HAVE_TYPEOF 1
+#define HAVE_BIG_ENDIAN 0
+#define HAVE_BYTESWAP_H 0
+#define HAVE_BSWAP_64 0
+#define HAVE_LITTLE_ENDIAN 1
+#endif /* CCAN_CONFIG_H */
diff --git a/damus-c/container_of.h b/damus-c/container_of.h
@@ -0,0 +1,145 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_CONTAINER_OF_H
+#define CCAN_CONTAINER_OF_H
+#include <stddef.h>
+
+#include "config.h"
+#include "check_type.h"
+
+/**
+ * container_of - get pointer to enclosing structure
+ * @member_ptr: pointer to the structure member
+ * @containing_type: the type this member is within
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does pointer
+ * subtraction to return the pointer to the enclosing type.
+ *
+ * Example:
+ * struct foo {
+ * int fielda, fieldb;
+ * // ...
+ * };
+ * struct info {
+ * int some_other_field;
+ * struct foo my_foo;
+ * };
+ *
+ * static struct info *foo_to_info(struct foo *foo)
+ * {
+ * return container_of(foo, struct info, my_foo);
+ * }
+ */
+#define container_of(member_ptr, containing_type, member) \
+ ((containing_type *) \
+ ((char *)(member_ptr) \
+ - container_off(containing_type, member)) \
+ + check_types_match(*(member_ptr), ((containing_type *)0)->member))
+
+
+/**
+ * container_of_or_null - get pointer to enclosing structure, or NULL
+ * @member_ptr: pointer to the structure member
+ * @containing_type: the type this member is within
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does pointer
+ * subtraction to return the pointer to the enclosing type, unless it
+ * is given NULL, in which case it also returns NULL.
+ *
+ * Example:
+ * struct foo {
+ * int fielda, fieldb;
+ * // ...
+ * };
+ * struct info {
+ * int some_other_field;
+ * struct foo my_foo;
+ * };
+ *
+ * static struct info *foo_to_info_allowing_null(struct foo *foo)
+ * {
+ * return container_of_or_null(foo, struct info, my_foo);
+ * }
+ */
+static inline char *container_of_or_null_(void *member_ptr, size_t offset)
+{
+ return member_ptr ? (char *)member_ptr - offset : NULL;
+}
+#define container_of_or_null(member_ptr, containing_type, member) \
+ ((containing_type *) \
+ container_of_or_null_(member_ptr, \
+ container_off(containing_type, member)) \
+ + check_types_match(*(member_ptr), ((containing_type *)0)->member))
+
+/**
+ * container_off - get offset to enclosing structure
+ * @containing_type: the type this member is within
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does
+ * typechecking and figures out the offset to the enclosing type.
+ *
+ * Example:
+ * struct foo {
+ * int fielda, fieldb;
+ * // ...
+ * };
+ * struct info {
+ * int some_other_field;
+ * struct foo my_foo;
+ * };
+ *
+ * static struct info *foo_to_info(struct foo *foo)
+ * {
+ * size_t off = container_off(struct info, my_foo);
+ * return (void *)((char *)foo - off);
+ * }
+ */
+#define container_off(containing_type, member) \
+ offsetof(containing_type, member)
+
+/**
+ * container_of_var - get pointer to enclosing structure using a variable
+ * @member_ptr: pointer to the structure member
+ * @container_var: a pointer of same type as this member's container
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does pointer
+ * subtraction to return the pointer to the enclosing type.
+ *
+ * Example:
+ * static struct info *foo_to_i(struct foo *foo)
+ * {
+ * struct info *i = container_of_var(foo, i, my_foo);
+ * return i;
+ * }
+ */
+#if HAVE_TYPEOF
+#define container_of_var(member_ptr, container_var, member) \
+ container_of(member_ptr, typeof(*container_var), member)
+#else
+#define container_of_var(member_ptr, container_var, member) \
+ ((void *)((char *)(member_ptr) - \
+ container_off_var(container_var, member)))
+#endif
+
+/**
+ * container_off_var - get offset of a field in enclosing structure
+ * @container_var: a pointer to a container structure
+ * @member: the name of a member within the structure.
+ *
+ * Given (any) pointer to a structure and a its member name, this
+ * macro does pointer subtraction to return offset of member in a
+ * structure memory layout.
+ *
+ */
+#if HAVE_TYPEOF
+#define container_off_var(var, member) \
+ container_off(typeof(*var), member)
+#else
+#define container_off_var(var, member) \
+ ((const char *)&(var)->member - (const char *)(var))
+#endif
+
+#endif /* CCAN_CONTAINER_OF_H */
diff --git a/damus-c/cppmagic.h b/damus-c/cppmagic.h
@@ -0,0 +1,191 @@
+/* MIT (BSD) license - see LICENSE file for details */
+#ifndef CCAN_CPPMAGIC_H
+#define CCAN_CPPMAGIC_H
+
+/**
+ * CPPMAGIC_NOTHING - expands to nothing
+ */
+#define CPPMAGIC_NOTHING()
+
+/**
+ * CPPMAGIC_STRINGIFY - convert arguments to a string literal
+ */
+#define _CPPMAGIC_STRINGIFY(...) #__VA_ARGS__
+#define CPPMAGIC_STRINGIFY(...) _CPPMAGIC_STRINGIFY(__VA_ARGS__)
+
+/**
+ * CPPMAGIC_GLUE2 - glue arguments together
+ *
+ * CPPMAGIC_GLUE2(@a_, @b_)
+ * expands to the expansion of @a_ followed immediately
+ * (combining tokens) by the expansion of @b_
+ */
+#define _CPPMAGIC_GLUE2(a_, b_) a_##b_
+#define CPPMAGIC_GLUE2(a_, b_) _CPPMAGIC_GLUE2(a_, b_)
+
+/**
+ * CPPMAGIC_1ST - return 1st argument
+ *
+ * CPPMAGIC_1ST(@a_, ...)
+ * expands to the expansion of @a_
+ */
+#define CPPMAGIC_1ST(a_, ...) a_
+
+/**
+ * CPPMAGIC_2ND - return 2nd argument
+ *
+ * CPPMAGIC_2ST(@a_, @b_, ...)
+ * expands to the expansion of @b_
+ */
+#define CPPMAGIC_2ND(a_, b_, ...) b_
+
+/**
+ * CPPMAGIC_ISZERO - is argument '0'
+ *
+ * CPPMAGIC_ISZERO(@a)
+ * expands to '1' if @a is '0', otherwise expands to '0'.
+ */
+#define _CPPMAGIC_ISPROBE(...) CPPMAGIC_2ND(__VA_ARGS__, 0)
+#define _CPPMAGIC_PROBE() $, 1
+#define _CPPMAGIC_ISZERO_0 _CPPMAGIC_PROBE()
+#define CPPMAGIC_ISZERO(a_) \
+ _CPPMAGIC_ISPROBE(CPPMAGIC_GLUE2(_CPPMAGIC_ISZERO_, a_))
+
+/**
+ * CPPMAGIC_NONZERO - is argument not '0'
+ *
+ * CPPMAGIC_NONZERO(@a)
+ * expands to '0' if @a is '0', otherwise expands to '1'.
+ */
+#define CPPMAGIC_NONZERO(a_) CPPMAGIC_ISZERO(CPPMAGIC_ISZERO(a_))
+
+/**
+ * CPPMAGIC_NONEMPTY - does the macro have any arguments?
+ *
+ * CPPMAGIC_NONEMPTY()
+ * expands to '0'
+ * CPPMAGIC_NONEMPTY(@a)
+ * CPPMAGIC_NONEMPTY(@a, ...)
+ * expand to '1'
+ */
+#define _CPPMAGIC_EOA() 0
+#define CPPMAGIC_NONEMPTY(...) \
+ CPPMAGIC_NONZERO(CPPMAGIC_1ST(_CPPMAGIC_EOA __VA_ARGS__)())
+
+/**
+ * CPPMAGIC_ISEMPTY - does the macro have no arguments?
+ *
+ * CPPMAGIC_ISEMPTY()
+ * expands to '1'
+ * CPPMAGIC_ISEMPTY(@a)
+ * CPPMAGIC_ISEMPTY(@a, ...)
+ * expand to '0'
+ */
+#define CPPMAGIC_ISEMPTY(...) \
+ CPPMAGIC_ISZERO(CPPMAGIC_NONEMPTY(__VA_ARGS__))
+
+/*
+ * CPPMAGIC_IFELSE - preprocessor conditional
+ *
+ * CPPMAGIC_IFELSE(@cond)(@if)(@else)
+ * expands to @else if @cond is '0', otherwise expands to @if
+ */
+#define _CPPMAGIC_IF_0(...) _CPPMAGIC_IF_0_ELSE
+#define _CPPMAGIC_IF_1(...) __VA_ARGS__ _CPPMAGIC_IF_1_ELSE
+#define _CPPMAGIC_IF_0_ELSE(...) __VA_ARGS__
+#define _CPPMAGIC_IF_1_ELSE(...)
+#define _CPPMAGIC_IFELSE(cond_) CPPMAGIC_GLUE2(_CPPMAGIC_IF_, cond_)
+#define CPPMAGIC_IFELSE(cond_) \
+ _CPPMAGIC_IFELSE(CPPMAGIC_NONZERO(cond_))
+
+/**
+ * CPPMAGIC_EVAL - force multiple expansion passes
+ *
+ * Forces macros in the arguments to be expanded repeatedly (up to
+ * 1024 times) even when CPP would usually stop expanding.
+ */
+#define CPPMAGIC_EVAL1(...) __VA_ARGS__
+#define CPPMAGIC_EVAL2(...) \
+ CPPMAGIC_EVAL1(CPPMAGIC_EVAL1(__VA_ARGS__))
+#define CPPMAGIC_EVAL4(...) \
+ CPPMAGIC_EVAL2(CPPMAGIC_EVAL2(__VA_ARGS__))
+#define CPPMAGIC_EVAL8(...) \
+ CPPMAGIC_EVAL4(CPPMAGIC_EVAL4(__VA_ARGS__))
+#define CPPMAGIC_EVAL16(...) \
+ CPPMAGIC_EVAL8(CPPMAGIC_EVAL8(__VA_ARGS__))
+#define CPPMAGIC_EVAL32(...) \
+ CPPMAGIC_EVAL16(CPPMAGIC_EVAL16(__VA_ARGS__))
+#define CPPMAGIC_EVAL64(...) \
+ CPPMAGIC_EVAL32(CPPMAGIC_EVAL32(__VA_ARGS__))
+#define CPPMAGIC_EVAL128(...) \
+ CPPMAGIC_EVAL64(CPPMAGIC_EVAL64(__VA_ARGS__))
+#define CPPMAGIC_EVAL256(...) \
+ CPPMAGIC_EVAL128(CPPMAGIC_EVAL128(__VA_ARGS__))
+#define CPPMAGIC_EVAL512(...) \
+ CPPMAGIC_EVAL256(CPPMAGIC_EVAL256(__VA_ARGS__))
+#define CPPMAGIC_EVAL1024(...) \
+ CPPMAGIC_EVAL512(CPPMAGIC_EVAL512(__VA_ARGS__))
+#define CPPMAGIC_EVAL(...) CPPMAGIC_EVAL1024(__VA_ARGS__)
+
+/**
+ * CPPMAGIC_DEFER1, CPPMAGIC_DEFER2 - defer expansion
+ */
+#define CPPMAGIC_DEFER1(a_) a_ CPPMAGIC_NOTHING()
+#define CPPMAGIC_DEFER2(a_) a_ CPPMAGIC_NOTHING CPPMAGIC_NOTHING()()
+
+/**
+ * CPPMAGIC_MAP - iterate another macro across arguments
+ * @m: name of a one argument macro
+ *
+ * CPPMAGIC_MAP(@m, @a1, @a2, ... @an)
+ * expands to the expansion of @m(@a1) , @m(@a2) , ... , @m(@an)
+ */
+#define _CPPMAGIC_MAP_() _CPPMAGIC_MAP
+#define _CPPMAGIC_MAP(m_, a_, ...) \
+ m_(a_) \
+ CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
+ (, CPPMAGIC_DEFER2(_CPPMAGIC_MAP_)()(m_, __VA_ARGS__)) \
+ ()
+#define CPPMAGIC_MAP(m_, ...) \
+ CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
+ (CPPMAGIC_EVAL(_CPPMAGIC_MAP(m_, __VA_ARGS__))) \
+ ()
+
+/**
+ * CPPMAGIC_2MAP - iterate another macro across pairs of arguments
+ * @m: name of a two argument macro
+ *
+ * CPPMAGIC_2MAP(@m, @a1, @b1, @a2, @b2, ..., @an, @bn)
+ * expands to the expansion of
+ * @m(@a1, @b1) , @m(@a2, @b2) , ... , @m(@an, @bn)
+ */
+#define _CPPMAGIC_2MAP_() _CPPMAGIC_2MAP
+#define _CPPMAGIC_2MAP(m_, a_, b_, ...) \
+ m_(a_, b_) \
+ CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
+ (, CPPMAGIC_DEFER2(_CPPMAGIC_2MAP_)()(m_, __VA_ARGS__)) \
+ ()
+#define CPPMAGIC_2MAP(m_, ...) \
+ CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
+ (CPPMAGIC_EVAL(_CPPMAGIC_2MAP(m_, __VA_ARGS__))) \
+ ()
+
+/**
+ * CPPMAGIC_JOIN - separate arguments with given delimiter
+ * @d: delimiter
+ *
+ * CPPMAGIC_JOIN(@d, @a1, @a2, ..., @an)
+ * expands to the expansion of @a1 @d @a2 @d ... @d @an
+ */
+#define _CPPMAGIC_JOIN_() _CPPMAGIC_JOIN
+#define _CPPMAGIC_JOIN(d_, a_, ...) \
+ a_ \
+ CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
+ (d_ CPPMAGIC_DEFER2(_CPPMAGIC_JOIN_)()(d_, __VA_ARGS__)) \
+ ()
+#define CPPMAGIC_JOIN(d_, ...) \
+ CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
+ (CPPMAGIC_EVAL(_CPPMAGIC_JOIN(d_, __VA_ARGS__))) \
+ ()
+
+#endif /* CCAN_CPPMAGIC_H */
diff --git a/damus-c/endian.h b/damus-c/endian.h
@@ -0,0 +1,363 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_ENDIAN_H
+#define CCAN_ENDIAN_H
+#include <stdint.h>
+#include "config.h"
+
+/**
+ * BSWAP_16 - reverse bytes in a constant uint16_t value.
+ * @val: constant value whose bytes to swap.
+ *
+ * Designed to be usable in constant-requiring initializers.
+ *
+ * Example:
+ * struct mystruct {
+ * char buf[BSWAP_16(0x1234)];
+ * };
+ */
+#define BSWAP_16(val) \
+ ((((uint16_t)(val) & 0x00ff) << 8) \
+ | (((uint16_t)(val) & 0xff00) >> 8))
+
+/**
+ * BSWAP_32 - reverse bytes in a constant uint32_t value.
+ * @val: constant value whose bytes to swap.
+ *
+ * Designed to be usable in constant-requiring initializers.
+ *
+ * Example:
+ * struct mystruct {
+ * char buf[BSWAP_32(0xff000000)];
+ * };
+ */
+#define BSWAP_32(val) \
+ ((((uint32_t)(val) & 0x000000ff) << 24) \
+ | (((uint32_t)(val) & 0x0000ff00) << 8) \
+ | (((uint32_t)(val) & 0x00ff0000) >> 8) \
+ | (((uint32_t)(val) & 0xff000000) >> 24))
+
+/**
+ * BSWAP_64 - reverse bytes in a constant uint64_t value.
+ * @val: constantvalue whose bytes to swap.
+ *
+ * Designed to be usable in constant-requiring initializers.
+ *
+ * Example:
+ * struct mystruct {
+ * char buf[BSWAP_64(0xff00000000000000ULL)];
+ * };
+ */
+#define BSWAP_64(val) \
+ ((((uint64_t)(val) & 0x00000000000000ffULL) << 56) \
+ | (((uint64_t)(val) & 0x000000000000ff00ULL) << 40) \
+ | (((uint64_t)(val) & 0x0000000000ff0000ULL) << 24) \
+ | (((uint64_t)(val) & 0x00000000ff000000ULL) << 8) \
+ | (((uint64_t)(val) & 0x000000ff00000000ULL) >> 8) \
+ | (((uint64_t)(val) & 0x0000ff0000000000ULL) >> 24) \
+ | (((uint64_t)(val) & 0x00ff000000000000ULL) >> 40) \
+ | (((uint64_t)(val) & 0xff00000000000000ULL) >> 56))
+
+#if HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+/**
+ * bswap_16 - reverse bytes in a uint16_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 4 as two bytes reversed"
+ * printf("1024 is %u as two bytes reversed\n", bswap_16(1024));
+ */
+static inline uint16_t bswap_16(uint16_t val)
+{
+ return BSWAP_16(val);
+}
+
+/**
+ * bswap_32 - reverse bytes in a uint32_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 262144 as four bytes reversed"
+ * printf("1024 is %u as four bytes reversed\n", bswap_32(1024));
+ */
+static inline uint32_t bswap_32(uint32_t val)
+{
+ return BSWAP_32(val);
+}
+#endif /* !HAVE_BYTESWAP_H */
+
+#if !HAVE_BSWAP_64
+/**
+ * bswap_64 - reverse bytes in a uint64_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 1125899906842624 as eight bytes reversed"
+ * printf("1024 is %llu as eight bytes reversed\n",
+ * (unsigned long long)bswap_64(1024));
+ */
+static inline uint64_t bswap_64(uint64_t val)
+{
+ return BSWAP_64(val);
+}
+#endif
+
+/* Needed for Glibc like endiness check */
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+
+/* Sanity check the defines. We don't handle weird endianness. */
+#if !HAVE_LITTLE_ENDIAN && !HAVE_BIG_ENDIAN
+#error "Unknown endian"
+#elif HAVE_LITTLE_ENDIAN && HAVE_BIG_ENDIAN
+#error "Can't compile for both big and little endian."
+#elif HAVE_LITTLE_ENDIAN
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#elif __BYTE_ORDER != __LITTLE_ENDIAN
+#error "__BYTE_ORDER already defined, but not equal to __LITTLE_ENDIAN"
+#endif
+#elif HAVE_BIG_ENDIAN
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER __BIG_ENDIAN
+#elif __BYTE_ORDER != __BIG_ENDIAN
+#error "__BYTE_ORDER already defined, but not equal to __BIG_ENDIAN"
+#endif
+#endif
+
+
+#ifdef __CHECKER__
+/* sparse needs forcing to remove bitwise attribute from ccan/short_types */
+#define ENDIAN_CAST __attribute__((force))
+#define ENDIAN_TYPE __attribute__((bitwise))
+#else
+#define ENDIAN_CAST
+#define ENDIAN_TYPE
+#endif
+
+typedef uint64_t ENDIAN_TYPE leint64_t;
+typedef uint64_t ENDIAN_TYPE beint64_t;
+typedef uint32_t ENDIAN_TYPE leint32_t;
+typedef uint32_t ENDIAN_TYPE beint32_t;
+typedef uint16_t ENDIAN_TYPE leint16_t;
+typedef uint16_t ENDIAN_TYPE beint16_t;
+
+#if HAVE_LITTLE_ENDIAN
+/**
+ * CPU_TO_LE64 - convert a constant uint64_t value to little-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_LE64(native) ((ENDIAN_CAST leint64_t)(native))
+
+/**
+ * CPU_TO_LE32 - convert a constant uint32_t value to little-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_LE32(native) ((ENDIAN_CAST leint32_t)(native))
+
+/**
+ * CPU_TO_LE16 - convert a constant uint16_t value to little-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_LE16(native) ((ENDIAN_CAST leint16_t)(native))
+
+/**
+ * LE64_TO_CPU - convert a little-endian uint64_t constant
+ * @le_val: little-endian constant to convert
+ */
+#define LE64_TO_CPU(le_val) ((ENDIAN_CAST uint64_t)(le_val))
+
+/**
+ * LE32_TO_CPU - convert a little-endian uint32_t constant
+ * @le_val: little-endian constant to convert
+ */
+#define LE32_TO_CPU(le_val) ((ENDIAN_CAST uint32_t)(le_val))
+
+/**
+ * LE16_TO_CPU - convert a little-endian uint16_t constant
+ * @le_val: little-endian constant to convert
+ */
+#define LE16_TO_CPU(le_val) ((ENDIAN_CAST uint16_t)(le_val))
+
+#else /* ... HAVE_BIG_ENDIAN */
+#define CPU_TO_LE64(native) ((ENDIAN_CAST leint64_t)BSWAP_64(native))
+#define CPU_TO_LE32(native) ((ENDIAN_CAST leint32_t)BSWAP_32(native))
+#define CPU_TO_LE16(native) ((ENDIAN_CAST leint16_t)BSWAP_16(native))
+#define LE64_TO_CPU(le_val) BSWAP_64((ENDIAN_CAST uint64_t)le_val)
+#define LE32_TO_CPU(le_val) BSWAP_32((ENDIAN_CAST uint32_t)le_val)
+#define LE16_TO_CPU(le_val) BSWAP_16((ENDIAN_CAST uint16_t)le_val)
+#endif /* HAVE_BIG_ENDIAN */
+
+#if HAVE_BIG_ENDIAN
+/**
+ * CPU_TO_BE64 - convert a constant uint64_t value to big-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_BE64(native) ((ENDIAN_CAST beint64_t)(native))
+
+/**
+ * CPU_TO_BE32 - convert a constant uint32_t value to big-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_BE32(native) ((ENDIAN_CAST beint32_t)(native))
+
+/**
+ * CPU_TO_BE16 - convert a constant uint16_t value to big-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_BE16(native) ((ENDIAN_CAST beint16_t)(native))
+
+/**
+ * BE64_TO_CPU - convert a big-endian uint64_t constant
+ * @le_val: big-endian constant to convert
+ */
+#define BE64_TO_CPU(le_val) ((ENDIAN_CAST uint64_t)(le_val))
+
+/**
+ * BE32_TO_CPU - convert a big-endian uint32_t constant
+ * @le_val: big-endian constant to convert
+ */
+#define BE32_TO_CPU(le_val) ((ENDIAN_CAST uint32_t)(le_val))
+
+/**
+ * BE16_TO_CPU - convert a big-endian uint16_t constant
+ * @le_val: big-endian constant to convert
+ */
+#define BE16_TO_CPU(le_val) ((ENDIAN_CAST uint16_t)(le_val))
+
+#else /* ... HAVE_LITTLE_ENDIAN */
+#define CPU_TO_BE64(native) ((ENDIAN_CAST beint64_t)BSWAP_64(native))
+#define CPU_TO_BE32(native) ((ENDIAN_CAST beint32_t)BSWAP_32(native))
+#define CPU_TO_BE16(native) ((ENDIAN_CAST beint16_t)BSWAP_16(native))
+#define BE64_TO_CPU(le_val) BSWAP_64((ENDIAN_CAST uint64_t)le_val)
+#define BE32_TO_CPU(le_val) BSWAP_32((ENDIAN_CAST uint32_t)le_val)
+#define BE16_TO_CPU(le_val) BSWAP_16((ENDIAN_CAST uint16_t)le_val)
+#endif /* HAVE_LITTE_ENDIAN */
+
+
+/**
+ * cpu_to_le64 - convert a uint64_t value to little-endian
+ * @native: value to convert
+ */
+static inline leint64_t cpu_to_le64(uint64_t native)
+{
+ return CPU_TO_LE64(native);
+}
+
+/**
+ * cpu_to_le32 - convert a uint32_t value to little-endian
+ * @native: value to convert
+ */
+static inline leint32_t cpu_to_le32(uint32_t native)
+{
+ return CPU_TO_LE32(native);
+}
+
+/**
+ * cpu_to_le16 - convert a uint16_t value to little-endian
+ * @native: value to convert
+ */
+static inline leint16_t cpu_to_le16(uint16_t native)
+{
+ return CPU_TO_LE16(native);
+}
+
+/**
+ * le64_to_cpu - convert a little-endian uint64_t value
+ * @le_val: little-endian value to convert
+ */
+static inline uint64_t le64_to_cpu(leint64_t le_val)
+{
+ return LE64_TO_CPU(le_val);
+}
+
+/**
+ * le32_to_cpu - convert a little-endian uint32_t value
+ * @le_val: little-endian value to convert
+ */
+static inline uint32_t le32_to_cpu(leint32_t le_val)
+{
+ return LE32_TO_CPU(le_val);
+}
+
+/**
+ * le16_to_cpu - convert a little-endian uint16_t value
+ * @le_val: little-endian value to convert
+ */
+static inline uint16_t le16_to_cpu(leint16_t le_val)
+{
+ return LE16_TO_CPU(le_val);
+}
+
+/**
+ * cpu_to_be64 - convert a uint64_t value to big endian.
+ * @native: value to convert
+ */
+static inline beint64_t cpu_to_be64(uint64_t native)
+{
+ return CPU_TO_BE64(native);
+}
+
+/**
+ * cpu_to_be32 - convert a uint32_t value to big endian.
+ * @native: value to convert
+ */
+static inline beint32_t cpu_to_be32(uint32_t native)
+{
+ return CPU_TO_BE32(native);
+}
+
+/**
+ * cpu_to_be16 - convert a uint16_t value to big endian.
+ * @native: value to convert
+ */
+static inline beint16_t cpu_to_be16(uint16_t native)
+{
+ return CPU_TO_BE16(native);
+}
+
+/**
+ * be64_to_cpu - convert a big-endian uint64_t value
+ * @be_val: big-endian value to convert
+ */
+static inline uint64_t be64_to_cpu(beint64_t be_val)
+{
+ return BE64_TO_CPU(be_val);
+}
+
+/**
+ * be32_to_cpu - convert a big-endian uint32_t value
+ * @be_val: big-endian value to convert
+ */
+static inline uint32_t be32_to_cpu(beint32_t be_val)
+{
+ return BE32_TO_CPU(be_val);
+}
+
+/**
+ * be16_to_cpu - convert a big-endian uint16_t value
+ * @be_val: big-endian value to convert
+ */
+static inline uint16_t be16_to_cpu(beint16_t be_val)
+{
+ return BE16_TO_CPU(be_val);
+}
+
+/* Whichever they include first, they get these definitions. */
+#ifdef CCAN_SHORT_TYPES_H
+/**
+ * be64/be32/be16 - 64/32/16 bit big-endian representation.
+ */
+typedef beint64_t be64;
+typedef beint32_t be32;
+typedef beint16_t be16;
+
+/**
+ * le64/le32/le16 - 64/32/16 bit little-endian representation.
+ */
+typedef leint64_t le64;
+typedef leint32_t le32;
+typedef leint16_t le16;
+#endif
+#endif /* CCAN_ENDIAN_H */
diff --git a/damus-c/hash_u5.c b/damus-c/hash_u5.c
@@ -0,0 +1,48 @@
+#include "config.h"
+#include "endian.h"
+#include "hash_u5.h"
+#include <string.h>
+
+void hash_u5_init(struct hash_u5 *hu5, const char *hrp)
+{
+ hu5->buf = 0;
+ hu5->num_bits = 0;
+ sha256_init(&hu5->hash);
+ sha256_update(&hu5->hash, hrp, strlen(hrp));
+}
+
+void hash_u5(struct hash_u5 *hu5, const u8 *u5, size_t len)
+{
+ size_t bits = len * 5;
+
+ while (bits) {
+ size_t n = 5;
+
+ if (bits < n)
+ n = bits;
+
+ hu5->buf <<= n;
+ hu5->buf |= (*u5 >> (5-n));
+ bits -= n;
+ hu5->num_bits += n;
+
+ if (n == 5)
+ u5++;
+
+ if (hu5->num_bits >= 32) {
+ be32 be32 = cpu_to_be32(hu5->buf >> (hu5->num_bits-32));
+ sha256_update(&hu5->hash, &be32, sizeof(be32));
+ hu5->num_bits -= 32;
+ }
+ }
+}
+
+void hash_u5_done(struct hash_u5 *hu5, struct sha256 *res)
+{
+ if (hu5->num_bits) {
+ be32 be32 = cpu_to_be32(hu5->buf << (32 - hu5->num_bits));
+
+ sha256_update(&hu5->hash, &be32, (hu5->num_bits + 7) / 8);
+ }
+ sha256_done(&hu5->hash, res);
+}
diff --git a/damus-c/hash_u5.h b/damus-c/hash_u5.h
@@ -0,0 +1,20 @@
+/* bech32 (thus bolt11) deal in 5-bit values */
+#ifndef LIGHTNING_COMMON_HASH_U5_H
+#define LIGHTNING_COMMON_HASH_U5_H
+#include "sha256.h"
+#include "short_types.h"
+
+/* Type to annotate a 5 bit value. */
+typedef unsigned char u5;
+
+struct hash_u5 {
+ u64 buf;
+ unsigned int num_bits;
+ struct sha256_ctx hash;
+};
+
+void hash_u5_init(struct hash_u5 *hu5, const char *hrp);
+void hash_u5(struct hash_u5 *hu5, const u5 *u5, size_t len);
+void hash_u5_done(struct hash_u5 *hu5, struct sha256 *res);
+
+#endif /* LIGHTNING_COMMON_HASH_U5_H */
diff --git a/damus-c/hex.c b/damus-c/hex.c
@@ -0,0 +1,66 @@
+/* CC0 license (public domain) - see LICENSE file for details */
+#include "hex.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static bool char_to_hex(unsigned char *val, char c)
+{
+ if (c >= '0' && c <= '9') {
+ *val = c - '0';
+ return true;
+ }
+ if (c >= 'a' && c <= 'f') {
+ *val = c - 'a' + 10;
+ return true;
+ }
+ if (c >= 'A' && c <= 'F') {
+ *val = c - 'A' + 10;
+ return true;
+ }
+ return false;
+}
+
+bool hex_decode(const char *str, size_t slen, void *buf, size_t bufsize)
+{
+ unsigned char v1, v2;
+ unsigned char *p = buf;
+
+ while (slen > 1) {
+ if (!char_to_hex(&v1, str[0]) || !char_to_hex(&v2, str[1]))
+ return false;
+ if (!bufsize)
+ return false;
+ *(p++) = (v1 << 4) | v2;
+ str += 2;
+ slen -= 2;
+ bufsize--;
+ }
+ return slen == 0 && bufsize == 0;
+}
+
+static char hexchar(unsigned int val)
+{
+ if (val < 10)
+ return '0' + val;
+ if (val < 16)
+ return 'a' + val - 10;
+ abort();
+}
+
+bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize)
+{
+ size_t i;
+
+ if (destsize < hex_str_size(bufsize))
+ return false;
+
+ for (i = 0; i < bufsize; i++) {
+ unsigned int c = ((const unsigned char *)buf)[i];
+ *(dest++) = hexchar(c >> 4);
+ *(dest++) = hexchar(c & 0xF);
+ }
+ *dest = '\0';
+
+ return true;
+}
diff --git a/damus-c/hex.h b/damus-c/hex.h
@@ -0,0 +1,73 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_HEX_H
+#define CCAN_HEX_H
+#include "config.h"
+#include <stdbool.h>
+#include <stdlib.h>
+
+/**
+ * hex_decode - Unpack a hex string.
+ * @str: the hexadecimal string
+ * @slen: the length of @str
+ * @buf: the buffer to write the data into
+ * @bufsize: the length of
+ *
+ * Returns false if there are any characters which aren't 0-9, a-f or A-F,
+ * of the string wasn't the right length for @bufsize.
+ *
+ * Example:
+ * unsigned char data[20];
+ *
+ * if (!hex_decode(argv[1], strlen(argv[1]), data, 20))
+ * printf("String is malformed!\n");
+ */
+bool hex_decode(const char *str, size_t slen, void *buf, size_t bufsize);
+
+/**
+ * hex_encode - Create a nul-terminated hex string
+ * @buf: the buffer to read the data from
+ * @bufsize: the length of @buf
+ * @dest: the string to fill
+ * @destsize: the max size of the string
+ *
+ * Returns true if the string, including terminator, fit in @destsize;
+ *
+ * Example:
+ * unsigned char buf[] = { 0x1F, 0x2F };
+ * char str[5];
+ *
+ * if (!hex_encode(buf, sizeof(buf), str, sizeof(str)))
+ * abort();
+ */
+bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize);
+
+/**
+ * hex_str_size - Calculate how big a nul-terminated hex string is
+ * @bytes: bytes of data to represent
+ *
+ * Example:
+ * unsigned char buf[] = { 0x1F, 0x2F };
+ * char str[hex_str_size(sizeof(buf))];
+ *
+ * hex_encode(buf, sizeof(buf), str, sizeof(str));
+ */
+static inline size_t hex_str_size(size_t bytes)
+{
+ return 2 * bytes + 1;
+}
+
+/**
+ * hex_data_size - Calculate how many bytes of data in a hex string
+ * @strlen: the length of the string (with or without NUL)
+ *
+ * Example:
+ * const char str[] = "1F2F";
+ * unsigned char buf[hex_data_size(sizeof(str))];
+ *
+ * hex_decode(str, strlen(str), buf, sizeof(buf));
+ */
+static inline size_t hex_data_size(size_t strlen)
+{
+ return strlen / 2;
+}
+#endif /* CCAN_HEX_H */
diff --git a/damus-c/likely.h b/damus-c/likely.h
@@ -0,0 +1,111 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_LIKELY_H
+#define CCAN_LIKELY_H
+#include "config.h"
+#include <stdbool.h>
+
+#ifndef CCAN_LIKELY_DEBUG
+#if HAVE_BUILTIN_EXPECT
+/**
+ * likely - indicate that a condition is likely to be true.
+ * @cond: the condition
+ *
+ * This uses a compiler extension where available to indicate a likely
+ * code path and optimize appropriately; it's also useful for readers
+ * to quickly identify exceptional paths through functions. The
+ * threshold for "likely" is usually considered to be between 90 and
+ * 99%; marginal cases should not be marked either way.
+ *
+ * See Also:
+ * unlikely(), likely_stats()
+ *
+ * Example:
+ * // Returns false if we overflow.
+ * static inline bool inc_int(unsigned int *val)
+ * {
+ * (*val)++;
+ * if (likely(*val))
+ * return true;
+ * return false;
+ * }
+ */
+#define likely(cond) __builtin_expect(!!(cond), 1)
+
+/**
+ * unlikely - indicate that a condition is unlikely to be true.
+ * @cond: the condition
+ *
+ * This uses a compiler extension where available to indicate an unlikely
+ * code path and optimize appropriately; see likely() above.
+ *
+ * See Also:
+ * likely(), likely_stats(), COLD (compiler.h)
+ *
+ * Example:
+ * // Prints a warning if we overflow.
+ * static inline void inc_int(unsigned int *val)
+ * {
+ * (*val)++;
+ * if (unlikely(*val == 0))
+ * fprintf(stderr, "Overflow!");
+ * }
+ */
+#define unlikely(cond) __builtin_expect(!!(cond), 0)
+#else
+#define likely(cond) (!!(cond))
+#define unlikely(cond) (!!(cond))
+#endif
+#else /* CCAN_LIKELY_DEBUG versions */
+#include <ccan/str/str.h>
+
+#define likely(cond) \
+ (_likely_trace(!!(cond), 1, stringify(cond), __FILE__, __LINE__))
+#define unlikely(cond) \
+ (_likely_trace(!!(cond), 0, stringify(cond), __FILE__, __LINE__))
+
+long _likely_trace(bool cond, bool expect,
+ const char *condstr,
+ const char *file, unsigned int line);
+/**
+ * likely_stats - return description of abused likely()/unlikely()
+ * @min_hits: minimum number of hits
+ * @percent: maximum percentage correct
+ *
+ * When CCAN_LIKELY_DEBUG is defined, likely() and unlikely() trace their
+ * results: this causes a significant slowdown, but allows analysis of
+ * whether the branches are labelled correctly.
+ *
+ * This function returns a malloc'ed description of the least-correct
+ * usage of likely() or unlikely(). It ignores places which have been
+ * called less than @min_hits times, and those which were predicted
+ * correctly more than @percent of the time. It returns NULL when
+ * nothing meets those criteria.
+ *
+ * Note that this call is destructive; the returned offender is
+ * removed from the trace so that the next call to likely_stats() will
+ * return the next-worst likely()/unlikely() usage.
+ *
+ * Example:
+ * // Print every place hit more than twice which was wrong > 5%.
+ * static void report_stats(void)
+ * {
+ * #ifdef CCAN_LIKELY_DEBUG
+ * const char *bad;
+ *
+ * while ((bad = likely_stats(2, 95)) != NULL) {
+ * printf("Suspicious likely: %s", bad);
+ * free(bad);
+ * }
+ * #endif
+ * }
+ */
+char *likely_stats(unsigned int min_hits, unsigned int percent);
+
+/**
+ * likely_stats_reset - free up memory of likely()/unlikely() branches.
+ *
+ * This can also plug memory leaks.
+ */
+void likely_stats_reset(void);
+#endif /* CCAN_LIKELY_DEBUG */
+#endif /* CCAN_LIKELY_H */
diff --git a/damus-c/list.c b/damus-c/list.c
@@ -0,0 +1,43 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#include <stdio.h>
+#include <stdlib.h>
+#include "list.h"
+
+static void *corrupt(const char *abortstr,
+ const struct list_node *head,
+ const struct list_node *node,
+ unsigned int count)
+{
+ if (abortstr) {
+ fprintf(stderr,
+ "%s: prev corrupt in node %p (%u) of %p\n",
+ abortstr, node, count, head);
+ abort();
+ }
+ return NULL;
+}
+
+struct list_node *list_check_node(const struct list_node *node,
+ const char *abortstr)
+{
+ const struct list_node *p, *n;
+ int count = 0;
+
+ for (p = node, n = node->next; n != node; p = n, n = n->next) {
+ count++;
+ if (n->prev != p)
+ return corrupt(abortstr, node, n, count);
+ }
+ /* Check prev on head node. */
+ if (node->prev != p)
+ return corrupt(abortstr, node, node, 0);
+
+ return (struct list_node *)node;
+}
+
+struct list_head *list_check(const struct list_head *h, const char *abortstr)
+{
+ if (!list_check_node(&h->n, abortstr))
+ return NULL;
+ return (struct list_head *)h;
+}
diff --git a/damus-c/list.h b/damus-c/list.h
@@ -0,0 +1,842 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#ifndef CCAN_LIST_H
+#define CCAN_LIST_H
+//#define CCAN_LIST_DEBUG 1
+#include <stdbool.h>
+#include <assert.h>
+#include "str.h"
+#include "container_of.h"
+#include "check_type.h"
+
+/**
+ * struct list_node - an entry in a doubly-linked list
+ * @next: next entry (self if empty)
+ * @prev: previous entry (self if empty)
+ *
+ * This is used as an entry in a linked list.
+ * Example:
+ * struct child {
+ * const char *name;
+ * // Linked list of all us children.
+ * struct list_node list;
+ * };
+ */
+struct list_node
+{
+ struct list_node *next, *prev;
+};
+
+/**
+ * struct list_head - the head of a doubly-linked list
+ * @h: the list_head (containing next and prev pointers)
+ *
+ * This is used as the head of a linked list.
+ * Example:
+ * struct parent {
+ * const char *name;
+ * struct list_head children;
+ * unsigned int num_children;
+ * };
+ */
+struct list_head
+{
+ struct list_node n;
+};
+
+/**
+ * list_check - check head of a list for consistency
+ * @h: the list_head
+ * @abortstr: the location to print on aborting, or NULL.
+ *
+ * Because list_nodes have redundant information, consistency checking between
+ * the back and forward links can be done. This is useful as a debugging check.
+ * If @abortstr is non-NULL, that will be printed in a diagnostic if the list
+ * is inconsistent, and the function will abort.
+ *
+ * Returns the list head if the list is consistent, NULL if not (it
+ * can never return NULL if @abortstr is set).
+ *
+ * See also: list_check_node()
+ *
+ * Example:
+ * static void dump_parent(struct parent *p)
+ * {
+ * struct child *c;
+ *
+ * printf("%s (%u children):\n", p->name, p->num_children);
+ * list_check(&p->children, "bad child list");
+ * list_for_each(&p->children, c, list)
+ * printf(" -> %s\n", c->name);
+ * }
+ */
+struct list_head *list_check(const struct list_head *h, const char *abortstr);
+
+/**
+ * list_check_node - check node of a list for consistency
+ * @n: the list_node
+ * @abortstr: the location to print on aborting, or NULL.
+ *
+ * Check consistency of the list node is in (it must be in one).
+ *
+ * See also: list_check()
+ *
+ * Example:
+ * static void dump_child(const struct child *c)
+ * {
+ * list_check_node(&c->list, "bad child list");
+ * printf("%s\n", c->name);
+ * }
+ */
+struct list_node *list_check_node(const struct list_node *n,
+ const char *abortstr);
+
+#define LIST_LOC __FILE__ ":" stringify(__LINE__)
+#ifdef CCAN_LIST_DEBUG
+#define list_debug(h, loc) list_check((h), loc)
+#define list_debug_node(n, loc) list_check_node((n), loc)
+#else
+#define list_debug(h, loc) ((void)loc, h)
+#define list_debug_node(n, loc) ((void)loc, n)
+#endif
+
+/**
+ * LIST_HEAD_INIT - initializer for an empty list_head
+ * @name: the name of the list.
+ *
+ * Explicit initializer for an empty list.
+ *
+ * See also:
+ * LIST_HEAD, list_head_init()
+ *
+ * Example:
+ * static struct list_head my_list = LIST_HEAD_INIT(my_list);
+ */
+#define LIST_HEAD_INIT(name) { { &(name).n, &(name).n } }
+
+/**
+ * LIST_HEAD - define and initialize an empty list_head
+ * @name: the name of the list.
+ *
+ * The LIST_HEAD macro defines a list_head and initializes it to an empty
+ * list. It can be prepended by "static" to define a static list_head.
+ *
+ * See also:
+ * LIST_HEAD_INIT, list_head_init()
+ *
+ * Example:
+ * static LIST_HEAD(my_global_list);
+ */
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+/**
+ * list_head_init - initialize a list_head
+ * @h: the list_head to set to the empty list
+ *
+ * Example:
+ * ...
+ * struct parent *parent = malloc(sizeof(*parent));
+ *
+ * list_head_init(&parent->children);
+ * parent->num_children = 0;
+ */
+static inline void list_head_init(struct list_head *h)
+{
+ h->n.next = h->n.prev = &h->n;
+}
+
+/**
+ * list_node_init - initialize a list_node
+ * @n: the list_node to link to itself.
+ *
+ * You don't need to use this normally! But it lets you list_del(@n)
+ * safely.
+ */
+static inline void list_node_init(struct list_node *n)
+{
+ n->next = n->prev = n;
+}
+
+/**
+ * list_add_after - add an entry after an existing node in a linked list
+ * @h: the list_head to add the node to (for debugging)
+ * @p: the existing list_node to add the node after
+ * @n: the new list_node to add to the list.
+ *
+ * The existing list_node must already be a member of the list.
+ * The new list_node does not need to be initialized; it will be overwritten.
+ *
+ * Example:
+ * struct child c1, c2, c3;
+ * LIST_HEAD(h);
+ *
+ * list_add_tail(&h, &c1.list);
+ * list_add_tail(&h, &c3.list);
+ * list_add_after(&h, &c1.list, &c2.list);
+ */
+#define list_add_after(h, p, n) list_add_after_(h, p, n, LIST_LOC)
+static inline void list_add_after_(struct list_head *h,
+ struct list_node *p,
+ struct list_node *n,
+ const char *abortstr)
+{
+ n->next = p->next;
+ n->prev = p;
+ p->next->prev = n;
+ p->next = n;
+ (void)list_debug(h, abortstr);
+}
+
+/**
+ * list_add - add an entry at the start of a linked list.
+ * @h: the list_head to add the node to
+ * @n: the list_node to add to the list.
+ *
+ * The list_node does not need to be initialized; it will be overwritten.
+ * Example:
+ * struct child *child = malloc(sizeof(*child));
+ *
+ * child->name = "marvin";
+ * list_add(&parent->children, &child->list);
+ * parent->num_children++;
+ */
+#define list_add(h, n) list_add_(h, n, LIST_LOC)
+static inline void list_add_(struct list_head *h,
+ struct list_node *n,
+ const char *abortstr)
+{
+ list_add_after_(h, &h->n, n, abortstr);
+}
+
+/**
+ * list_add_before - add an entry before an existing node in a linked list
+ * @h: the list_head to add the node to (for debugging)
+ * @p: the existing list_node to add the node before
+ * @n: the new list_node to add to the list.
+ *
+ * The existing list_node must already be a member of the list.
+ * The new list_node does not need to be initialized; it will be overwritten.
+ *
+ * Example:
+ * list_head_init(&h);
+ * list_add_tail(&h, &c1.list);
+ * list_add_tail(&h, &c3.list);
+ * list_add_before(&h, &c3.list, &c2.list);
+ */
+#define list_add_before(h, p, n) list_add_before_(h, p, n, LIST_LOC)
+static inline void list_add_before_(struct list_head *h,
+ struct list_node *p,
+ struct list_node *n,
+ const char *abortstr)
+{
+ n->next = p;
+ n->prev = p->prev;
+ p->prev->next = n;
+ p->prev = n;
+ (void)list_debug(h, abortstr);
+}
+
+/**
+ * list_add_tail - add an entry at the end of a linked list.
+ * @h: the list_head to add the node to
+ * @n: the list_node to add to the list.
+ *
+ * The list_node does not need to be initialized; it will be overwritten.
+ * Example:
+ * list_add_tail(&parent->children, &child->list);
+ * parent->num_children++;
+ */
+#define list_add_tail(h, n) list_add_tail_(h, n, LIST_LOC)
+static inline void list_add_tail_(struct list_head *h,
+ struct list_node *n,
+ const char *abortstr)
+{
+ list_add_before_(h, &h->n, n, abortstr);
+}
+
+/**
+ * list_empty - is a list empty?
+ * @h: the list_head
+ *
+ * If the list is empty, returns true.
+ *
+ * Example:
+ * assert(list_empty(&parent->children) == (parent->num_children == 0));
+ */
+#define list_empty(h) list_empty_(h, LIST_LOC)
+static inline bool list_empty_(const struct list_head *h, const char* abortstr)
+{
+ (void)list_debug(h, abortstr);
+ return h->n.next == &h->n;
+}
+
+/**
+ * list_empty_nodebug - is a list empty (and don't perform debug checks)?
+ * @h: the list_head
+ *
+ * If the list is empty, returns true.
+ * This differs from list_empty() in that if CCAN_LIST_DEBUG is set it
+ * will NOT perform debug checks. Only use this function if you REALLY
+ * know what you're doing.
+ *
+ * Example:
+ * assert(list_empty_nodebug(&parent->children) == (parent->num_children == 0));
+ */
+#ifndef CCAN_LIST_DEBUG
+#define list_empty_nodebug(h) list_empty(h)
+#else
+static inline bool list_empty_nodebug(const struct list_head *h)
+{
+ return h->n.next == &h->n;
+}
+#endif
+
+/**
+ * list_empty_nocheck - is a list empty?
+ * @h: the list_head
+ *
+ * If the list is empty, returns true. This doesn't perform any
+ * debug check for list consistency, so it can be called without
+ * locks, racing with the list being modified. This is ok for
+ * checks where an incorrect result is not an issue (optimized
+ * bail out path for example).
+ */
+static inline bool list_empty_nocheck(const struct list_head *h)
+{
+ return h->n.next == &h->n;
+}
+
+/**
+ * list_del - delete an entry from an (unknown) linked list.
+ * @n: the list_node to delete from the list.
+ *
+ * Note that this leaves @n in an undefined state; it can be added to
+ * another list, but not deleted again.
+ *
+ * See also:
+ * list_del_from(), list_del_init()
+ *
+ * Example:
+ * list_del(&child->list);
+ * parent->num_children--;
+ */
+#define list_del(n) list_del_(n, LIST_LOC)
+static inline void list_del_(struct list_node *n, const char* abortstr)
+{
+ (void)list_debug_node(n, abortstr);
+ n->next->prev = n->prev;
+ n->prev->next = n->next;
+#ifdef CCAN_LIST_DEBUG
+ /* Catch use-after-del. */
+ n->next = n->prev = NULL;
+#endif
+}
+
+/**
+ * list_del_init - delete a node, and reset it so it can be deleted again.
+ * @n: the list_node to be deleted.
+ *
+ * list_del(@n) or list_del_init() again after this will be safe,
+ * which can be useful in some cases.
+ *
+ * See also:
+ * list_del_from(), list_del()
+ *
+ * Example:
+ * list_del_init(&child->list);
+ * parent->num_children--;
+ */
+#define list_del_init(n) list_del_init_(n, LIST_LOC)
+static inline void list_del_init_(struct list_node *n, const char *abortstr)
+{
+ list_del_(n, abortstr);
+ list_node_init(n);
+}
+
+/**
+ * list_del_from - delete an entry from a known linked list.
+ * @h: the list_head the node is in.
+ * @n: the list_node to delete from the list.
+ *
+ * This explicitly indicates which list a node is expected to be in,
+ * which is better documentation and can catch more bugs.
+ *
+ * See also: list_del()
+ *
+ * Example:
+ * list_del_from(&parent->children, &child->list);
+ * parent->num_children--;
+ */
+static inline void list_del_from(struct list_head *h, struct list_node *n)
+{
+#ifdef CCAN_LIST_DEBUG
+ {
+ /* Thorough check: make sure it was in list! */
+ struct list_node *i;
+ for (i = h->n.next; i != n; i = i->next)
+ assert(i != &h->n);
+ }
+#endif /* CCAN_LIST_DEBUG */
+
+ /* Quick test that catches a surprising number of bugs. */
+ assert(!list_empty(h));
+ list_del(n);
+}
+
+/**
+ * list_swap - swap out an entry from an (unknown) linked list for a new one.
+ * @o: the list_node to replace from the list.
+ * @n: the list_node to insert in place of the old one.
+ *
+ * Note that this leaves @o in an undefined state; it can be added to
+ * another list, but not deleted/swapped again.
+ *
+ * See also:
+ * list_del()
+ *
+ * Example:
+ * struct child x1, x2;
+ * LIST_HEAD(xh);
+ *
+ * list_add(&xh, &x1.list);
+ * list_swap(&x1.list, &x2.list);
+ */
+#define list_swap(o, n) list_swap_(o, n, LIST_LOC)
+static inline void list_swap_(struct list_node *o,
+ struct list_node *n,
+ const char* abortstr)
+{
+ (void)list_debug_node(o, abortstr);
+ *n = *o;
+ n->next->prev = n;
+ n->prev->next = n;
+#ifdef CCAN_LIST_DEBUG
+ /* Catch use-after-del. */
+ o->next = o->prev = NULL;
+#endif
+}
+
+/**
+ * list_entry - convert a list_node back into the structure containing it.
+ * @n: the list_node
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * Example:
+ * // First list entry is children.next; convert back to child.
+ * child = list_entry(parent->children.n.next, struct child, list);
+ *
+ * See Also:
+ * list_top(), list_for_each()
+ */
+#define list_entry(n, type, member) container_of(n, type, member)
+
+/**
+ * list_top - get the first entry in a list
+ * @h: the list_head
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ * struct child *first;
+ * first = list_top(&parent->children, struct child, list);
+ * if (!first)
+ * printf("Empty list!\n");
+ */
+#define list_top(h, type, member) \
+ ((type *)list_top_((h), list_off_(type, member)))
+
+static inline const void *list_top_(const struct list_head *h, size_t off)
+{
+ if (list_empty(h))
+ return NULL;
+ return (const char *)h->n.next - off;
+}
+
+/**
+ * list_pop - remove the first entry in a list
+ * @h: the list_head
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ * struct child *one;
+ * one = list_pop(&parent->children, struct child, list);
+ * if (!one)
+ * printf("Empty list!\n");
+ */
+#define list_pop(h, type, member) \
+ ((type *)list_pop_((h), list_off_(type, member)))
+
+static inline const void *list_pop_(const struct list_head *h, size_t off)
+{
+ struct list_node *n;
+
+ if (list_empty(h))
+ return NULL;
+ n = h->n.next;
+ list_del(n);
+ return (const char *)n - off;
+}
+
+/**
+ * list_tail - get the last entry in a list
+ * @h: the list_head
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ * struct child *last;
+ * last = list_tail(&parent->children, struct child, list);
+ * if (!last)
+ * printf("Empty list!\n");
+ */
+#define list_tail(h, type, member) \
+ ((type *)list_tail_((h), list_off_(type, member)))
+
+static inline const void *list_tail_(const struct list_head *h, size_t off)
+{
+ if (list_empty(h))
+ return NULL;
+ return (const char *)h->n.prev - off;
+}
+
+/**
+ * list_for_each - iterate through a list.
+ * @h: the list_head (warning: evaluated multiple times!)
+ * @i: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list. It's
+ * a for loop, so you can break and continue as normal.
+ *
+ * Example:
+ * list_for_each(&parent->children, child, list)
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each(h, i, member) \
+ list_for_each_off(h, i, list_off_var_(i, member))
+
+/**
+ * list_for_each_rev - iterate through a list backwards.
+ * @h: the list_head
+ * @i: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list. It's
+ * a for loop, so you can break and continue as normal.
+ *
+ * Example:
+ * list_for_each_rev(&parent->children, child, list)
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each_rev(h, i, member) \
+ list_for_each_rev_off(h, i, list_off_var_(i, member))
+
+/**
+ * list_for_each_rev_safe - iterate through a list backwards,
+ * maybe during deletion
+ * @h: the list_head
+ * @i: the structure containing the list_node
+ * @nxt: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list backwards.
+ * It's a for loop, so you can break and continue as normal. The extra
+ * variable * @nxt is used to hold the next element, so you can delete @i
+ * from the list.
+ *
+ * Example:
+ * struct child *next;
+ * list_for_each_rev_safe(&parent->children, child, next, list) {
+ * printf("Name: %s\n", child->name);
+ * }
+ */
+#define list_for_each_rev_safe(h, i, nxt, member) \
+ list_for_each_rev_safe_off(h, i, nxt, list_off_var_(i, member))
+
+/**
+ * list_for_each_safe - iterate through a list, maybe during deletion
+ * @h: the list_head
+ * @i: the structure containing the list_node
+ * @nxt: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list. It's
+ * a for loop, so you can break and continue as normal. The extra variable
+ * @nxt is used to hold the next element, so you can delete @i from the list.
+ *
+ * Example:
+ * list_for_each_safe(&parent->children, child, next, list) {
+ * list_del(&child->list);
+ * parent->num_children--;
+ * }
+ */
+#define list_for_each_safe(h, i, nxt, member) \
+ list_for_each_safe_off(h, i, nxt, list_off_var_(i, member))
+
+/**
+ * list_next - get the next entry in a list
+ * @h: the list_head
+ * @i: a pointer to an entry in the list.
+ * @member: the list_node member of the structure
+ *
+ * If @i was the last entry in the list, returns NULL.
+ *
+ * Example:
+ * struct child *second;
+ * second = list_next(&parent->children, first, list);
+ * if (!second)
+ * printf("No second child!\n");
+ */
+#define list_next(h, i, member) \
+ ((list_typeof(i))list_entry_or_null(list_debug(h, \
+ __FILE__ ":" stringify(__LINE__)), \
+ (i)->member.next, \
+ list_off_var_((i), member)))
+
+/**
+ * list_prev - get the previous entry in a list
+ * @h: the list_head
+ * @i: a pointer to an entry in the list.
+ * @member: the list_node member of the structure
+ *
+ * If @i was the first entry in the list, returns NULL.
+ *
+ * Example:
+ * first = list_prev(&parent->children, second, list);
+ * if (!first)
+ * printf("Can't go back to first child?!\n");
+ */
+#define list_prev(h, i, member) \
+ ((list_typeof(i))list_entry_or_null(list_debug(h, \
+ __FILE__ ":" stringify(__LINE__)), \
+ (i)->member.prev, \
+ list_off_var_((i), member)))
+
+/**
+ * list_append_list - empty one list onto the end of another.
+ * @to: the list to append into
+ * @from: the list to empty.
+ *
+ * This takes the entire contents of @from and moves it to the end of
+ * @to. After this @from will be empty.
+ *
+ * Example:
+ * struct list_head adopter;
+ *
+ * list_append_list(&adopter, &parent->children);
+ * assert(list_empty(&parent->children));
+ * parent->num_children = 0;
+ */
+#define list_append_list(t, f) list_append_list_(t, f, \
+ __FILE__ ":" stringify(__LINE__))
+static inline void list_append_list_(struct list_head *to,
+ struct list_head *from,
+ const char *abortstr)
+{
+ struct list_node *from_tail = list_debug(from, abortstr)->n.prev;
+ struct list_node *to_tail = list_debug(to, abortstr)->n.prev;
+
+ /* Sew in head and entire list. */
+ to->n.prev = from_tail;
+ from_tail->next = &to->n;
+ to_tail->next = &from->n;
+ from->n.prev = to_tail;
+
+ /* Now remove head. */
+ list_del(&from->n);
+ list_head_init(from);
+}
+
+/**
+ * list_prepend_list - empty one list into the start of another.
+ * @to: the list to prepend into
+ * @from: the list to empty.
+ *
+ * This takes the entire contents of @from and moves it to the start
+ * of @to. After this @from will be empty.
+ *
+ * Example:
+ * list_prepend_list(&adopter, &parent->children);
+ * assert(list_empty(&parent->children));
+ * parent->num_children = 0;
+ */
+#define list_prepend_list(t, f) list_prepend_list_(t, f, LIST_LOC)
+static inline void list_prepend_list_(struct list_head *to,
+ struct list_head *from,
+ const char *abortstr)
+{
+ struct list_node *from_tail = list_debug(from, abortstr)->n.prev;
+ struct list_node *to_head = list_debug(to, abortstr)->n.next;
+
+ /* Sew in head and entire list. */
+ to->n.next = &from->n;
+ from->n.prev = &to->n;
+ to_head->prev = from_tail;
+ from_tail->next = to_head;
+
+ /* Now remove head. */
+ list_del(&from->n);
+ list_head_init(from);
+}
+
+/* internal macros, do not use directly */
+#define list_for_each_off_dir_(h, i, off, dir) \
+ for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir, \
+ (off)); \
+ list_node_from_off_((void *)i, (off)) != &(h)->n; \
+ i = list_node_to_off_(list_node_from_off_((void *)i, (off))->dir, \
+ (off)))
+
+#define list_for_each_safe_off_dir_(h, i, nxt, off, dir) \
+ for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir, \
+ (off)), \
+ nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir, \
+ (off)); \
+ list_node_from_off_(i, (off)) != &(h)->n; \
+ i = nxt, \
+ nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir, \
+ (off)))
+
+/**
+ * list_for_each_off - iterate through a list of memory regions.
+ * @h: the list_head
+ * @i: the pointer to a memory region which contains list node data.
+ * @off: offset(relative to @i) at which list node data resides.
+ *
+ * This is a low-level wrapper to iterate @i over the entire list, used to
+ * implement all oher, more high-level, for-each constructs. It's a for loop,
+ * so you can break and continue as normal.
+ *
+ * WARNING! Being the low-level macro that it is, this wrapper doesn't know
+ * nor care about the type of @i. The only assumption made is that @i points
+ * to a chunk of memory that at some @offset, relative to @i, contains a
+ * properly filled `struct list_node' which in turn contains pointers to
+ * memory chunks and it's turtles all the way down. With all that in mind
+ * remember that given the wrong pointer/offset couple this macro will
+ * happily churn all you memory until SEGFAULT stops it, in other words
+ * caveat emptor.
+ *
+ * It is worth mentioning that one of legitimate use-cases for that wrapper
+ * is operation on opaque types with known offset for `struct list_node'
+ * member(preferably 0), because it allows you not to disclose the type of
+ * @i.
+ *
+ * Example:
+ * list_for_each_off(&parent->children, child,
+ * offsetof(struct child, list))
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each_off(h, i, off) \
+ list_for_each_off_dir_((h),(i),(off),next)
+
+/**
+ * list_for_each_rev_off - iterate through a list of memory regions backwards
+ * @h: the list_head
+ * @i: the pointer to a memory region which contains list node data.
+ * @off: offset(relative to @i) at which list node data resides.
+ *
+ * See list_for_each_off for details
+ */
+#define list_for_each_rev_off(h, i, off) \
+ list_for_each_off_dir_((h),(i),(off),prev)
+
+/**
+ * list_for_each_safe_off - iterate through a list of memory regions, maybe
+ * during deletion
+ * @h: the list_head
+ * @i: the pointer to a memory region which contains list node data.
+ * @nxt: the structure containing the list_node
+ * @off: offset(relative to @i) at which list node data resides.
+ *
+ * For details see `list_for_each_off' and `list_for_each_safe'
+ * descriptions.
+ *
+ * Example:
+ * list_for_each_safe_off(&parent->children, child,
+ * next, offsetof(struct child, list))
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each_safe_off(h, i, nxt, off) \
+ list_for_each_safe_off_dir_((h),(i),(nxt),(off),next)
+
+/**
+ * list_for_each_rev_safe_off - iterate backwards through a list of
+ * memory regions, maybe during deletion
+ * @h: the list_head
+ * @i: the pointer to a memory region which contains list node data.
+ * @nxt: the structure containing the list_node
+ * @off: offset(relative to @i) at which list node data resides.
+ *
+ * For details see `list_for_each_rev_off' and `list_for_each_rev_safe'
+ * descriptions.
+ *
+ * Example:
+ * list_for_each_rev_safe_off(&parent->children, child,
+ * next, offsetof(struct child, list))
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each_rev_safe_off(h, i, nxt, off) \
+ list_for_each_safe_off_dir_((h),(i),(nxt),(off),prev)
+
+/* Other -off variants. */
+#define list_entry_off(n, type, off) \
+ ((type *)list_node_from_off_((n), (off)))
+
+#define list_head_off(h, type, off) \
+ ((type *)list_head_off((h), (off)))
+
+#define list_tail_off(h, type, off) \
+ ((type *)list_tail_((h), (off)))
+
+#define list_add_off(h, n, off) \
+ list_add((h), list_node_from_off_((n), (off)))
+
+#define list_del_off(n, off) \
+ list_del(list_node_from_off_((n), (off)))
+
+#define list_del_from_off(h, n, off) \
+ list_del_from(h, list_node_from_off_((n), (off)))
+
+/* Offset helper functions so we only single-evaluate. */
+static inline void *list_node_to_off_(struct list_node *node, size_t off)
+{
+ return (void *)((char *)node - off);
+}
+static inline struct list_node *list_node_from_off_(void *ptr, size_t off)
+{
+ return (struct list_node *)((char *)ptr + off);
+}
+
+/* Get the offset of the member, but make sure it's a list_node. */
+#define list_off_(type, member) \
+ (container_off(type, member) + \
+ check_type(((type *)0)->member, struct list_node))
+
+#define list_off_var_(var, member) \
+ (container_off_var(var, member) + \
+ check_type(var->member, struct list_node))
+
+#if HAVE_TYPEOF
+#define list_typeof(var) typeof(var)
+#else
+#define list_typeof(var) void *
+#endif
+
+/* Returns member, or NULL if at end of list. */
+static inline void *list_entry_or_null(const struct list_head *h,
+ const struct list_node *n,
+ size_t off)
+{
+ if (n == &h->n)
+ return NULL;
+ return (char *)n - off;
+}
+#endif /* CCAN_LIST_H */
diff --git a/damus-c/mem.c b/damus-c/mem.c
@@ -0,0 +1,128 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+#include "mem.h"
+
+#if !HAVE_MEMMEM
+void *memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen)
+{
+ const char *p;
+
+ if (needlelen > haystacklen)
+ return NULL;
+
+ p = haystack;
+
+ for (p = haystack;
+ (p + needlelen) <= ((const char *)haystack + haystacklen);
+ p++)
+ if (memcmp(p, needle, needlelen) == 0)
+ return (void *)p;
+
+ return NULL;
+}
+#endif
+
+#if !HAVE_MEMRCHR
+void *memrchr(const void *s, int c, size_t n)
+{
+ unsigned char *p = (unsigned char *)s;
+
+ while (n) {
+ if (p[n-1] == c)
+ return p + n - 1;
+ n--;
+ }
+
+ return NULL;
+}
+#endif
+
+void *mempbrkm(const void *data_, size_t len, const void *accept_, size_t accept_len)
+{
+ const char *data = data_, *accept = accept_;
+ size_t i, j;
+
+ for (i = 0; i < len; i++)
+ for (j = 0; j < accept_len; j++)
+ if (accept[j] == data[i])
+ return (void *)&data[i];
+ return NULL;
+}
+
+void *memcchr(void const *data, int c, size_t data_len)
+{
+ char const *p = data;
+ size_t i;
+
+ for (i = 0; i < data_len; i++)
+ if (p[i] != c)
+ return (void *)&p[i];
+
+ return NULL;
+}
+
+#define MEMSWAP_TMP_SIZE 256
+
+void memswap(void *a, void *b, size_t n)
+{
+ char *ap = a;
+ char *bp = b;
+ char tmp[MEMSWAP_TMP_SIZE];
+
+ assert(!memoverlaps(a, n, b, n));
+
+ while (n) {
+ size_t m = n > MEMSWAP_TMP_SIZE ? MEMSWAP_TMP_SIZE : n;
+
+ memcpy(tmp, bp, m);
+ memcpy(bp, ap, m);
+ memcpy(ap, tmp, m);
+
+ ap += m;
+ bp += m;
+ n -= m;
+ }
+}
+
+bool memeqzero(const void *data, size_t length)
+{
+ const unsigned char *p = data;
+ size_t len;
+
+ /* Check first 16 bytes manually */
+ for (len = 0; len < 16; len++) {
+ if (!length)
+ return true;
+ if (*p)
+ return false;
+ p++;
+ length--;
+ }
+
+ /* Now we know that's zero, memcmp with self. */
+ return memcmp(data, p, length) == 0;
+}
+
+void memtaint(void *data, size_t len)
+{
+ /* Using 16 bytes is a bit quicker than 4 */
+ const unsigned tainter[]
+ = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
+ char *p = data;
+
+ while (len >= sizeof(tainter)) {
+ memcpy(p, tainter, sizeof(tainter));
+ p += sizeof(tainter);
+ len -= sizeof(tainter);
+ }
+ memcpy(p, tainter, len);
+
+#if HAVE_VALGRIND_MEMCHECK_H
+ VALGRIND_MAKE_MEM_UNDEFINED(data, len);
+#endif
+}
diff --git a/damus-c/mem.h b/damus-c/mem.h
@@ -0,0 +1,295 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_MEM_H
+#define CCAN_MEM_H
+
+#include "config.h"
+#include "compiler.h"
+
+#include <string.h>
+#include <stdbool.h>
+
+#if !HAVE_MEMMEM
+PURE_FUNCTION
+void *memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+#endif
+
+#if !HAVE_MEMRCHR
+PURE_FUNCTION
+void *memrchr(const void *s, int c, size_t n);
+#endif
+
+/**
+ * mempbrkm - locates the first occurrence in @data of any bytes in @accept
+ * @data: where we search
+ * @len: length of data in bytes
+ * @accept: array of bytes we search for
+ * @accept_len: # of bytes in accept
+ *
+ * Returns a pointer to the byte in @data that matches one of the bytes in
+ * @accept, or NULL if no such byte is found.
+ *
+ * Example:
+ * char otherbytes[] = "Hello \0world";
+ * size_t otherbytes_len = sizeof(otherbytes) - 1;
+ * char *r = mempbrkm(otherbytes, otherbytes_len, "\0b", 2);
+ * if (r) {
+ * printf("Found %c\n", *r);
+ * } else {
+ * printf("Nada\n");
+ * }
+ *
+ */
+PURE_FUNCTION
+void *mempbrkm(const void *data, size_t len, const void *accept, size_t accept_len);
+
+/**
+ * mempbrk - locates the first occurrence in @data of any bytes in @accept
+ * @data: where we search
+ * @len: length of data in bytes
+ * @accept: NUL terminated string containing the bytes we search for
+ *
+ * Returns a pointer to the byte in @data that matches one of the bytes in
+ * @accept, or NULL if no such byte is found.
+ *
+ * Example:
+ *
+ * r = mempbrk(otherbytes, otherbytes_len, "abcde");
+ * if (r) {
+ * printf("Found %c\n", *r);
+ * } else {
+ * printf("Nada\n");
+ * }
+ */
+PURE_FUNCTION
+static inline char *mempbrk(const void *data, size_t len, const char *accept)
+{
+ return mempbrkm(data, len, accept, strlen(accept));
+}
+
+/**
+ * memcchr - scan memory until a character does _not_ match
+ * @data: pointer to memory to scan
+ * @data_len: length of data
+ * @c: character to scan for
+ *
+ * The complement of memchr().
+ *
+ * Returns a pointer to the first character which is _not_ @c. If all memory in
+ * @data is @c, returns NULL.
+ *
+ * Example:
+ * char somebytes[] = "HI By\0e";
+ * size_t bytes_len = sizeof(somebytes) - 1;
+ * r = memcchr(somebytes, ' ', bytes_len);
+ * if (r) {
+ * printf("Found %c after trimming spaces\n", *r);
+ * }
+ */
+PURE_FUNCTION
+void *memcchr(void const *data, int c, size_t data_len);
+
+/**
+ * memeq - Are two byte arrays equal?
+ * @a: first array
+ * @al: bytes in first array
+ * @b: second array
+ * @bl: bytes in second array
+ *
+ * Example:
+ * if (memeq(somebytes, bytes_len, otherbytes, otherbytes_len)) {
+ * printf("memory blocks are the same!\n");
+ * }
+ */
+PURE_FUNCTION
+static inline bool memeq(const void *a, size_t al, const void *b, size_t bl)
+{
+ return al == bl && !memcmp(a, b, bl);
+}
+
+/**
+ * memstarts - determine if @data starts with @prefix
+ * @data: does this begin with @prefix?
+ * @data_len: bytes in @data
+ * @prefix: does @data begin with these bytes?
+ * @prefix_len: bytes in @prefix
+ *
+ * Returns true if @data starts with @prefix, otherwise return false.
+ *
+ * Example:
+ * if (memstarts(somebytes, bytes_len, otherbytes, otherbytes_len)) {
+ * printf("somebytes starts with otherbytes!\n");
+ * }
+ */
+PURE_FUNCTION
+static inline bool memstarts(void const *data, size_t data_len,
+ void const *prefix, size_t prefix_len)
+{
+ if (prefix_len > data_len)
+ return false;
+ return memeq(data, prefix_len, prefix, prefix_len);
+}
+
+/**
+ * memeqstr - Is a byte array equal to a NUL terminated string?
+ * @data: byte array
+ * @length: length of @data in bytes
+ * @string: NUL terminated string
+ *
+ * The '\0' byte is ignored when checking if @bytes == @string.
+ *
+ * Example:
+ * if (memeqstr(somebytes, bytes_len, "foo")) {
+ * printf("somebytes == 'foo'!\n");
+ * }
+ */
+PURE_FUNCTION
+static inline bool memeqstr(const void *data, size_t length, const char *string)
+{
+ return memeq(data, length, string, strlen(string));
+}
+
+/**
+ * memeqzero - Is a byte array all zeroes?
+ * @data: byte array
+ * @length: length of @data in bytes
+ *
+ * Example:
+ * if (memeqzero(somebytes, bytes_len)) {
+ * printf("somebytes == 0!\n");
+ * }
+ */
+PURE_FUNCTION
+bool memeqzero(const void *data, size_t length);
+
+/**
+ * memstarts_str - Does this byte array start with a string prefix?
+ * @a: byte array
+ * @al: length in bytes
+ * @s: string prefix
+ *
+ * Example:
+ * if (memstarts_str(somebytes, bytes_len, "It")) {
+ * printf("somebytes starts with 'It'\n");
+ * }
+ */
+PURE_FUNCTION
+static inline bool memstarts_str(const void *a, size_t al, const char *s)
+{
+ return memstarts(a, al, s, strlen(s));
+}
+
+/**
+ * memends - Does this byte array end with a given byte-array suffix?
+ * @s: byte array
+ * @s_len: length in bytes
+ * @suffix: byte array suffix
+ * @suffix_len: length of suffix in bytes
+ *
+ * Returns true if @suffix appears as a substring at the end of @s,
+ * false otherwise.
+ */
+PURE_FUNCTION
+static inline bool memends(const void *s, size_t s_len, const void *suffix, size_t suffix_len)
+{
+ return (s_len >= suffix_len) && (memcmp((const char *)s + s_len - suffix_len,
+ suffix, suffix_len) == 0);
+}
+
+/**
+ * memends_str - Does this byte array end with a string suffix?
+ * @a: byte array
+ * @al: length in bytes
+ * @s: string suffix
+ *
+ * Example:
+ * if (memends_str(somebytes, bytes_len, "It")) {
+ * printf("somebytes ends with with 'It'\n");
+ * }
+ */
+PURE_FUNCTION
+static inline bool memends_str(const void *a, size_t al, const char *s)
+{
+ return memends(a, al, s, strlen(s));
+}
+
+/**
+ * memoverlaps - Do two memory ranges overlap?
+ * @a: pointer to first memory range
+ * @al: length of first memory range
+ * @b: pointer to second memory range
+ * @al: length of second memory range
+ */
+CONST_FUNCTION
+static inline bool memoverlaps(const void *a_, size_t al,
+ const void *b_, size_t bl)
+{
+ const char *a = a_;
+ const char *b = b_;
+
+ return (a < (b + bl)) && (b < (a + al));
+}
+
+/*
+ * memswap - Exchange two memory regions
+ * @a: first region
+ * @b: second region
+ * @n: length of the regions
+ *
+ * Undefined results if the two memory regions overlap.
+ */
+void memswap(void *a, void *b, size_t n);
+
+#if HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+static inline void *memcheck_(const void *data, size_t len)
+{
+ VALGRIND_CHECK_MEM_IS_DEFINED(data, len);
+ return (void *)data;
+}
+#else
+static inline void *memcheck_(const void *data, size_t len)
+{
+ (void)len;
+ return (void *)data;
+}
+#endif
+
+#if HAVE_TYPEOF
+/**
+ * memcheck - check that a memory region is initialized
+ * @data: start of region
+ * @len: length in bytes
+ *
+ * When running under valgrind, this causes an error to be printed
+ * if the entire region is not defined. Otherwise valgrind only
+ * reports an error when an undefined value is used for a branch, or
+ * written out.
+ *
+ * Example:
+ * // Search for space, but make sure it's all initialized.
+ * if (memchr(memcheck(somebytes, bytes_len), ' ', bytes_len)) {
+ * printf("space was found!\n");
+ * }
+ */
+#define memcheck(data, len) ((__typeof__((data)+0))memcheck_((data), (len)))
+#else
+#define memcheck(data, len) memcheck_((data), (len))
+#endif
+
+/**
+ * memtaint - mark a memory region unused
+ * @data: start of region
+ * @len: length in bytes
+ *
+ * This writes an "0xdeadbeef" eyecatcher repeatedly to the memory.
+ * When running under valgrind, it also tells valgrind that the memory is
+ * uninitialized, triggering valgrind errors if it is used for branches
+ * or written out (or passed to memcheck!) in future.
+ *
+ * Example:
+ * // We'll reuse this buffer later, but be sure we don't access it.
+ * memtaint(somebytes, bytes_len);
+ */
+void memtaint(void *data, size_t len);
+#endif /* CCAN_MEM_H */
diff --git a/damus-c/node_id.c b/damus-c/node_id.c
@@ -0,0 +1,64 @@
+#include "config.h"
+#include <assert.h>
+#include "array_size.h"
+#include "mem.h"
+#include "hex.h"
+#include "talstr.h"
+#include "node_id.h"
+
+/* Convert from pubkey to compressed pubkey. */
+/*
+void node_id_from_pubkey(struct node_id *id, const struct pubkey *key)
+{
+ size_t outlen = ARRAY_SIZE(id->k);
+ if (!secp256k1_ec_pubkey_serialize(secp256k1_ctx, id->k, &outlen,
+ &key->pubkey,
+ SECP256K1_EC_COMPRESSED))
+ abort();
+}
+
+WARN_UNUSED_RESULT
+bool pubkey_from_node_id(struct pubkey *key, const struct node_id *id)
+{
+ return secp256k1_ec_pubkey_parse(secp256k1_ctx, &key->pubkey,
+ memcheck(id->k, sizeof(id->k)),
+ sizeof(id->k));
+}
+
+WARN_UNUSED_RESULT
+bool point32_from_node_id(struct point32 *key, const struct node_id *id)
+{
+ struct pubkey k;
+ if (!pubkey_from_node_id(&k, id))
+ return false;
+ return secp256k1_xonly_pubkey_from_pubkey(secp256k1_ctx, &key->pubkey,
+ NULL, &k.pubkey) == 1;
+}
+*/
+
+char *tal_hexstr(const tal_t *ctx, const void *data, size_t len)
+{
+ char *str = tal_arr(ctx, char, hex_str_size(len));
+ hex_encode(data, len, str, hex_str_size(len));
+ return str;
+}
+
+
+/* Convert to hex string of SEC1 encoding */
+char *node_id_to_hexstr(const tal_t *ctx, const struct node_id *id)
+{
+ return tal_hexstr(ctx, id->k, sizeof(id->k));
+}
+
+/* Convert from hex string of SEC1 encoding */
+
+bool node_id_from_hexstr(const char *str, size_t slen, struct node_id *id)
+{
+ return hex_decode(str, slen, id->k, sizeof(id->k));
+ /* && node_id_valid(id);*/
+}
+
+int node_id_cmp(const struct node_id *a, const struct node_id *b)
+{
+ return memcmp(a->k, b->k, sizeof(a->k));
+}
diff --git a/damus-c/node_id.h b/damus-c/node_id.h
@@ -0,0 +1,38 @@
+/* Encapsulation for pubkeys used as node ids: more compact, more dangerous. */
+#ifndef LIGHTNING_COMMON_NODE_ID_H
+#define LIGHTNING_COMMON_NODE_ID_H
+#include "config.h"
+#include "short_types.h"
+#include "tal.h"
+
+struct node_id {
+ u8 k[33];
+};
+
+static inline bool node_id_eq(const struct node_id *a,
+ const struct node_id *b)
+{
+ return memcmp(a->k, b->k, sizeof(a->k)) == 0;
+}
+
+/* Is this actually a valid pubkey? Relatively expensive. */
+//bool node_id_valid(const struct node_id *id);
+
+/* Convert to hex string of SEC1 encoding. */
+char *node_id_to_hexstr(const tal_t *ctx, const struct node_id *id);
+
+/* Convert from hex string of SEC1 encoding: checks validity! */
+bool node_id_from_hexstr(const char *str, size_t slen, struct node_id *id);
+
+/* Compare the keys `a` and `b`. Return <0 if `a`<`b`, 0 if equal and >0 otherwise */
+int node_id_cmp(const struct node_id *a, const struct node_id *b);
+
+/* If the two nodes[] are id1 and id2, which index would id1 be? */
+static inline int node_id_idx(const struct node_id *id1,
+ const struct node_id *id2)
+{
+ return node_id_cmp(id1, id2) > 0;
+}
+
+/* marshal/unmarshal functions */
+#endif /* LIGHTNING_COMMON_NODE_ID_H */
diff --git a/damus-c/overflows.h b/damus-c/overflows.h
@@ -0,0 +1,43 @@
+#ifndef LIGHTNING_COMMON_OVERFLOWS_H
+#define LIGHTNING_COMMON_OVERFLOWS_H
+#include "config.h"
+#include "short_types.h"
+
+static inline bool add_overflows_size_t(uint64_t a, uint64_t b)
+{
+ return (size_t)a != a || (size_t)b != b || (a + b) < (size_t)a;
+}
+
+static inline bool add_overflows_u64(uint64_t a, uint64_t b)
+{
+ return (a + b) < a;
+}
+
+static inline bool mul_overflows_u64(uint64_t a, uint64_t b)
+{
+ uint64_t ret;
+
+ if (a == 0)
+ return false;
+ ret = a * b;
+ return (ret / a != b);
+}
+
+static inline bool assign_overflow_u8(u8 *dst, uint64_t v)
+{
+ *dst = v;
+ return *dst == v;
+}
+
+static inline bool assign_overflow_u16(u16 *dst, uint64_t v)
+{
+ *dst = v;
+ return *dst == v;
+}
+
+static inline bool assign_overflow_u32(u32 *dst, uint64_t v)
+{
+ *dst = v;
+ return *dst == v;
+}
+#endif /* LIGHTNING_COMMON_OVERFLOWS_H */
diff --git a/damus-c/sha256.c b/damus-c/sha256.c
@@ -0,0 +1,308 @@
+/* MIT (BSD) license - see LICENSE file for details */
+/* SHA256 core code translated from the Bitcoin project's C++:
+ *
+ * src/crypto/sha256.cpp commit 417532c8acb93c36c2b6fd052b7c11b6a2906aa2
+ * Copyright (c) 2014 The Bitcoin Core developers
+ * Distributed under the MIT software license, see the accompanying
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.
+ */
+#include "sha256.h"
+#include "compiler.h"
+#include "endian.h"
+#include <stdbool.h>
+#include <assert.h>
+#include <string.h>
+
+static void invalidate_sha256(struct sha256_ctx *ctx)
+{
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+ ctx->c.md_len = 0;
+#else
+ ctx->bytes = (size_t)-1;
+#endif
+}
+
+static void check_sha256(struct sha256_ctx *ctx UNUSED)
+{
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+ assert(ctx->c.md_len != 0);
+#else
+ assert(ctx->bytes != (size_t)-1);
+#endif
+}
+
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+void sha256_init(struct sha256_ctx *ctx)
+{
+ SHA256_Init(&ctx->c);
+}
+
+void sha256_update(struct sha256_ctx *ctx, const void *p, size_t size)
+{
+ check_sha256(ctx);
+ SHA256_Update(&ctx->c, p, size);
+}
+
+void sha256_done(struct sha256_ctx *ctx, struct sha256 *res)
+{
+ SHA256_Final(res->u.u8, &ctx->c);
+ invalidate_sha256(ctx);
+}
+#else
+static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z)
+{
+ return z ^ (x & (y ^ z));
+}
+static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z)
+{
+ return (x & y) | (z & (x | y));
+}
+static uint32_t Sigma0(uint32_t x)
+{
+ return (x >> 2 | x << 30) ^ (x >> 13 | x << 19) ^ (x >> 22 | x << 10);
+}
+static uint32_t Sigma1(uint32_t x)
+{
+ return (x >> 6 | x << 26) ^ (x >> 11 | x << 21) ^ (x >> 25 | x << 7);
+}
+static uint32_t sigma0(uint32_t x)
+{
+ return (x >> 7 | x << 25) ^ (x >> 18 | x << 14) ^ (x >> 3);
+}
+static uint32_t sigma1(uint32_t x)
+{
+ return (x >> 17 | x << 15) ^ (x >> 19 | x << 13) ^ (x >> 10);
+}
+
+/** One round of SHA-256. */
+static void Round(uint32_t a, uint32_t b, uint32_t c, uint32_t *d, uint32_t e, uint32_t f, uint32_t g, uint32_t *h, uint32_t k, uint32_t w)
+{
+ uint32_t t1 = *h + Sigma1(e) + Ch(e, f, g) + k + w;
+ uint32_t t2 = Sigma0(a) + Maj(a, b, c);
+ *d += t1;
+ *h = t1 + t2;
+}
+
+/** Perform one SHA-256 transformation, processing a 64-byte chunk. */
+static void Transform(uint32_t *s, const uint32_t *chunk)
+{
+ uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
+ uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
+
+ Round(a, b, c, &d, e, f, g, &h, 0x428a2f98, w0 = be32_to_cpu(chunk[0]));
+ Round(h, a, b, &c, d, e, f, &g, 0x71374491, w1 = be32_to_cpu(chunk[1]));
+ Round(g, h, a, &b, c, d, e, &f, 0xb5c0fbcf, w2 = be32_to_cpu(chunk[2]));
+ Round(f, g, h, &a, b, c, d, &e, 0xe9b5dba5, w3 = be32_to_cpu(chunk[3]));
+ Round(e, f, g, &h, a, b, c, &d, 0x3956c25b, w4 = be32_to_cpu(chunk[4]));
+ Round(d, e, f, &g, h, a, b, &c, 0x59f111f1, w5 = be32_to_cpu(chunk[5]));
+ Round(c, d, e, &f, g, h, a, &b, 0x923f82a4, w6 = be32_to_cpu(chunk[6]));
+ Round(b, c, d, &e, f, g, h, &a, 0xab1c5ed5, w7 = be32_to_cpu(chunk[7]));
+ Round(a, b, c, &d, e, f, g, &h, 0xd807aa98, w8 = be32_to_cpu(chunk[8]));
+ Round(h, a, b, &c, d, e, f, &g, 0x12835b01, w9 = be32_to_cpu(chunk[9]));
+ Round(g, h, a, &b, c, d, e, &f, 0x243185be, w10 = be32_to_cpu(chunk[10]));
+ Round(f, g, h, &a, b, c, d, &e, 0x550c7dc3, w11 = be32_to_cpu(chunk[11]));
+ Round(e, f, g, &h, a, b, c, &d, 0x72be5d74, w12 = be32_to_cpu(chunk[12]));
+ Round(d, e, f, &g, h, a, b, &c, 0x80deb1fe, w13 = be32_to_cpu(chunk[13]));
+ Round(c, d, e, &f, g, h, a, &b, 0x9bdc06a7, w14 = be32_to_cpu(chunk[14]));
+ Round(b, c, d, &e, f, g, h, &a, 0xc19bf174, w15 = be32_to_cpu(chunk[15]));
+
+ Round(a, b, c, &d, e, f, g, &h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
+ Round(h, a, b, &c, d, e, f, &g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
+ Round(g, h, a, &b, c, d, e, &f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3));
+ Round(f, g, h, &a, b, c, d, &e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4));
+ Round(e, f, g, &h, a, b, c, &d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5));
+ Round(d, e, f, &g, h, a, b, &c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6));
+ Round(c, d, e, &f, g, h, a, &b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7));
+ Round(b, c, d, &e, f, g, h, &a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8));
+ Round(a, b, c, &d, e, f, g, &h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9));
+ Round(h, a, b, &c, d, e, f, &g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10));
+ Round(g, h, a, &b, c, d, e, &f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11));
+ Round(f, g, h, &a, b, c, d, &e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12));
+ Round(e, f, g, &h, a, b, c, &d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, &g, h, a, b, &c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, &f, g, h, a, &b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, &e, f, g, h, &a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0));
+
+ Round(a, b, c, &d, e, f, g, &h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1));
+ Round(h, a, b, &c, d, e, f, &g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2));
+ Round(g, h, a, &b, c, d, e, &f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3));
+ Round(f, g, h, &a, b, c, d, &e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4));
+ Round(e, f, g, &h, a, b, c, &d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5));
+ Round(d, e, f, &g, h, a, b, &c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6));
+ Round(c, d, e, &f, g, h, a, &b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7));
+ Round(b, c, d, &e, f, g, h, &a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8));
+ Round(a, b, c, &d, e, f, g, &h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9));
+ Round(h, a, b, &c, d, e, f, &g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10));
+ Round(g, h, a, &b, c, d, e, &f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11));
+ Round(f, g, h, &a, b, c, d, &e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12));
+ Round(e, f, g, &h, a, b, c, &d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, &g, h, a, b, &c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, &f, g, h, a, &b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, &e, f, g, h, &a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0));
+
+ Round(a, b, c, &d, e, f, g, &h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1));
+ Round(h, a, b, &c, d, e, f, &g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2));
+ Round(g, h, a, &b, c, d, e, &f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3));
+ Round(f, g, h, &a, b, c, d, &e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4));
+ Round(e, f, g, &h, a, b, c, &d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5));
+ Round(d, e, f, &g, h, a, b, &c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6));
+ Round(c, d, e, &f, g, h, a, &b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7));
+ Round(b, c, d, &e, f, g, h, &a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8));
+ Round(a, b, c, &d, e, f, g, &h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9));
+ Round(h, a, b, &c, d, e, f, &g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10));
+ Round(g, h, a, &b, c, d, e, &f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11));
+ Round(f, g, h, &a, b, c, d, &e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12));
+ Round(e, f, g, &h, a, b, c, &d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13));
+ Round(d, e, f, &g, h, a, b, &c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14));
+ Round(c, d, e, &f, g, h, a, &b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15));
+ Round(b, c, d, &e, f, g, h, &a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0));
+
+ s[0] += a;
+ s[1] += b;
+ s[2] += c;
+ s[3] += d;
+ s[4] += e;
+ s[5] += f;
+ s[6] += g;
+ s[7] += h;
+}
+
+static bool alignment_ok(const void *p UNUSED, size_t n UNUSED)
+{
+#if HAVE_UNALIGNED_ACCESS
+ return true;
+#else
+ return ((size_t)p % n == 0);
+#endif
+}
+
+static void add(struct sha256_ctx *ctx, const void *p, size_t len)
+{
+ const unsigned char *data = p;
+ size_t bufsize = ctx->bytes % 64;
+
+ if (bufsize + len >= 64) {
+ /* Fill the buffer, and process it. */
+ memcpy(ctx->buf.u8 + bufsize, data, 64 - bufsize);
+ ctx->bytes += 64 - bufsize;
+ data += 64 - bufsize;
+ len -= 64 - bufsize;
+ Transform(ctx->s, ctx->buf.u32);
+ bufsize = 0;
+ }
+
+ while (len >= 64) {
+ /* Process full chunks directly from the source. */
+ if (alignment_ok(data, sizeof(uint32_t)))
+ Transform(ctx->s, (const uint32_t *)data);
+ else {
+ memcpy(ctx->buf.u8, data, sizeof(ctx->buf));
+ Transform(ctx->s, ctx->buf.u32);
+ }
+ ctx->bytes += 64;
+ data += 64;
+ len -= 64;
+ }
+
+ if (len) {
+ /* Fill the buffer with what remains. */
+ memcpy(ctx->buf.u8 + bufsize, data, len);
+ ctx->bytes += len;
+ }
+}
+
+void sha256_init(struct sha256_ctx *ctx)
+{
+ struct sha256_ctx init = SHA256_INIT;
+ *ctx = init;
+}
+
+void sha256_update(struct sha256_ctx *ctx, const void *p, size_t size)
+{
+ check_sha256(ctx);
+ add(ctx, p, size);
+}
+
+void sha256_done(struct sha256_ctx *ctx, struct sha256 *res)
+{
+ static const unsigned char pad[64] = {0x80};
+ uint64_t sizedesc;
+ size_t i;
+
+ sizedesc = cpu_to_be64((uint64_t)ctx->bytes << 3);
+ /* Add '1' bit to terminate, then all 0 bits, up to next block - 8. */
+ add(ctx, pad, 1 + ((128 - 8 - (ctx->bytes % 64) - 1) % 64));
+ /* Add number of bits of data (big endian) */
+ add(ctx, &sizedesc, 8);
+ for (i = 0; i < sizeof(ctx->s) / sizeof(ctx->s[0]); i++)
+ res->u.u32[i] = cpu_to_be32(ctx->s[i]);
+ invalidate_sha256(ctx);
+}
+#endif
+
+void sha256(struct sha256 *sha, const void *p, size_t size)
+{
+ struct sha256_ctx ctx;
+
+ sha256_init(&ctx);
+ sha256_update(&ctx, p, size);
+ sha256_done(&ctx, sha);
+}
+
+void sha256_u8(struct sha256_ctx *ctx, uint8_t v)
+{
+ sha256_update(ctx, &v, sizeof(v));
+}
+
+void sha256_u16(struct sha256_ctx *ctx, uint16_t v)
+{
+ sha256_update(ctx, &v, sizeof(v));
+}
+
+void sha256_u32(struct sha256_ctx *ctx, uint32_t v)
+{
+ sha256_update(ctx, &v, sizeof(v));
+}
+
+void sha256_u64(struct sha256_ctx *ctx, uint64_t v)
+{
+ sha256_update(ctx, &v, sizeof(v));
+}
+
+/* Add as little-endian */
+void sha256_le16(struct sha256_ctx *ctx, uint16_t v)
+{
+ leint16_t lev = cpu_to_le16(v);
+ sha256_update(ctx, &lev, sizeof(lev));
+}
+
+void sha256_le32(struct sha256_ctx *ctx, uint32_t v)
+{
+ leint32_t lev = cpu_to_le32(v);
+ sha256_update(ctx, &lev, sizeof(lev));
+}
+
+void sha256_le64(struct sha256_ctx *ctx, uint64_t v)
+{
+ leint64_t lev = cpu_to_le64(v);
+ sha256_update(ctx, &lev, sizeof(lev));
+}
+
+/* Add as big-endian */
+void sha256_be16(struct sha256_ctx *ctx, uint16_t v)
+{
+ beint16_t bev = cpu_to_be16(v);
+ sha256_update(ctx, &bev, sizeof(bev));
+}
+
+void sha256_be32(struct sha256_ctx *ctx, uint32_t v)
+{
+ beint32_t bev = cpu_to_be32(v);
+ sha256_update(ctx, &bev, sizeof(bev));
+}
+
+void sha256_be64(struct sha256_ctx *ctx, uint64_t v)
+{
+ beint64_t bev = cpu_to_be64(v);
+ sha256_update(ctx, &bev, sizeof(bev));
+}
diff --git a/damus-c/sha256.h b/damus-c/sha256.h
@@ -0,0 +1,147 @@
+#ifndef CCAN_CRYPTO_SHA256_H
+#define CCAN_CRYPTO_SHA256_H
+/* BSD-MIT - see LICENSE file for details */
+#include "config.h"
+#include <stdint.h>
+#include <stdlib.h>
+
+/* Uncomment this to use openssl's SHA256 routines (and link with -lcrypto) */
+/*#define CCAN_CRYPTO_SHA256_USE_OPENSSL 1*/
+
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+#include <openssl/sha.h>
+#endif
+
+/**
+ * struct sha256 - structure representing a completed SHA256.
+ * @u.u8: an unsigned char array.
+ * @u.u32: a 32-bit integer array.
+ *
+ * Other fields may be added to the union in future.
+ */
+struct sha256 {
+ union {
+ uint32_t u32[8];
+ unsigned char u8[32];
+ } u;
+};
+
+/**
+ * sha256 - return sha256 of an object.
+ * @sha256: the sha256 to fill in
+ * @p: pointer to memory,
+ * @size: the number of bytes pointed to by
+ *
+ * The bytes pointed to by @p is SHA256 hashed into @sha256. This is
+ * equivalent to sha256_init(), sha256_update() then sha256_done().
+ */
+void sha256(struct sha256 *sha, const void *p, size_t size);
+
+/**
+ * struct sha256_ctx - structure to store running context for sha256
+ */
+struct sha256_ctx {
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+ SHA256_CTX c;
+#else
+ uint32_t s[8];
+ union {
+ uint32_t u32[16];
+ unsigned char u8[64];
+ } buf;
+ size_t bytes;
+#endif
+};
+
+/**
+ * sha256_init - initialize an SHA256 context.
+ * @ctx: the sha256_ctx to initialize
+ *
+ * This must be called before sha256_update or sha256_done, or
+ * alternately you can assign SHA256_INIT.
+ *
+ * If it was already initialized, this forgets anything which was
+ * hashed before.
+ *
+ * Example:
+ * static void hash_all(const char **arr, struct sha256 *hash)
+ * {
+ * size_t i;
+ * struct sha256_ctx ctx;
+ *
+ * sha256_init(&ctx);
+ * for (i = 0; arr[i]; i++)
+ * sha256_update(&ctx, arr[i], strlen(arr[i]));
+ * sha256_done(&ctx, hash);
+ * }
+ */
+void sha256_init(struct sha256_ctx *ctx);
+
+/**
+ * SHA256_INIT - initializer for an SHA256 context.
+ *
+ * This can be used to statically initialize an SHA256 context (instead
+ * of sha256_init()).
+ *
+ * Example:
+ * static void hash_all(const char **arr, struct sha256 *hash)
+ * {
+ * size_t i;
+ * struct sha256_ctx ctx = SHA256_INIT;
+ *
+ * for (i = 0; arr[i]; i++)
+ * sha256_update(&ctx, arr[i], strlen(arr[i]));
+ * sha256_done(&ctx, hash);
+ * }
+ */
+#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
+#define SHA256_INIT \
+ { { { 0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, \
+ 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul }, \
+ 0x0, 0x0, \
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \
+ 0x0, 0x20 } }
+#else
+#define SHA256_INIT \
+ { { 0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, \
+ 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul }, \
+ { { 0 } }, 0 }
+#endif
+
+/**
+ * sha256_update - include some memory in the hash.
+ * @ctx: the sha256_ctx to use
+ * @p: pointer to memory,
+ * @size: the number of bytes pointed to by
+ *
+ * You can call this multiple times to hash more data, before calling
+ * sha256_done().
+ */
+void sha256_update(struct sha256_ctx *ctx, const void *p, size_t size);
+
+/**
+ * sha256_done - finish SHA256 and return the hash
+ * @ctx: the sha256_ctx to complete
+ * @res: the hash to return.
+ *
+ * Note that @ctx is *destroyed* by this, and must be reinitialized.
+ * To avoid that, pass a copy instead.
+ */
+void sha256_done(struct sha256_ctx *sha256, struct sha256 *res);
+
+/* Add various types to an SHA256 hash */
+void sha256_u8(struct sha256_ctx *ctx, uint8_t v);
+void sha256_u16(struct sha256_ctx *ctx, uint16_t v);
+void sha256_u32(struct sha256_ctx *ctx, uint32_t v);
+void sha256_u64(struct sha256_ctx *ctx, uint64_t v);
+
+/* Add as little-endian */
+void sha256_le16(struct sha256_ctx *ctx, uint16_t v);
+void sha256_le32(struct sha256_ctx *ctx, uint32_t v);
+void sha256_le64(struct sha256_ctx *ctx, uint64_t v);
+
+/* Add as big-endian */
+void sha256_be16(struct sha256_ctx *ctx, uint16_t v);
+void sha256_be32(struct sha256_ctx *ctx, uint32_t v);
+void sha256_be64(struct sha256_ctx *ctx, uint64_t v);
+#endif /* CCAN_CRYPTO_SHA256_H */
diff --git a/damus-c/short_types.h b/damus-c/short_types.h
@@ -0,0 +1,35 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_SHORT_TYPES_H
+#define CCAN_SHORT_TYPES_H
+#include <stdint.h>
+
+/**
+ * u64/s64/u32/s32/u16/s16/u8/s8 - short names for explicitly-sized types.
+ */
+typedef uint64_t u64;
+typedef int64_t s64;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint16_t u16;
+typedef int16_t s16;
+typedef uint8_t u8;
+typedef int8_t s8;
+
+/* Whichever they include first, they get these definitions. */
+#ifdef CCAN_ENDIAN_H
+/**
+ * be64/be32/be16 - 64/32/16 bit big-endian representation.
+ */
+typedef beint64_t be64;
+typedef beint32_t be32;
+typedef beint16_t be16;
+
+/**
+ * le64/le32/le16 - 64/32/16 bit little-endian representation.
+ */
+typedef leint64_t le64;
+typedef leint32_t le32;
+typedef leint16_t le16;
+#endif
+
+#endif /* CCAN_SHORT_TYPES_H */
diff --git a/damus-c/str.h b/damus-c/str.h
@@ -0,0 +1,228 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_STR_H
+#define CCAN_STR_H
+#include "config.h"
+#include <string.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <ctype.h>
+
+/**
+ * streq - Are two strings equal?
+ * @a: first string
+ * @b: first string
+ *
+ * This macro is arguably more readable than "!strcmp(a, b)".
+ *
+ * Example:
+ * if (streq(somestring, ""))
+ * printf("String is empty!\n");
+ */
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+/**
+ * strstarts - Does this string start with this prefix?
+ * @str: string to test
+ * @prefix: prefix to look for at start of str
+ *
+ * Example:
+ * if (strstarts(somestring, "foo"))
+ * printf("String %s begins with 'foo'!\n", somestring);
+ */
+#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0)
+
+/**
+ * strends - Does this string end with this postfix?
+ * @str: string to test
+ * @postfix: postfix to look for at end of str
+ *
+ * Example:
+ * if (strends(somestring, "foo"))
+ * printf("String %s end with 'foo'!\n", somestring);
+ */
+static inline bool strends(const char *str, const char *postfix)
+{
+ if (strlen(str) < strlen(postfix))
+ return false;
+
+ return streq(str + strlen(str) - strlen(postfix), postfix);
+}
+
+/**
+ * stringify - Turn expression into a string literal
+ * @expr: any C expression
+ *
+ * Example:
+ * #define PRINT_COND_IF_FALSE(cond) \
+ * ((cond) || printf("%s is false!", stringify(cond)))
+ */
+#define stringify(expr) stringify_1(expr)
+/* Double-indirection required to stringify expansions */
+#define stringify_1(expr) #expr
+
+/**
+ * strcount - Count number of (non-overlapping) occurrences of a substring.
+ * @haystack: a C string
+ * @needle: a substring
+ *
+ * Example:
+ * assert(strcount("aaa aaa", "a") == 6);
+ * assert(strcount("aaa aaa", "ab") == 0);
+ * assert(strcount("aaa aaa", "aa") == 2);
+ */
+size_t strcount(const char *haystack, const char *needle);
+
+/**
+ * STR_MAX_CHARS - Maximum possible size of numeric string for this type.
+ * @type_or_expr: a pointer or integer type or expression.
+ *
+ * This provides enough space for a nul-terminated string which represents the
+ * largest possible value for the type or expression.
+ *
+ * Note: The implementation adds extra space so hex values or negative
+ * values will fit (eg. sprintf(... "%p"). )
+ *
+ * Example:
+ * char str[STR_MAX_CHARS(int)];
+ *
+ * sprintf(str, "%i", 7);
+ */
+#define STR_MAX_CHARS(type_or_expr) \
+ ((sizeof(type_or_expr) * CHAR_BIT + 8) / 9 * 3 + 2 \
+ + STR_MAX_CHARS_TCHECK_(type_or_expr))
+
+#if HAVE_TYPEOF
+/* Only a simple type can have 0 assigned, so test that. */
+#define STR_MAX_CHARS_TCHECK_(type_or_expr) \
+ (sizeof(({ typeof(type_or_expr) x = 0; x; }))*0)
+#else
+#define STR_MAX_CHARS_TCHECK_(type_or_expr) 0
+#endif
+
+/**
+ * cisalnum - isalnum() which takes a char (and doesn't accept EOF)
+ * @c: a character
+ *
+ * Surprisingly, the standard ctype.h isalnum() takes an int, which
+ * must have the value of EOF (-1) or an unsigned char. This variant
+ * takes a real char, and doesn't accept EOF.
+ */
+static inline bool cisalnum(char c)
+{
+ return isalnum((unsigned char)c);
+}
+static inline bool cisalpha(char c)
+{
+ return isalpha((unsigned char)c);
+}
+static inline bool cisascii(char c)
+{
+ return isascii((unsigned char)c);
+}
+#if HAVE_ISBLANK
+static inline bool cisblank(char c)
+{
+ return isblank((unsigned char)c);
+}
+#endif
+static inline bool ciscntrl(char c)
+{
+ return iscntrl((unsigned char)c);
+}
+static inline bool cisdigit(char c)
+{
+ return isdigit((unsigned char)c);
+}
+static inline bool cisgraph(char c)
+{
+ return isgraph((unsigned char)c);
+}
+static inline bool cislower(char c)
+{
+ return islower((unsigned char)c);
+}
+static inline bool cisprint(char c)
+{
+ return isprint((unsigned char)c);
+}
+static inline bool cispunct(char c)
+{
+ return ispunct((unsigned char)c);
+}
+static inline bool cisspace(char c)
+{
+ return isspace((unsigned char)c);
+}
+static inline bool cisupper(char c)
+{
+ return isupper((unsigned char)c);
+}
+static inline bool cisxdigit(char c)
+{
+ return isxdigit((unsigned char)c);
+}
+
+#include "str_debug.h"
+
+/* These checks force things out of line, hence they are under DEBUG. */
+#ifdef CCAN_STR_DEBUG
+#include <ccan/build_assert/build_assert.h>
+
+/* These are commonly misused: they take -1 or an *unsigned* char value. */
+#undef isalnum
+#undef isalpha
+#undef isascii
+#undef isblank
+#undef iscntrl
+#undef isdigit
+#undef isgraph
+#undef islower
+#undef isprint
+#undef ispunct
+#undef isspace
+#undef isupper
+#undef isxdigit
+
+/* You can use a char if char is unsigned. */
+#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
+#define str_check_arg_(i) \
+ ((i) + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(i), \
+ char) \
+ || (char)255 > 0))
+#else
+#define str_check_arg_(i) (i)
+#endif
+
+#define isalnum(i) str_isalnum(str_check_arg_(i))
+#define isalpha(i) str_isalpha(str_check_arg_(i))
+#define isascii(i) str_isascii(str_check_arg_(i))
+#if HAVE_ISBLANK
+#define isblank(i) str_isblank(str_check_arg_(i))
+#endif
+#define iscntrl(i) str_iscntrl(str_check_arg_(i))
+#define isdigit(i) str_isdigit(str_check_arg_(i))
+#define isgraph(i) str_isgraph(str_check_arg_(i))
+#define islower(i) str_islower(str_check_arg_(i))
+#define isprint(i) str_isprint(str_check_arg_(i))
+#define ispunct(i) str_ispunct(str_check_arg_(i))
+#define isspace(i) str_isspace(str_check_arg_(i))
+#define isupper(i) str_isupper(str_check_arg_(i))
+#define isxdigit(i) str_isxdigit(str_check_arg_(i))
+
+#if HAVE_TYPEOF
+/* With GNU magic, we can make const-respecting standard string functions. */
+#undef strstr
+#undef strchr
+#undef strrchr
+
+/* + 0 is needed to decay array into pointer. */
+#define strstr(haystack, needle) \
+ ((typeof((haystack) + 0))str_strstr((haystack), (needle)))
+#define strchr(haystack, c) \
+ ((typeof((haystack) + 0))str_strchr((haystack), (c)))
+#define strrchr(haystack, c) \
+ ((typeof((haystack) + 0))str_strrchr((haystack), (c)))
+#endif
+#endif /* CCAN_STR_DEBUG */
+
+#endif /* CCAN_STR_H */
diff --git a/damus-c/str_debug.h b/damus-c/str_debug.h
@@ -0,0 +1,30 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_STR_DEBUG_H
+#define CCAN_STR_DEBUG_H
+
+/* #define CCAN_STR_DEBUG 1 */
+
+#ifdef CCAN_STR_DEBUG
+/* Because we mug the real ones with macros, we need our own wrappers. */
+int str_isalnum(int i);
+int str_isalpha(int i);
+int str_isascii(int i);
+#if HAVE_ISBLANK
+int str_isblank(int i);
+#endif
+int str_iscntrl(int i);
+int str_isdigit(int i);
+int str_isgraph(int i);
+int str_islower(int i);
+int str_isprint(int i);
+int str_ispunct(int i);
+int str_isspace(int i);
+int str_isupper(int i);
+int str_isxdigit(int i);
+
+char *str_strstr(const char *haystack, const char *needle);
+char *str_strchr(const char *s, int c);
+char *str_strrchr(const char *s, int c);
+#endif /* CCAN_STR_DEBUG */
+
+#endif /* CCAN_STR_DEBUG_H */
diff --git a/damus-c/structeq.h b/damus-c/structeq.h
@@ -0,0 +1,46 @@
+/* MIT (BSD) license - see LICENSE file for details */
+#ifndef CCAN_STRUCTEQ_H
+#define CCAN_STRUCTEQ_H
+#include "build_assert.h"
+#include "cppmagic.h"
+#include <string.h>
+#include <stdbool.h>
+
+/**
+ * STRUCTEQ_DEF - define an ..._eq function to compare two structures.
+ * @sname: name of the structure, and function (<sname>_eq) to define.
+ * @padbytes: number of bytes of expected padding, or negative "max".
+ * @...: name of every member of the structure.
+ *
+ * This generates a single memcmp() call in the common case where the
+ * structure contains no padding. Since it can't tell the difference between
+ * padding and a missing member, @padbytes can be used to assert that
+ * there isn't any, or how many we expect. A negative number means
+ * "up to or equal to that amount of padding", as padding can be
+ * platform dependent.
+ */
+#define STRUCTEQ_DEF(sname, padbytes, ...) \
+static inline bool CPPMAGIC_GLUE2(sname, _eq)(const struct sname *_a, \
+ const struct sname *_b) \
+{ \
+ BUILD_ASSERT(((padbytes) < 0 && \
+ CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
+ __VA_ARGS__)) \
+ - (padbytes) >= sizeof(*_a)) \
+ || CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
+ __VA_ARGS__)) \
+ + (padbytes) == sizeof(*_a)); \
+ if (CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, __VA_ARGS__)) \
+ == sizeof(*_a)) \
+ return memcmp(_a, _b, sizeof(*_a)) == 0; \
+ else \
+ return CPPMAGIC_JOIN(&&, \
+ CPPMAGIC_MAP(STRUCTEQ_MEMBER_CMP_, \
+ __VA_ARGS__)); \
+}
+
+/* Helpers */
+#define STRUCTEQ_MEMBER_SIZE_(m) sizeof((_a)->m)
+#define STRUCTEQ_MEMBER_CMP_(m) memcmp(&_a->m, &_b->m, sizeof(_a->m)) == 0
+
+#endif /* CCAN_STRUCTEQ_H */
diff --git a/damus-c/take.c b/damus-c/take.c
@@ -0,0 +1,126 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#include "take.h"
+#include "likely.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const void **takenarr;
+static const char **labelarr;
+static size_t max_taken, num_taken;
+static size_t allocfail;
+static void (*allocfailfn)(const void *p);
+
+void *take_(const void *p, const char *label)
+{
+ /* Overallocate: it's better than risking calloc returning NULL! */
+ if (unlikely(label && !labelarr))
+ labelarr = calloc(max_taken+1, sizeof(*labelarr));
+
+ if (unlikely(num_taken == max_taken)) {
+ const void **new;
+
+ new = realloc(takenarr, sizeof(*takenarr) * (max_taken+1));
+ if (unlikely(!new)) {
+ if (allocfailfn) {
+ allocfail++;
+ allocfailfn(p);
+ return NULL;
+ }
+ /* Otherwise we leak p. */
+ return (void *)p;
+ }
+ takenarr = new;
+ /* Once labelarr is set, we maintain it. */
+ if (labelarr) {
+ const char **labelarr_new;
+ labelarr_new = realloc(labelarr,
+ sizeof(*labelarr) * (max_taken+1));
+ if (labelarr_new) {
+ labelarr = labelarr_new;
+ } else {
+ /* num_taken will be out of sync with the size of
+ * labelarr after realloc failure.
+ * Just pretend that we never had labelarr allocated. */
+ free(labelarr);
+ labelarr = NULL;
+ }
+ }
+ max_taken++;
+ }
+ if (unlikely(labelarr))
+ labelarr[num_taken] = label;
+ takenarr[num_taken++] = p;
+
+ return (void *)p;
+}
+
+static size_t find_taken(const void *p)
+{
+ size_t i;
+
+ for (i = 0; i < num_taken; i++) {
+ if (takenarr[i] == p)
+ return i+1;
+ }
+ return 0;
+}
+
+bool taken(const void *p)
+{
+ size_t i;
+
+ if (!p && unlikely(allocfail)) {
+ allocfail--;
+ return true;
+ }
+
+ i = find_taken(p);
+ if (!i)
+ return false;
+
+ memmove(&takenarr[i-1], &takenarr[i],
+ (--num_taken - (i - 1))*sizeof(takenarr[0]));
+ return true;
+}
+
+bool is_taken(const void *p)
+{
+ if (!p && unlikely(allocfail))
+ return true;
+
+ return find_taken(p) > 0;
+}
+
+const char *taken_any(void)
+{
+ static char pointer_buf[32];
+
+ if (num_taken == 0)
+ return NULL;
+
+ /* We're *allowed* to have some with labels, some without. */
+ if (labelarr) {
+ size_t i;
+ for (i = 0; i < num_taken; i++)
+ if (labelarr[i])
+ return labelarr[i];
+ }
+
+ sprintf(pointer_buf, "%p", takenarr[0]);
+ return pointer_buf;
+}
+
+void take_cleanup(void)
+{
+ max_taken = num_taken = 0;
+ free(takenarr);
+ takenarr = NULL;
+ free(labelarr);
+ labelarr = NULL;
+}
+
+void take_allocfail(void (*fn)(const void *p))
+{
+ allocfailfn = fn;
+}
diff --git a/damus-c/take.h b/damus-c/take.h
@@ -0,0 +1,136 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_TAKE_H
+#define CCAN_TAKE_H
+#include "config.h"
+#include <stdbool.h>
+#include "str.h"
+
+#ifdef CCAN_TAKE_DEBUG
+#define TAKE_LABEL(p) __FILE__ ":" stringify(__LINE__) ":" stringify(p)
+#else
+#define TAKE_LABEL(p) NULL
+#endif
+
+/**
+ * TAKES - annotate a formal parameter as being take()-able
+ *
+ * This doesn't do anything, but useful for documentation.
+ *
+ * Example:
+ * void print_string(const char *str TAKES);
+ *
+ */
+#define TAKES
+
+/**
+ * take - record a pointer to be consumed by the function its handed to.
+ * @p: the pointer to mark, or NULL.
+ *
+ * This marks a pointer object to be freed by the called function,
+ * which is extremely useful for chaining functions. It works on
+ * NULL, for pass-through error handling.
+ */
+#define take(p) (take_typeof(p) take_((p), TAKE_LABEL(p)))
+
+/**
+ * taken - check (and un-take) a pointer was passed with take()
+ * @p: the pointer to check.
+ *
+ * A function which accepts take() arguments uses this to see if it
+ * should own the pointer; it will be removed from the take list, so
+ * this only returns true once.
+ *
+ * Example:
+ * // Silly routine to add 1
+ * static int *add_one(const int *num TAKES)
+ * {
+ * int *ret;
+ * if (taken(num))
+ * ret = (int *)num;
+ * else
+ * ret = malloc(sizeof(int));
+ * if (ret)
+ * *ret = (*num) + 1;
+ * return ret;
+ * }
+ */
+bool taken(const void *p);
+
+/**
+ * is_taken - check if a pointer was passed with take()
+ * @p: the pointer to check.
+ *
+ * This is like the above, but doesn't remove it from the taken list.
+ *
+ * Example:
+ * // Silly routine to add 1: doesn't handle taken args!
+ * static int *add_one_notake(const int *num)
+ * {
+ * int *ret = malloc(sizeof(int));
+ * assert(!is_taken(num));
+ * if (ret)
+ * *ret = (*num) + 1;
+ * return ret;
+ * }
+ */
+bool is_taken(const void *p);
+
+/**
+ * taken_any - are there any taken pointers?
+ *
+ * Mainly useful for debugging take() leaks. With CCAN_TAKE_DEBUG, returns
+ * the label where the pointer was passed to take(), otherwise returns
+ * a static char buffer with the pointer value in it. NULL if none are taken.
+ *
+ * Example:
+ * static void cleanup(void)
+ * {
+ * assert(!taken_any());
+ * }
+ */
+const char *taken_any(void);
+
+/**
+ * take_cleanup - remove all taken pointers from list.
+ *
+ * This is useful in atexit() handlers for valgrind-style leak detection.
+ *
+ * Example:
+ * static void cleanup2(void)
+ * {
+ * take_cleanup();
+ * }
+ */
+void take_cleanup(void);
+
+/**
+ * take_allocfail - set function to call if we can't reallocated taken array.
+ * @fn: the function.
+ *
+ * If this is not set, then if the array reallocation fails, the
+ * pointer won't be marked taken(). If @fn returns, it is expected to
+ * free the pointer; we return NULL from take() and the function handles
+ * it like any allocation failure.
+ *
+ * Example:
+ * static void free_on_fail(const void *p)
+ * {
+ * free((void *)p);
+ * }
+ *
+ * static void init(void)
+ * {
+ * take_allocfail(free_on_fail);
+ * }
+ */
+void take_allocfail(void (*fn)(const void *p));
+
+/* Private functions */
+#if HAVE_TYPEOF
+#define take_typeof(ptr) (__typeof__(ptr))
+#else
+#define take_typeof(ptr)
+#endif
+
+void *take_(const void *p, const char *label);
+#endif /* CCAN_TAKE_H */
diff --git a/damus-c/tal.c b/damus-c/tal.c
@@ -0,0 +1,972 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#include "tal.h"
+#include "compiler.h"
+#include "list.h"
+#include "alignof.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <limits.h>
+#include <stdint.h>
+#include <errno.h>
+
+//#define TAL_DEBUG 1
+
+#define NOTIFY_IS_DESTRUCTOR 512
+#define NOTIFY_EXTRA_ARG 1024
+
+/* This makes our parent_child ptr stand out for to_tal_hdr checks */
+#define TAL_PTR_OBFUSTICATOR ((intptr_t)0x1984200820142016ULL)
+
+/* 32-bit type field, first byte 0 in either endianness. */
+enum prop_type {
+ CHILDREN = 0x00c1d500,
+ NAME = 0x00111100,
+ NOTIFIER = 0x00071f00,
+};
+
+struct tal_hdr {
+ struct list_node list;
+ struct prop_hdr *prop;
+ /* XOR with TAL_PTR_OBFUSTICATOR */
+ intptr_t parent_child;
+ size_t bytelen;
+};
+
+struct prop_hdr {
+ enum prop_type type;
+ struct prop_hdr *next;
+};
+
+struct children {
+ struct prop_hdr hdr; /* CHILDREN */
+ struct tal_hdr *parent;
+ struct list_head children; /* Head of siblings. */
+};
+
+struct name {
+ struct prop_hdr hdr; /* NAME */
+ char name[];
+};
+
+struct notifier {
+ struct prop_hdr hdr; /* NOTIFIER */
+ enum tal_notify_type types;
+ union notifier_cb {
+ void (*notifyfn)(tal_t *, enum tal_notify_type, void *);
+ void (*destroy)(tal_t *); /* If NOTIFY_IS_DESTRUCTOR set */
+ void (*destroy2)(tal_t *, void *); /* If NOTIFY_EXTRA_ARG */
+ } u;
+};
+
+/* Extra arg */
+struct notifier_extra_arg {
+ struct notifier n;
+ void *arg;
+};
+
+#define EXTRA_ARG(n) (((struct notifier_extra_arg *)(n))->arg)
+
+static struct {
+ struct tal_hdr hdr;
+ struct children c;
+} null_parent = { { { &null_parent.hdr.list, &null_parent.hdr.list },
+ &null_parent.c.hdr, TAL_PTR_OBFUSTICATOR, 0 },
+ { { CHILDREN, NULL },
+ &null_parent.hdr,
+ { { &null_parent.c.children.n,
+ &null_parent.c.children.n } }
+ }
+};
+
+
+static void *(*allocfn)(size_t size) = malloc;
+static void *(*resizefn)(void *, size_t size) = realloc;
+static void (*freefn)(void *) = free;
+static void (*errorfn)(const char *msg) = (void *)abort;
+/* Count on non-destrutor notifiers; often stays zero. */
+static size_t notifiers = 0;
+
+static inline void COLD call_error(const char *msg)
+{
+ errorfn(msg);
+}
+
+static bool get_destroying_bit(intptr_t parent_child)
+{
+ return parent_child & 1;
+}
+
+static void set_destroying_bit(intptr_t *parent_child)
+{
+ *parent_child |= 1;
+}
+
+static struct children *ignore_destroying_bit(intptr_t parent_child)
+{
+ return (void *)((parent_child ^ TAL_PTR_OBFUSTICATOR) & ~(intptr_t)1);
+}
+
+/* This means valgrind can see leaks. */
+void tal_cleanup(void)
+{
+ struct tal_hdr *i;
+
+ while ((i = list_top(&null_parent.c.children, struct tal_hdr, list))) {
+ list_del(&i->list);
+ memset(i, 0, sizeof(*i));
+ }
+
+ /* Cleanup any taken pointers. */
+ take_cleanup();
+}
+
+/* We carefully start all real properties with a zero byte. */
+static bool is_literal(const struct prop_hdr *prop)
+{
+ return ((char *)prop)[0] != 0;
+}
+
+#ifndef NDEBUG
+static const void *bounds_start, *bounds_end;
+
+static void update_bounds(const void *new, size_t size)
+{
+ if (unlikely(!bounds_start)) {
+ bounds_start = new;
+ bounds_end = (char *)new + size;
+ } else if (new < bounds_start)
+ bounds_start = new;
+ else if ((char *)new + size > (char *)bounds_end)
+ bounds_end = (char *)new + size;
+}
+
+static bool in_bounds(const void *p)
+{
+ return !p
+ || (p >= (void *)&null_parent && p <= (void *)(&null_parent + 1))
+ || (p >= bounds_start && p <= bounds_end);
+}
+#else
+static void update_bounds(const void *new, size_t size)
+{
+}
+
+static bool in_bounds(const void *p)
+{
+ return true;
+}
+#endif
+
+static void check_bounds(const void *p)
+{
+ if (!in_bounds(p))
+ call_error("Not a valid header");
+}
+
+static struct tal_hdr *to_tal_hdr(const void *ctx)
+{
+ struct tal_hdr *t;
+
+ t = (struct tal_hdr *)((char *)ctx - sizeof(struct tal_hdr));
+ check_bounds(t);
+ check_bounds(ignore_destroying_bit(t->parent_child));
+ check_bounds(t->list.next);
+ check_bounds(t->list.prev);
+ if (t->prop && !is_literal(t->prop))
+ check_bounds(t->prop);
+ return t;
+}
+
+static struct tal_hdr *to_tal_hdr_or_null(const void *ctx)
+{
+ if (!ctx)
+ return &null_parent.hdr;
+ return to_tal_hdr(ctx);
+}
+
+static void *from_tal_hdr(const struct tal_hdr *hdr)
+{
+ return (void *)(hdr + 1);
+}
+
+static void *from_tal_hdr_or_null(const struct tal_hdr *hdr)
+{
+ if (hdr == &null_parent.hdr)
+ return NULL;
+ return from_tal_hdr(hdr);
+}
+
+#ifdef TAL_DEBUG
+static struct tal_hdr *debug_tal(struct tal_hdr *tal)
+{
+ tal_check(from_tal_hdr_or_null(tal), "TAL_DEBUG ");
+ return tal;
+}
+#else
+static struct tal_hdr *debug_tal(struct tal_hdr *tal)
+{
+ return tal;
+}
+#endif
+
+static void notify(const struct tal_hdr *ctx,
+ enum tal_notify_type type, const void *info,
+ int saved_errno)
+{
+ const struct prop_hdr *p;
+
+ for (p = ctx->prop; p; p = p->next) {
+ struct notifier *n;
+
+ if (is_literal(p))
+ break;
+ if (p->type != NOTIFIER)
+ continue;
+ n = (struct notifier *)p;
+ if (n->types & type) {
+ errno = saved_errno;
+ if (n->types & NOTIFY_IS_DESTRUCTOR) {
+ /* Blatt this notifier in case it tries to
+ * tal_del_destructor() from inside */
+ union notifier_cb cb = n->u;
+ /* It's a union, so this NULLs destroy2 too! */
+ n->u.destroy = NULL;
+ if (n->types & NOTIFY_EXTRA_ARG)
+ cb.destroy2(from_tal_hdr(ctx),
+ EXTRA_ARG(n));
+ else
+ cb.destroy(from_tal_hdr(ctx));
+ } else
+ n->u.notifyfn(from_tal_hdr_or_null(ctx), type,
+ (void *)info);
+ }
+ }
+}
+
+static void *allocate(size_t size)
+{
+ void *ret = allocfn(size);
+ if (!ret)
+ call_error("allocation failed");
+ else
+ update_bounds(ret, size);
+ return ret;
+}
+
+static struct prop_hdr **find_property_ptr(const struct tal_hdr *t,
+ enum prop_type type)
+{
+ struct prop_hdr **p;
+
+ for (p = (struct prop_hdr **)&t->prop; *p; p = &(*p)->next) {
+ if (is_literal(*p)) {
+ if (type == NAME)
+ return p;
+ break;
+ }
+ if ((*p)->type == type)
+ return p;
+ }
+ return NULL;
+}
+
+static void *find_property(const struct tal_hdr *parent, enum prop_type type)
+{
+ struct prop_hdr **p = find_property_ptr(parent, type);
+
+ if (p)
+ return *p;
+ return NULL;
+}
+
+static void init_property(struct prop_hdr *hdr,
+ struct tal_hdr *parent,
+ enum prop_type type)
+{
+ hdr->type = type;
+ hdr->next = parent->prop;
+ parent->prop = hdr;
+}
+
+static struct notifier *add_notifier_property(struct tal_hdr *t,
+ enum tal_notify_type types,
+ void (*fn)(void *,
+ enum tal_notify_type,
+ void *),
+ void *extra_arg)
+{
+ struct notifier *prop;
+
+ if (types & NOTIFY_EXTRA_ARG)
+ prop = allocate(sizeof(struct notifier_extra_arg));
+ else
+ prop = allocate(sizeof(struct notifier));
+
+ if (prop) {
+ init_property(&prop->hdr, t, NOTIFIER);
+ prop->types = types;
+ prop->u.notifyfn = fn;
+ if (types & NOTIFY_EXTRA_ARG)
+ EXTRA_ARG(prop) = extra_arg;
+ }
+ return prop;
+}
+
+static enum tal_notify_type del_notifier_property(struct tal_hdr *t,
+ void (*fn)(tal_t *,
+ enum tal_notify_type,
+ void *),
+ bool match_extra_arg,
+ void *extra_arg)
+{
+ struct prop_hdr **p;
+
+ for (p = (struct prop_hdr **)&t->prop; *p; p = &(*p)->next) {
+ struct notifier *n;
+ enum tal_notify_type types;
+
+ if (is_literal(*p))
+ break;
+ if ((*p)->type != NOTIFIER)
+ continue;
+ n = (struct notifier *)*p;
+ if (n->u.notifyfn != fn)
+ continue;
+
+ types = n->types;
+ if ((types & NOTIFY_EXTRA_ARG)
+ && match_extra_arg
+ && extra_arg != EXTRA_ARG(n))
+ continue;
+
+ *p = (*p)->next;
+ freefn(n);
+ return types & ~(NOTIFY_IS_DESTRUCTOR|NOTIFY_EXTRA_ARG);
+ }
+ return 0;
+}
+
+static struct name *add_name_property(struct tal_hdr *t, const char *name)
+{
+ struct name *prop;
+
+ prop = allocate(sizeof(*prop) + strlen(name) + 1);
+ if (prop) {
+ init_property(&prop->hdr, t, NAME);
+ strcpy(prop->name, name);
+ }
+ return prop;
+}
+
+static struct children *add_child_property(struct tal_hdr *parent,
+ struct tal_hdr *child UNNEEDED)
+{
+ struct children *prop = allocate(sizeof(*prop));
+ if (prop) {
+ init_property(&prop->hdr, parent, CHILDREN);
+ prop->parent = parent;
+ list_head_init(&prop->children);
+ }
+ return prop;
+}
+
+static bool add_child(struct tal_hdr *parent, struct tal_hdr *child)
+{
+ struct children *children = find_property(parent, CHILDREN);
+
+ if (!children) {
+ children = add_child_property(parent, child);
+ if (!children)
+ return false;
+ }
+ list_add(&children->children, &child->list);
+ child->parent_child = (intptr_t)children ^ TAL_PTR_OBFUSTICATOR;
+ return true;
+}
+
+static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno)
+{
+ struct prop_hdr **prop, *p, *next;
+
+ assert(!taken(from_tal_hdr(t)));
+
+ /* Already being destroyed? Don't loop. */
+ if (unlikely(get_destroying_bit(t->parent_child)))
+ return;
+
+ set_destroying_bit(&t->parent_child);
+
+ /* Call free notifiers. */
+ notify(t, TAL_NOTIFY_FREE, (tal_t *)orig, saved_errno);
+
+ /* Now free children and groups. */
+ prop = find_property_ptr(t, CHILDREN);
+ if (prop) {
+ struct tal_hdr *i;
+ struct children *c = (struct children *)*prop;
+
+ while ((i = list_top(&c->children, struct tal_hdr, list))) {
+ list_del(&i->list);
+ del_tree(i, orig, saved_errno);
+ }
+ }
+
+ /* Finally free our properties. */
+ for (p = t->prop; p && !is_literal(p); p = next) {
+ next = p->next;
+ freefn(p);
+ }
+ freefn(t);
+}
+
+void *tal_alloc_(const tal_t *ctx, size_t size, bool clear, const char *label)
+{
+ struct tal_hdr *child, *parent = debug_tal(to_tal_hdr_or_null(ctx));
+
+ child = allocate(sizeof(struct tal_hdr) + size);
+ if (!child)
+ return NULL;
+ if (clear)
+ memset(from_tal_hdr(child), 0, size);
+ child->prop = (void *)label;
+ child->bytelen = size;
+
+ if (!add_child(parent, child)) {
+ freefn(child);
+ return NULL;
+ }
+ debug_tal(parent);
+ if (notifiers)
+ notify(parent, TAL_NOTIFY_ADD_CHILD, from_tal_hdr(child), 0);
+ return from_tal_hdr(debug_tal(child));
+}
+
+static bool adjust_size(size_t *size, size_t count)
+{
+ const size_t extra = sizeof(struct tal_hdr);
+
+ /* Multiplication wrap */
+ if (count && unlikely(*size * count / *size != count))
+ goto overflow;
+
+ *size *= count;
+
+ /* Make sure we don't wrap adding header. */
+ if (*size + extra < extra)
+ goto overflow;
+ return true;
+overflow:
+ call_error("allocation size overflow");
+ return false;
+}
+
+void *tal_alloc_arr_(const tal_t *ctx, size_t size, size_t count, bool clear,
+ const char *label)
+{
+ if (!adjust_size(&size, count))
+ return NULL;
+
+ return tal_alloc_(ctx, size, clear, label);
+}
+
+void *tal_free(const tal_t *ctx)
+{
+ if (ctx) {
+ struct tal_hdr *t;
+ int saved_errno = errno;
+ t = debug_tal(to_tal_hdr(ctx));
+ if (unlikely(get_destroying_bit(t->parent_child)))
+ return NULL;
+ if (notifiers)
+ notify(ignore_destroying_bit(t->parent_child)->parent,
+ TAL_NOTIFY_DEL_CHILD, ctx, saved_errno);
+ list_del(&t->list);
+ del_tree(t, ctx, saved_errno);
+ errno = saved_errno;
+ }
+ return NULL;
+}
+
+void *tal_steal_(const tal_t *new_parent, const tal_t *ctx)
+{
+ if (ctx) {
+ struct tal_hdr *newpar, *t, *old_parent;
+
+ newpar = debug_tal(to_tal_hdr_or_null(new_parent));
+ t = debug_tal(to_tal_hdr(ctx));
+
+ /* Unlink it from old parent. */
+ list_del(&t->list);
+ old_parent = ignore_destroying_bit(t->parent_child)->parent;
+
+ if (unlikely(!add_child(newpar, t))) {
+ /* We can always add to old parent, because it has a
+ * children property already. */
+ if (!add_child(old_parent, t))
+ abort();
+ return NULL;
+ }
+ debug_tal(newpar);
+ if (notifiers)
+ notify(t, TAL_NOTIFY_STEAL, new_parent, 0);
+ }
+ return (void *)ctx;
+}
+
+bool tal_add_destructor_(const tal_t *ctx, void (*destroy)(void *me))
+{
+ tal_t *t = debug_tal(to_tal_hdr(ctx));
+ return add_notifier_property(t, TAL_NOTIFY_FREE|NOTIFY_IS_DESTRUCTOR,
+ (void *)destroy, NULL);
+}
+
+bool tal_add_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg),
+ void *arg)
+{
+ tal_t *t = debug_tal(to_tal_hdr(ctx));
+ return add_notifier_property(t, TAL_NOTIFY_FREE|NOTIFY_IS_DESTRUCTOR
+ |NOTIFY_EXTRA_ARG,
+ (void *)destroy, arg);
+}
+
+/* We could support notifiers with an extra arg, but we didn't add to API */
+bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types,
+ void (*callback)(tal_t *, enum tal_notify_type, void *))
+{
+ struct tal_hdr *t = debug_tal(to_tal_hdr_or_null(ctx));
+ struct notifier *n;
+
+ assert(types);
+ assert((types & ~(TAL_NOTIFY_FREE | TAL_NOTIFY_STEAL | TAL_NOTIFY_MOVE
+ | TAL_NOTIFY_RESIZE | TAL_NOTIFY_RENAME
+ | TAL_NOTIFY_ADD_CHILD | TAL_NOTIFY_DEL_CHILD
+ | TAL_NOTIFY_ADD_NOTIFIER
+ | TAL_NOTIFY_DEL_NOTIFIER)) == 0);
+
+ /* Don't call notifier about itself: set types after! */
+ n = add_notifier_property(t, 0, callback, NULL);
+ if (unlikely(!n))
+ return false;
+
+ if (notifiers)
+ notify(t, TAL_NOTIFY_ADD_NOTIFIER, callback, 0);
+
+ n->types = types;
+ if (types != TAL_NOTIFY_FREE)
+ notifiers++;
+ return true;
+}
+
+bool tal_del_notifier_(const tal_t *ctx,
+ void (*callback)(tal_t *, enum tal_notify_type, void *),
+ bool match_extra_arg, void *extra_arg)
+{
+ struct tal_hdr *t = debug_tal(to_tal_hdr_or_null(ctx));
+ enum tal_notify_type types;
+
+ types = del_notifier_property(t, callback, match_extra_arg, extra_arg);
+ if (types) {
+ notify(t, TAL_NOTIFY_DEL_NOTIFIER, callback, 0);
+ if (types != TAL_NOTIFY_FREE)
+ notifiers--;
+ return true;
+ }
+ return false;
+}
+
+bool tal_del_destructor_(const tal_t *ctx, void (*destroy)(void *me))
+{
+ return tal_del_notifier_(ctx, (void *)destroy, false, NULL);
+}
+
+bool tal_del_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg),
+ void *arg)
+{
+ return tal_del_notifier_(ctx, (void *)destroy, true, arg);
+}
+
+bool tal_set_name_(tal_t *ctx, const char *name, bool literal)
+{
+ struct tal_hdr *t = debug_tal(to_tal_hdr(ctx));
+ struct prop_hdr **prop = find_property_ptr(t, NAME);
+
+ /* Get rid of any old name */
+ if (prop) {
+ struct name *name = (struct name *)*prop;
+ if (is_literal(&name->hdr))
+ *prop = NULL;
+ else {
+ *prop = name->hdr.next;
+ freefn(name);
+ }
+ }
+
+ if (literal && name[0]) {
+ struct prop_hdr **p;
+
+ /* Append literal. */
+ for (p = &t->prop; *p && !is_literal(*p); p = &(*p)->next);
+ *p = (struct prop_hdr *)name;
+ } else if (!add_name_property(t, name))
+ return false;
+
+ debug_tal(t);
+ if (notifiers)
+ notify(t, TAL_NOTIFY_RENAME, name, 0);
+ return true;
+}
+
+const char *tal_name(const tal_t *t)
+{
+ struct name *n;
+
+ n = find_property(debug_tal(to_tal_hdr(t)), NAME);
+ if (!n)
+ return NULL;
+
+ if (is_literal(&n->hdr))
+ return (const char *)n;
+ return n->name;
+}
+
+size_t tal_bytelen(const tal_t *ptr)
+{
+ /* NULL -> null_parent which has bytelen 0 */
+ struct tal_hdr *t = debug_tal(to_tal_hdr_or_null(ptr));
+
+ return t->bytelen;
+}
+
+/* Start one past first child: make stopping natural in circ. list. */
+static struct tal_hdr *first_child(struct tal_hdr *parent)
+{
+ struct children *child;
+
+ child = find_property(parent, CHILDREN);
+ if (!child)
+ return NULL;
+
+ return list_top(&child->children, struct tal_hdr, list);
+}
+
+tal_t *tal_first(const tal_t *root)
+{
+ struct tal_hdr *c, *t = debug_tal(to_tal_hdr_or_null(root));
+
+ c = first_child(t);
+ if (!c)
+ return NULL;
+ return from_tal_hdr(c);
+}
+
+tal_t *tal_next(const tal_t *prev)
+{
+ struct tal_hdr *next, *prevhdr = debug_tal(to_tal_hdr(prev));
+ struct list_head *head;
+
+ head = &ignore_destroying_bit(prevhdr->parent_child)->children;
+ next = list_next(head, prevhdr, list);
+ if (!next)
+ return NULL;
+ return from_tal_hdr(next);
+}
+
+tal_t *tal_parent(const tal_t *ctx)
+{
+ struct tal_hdr *t;
+
+ if (!ctx)
+ return NULL;
+
+ t = debug_tal(to_tal_hdr(ctx));
+ if (ignore_destroying_bit(t->parent_child)->parent == &null_parent.hdr)
+ return NULL;
+ return from_tal_hdr(ignore_destroying_bit(t->parent_child)->parent);
+}
+
+bool tal_resize_(tal_t **ctxp, size_t size, size_t count, bool clear)
+{
+ struct tal_hdr *old_t, *t;
+ struct children *child;
+
+ old_t = debug_tal(to_tal_hdr(*ctxp));
+
+ if (!adjust_size(&size, count))
+ return false;
+
+ t = resizefn(old_t, sizeof(struct tal_hdr) + size);
+ if (!t) {
+ call_error("Reallocation failure");
+ return false;
+ }
+
+ /* Clear between old end and new end. */
+ if (clear && size > t->bytelen) {
+ char *old_end = (char *)(t + 1) + t->bytelen;
+ memset(old_end, 0, size - t->bytelen);
+ }
+
+ /* Update length. */
+ t->bytelen = size;
+ update_bounds(t, sizeof(struct tal_hdr) + size);
+
+ /* If it didn't move, we're done! */
+ if (t != old_t) {
+ /* Fix up linked list pointers. */
+ t->list.next->prev = t->list.prev->next = &t->list;
+
+ /* Copy take() property. */
+ if (taken(from_tal_hdr(old_t)))
+ take(from_tal_hdr(t));
+
+ /* Fix up child property's parent pointer. */
+ child = find_property(t, CHILDREN);
+ if (child) {
+ assert(child->parent == old_t);
+ child->parent = t;
+ }
+ *ctxp = from_tal_hdr(debug_tal(t));
+ if (notifiers)
+ notify(t, TAL_NOTIFY_MOVE, from_tal_hdr(old_t), 0);
+ }
+ if (notifiers)
+ notify(t, TAL_NOTIFY_RESIZE, (void *)size, 0);
+
+ return true;
+}
+
+bool tal_expand_(tal_t **ctxp, const void *src, size_t size, size_t count)
+{
+ size_t old_len;
+ bool ret = false;
+
+ old_len = debug_tal(to_tal_hdr(*ctxp))->bytelen;
+
+ /* Check for additive overflow */
+ if (old_len + count * size < old_len) {
+ call_error("dup size overflow");
+ goto out;
+ }
+
+ /* Don't point src inside thing we're expanding! */
+ assert(src < *ctxp
+ || (char *)src >= (char *)(*ctxp) + old_len);
+
+ if (!tal_resize_(ctxp, size, old_len/size + count, false))
+ goto out;
+
+ memcpy((char *)*ctxp + old_len, src, count * size);
+ ret = true;
+
+out:
+ if (taken(src))
+ tal_free(src);
+ return ret;
+}
+
+void *tal_dup_(const tal_t *ctx, const void *p, size_t size,
+ size_t n, size_t extra, bool nullok, const char *label)
+{
+ void *ret;
+ size_t nbytes = size;
+
+ if (nullok && p == NULL) {
+ /* take(NULL) works. */
+ (void)taken(p);
+ return NULL;
+ }
+
+ if (!adjust_size(&nbytes, n)) {
+ if (taken(p))
+ tal_free(p);
+ return NULL;
+ }
+
+ /* Beware addition overflow! */
+ if (n + extra < n) {
+ call_error("dup size overflow");
+ if (taken(p))
+ tal_free(p);
+ return NULL;
+ }
+
+ if (taken(p)) {
+ if (unlikely(!p))
+ return NULL;
+ if (unlikely(!tal_resize_((void **)&p, size, n + extra, false)))
+ return tal_free(p);
+ if (unlikely(!tal_steal(ctx, p)))
+ return tal_free(p);
+ return (void *)p;
+ }
+
+ ret = tal_alloc_arr_(ctx, size, n + extra, false, label);
+ if (ret)
+ memcpy(ret, p, nbytes);
+ return ret;
+}
+
+void *tal_dup_talarr_(const tal_t *ctx, const tal_t *src TAKES, const char *label)
+{
+ return tal_dup_(ctx, src, 1, tal_bytelen(src), 0, true, label);
+}
+
+void tal_set_backend(void *(*alloc_fn)(size_t size),
+ void *(*resize_fn)(void *, size_t size),
+ void (*free_fn)(void *),
+ void (*error_fn)(const char *msg))
+{
+ if (alloc_fn)
+ allocfn = alloc_fn;
+ if (resize_fn)
+ resizefn = resize_fn;
+ if (free_fn)
+ freefn = free_fn;
+ if (error_fn)
+ errorfn = error_fn;
+}
+
+#ifdef CCAN_TAL_DEBUG
+static void dump_node(unsigned int indent, const struct tal_hdr *t)
+{
+ unsigned int i;
+ const struct prop_hdr *p;
+
+ for (i = 0; i < indent; i++)
+ fprintf(stderr, " ");
+ fprintf(stderr, "%p len=%zu", t, t->bytelen);
+ for (p = t->prop; p; p = p->next) {
+ struct children *c;
+ struct name *n;
+ struct notifier *no;
+ if (is_literal(p)) {
+ fprintf(stderr, " \"%s\"", (const char *)p);
+ break;
+ }
+ switch (p->type) {
+ case CHILDREN:
+ c = (struct children *)p;
+ fprintf(stderr, " CHILDREN(%p):parent=%p,children={%p,%p}",
+ p, c->parent,
+ c->children.n.prev, c->children.n.next);
+ break;
+ case NAME:
+ n = (struct name *)p;
+ fprintf(stderr, " NAME(%p):%s", p, n->name);
+ break;
+ case NOTIFIER:
+ no = (struct notifier *)p;
+ fprintf(stderr, " NOTIFIER(%p):fn=%p", p, no->u.notifyfn);
+ break;
+ default:
+ fprintf(stderr, " **UNKNOWN(%p):%i**", p, p->type);
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+static void tal_dump_(unsigned int level, const struct tal_hdr *t)
+{
+ struct children *children;
+
+ dump_node(level, t);
+
+ children = find_property(t, CHILDREN);
+ if (children) {
+ struct tal_hdr *i;
+
+ list_for_each(&children->children, i, list)
+ tal_dump_(level + 1, i);
+ }
+}
+
+void tal_dump(void)
+{
+ tal_dump_(0, &null_parent.hdr);
+}
+#endif /* CCAN_TAL_DEBUG */
+
+#ifndef NDEBUG
+static bool check_err(struct tal_hdr *t, const char *errorstr,
+ const char *errmsg)
+{
+ if (errorstr) {
+ /* Try not to malloc: it may be corrupted. */
+ char msg[strlen(errorstr) + 20 + strlen(errmsg) + 1];
+ sprintf(msg, "%s:%p %s", errorstr, from_tal_hdr(t), errmsg);
+ call_error(msg);
+ }
+ return false;
+}
+
+static bool check_node(struct children *parent_child,
+ struct tal_hdr *t, const char *errorstr)
+{
+ struct prop_hdr *p;
+ struct name *name = NULL;
+ struct children *children = NULL;
+
+ if (!in_bounds(t))
+ return check_err(t, errorstr, "invalid pointer");
+
+ if (ignore_destroying_bit(t->parent_child) != parent_child)
+ return check_err(t, errorstr, "incorrect parent");
+
+ for (p = t->prop; p; p = p->next) {
+ if (is_literal(p)) {
+ if (name)
+ return check_err(t, errorstr,
+ "has extra literal");
+ break;
+ }
+ if (!in_bounds(p))
+ return check_err(t, errorstr,
+ "has bad property pointer");
+
+ switch (p->type) {
+ case CHILDREN:
+ if (children)
+ return check_err(t, errorstr,
+ "has two child nodes");
+ children = (struct children *)p;
+ break;
+ case NOTIFIER:
+ break;
+ case NAME:
+ if (name)
+ return check_err(t, errorstr,
+ "has two names");
+ name = (struct name *)p;
+ break;
+ default:
+ return check_err(t, errorstr, "has unknown property");
+ }
+ }
+ if (children) {
+ struct tal_hdr *i;
+
+ if (!list_check(&children->children, errorstr))
+ return false;
+ list_for_each(&children->children, i, list) {
+ if (!check_node(children, i, errorstr))
+ return false;
+ }
+ }
+ return true;
+}
+
+bool tal_check(const tal_t *ctx, const char *errorstr)
+{
+ struct tal_hdr *t = to_tal_hdr_or_null(ctx);
+
+ return check_node(ignore_destroying_bit(t->parent_child), t, errorstr);
+}
+#else /* NDEBUG */
+bool tal_check(const tal_t *ctx, const char *errorstr)
+{
+ return true;
+}
+#endif
diff --git a/damus-c/tal.h b/damus-c/tal.h
@@ -0,0 +1,553 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#ifndef CCAN_TAL_H
+#define CCAN_TAL_H
+#include "config.h"
+#include "compiler.h"
+#include "likely.h"
+#include "typesafe_cb.h"
+#include "str.h"
+#include "take.h"
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+/**
+ * tal_t - convenient alias for void to mark tal pointers.
+ *
+ * Since any pointer can be a tal-allocated pointer, it's often
+ * useful to use this typedef to mark them explicitly.
+ */
+typedef void tal_t;
+
+/**
+ * tal - basic allocator function
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @type: the type to allocate.
+ *
+ * Allocates a specific type, with a given parent context. The name
+ * of the object is a string of the type, but if CCAN_TAL_DEBUG is
+ * defined it also contains the file and line which allocated it.
+ *
+ * tal_count() of the return will be 1.
+ *
+ * Example:
+ * int *p = tal(NULL, int);
+ * *p = 1;
+ */
+#define tal(ctx, type) \
+ tal_label(ctx, type, TAL_LABEL(type, ""))
+
+/**
+ * talz - zeroing allocator function
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @type: the type to allocate.
+ *
+ * Equivalent to tal() followed by memset() to zero.
+ *
+ * Example:
+ * p = talz(NULL, int);
+ * assert(*p == 0);
+ */
+#define talz(ctx, type) \
+ talz_label(ctx, type, TAL_LABEL(type, ""))
+
+/**
+ * tal_free - free a tal-allocated pointer.
+ * @p: NULL, or tal allocated object to free.
+ *
+ * This calls the destructors for p (if any), then does the same for all its
+ * children (recursively) before finally freeing the memory. It returns
+ * NULL, for convenience.
+ *
+ * Note: errno is preserved by this call, and also saved and restored
+ * for any destructors or notifiers.
+ *
+ * Example:
+ * p = tal_free(p);
+ */
+void *tal_free(const tal_t *p);
+
+/**
+ * tal_arr - allocate an array of objects.
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @type: the type to allocate.
+ * @count: the number to allocate.
+ *
+ * tal_count() of the returned pointer will be @count.
+ *
+ * Example:
+ * p = tal_arr(NULL, int, 2);
+ * p[0] = 0;
+ * p[1] = 1;
+ */
+#define tal_arr(ctx, type, count) \
+ tal_arr_label(ctx, type, count, TAL_LABEL(type, "[]"))
+
+/**
+ * tal_arrz - allocate an array of zeroed objects.
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @type: the type to allocate.
+ * @count: the number to allocate.
+ *
+ * Equivalent to tal_arr() followed by memset() to zero.
+ *
+ * Example:
+ * p = tal_arrz(NULL, int, 2);
+ * assert(p[0] == 0 && p[1] == 0);
+ */
+#define tal_arrz(ctx, type, count) \
+ tal_arrz_label(ctx, type, count, TAL_LABEL(type, "[]"))
+
+/**
+ * tal_resize - enlarge or reduce a tal object.
+ * @p: A pointer to the tal allocated array to resize.
+ * @count: the number to allocate.
+ *
+ * This returns true on success (and may move *@p), or false on failure.
+ * On success, tal_count() of *@p will be @count.
+ *
+ * Note: if *p is take(), it will still be take() upon return, even if it
+ * has been moved.
+ *
+ * Example:
+ * tal_resize(&p, 100);
+ */
+#define tal_resize(p, count) \
+ tal_resize_((void **)(p), sizeof**(p), (count), false)
+
+/**
+ * tal_resizez - enlarge or reduce a tal object; zero out extra.
+ * @p: A pointer to the tal allocated array to resize.
+ * @count: the number to allocate.
+ *
+ * This returns true on success (and may move *@p), or false on failure.
+ *
+ * Example:
+ * tal_resizez(&p, 200);
+ */
+#define tal_resizez(p, count) \
+ tal_resize_((void **)(p), sizeof**(p), (count), true)
+
+/**
+ * tal_steal - change the parent of a tal-allocated pointer.
+ * @ctx: The new parent.
+ * @ptr: The tal allocated object to move, or NULL.
+ *
+ * This may need to perform an allocation, in which case it may fail; thus
+ * it can return NULL, otherwise returns @ptr. If @ptr is NULL, this function does
+ * nothing.
+ */
+#if HAVE_STATEMENT_EXPR
+/* Weird macro avoids gcc's 'warning: value computed is not used'. */
+#define tal_steal(ctx, ptr) \
+ ({ (tal_typeof(ptr) tal_steal_((ctx),(ptr))); })
+#else
+#define tal_steal(ctx, ptr) \
+ (tal_typeof(ptr) tal_steal_((ctx),(ptr)))
+#endif
+
+/**
+ * tal_add_destructor - add a callback function when this context is destroyed.
+ * @ptr: The tal allocated object.
+ * @function: the function to call before it's freed.
+ *
+ * This is a more convenient form of tal_add_notifier(@ptr,
+ * TAL_NOTIFY_FREE, ...), in that the function prototype takes only @ptr.
+ *
+ * Note that this can only fail if your allocfn fails and your errorfn returns.
+ */
+#define tal_add_destructor(ptr, function) \
+ tal_add_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr)))
+
+/**
+ * tal_del_destructor - remove a destructor callback function.
+ * @ptr: The tal allocated object.
+ * @function: the function to call before it's freed.
+ *
+ * If @function has not been successfully added as a destructor, this returns
+ * false. Note that if we're inside the destructor call itself, this will
+ * return false.
+ */
+#define tal_del_destructor(ptr, function) \
+ tal_del_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr)))
+
+/**
+ * tal_add_destructor2 - add a 2-arg callback function when context is destroyed.
+ * @ptr: The tal allocated object.
+ * @function: the function to call before it's freed.
+ * @arg: the extra argument to the function.
+ *
+ * Sometimes an extra argument is required for a destructor; this
+ * saves the extra argument internally to avoid the caller having to
+ * do an extra allocation.
+ *
+ * Note that this can only fail if your allocfn fails and your errorfn returns.
+ */
+#define tal_add_destructor2(ptr, function, arg) \
+ tal_add_destructor2_((ptr), \
+ typesafe_cb_cast(void (*)(tal_t *, void *), \
+ void (*)(__typeof__(ptr), \
+ __typeof__(arg)), \
+ (function)), \
+ (arg))
+
+/**
+ * tal_del_destructor - remove a destructor callback function.
+ * @ptr: The tal allocated object.
+ * @function: the function to call before it's freed.
+ *
+ * If @function has not been successfully added as a destructor, this returns
+ * false. Note that if we're inside the destructor call itself, this will
+ * return false.
+ */
+#define tal_del_destructor(ptr, function) \
+ tal_del_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr)))
+
+/**
+ * tal_del_destructor2 - remove 2-arg callback function.
+ * @ptr: The tal allocated object.
+ * @function: the function to call before it's freed.
+ * @arg: the extra argument to the function.
+ *
+ * If @function has not been successfully added as a destructor with
+ * @arg, this returns false.
+ */
+#define tal_del_destructor2(ptr, function, arg) \
+ tal_del_destructor2_((ptr), \
+ typesafe_cb_cast(void (*)(tal_t *, void *), \
+ void (*)(__typeof__(ptr), \
+ __typeof__(arg)), \
+ (function)), \
+ (arg))
+enum tal_notify_type {
+ TAL_NOTIFY_FREE = 1,
+ TAL_NOTIFY_STEAL = 2,
+ TAL_NOTIFY_MOVE = 4,
+ TAL_NOTIFY_RESIZE = 8,
+ TAL_NOTIFY_RENAME = 16,
+ TAL_NOTIFY_ADD_CHILD = 32,
+ TAL_NOTIFY_DEL_CHILD = 64,
+ TAL_NOTIFY_ADD_NOTIFIER = 128,
+ TAL_NOTIFY_DEL_NOTIFIER = 256
+};
+
+/**
+ * tal_add_notifier - add a callback function when this context changes.
+ * @ptr: The tal allocated object, or NULL.
+ * @types: Bitwise OR of the types the callback is interested in.
+ * @callback: the function to call.
+ *
+ * Note that this can only fail if your allocfn fails and your errorfn
+ * returns. Also note that notifiers are not reliable in the case
+ * where an allocation fails, as they may be called before any
+ * allocation is actually done.
+ *
+ * TAL_NOTIFY_FREE is called when @ptr is freed, either directly or
+ * because an ancestor is freed: @info is the argument to tal_free().
+ * It is exactly equivalent to a destructor, with more information.
+ * errno is set to the value it was at the call of tal_free().
+ *
+ * TAL_NOTIFY_STEAL is called when @ptr's parent changes: @info is the
+ * new parent.
+ *
+ * TAL_NOTIFY_MOVE is called when @ptr is realloced (via tal_resize)
+ * and moved. In this case, @ptr arg here is the new memory, and
+ * @info is the old pointer.
+ *
+ * TAL_NOTIFY_RESIZE is called when @ptr is realloced via tal_resize:
+ * @info is the new size, in bytes. If the pointer has moved,
+ * TAL_NOTIFY_MOVE callbacks are called first.
+ *
+ * TAL_NOTIFY_ADD_CHILD/TAL_NOTIFY_DEL_CHILD are called when @ptr is
+ * the context for a tal() allocating call, or a direct child is
+ * tal_free()d: @info is the child. Note that TAL_NOTIFY_DEL_CHILD is
+ * not called when this context is tal_free()d: TAL_NOTIFY_FREE is
+ * considered sufficient for that case.
+ *
+ * TAL_NOTIFY_ADD_NOTIFIER/TAL_NOTIFIER_DEL_NOTIFIER are called when a
+ * notifier is added or removed (not for this notifier): @info is the
+ * callback. This is also called for tal_add_destructor and
+ * tal_del_destructor.
+ */
+#define tal_add_notifier(ptr, types, callback) \
+ tal_add_notifier_((ptr), (types), \
+ typesafe_cb_postargs(void, tal_t *, (callback), \
+ (ptr), \
+ enum tal_notify_type, void *))
+
+/**
+ * tal_del_notifier - remove a notifier callback function.
+ * @ptr: The tal allocated object.
+ * @callback: the function to call.
+ */
+#define tal_del_notifier(ptr, callback) \
+ tal_del_notifier_((ptr), \
+ typesafe_cb_postargs(void, void *, (callback), \
+ (ptr), \
+ enum tal_notify_type, void *), \
+ false, NULL)
+
+/**
+ * tal_set_name - attach a name to a tal pointer.
+ * @ptr: The tal allocated object.
+ * @name: The name to use.
+ *
+ * The name is copied, unless we're certain it's a string literal.
+ */
+#define tal_set_name(ptr, name) \
+ tal_set_name_((ptr), (name), TAL_IS_LITERAL(name))
+
+/**
+ * tal_name - get the name for a tal pointer.
+ * @ptr: The tal allocated object.
+ *
+ * Returns NULL if no name has been set.
+ */
+const char *tal_name(const tal_t *ptr);
+
+/**
+ * tal_count - get the count of objects in a tal object.
+ * @ptr: The tal allocated object (or NULL)
+ *
+ * Returns 0 if @ptr is NULL. Note that if the allocation was done as a
+ * different type to @ptr, the result may not match the @count argument
+ * (or implied 1) of that allocation!
+ */
+#define tal_count(p) (tal_bytelen(p) / sizeof(*p))
+
+/**
+ * tal_bytelen - get the count of bytes in a tal object.
+ * @ptr: The tal allocated object (or NULL)
+ *
+ * Returns 0 if @ptr is NULL.
+ */
+size_t tal_bytelen(const tal_t *ptr);
+
+/**
+ * tal_first - get the first immediate tal object child.
+ * @root: The tal allocated object to start with, or NULL.
+ *
+ * Returns NULL if there are no children.
+ */
+tal_t *tal_first(const tal_t *root);
+
+/**
+ * tal_next - get the next immediate tal object child.
+ * @prev: The return value from tal_first or tal_next.
+ *
+ * Returns NULL if there are no more immediate children. This should be safe to
+ * call on an altering tree unless @prev is no longer valid.
+ */
+tal_t *tal_next(const tal_t *prev);
+
+/**
+ * tal_parent - get the parent of a tal object.
+ * @ctx: The tal allocated object.
+ *
+ * Returns the parent, which may be NULL. Returns NULL if @ctx is NULL.
+ */
+tal_t *tal_parent(const tal_t *ctx);
+
+/**
+ * tal_dup - duplicate an object.
+ * @ctx: The tal allocated object to be parent of the result (may be NULL).
+ * @type: the type (should match type of @p!)
+ * @p: the object to copy (or reparented if take()). Must not be NULL.
+ */
+#define tal_dup(ctx, type, p) \
+ tal_dup_label(ctx, type, p, TAL_LABEL(type, ""), false)
+
+/**
+ * tal_dup_or_null - duplicate an object, or just pass NULL.
+ * @ctx: The tal allocated object to be parent of the result (may be NULL).
+ * @type: the type (should match type of @p!)
+ * @p: the object to copy (or reparented if take())
+ *
+ * if @p is NULL, just return NULL, otherwise to tal_dup().
+ */
+#define tal_dup_or_null(ctx, type, p) \
+ tal_dup_label(ctx, type, p, TAL_LABEL(type, ""), true)
+
+/**
+ * tal_dup_arr - duplicate an array.
+ * @ctx: The tal allocated object to be parent of the result (may be NULL).
+ * @type: the type (should match type of @p!)
+ * @p: the array to copy (or resized & reparented if take())
+ * @n: the number of sizeof(type) entries to copy.
+ * @extra: the number of extra sizeof(type) entries to allocate.
+ */
+#define tal_dup_arr(ctx, type, p, n, extra) \
+ tal_dup_arr_label(ctx, type, p, n, extra, TAL_LABEL(type, "[]"))
+
+
+/**
+ * tal_dup_arr - duplicate a tal array.
+ * @ctx: The tal allocated object to be parent of the result (may be NULL).
+ * @type: the type (should match type of @p!)
+ * @p: the tal array to copy (or resized & reparented if take())
+ *
+ * The comon case of duplicating an entire tal array.
+ */
+#define tal_dup_talarr(ctx, type, p) \
+ ((type *)tal_dup_talarr_((ctx), tal_typechk_(p, type *), \
+ TAL_LABEL(type, "[]")))
+/* Lower-level interfaces, where you want to supply your own label string. */
+#define tal_label(ctx, type, label) \
+ ((type *)tal_alloc_((ctx), sizeof(type), false, label))
+#define talz_label(ctx, type, label) \
+ ((type *)tal_alloc_((ctx), sizeof(type), true, label))
+#define tal_arr_label(ctx, type, count, label) \
+ ((type *)tal_alloc_arr_((ctx), sizeof(type), (count), false, label))
+#define tal_arrz_label(ctx, type, count, label) \
+ ((type *)tal_alloc_arr_((ctx), sizeof(type), (count), true, label))
+#define tal_dup_label(ctx, type, p, label, nullok) \
+ ((type *)tal_dup_((ctx), tal_typechk_(p, type *), \
+ sizeof(type), 1, 0, nullok, \
+ label))
+#define tal_dup_arr_label(ctx, type, p, n, extra, label) \
+ ((type *)tal_dup_((ctx), tal_typechk_(p, type *), \
+ sizeof(type), (n), (extra), false, \
+ label))
+
+/**
+ * tal_set_backend - set the allocation or error functions to use
+ * @alloc_fn: allocator or NULL (default is malloc)
+ * @resize_fn: re-allocator or NULL (default is realloc)
+ * @free_fn: free function or NULL (default is free)
+ * @error_fn: called on errors or NULL (default is abort)
+ *
+ * The defaults are set up so tal functions never return NULL, but you
+ * can override erorr_fn to change that. error_fn can return, and is
+ * called if alloc_fn or resize_fn fail.
+ *
+ * If any parameter is NULL, that function is unchanged.
+ */
+void tal_set_backend(void *(*alloc_fn)(size_t size),
+ void *(*resize_fn)(void *, size_t size),
+ void (*free_fn)(void *),
+ void (*error_fn)(const char *msg));
+
+/**
+ * tal_expand - expand a tal array with contents.
+ * @a1p: a pointer to the tal array to expand.
+ * @a2: the second array (can be take()).
+ * @num2: the number of elements in the second array.
+ *
+ * Note that *@a1 and @a2 should be the same type. tal_count(@a1) will
+ * be increased by @num2.
+ *
+ * Example:
+ * int *arr1 = tal_arrz(NULL, int, 2);
+ * int arr2[2] = { 1, 3 };
+ *
+ * tal_expand(&arr1, arr2, 2);
+ * assert(tal_count(arr1) == 4);
+ * assert(arr1[2] == 1);
+ * assert(arr1[3] == 3);
+ */
+#define tal_expand(a1p, a2, num2) \
+ tal_expand_((void **)(a1p), (a2), sizeof**(a1p), \
+ (num2) + 0*sizeof(*(a1p) == (a2)))
+
+/**
+ * tal_cleanup - remove pointers from NULL node
+ *
+ * Internally, tal keeps a list of nodes allocated from @ctx NULL; this
+ * prevents valgrind from noticing memory leaks. This re-initializes
+ * that list to empty.
+ *
+ * It also calls take_cleanup() for you.
+ */
+void tal_cleanup(void);
+
+
+/**
+ * tal_check - sanity check a tal context and its children.
+ * @ctx: a tal context, or NULL.
+ * @errorstr: a string to prepend calls to error_fn, or NULL.
+ *
+ * This sanity-checks a tal tree (unless NDEBUG is defined, in which case
+ * it simply returns true). If errorstr is not null, error_fn is called
+ * when a problem is found, otherwise it is not.
+ *
+ * See also:
+ * tal_set_backend()
+ */
+bool tal_check(const tal_t *ctx, const char *errorstr);
+
+#ifdef CCAN_TAL_DEBUG
+/**
+ * tal_dump - dump entire tal tree to stderr.
+ *
+ * This is a helper for debugging tal itself, which dumps all the tal internal
+ * state.
+ */
+void tal_dump(void);
+#endif
+
+/* Internal support functions */
+#ifndef TAL_LABEL
+#ifdef CCAN_TAL_NO_LABELS
+#define TAL_LABEL(type, arr) NULL
+#else
+#ifdef CCAN_TAL_DEBUG
+#define TAL_LABEL(type, arr) \
+ __FILE__ ":" stringify(__LINE__) ":" stringify(type) arr
+#else
+#define TAL_LABEL(type, arr) stringify(type) arr
+#endif /* CCAN_TAL_DEBUG */
+#endif
+#endif
+
+#if HAVE_BUILTIN_CONSTANT_P
+#define TAL_IS_LITERAL(str) __builtin_constant_p(str)
+#else
+#define TAL_IS_LITERAL(str) (sizeof(&*(str)) != sizeof(char *))
+#endif
+
+bool tal_set_name_(tal_t *ctx, const char *name, bool literal);
+
+#if HAVE_TYPEOF
+#define tal_typeof(ptr) (__typeof__(ptr))
+#if HAVE_STATEMENT_EXPR
+/* Careful: ptr can be const foo *, ptype is foo *. Also, ptr could
+ * be an array, eg "hello". */
+#define tal_typechk_(ptr, ptype) ({ __typeof__((ptr)+0) _p = (ptype)(ptr); _p; })
+#else
+#define tal_typechk_(ptr, ptype) (ptr)
+#endif
+#else /* !HAVE_TYPEOF */
+#define tal_typeof(ptr)
+#define tal_typechk_(ptr, ptype) (ptr)
+#endif
+
+void *tal_alloc_(const tal_t *ctx, size_t bytes, bool clear, const char *label);
+void *tal_alloc_arr_(const tal_t *ctx, size_t bytes, size_t count, bool clear,
+ const char *label);
+
+void *tal_dup_(const tal_t *ctx, const void *p TAKES, size_t size,
+ size_t n, size_t extra, bool nullok, const char *label);
+void *tal_dup_talarr_(const tal_t *ctx, const tal_t *src TAKES,
+ const char *label);
+
+tal_t *tal_steal_(const tal_t *new_parent, const tal_t *t);
+
+bool tal_resize_(tal_t **ctxp, size_t size, size_t count, bool clear);
+bool tal_expand_(tal_t **ctxp, const void *src TAKES, size_t size, size_t count);
+
+bool tal_add_destructor_(const tal_t *ctx, void (*destroy)(void *me));
+bool tal_add_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg),
+ void *arg);
+bool tal_del_destructor_(const tal_t *ctx, void (*destroy)(void *me));
+bool tal_del_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg),
+ void *arg);
+
+bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types,
+ void (*notify)(tal_t *ctx, enum tal_notify_type,
+ void *info));
+bool tal_del_notifier_(const tal_t *ctx,
+ void (*notify)(tal_t *ctx, enum tal_notify_type,
+ void *info),
+ bool match_extra_arg, void *arg);
+#endif /* CCAN_TAL_H */
diff --git a/damus-c/talstr.c b/damus-c/talstr.c
@@ -0,0 +1,315 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "talstr.h"
+#include <sys/types.h>
+#include <regex.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "str.h"
+
+char *tal_strdup_(const tal_t *ctx, const char *p, const char *label)
+{
+ /* We have to let through NULL for take(). */
+ return tal_dup_arr_label(ctx, char, p, p ? strlen(p) + 1: 1, 0, label);
+}
+
+char *tal_strndup_(const tal_t *ctx, const char *p, size_t n, const char *label)
+{
+ size_t len;
+ char *ret;
+
+ /* We have to let through NULL for take(). */
+ if (likely(p))
+ len = strnlen(p, n);
+ else
+ len = n;
+
+ ret = tal_dup_arr_label(ctx, char, p, len, 1, label);
+ if (ret)
+ ret[len] = '\0';
+ return ret;
+}
+
+char *tal_fmt_(const tal_t *ctx, const char *label, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = tal_vfmt_(ctx, fmt, ap, label);
+ va_end(ap);
+
+ return ret;
+}
+
+static bool do_vfmt(char **buf, size_t off, const char *fmt, va_list ap)
+{
+ /* A decent guess to start. */
+ size_t max = strlen(fmt) * 2 + 1;
+ bool ok;
+
+ for (;;) {
+ va_list ap2;
+ int ret;
+
+ if (!tal_resize(buf, off + max)) {
+ ok = false;
+ break;
+ }
+
+ va_copy(ap2, ap);
+ ret = vsnprintf(*buf + off, max, fmt, ap2);
+ va_end(ap2);
+
+ if (ret < max) {
+ ok = true;
+ /* Make sure tal_count() is correct! */
+ tal_resize(buf, off + ret + 1);
+ break;
+ }
+ max *= 2;
+ }
+
+ if (taken(fmt))
+ tal_free(fmt);
+ return ok;
+}
+
+char *tal_vfmt_(const tal_t *ctx, const char *fmt, va_list ap, const char *label)
+{
+ char *buf;
+
+ if (!fmt && taken(fmt))
+ return NULL;
+
+ /* A decent guess to start. */
+ buf = tal_arr_label(ctx, char, strlen(fmt) * 2, label);
+ if (!do_vfmt(&buf, 0, fmt, ap))
+ buf = tal_free(buf);
+ return buf;
+}
+
+bool tal_append_vfmt(char **baseptr, const char *fmt, va_list ap)
+{
+ if (!fmt && taken(fmt))
+ return false;
+
+ return do_vfmt(baseptr, strlen(*baseptr), fmt, ap);
+}
+
+bool tal_append_fmt(char **baseptr, const char *fmt, ...)
+{
+ va_list ap;
+ bool ret;
+
+ va_start(ap, fmt);
+ ret = tal_append_vfmt(baseptr, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+char *tal_strcat_(const tal_t *ctx, const char *s1, const char *s2,
+ const char *label)
+{
+ size_t len1, len2;
+ char *ret;
+
+ if (unlikely(!s2) && taken(s2)) {
+ if (taken(s1))
+ tal_free(s1);
+ return NULL;
+ }
+ /* We have to let through NULL for take(). */
+ len1 = s1 ? strlen(s1) : 0;
+ len2 = strlen(s2);
+
+ ret = tal_dup_arr_label(ctx, char, s1, len1, len2 + 1, label);
+ if (likely(ret))
+ memcpy(ret + len1, s2, len2 + 1);
+
+ if (taken(s2))
+ tal_free(s2);
+ return ret;
+}
+
+char **tal_strsplit_(const tal_t *ctx,
+ const char *string, const char *delims, enum strsplit flags,
+ const char *label)
+{
+ char **parts, *str;
+ size_t max = 64, num = 0;
+
+ parts = tal_arr(ctx, char *, max + 1);
+ if (unlikely(!parts)) {
+ if (taken(string))
+ tal_free(string);
+ if (taken(delims))
+ tal_free(delims);
+ return NULL;
+ }
+ str = tal_strdup(parts, string);
+ if (unlikely(!str))
+ goto fail;
+ if (unlikely(!delims) && is_taken(delims))
+ goto fail;
+
+ if (flags == STR_NO_EMPTY)
+ str += strspn(str, delims);
+
+ while (*str != '\0') {
+ size_t len = strcspn(str, delims), dlen;
+
+ parts[num] = str;
+ dlen = strspn(str + len, delims);
+ parts[num][len] = '\0';
+ if (flags == STR_EMPTY_OK && dlen)
+ dlen = 1;
+ str += len + dlen;
+ if (++num == max && !tal_resize(&parts, max*=2 + 1))
+ goto fail;
+ }
+ parts[num] = NULL;
+
+ /* Ensure that tal_count() is correct. */
+ if (unlikely(!tal_resize(&parts, num+1)))
+ goto fail;
+
+ if (taken(delims))
+ tal_free(delims);
+ return parts;
+
+fail:
+ tal_free(parts);
+ if (taken(delims))
+ tal_free(delims);
+ return NULL;
+}
+
+char *tal_strjoin_(const tal_t *ctx,
+ char *strings[], const char *delim, enum strjoin flags,
+ const char *label)
+{
+ unsigned int i;
+ char *ret = NULL;
+ size_t totlen = 0, dlen;
+
+ if (unlikely(!strings) && is_taken(strings))
+ goto fail;
+
+ if (unlikely(!delim) && is_taken(delim))
+ goto fail;
+
+ dlen = strlen(delim);
+ ret = tal_arr_label(ctx, char, dlen*2+1, label);
+ if (!ret)
+ goto fail;
+
+ ret[0] = '\0';
+ for (i = 0; strings[i]; i++) {
+ size_t len = strlen(strings[i]);
+
+ if (flags == STR_NO_TRAIL && !strings[i+1])
+ dlen = 0;
+ if (!tal_resize(&ret, totlen + len + dlen + 1))
+ goto fail;
+ memcpy(ret + totlen, strings[i], len);
+ totlen += len;
+ memcpy(ret + totlen, delim, dlen);
+ totlen += dlen;
+ }
+ ret[totlen] = '\0';
+ /* Make sure tal_count() is correct! */
+ tal_resize(&ret, totlen+1);
+out:
+ if (taken(strings))
+ tal_free(strings);
+ if (taken(delim))
+ tal_free(delim);
+ return ret;
+fail:
+ ret = tal_free(ret);
+ goto out;
+}
+
+static size_t count_open_braces(const char *string)
+{
+#if 1
+ size_t num = 0, esc = 0;
+
+ while (*string) {
+ if (*string == '\\')
+ esc++;
+ else {
+ /* An odd number of \ means it's escaped. */
+ if (*string == '(' && (esc & 1) == 0)
+ num++;
+ esc = 0;
+ }
+ string++;
+ }
+ return num;
+#else
+ return strcount(string, "(");
+#endif
+}
+
+bool tal_strreg_(const tal_t *ctx, const char *string, const char *label,
+ const char *regex, ...)
+{
+ size_t nmatch = 1 + count_open_braces(regex);
+ regmatch_t matches[nmatch];
+ regex_t r;
+ bool ret = false;
+ unsigned int i;
+ va_list ap;
+
+ if (unlikely(!regex) && is_taken(regex))
+ goto fail_no_re;
+
+ if (regcomp(&r, regex, REG_EXTENDED) != 0)
+ goto fail_no_re;
+
+ if (unlikely(!string) && is_taken(string))
+ goto fail;
+
+ if (regexec(&r, string, nmatch, matches, 0) != 0)
+ goto fail;
+
+ ret = true;
+ va_start(ap, regex);
+ for (i = 1; i < nmatch; i++) {
+ char **arg = va_arg(ap, char **);
+ if (arg) {
+ /* eg. ([a-z])? can give "no match". */
+ if (matches[i].rm_so == -1)
+ *arg = NULL;
+ else {
+ *arg = tal_strndup_(ctx,
+ string + matches[i].rm_so,
+ matches[i].rm_eo
+ - matches[i].rm_so,
+ label);
+ /* FIXME: If we fail, we set some and leak! */
+ if (!*arg) {
+ ret = false;
+ break;
+ }
+ }
+ }
+ }
+ va_end(ap);
+fail:
+ regfree(&r);
+fail_no_re:
+ if (taken(regex))
+ tal_free(regex);
+ if (taken(string))
+ tal_free(string);
+ return ret;
+}
diff --git a/damus-c/talstr.h b/damus-c/talstr.h
@@ -0,0 +1,225 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#ifndef CCAN_STR_TAL_H
+#define CCAN_STR_TAL_H
+#ifdef TAL_USE_TALLOC
+#include <ccan/tal/talloc/talloc.h>
+#else
+#include "tal.h"
+#endif
+#include <string.h>
+#include <stdbool.h>
+
+/**
+ * tal_strdup - duplicate a string
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @p: the string to copy (can be take()).
+ *
+ * The returned string will have tal_count() == strlen() + 1.
+ */
+#define tal_strdup(ctx, p) tal_strdup_(ctx, p, TAL_LABEL(char, "[]"))
+char *tal_strdup_(const tal_t *ctx, const char *p TAKES, const char *label);
+
+/**
+ * tal_strndup - duplicate a limited amount of a string.
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @p: the string to copy (can be take()).
+ * @n: the maximum length to copy.
+ *
+ * Always gives a nul-terminated string, with strlen() <= @n.
+ * The returned string will have tal_count() == strlen() + 1.
+ */
+#define tal_strndup(ctx, p, n) tal_strndup_(ctx, p, n, TAL_LABEL(char, "[]"))
+char *tal_strndup_(const tal_t *ctx, const char *p TAKES, size_t n,
+ const char *label);
+
+/**
+ * tal_fmt - allocate a formatted string
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @fmt: the printf-style format (can be take()).
+ *
+ * The returned string will have tal_count() == strlen() + 1.
+ */
+#define tal_fmt(ctx, ...) \
+ tal_fmt_(ctx, TAL_LABEL(char, "[]"), __VA_ARGS__)
+char *tal_fmt_(const tal_t *ctx, const char *label, const char *fmt TAKES,
+ ...) PRINTF_FMT(3,4);
+
+/**
+ * tal_vfmt - allocate a formatted string (va_list version)
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @fmt: the printf-style format (can be take()).
+ * @va: the va_list containing the format args.
+ *
+ * The returned string will have tal_count() == strlen() + 1.
+ */
+#define tal_vfmt(ctx, fmt, va) \
+ tal_vfmt_(ctx, fmt, va, TAL_LABEL(char, "[]"))
+char *tal_vfmt_(const tal_t *ctx, const char *fmt TAKES, va_list ap,
+ const char *label)
+ PRINTF_FMT(2,0);
+
+/**
+ * tal_append_fmt - append a formatted string to a talloc string.
+ * @baseptr: a pointer to the tal string to be appended to.
+ * @fmt: the printf-style format (can be take()).
+ *
+ * Returns false on allocation failure.
+ * Otherwise tal_count(*@baseptr) == strlen(*@baseptr) + 1.
+ */
+bool tal_append_fmt(char **baseptr, const char *fmt TAKES, ...) PRINTF_FMT(2,3);
+
+/**
+ * tal_append_vfmt - append a formatted string to a talloc string (va_list)
+ * @baseptr: a pointer to the tal string to be appended to.
+ * @fmt: the printf-style format (can be take()).
+ * @va: the va_list containing the format args.
+ *
+ * Returns false on allocation failure.
+ * Otherwise tal_count(*@baseptr) == strlen(*@baseptr) + 1.
+ */
+bool tal_append_vfmt(char **baseptr, const char *fmt TAKES, va_list ap);
+
+/**
+ * tal_strcat - join two strings together
+ * @ctx: NULL, or tal allocated object to be parent.
+ * @s1: the first string (can be take()).
+ * @s2: the second string (can be take()).
+ *
+ * The returned string will have tal_count() == strlen() + 1.
+ */
+#define tal_strcat(ctx, s1, s2) tal_strcat_(ctx, s1, s2, TAL_LABEL(char, "[]"))
+char *tal_strcat_(const tal_t *ctx, const char *s1 TAKES, const char *s2 TAKES,
+ const char *label);
+
+enum strsplit {
+ STR_EMPTY_OK,
+ STR_NO_EMPTY
+};
+
+/**
+ * tal_strsplit - Split string into an array of substrings
+ * @ctx: the context to tal from (often NULL).
+ * @string: the string to split (can be take()).
+ * @delims: delimiters where lines should be split (can be take()).
+ * @flags: whether to include empty substrings.
+ *
+ * This function splits a single string into multiple strings.
+ *
+ * If @string is take(), the returned array will point into the
+ * mangled @string.
+ *
+ * Multiple delimiters result in empty substrings. By definition, no
+ * delimiters will appear in the substrings.
+ *
+ * The final char * in the array will be NULL, and tal_count() will
+ * return the number of elements plus 1 (for that NULL).
+ *
+ * Example:
+ * #include <ccan/tal/str/str.h>
+ * ...
+ * static unsigned int count_long_lines(const char *string)
+ * {
+ * char **lines;
+ * unsigned int i, long_lines = 0;
+ *
+ * // Can only fail on out-of-memory.
+ * lines = tal_strsplit(NULL, string, "\n", STR_NO_EMPTY);
+ * for (i = 0; lines[i] != NULL; i++)
+ * if (strlen(lines[i]) > 80)
+ * long_lines++;
+ * tal_free(lines);
+ * return long_lines;
+ * }
+ */
+#define tal_strsplit(ctx, string, delims, flag) \
+ tal_strsplit_(ctx, string, delims, flag, TAL_LABEL(char *, "[]"))
+char **tal_strsplit_(const tal_t *ctx,
+ const char *string TAKES,
+ const char *delims TAKES,
+ enum strsplit flag,
+ const char *label);
+
+enum strjoin {
+ STR_TRAIL,
+ STR_NO_TRAIL
+};
+
+/**
+ * tal_strjoin - Join an array of substrings into one long string
+ * @ctx: the context to tal from (often NULL).
+ * @strings: the NULL-terminated array of strings to join (can be take())
+ * @delim: the delimiter to insert between the strings (can be take())
+ * @flags: whether to add a delimieter to the end
+ *
+ * This function joins an array of strings into a single string. The
+ * return value is allocated using tal. Each string in @strings is
+ * followed by a copy of @delim.
+ *
+ * The returned string will have tal_count() == strlen() + 1.
+ *
+ * Example:
+ * // Append the string "--EOL" to each line.
+ * static char *append_to_all_lines(const char *string)
+ * {
+ * char **lines, *ret;
+ *
+ * lines = tal_strsplit(NULL, string, "\n", STR_EMPTY_OK);
+ * ret = tal_strjoin(NULL, lines, "-- EOL\n", STR_TRAIL);
+ * tal_free(lines);
+ * return ret;
+ * }
+ */
+#define tal_strjoin(ctx, strings, delim, flags) \
+ tal_strjoin_(ctx, strings, delim, flags, TAL_LABEL(char, "[]"))
+char *tal_strjoin_(const void *ctx,
+ char *strings[] TAKES,
+ const char *delim TAKES,
+ enum strjoin flags,
+ const char *label);
+
+/**
+ * tal_strreg - match/extract from a string via (extended) regular expressions.
+ * @ctx: the context to tal from (often NULL)
+ * @string: the string to try to match (can be take())
+ * @regex: the regular expression to match (can be take())
+ * ...: pointers to strings to allocate for subexpressions.
+ *
+ * Returns true if we matched, in which case any parenthesized
+ * expressions in @regex are allocated and placed in the char **
+ * arguments following @regex. NULL arguments mean the match is not
+ * saved. The order of the strings is the order
+ * of opening braces in the expression: in the case of repeated
+ * expressions (eg "([a-z])*") the last one is saved, in the case of
+ * non-existent matches (eg "([a-z]*)?") the pointer is set to NULL.
+ *
+ * Allocation failures or malformed regular expressions return false.
+ * The allocated strings will have tal_count() == strlen() + 1.
+ *
+ * See Also:
+ * regcomp(3), regex(3).
+ *
+ * Example:
+ * // Given "My name is Rusty" outputs "Hello Rusty!\n"
+ * // Given "my first name is Rusty Russell" outputs "Hello Rusty Russell!\n"
+ * // Given "My name isnt Rusty Russell" outputs "Hello there!\n"
+ * int main(int argc, char *argv[])
+ * {
+ * char *person, *input;
+ *
+ * (void)argc;
+ * // Join args and trim trailing space.
+ * input = tal_strjoin(NULL, argv+1, " ", STR_NO_TRAIL);
+ * if (tal_strreg(NULL, input,
+ * "[Mm]y (first )?name is ([A-Za-z ]+)",
+ * NULL, &person))
+ * printf("Hello %s!\n", person);
+ * else
+ * printf("Hello there!\n");
+ * return 0;
+ * }
+ */
+#define tal_strreg(ctx, string, ...) \
+ tal_strreg_(ctx, string, TAL_LABEL(char, "[]"), __VA_ARGS__)
+bool tal_strreg_(const void *ctx, const char *string TAKES,
+ const char *label, const char *regex, ...);
+#endif /* CCAN_STR_TAL_H */
diff --git a/damus-c/typesafe_cb.h b/damus-c/typesafe_cb.h
@@ -0,0 +1,134 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_TYPESAFE_CB_H
+#define CCAN_TYPESAFE_CB_H
+#include "config.h"
+
+#if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P
+/**
+ * typesafe_cb_cast - only cast an expression if it matches a given type
+ * @desttype: the type to cast to
+ * @oktype: the type we allow
+ * @expr: the expression to cast
+ *
+ * This macro is used to create functions which allow multiple types.
+ * The result of this macro is used somewhere that a @desttype type is
+ * expected: if @expr is exactly of type @oktype, then it will be
+ * cast to @desttype type, otherwise left alone.
+ *
+ * This macro can be used in static initializers.
+ *
+ * This is merely useful for warnings: if the compiler does not
+ * support the primitives required for typesafe_cb_cast(), it becomes an
+ * unconditional cast, and the @oktype argument is not used. In
+ * particular, this means that @oktype can be a type which uses the
+ * "typeof": it will not be evaluated if typeof is not supported.
+ *
+ * Example:
+ * // We can take either an unsigned long or a void *.
+ * void _set_some_value(void *val);
+ * #define set_some_value(e) \
+ * _set_some_value(typesafe_cb_cast(void *, unsigned long, (e)))
+ */
+#define typesafe_cb_cast(desttype, oktype, expr) \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(__typeof__(0?(expr):(expr)), \
+ oktype), \
+ (desttype)(expr), (expr))
+#else
+#define typesafe_cb_cast(desttype, oktype, expr) ((desttype)(expr))
+#endif
+
+/**
+ * typesafe_cb_cast3 - only cast an expression if it matches given types
+ * @desttype: the type to cast to
+ * @ok1: the first type we allow
+ * @ok2: the second type we allow
+ * @ok3: the third type we allow
+ * @expr: the expression to cast
+ *
+ * This is a convenient wrapper for multiple typesafe_cb_cast() calls.
+ * You can chain them inside each other (ie. use typesafe_cb_cast()
+ * for expr) if you need more than 3 arguments.
+ *
+ * Example:
+ * // We can take either a long, unsigned long, void * or a const void *.
+ * void _set_some_value(void *val);
+ * #define set_some_value(expr) \
+ * _set_some_value(typesafe_cb_cast3(void *,, \
+ * long, unsigned long, const void *,\
+ * (expr)))
+ */
+#define typesafe_cb_cast3(desttype, ok1, ok2, ok3, expr) \
+ typesafe_cb_cast(desttype, ok1, \
+ typesafe_cb_cast(desttype, ok2, \
+ typesafe_cb_cast(desttype, ok3, \
+ (expr))))
+
+/**
+ * typesafe_cb - cast a callback function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @atype: the (pointer) type which the callback function expects.
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * If a callback function takes a single argument, this macro does
+ * appropriate casts to a function which takes a single atype argument if the
+ * callback provided matches the @arg.
+ *
+ * It is assumed that @arg is of pointer type: usually @arg is passed
+ * or assigned to a void * elsewhere anyway.
+ *
+ * Example:
+ * void _register_callback(void (*fn)(void *arg), void *arg);
+ * #define register_callback(fn, arg) \
+ * _register_callback(typesafe_cb(void, (fn), void*, (arg)), (arg))
+ */
+#define typesafe_cb(rtype, atype, fn, arg) \
+ typesafe_cb_cast(rtype (*)(atype), \
+ rtype (*)(__typeof__(arg)), \
+ (fn))
+
+/**
+ * typesafe_cb_preargs - cast a callback function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @atype: the (pointer) type which the callback function expects.
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * This is a version of typesafe_cb() for callbacks that take other arguments
+ * before the @arg.
+ *
+ * Example:
+ * void _register_callback(void (*fn)(int, void *arg), void *arg);
+ * #define register_callback(fn, arg) \
+ * _register_callback(typesafe_cb_preargs(void, void *, \
+ * (fn), (arg), int), \
+ * (arg))
+ */
+#define typesafe_cb_preargs(rtype, atype, fn, arg, ...) \
+ typesafe_cb_cast(rtype (*)(__VA_ARGS__, atype), \
+ rtype (*)(__VA_ARGS__, __typeof__(arg)), \
+ (fn))
+
+/**
+ * typesafe_cb_postargs - cast a callback function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @atype: the (pointer) type which the callback function expects.
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * This is a version of typesafe_cb() for callbacks that take other arguments
+ * after the @arg.
+ *
+ * Example:
+ * void _register_callback(void (*fn)(void *arg, int), void *arg);
+ * #define register_callback(fn, arg) \
+ * _register_callback(typesafe_cb_postargs(void, (fn), void *, \
+ * (arg), int), \
+ * (arg))
+ */
+#define typesafe_cb_postargs(rtype, atype, fn, arg, ...) \
+ typesafe_cb_cast(rtype (*)(atype, __VA_ARGS__), \
+ rtype (*)(__typeof__(arg), __VA_ARGS__), \
+ (fn))
+#endif /* CCAN_CAST_IF_TYPE_H */
diff --git a/damus-c/utf8.c b/damus-c/utf8.c
@@ -178,3 +178,22 @@ size_t utf8_encode(uint32_t point, char dest[UTF8_MAX_LEN])
return 4;
}
+/* Check for valid UTF-8 */
+bool utf8_check(const void *vbuf, size_t buflen)
+{
+ const unsigned char *buf = vbuf;
+ struct utf8_state utf8_state = UTF8_STATE_INIT;
+ bool need_more = false;
+
+ for (size_t i = 0; i < buflen; i++) {
+ if (!utf8_decode(&utf8_state, buf[i])) {
+ need_more = true;
+ continue;
+ }
+ need_more = false;
+ if (errno != 0)
+ return false;
+ }
+ return !need_more;
+}
+
diff --git a/damus-c/utf8.h b/damus-c/utf8.h
@@ -51,4 +51,7 @@ bool utf8_decode(struct utf8_state *utf8_state, char c);
* Sets errno to ERANGE if point was invalid.
*/
size_t utf8_encode(uint32_t point, char dest[UTF8_MAX_LEN]);
+
+/* Check for valid UTF-8 */
+bool utf8_check(const void *vbuf, size_t buflen);
#endif /* CCAN_UTF8_H */