amount: Add decimal format for msats
What changed, and why it matters
This commit adds a new helper function that prints millibitcoin amounts as satoshis with a decimal point (for example, 10111 millisatoshis is shown as '10.111sat'). It is purely a logging and display improvement for splicing-related diagnostics. There is no change to how money is handled, validated, or moved.
No security action required. Review as normal code-quality change if desired.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces fmt_amount_m_as_sat() in common/amount.c/h and unit tests in common/test/run-amount.c. The function formats a struct amount_msat as whole satoshis plus a fractional part, stripping trailing zeros. It does not alter parsing, arithmetic, overflow checks, or any consensus-critical code path. The only new dependency is
Changed components
common/amount.ccommon/amount.hcommon/test/run-amount.cInspect captured patch +73 / −0
diff --git a/common/amount.c b/common/amount.c
index cf872d0c..d25448e9 100644
--- a/common/amount.c
+++ b/common/amount.c
@@ -7,6 +7,7 @@
#include <common/overflows.h>
#include <common/utils.h>
#include <inttypes.h>
+#include <stdio.h>
#include <wire/wire.h>
bool amount_sat_to_msat(struct amount_msat *msat,
@@ -64,6 +65,24 @@ char *fmt_amount_msat(const tal_t *ctx, struct amount_msat msat)
return tal_fmt(ctx, "%"PRIu64"msat", msat.millisatoshis);
}
+#define LSIZE 5
+
+char *fmt_amount_m_as_sat(const tal_t *ctx, struct amount_msat msat)
+{
+ char last[LSIZE] = {0};
+
+ if (msat.millisatoshis % MSAT_PER_SAT) {
+ snprintf(last, LSIZE, ".%03"PRIu64,
+ msat.millisatoshis % MSAT_PER_SAT);
+ while(last[strlen(last) - 1] == '0')
+ last[strlen(last) - 1] = 0;
+ }
+
+ return tal_fmt(ctx, "%"PRIu64"%ssat",
+ msat.millisatoshis / MSAT_PER_SAT,
+ last);
+}
+
const char *fmt_amount_sat_btc(const tal_t *ctx,
struct amount_sat sat,
bool append_unit)
diff --git a/common/amount.h b/common/amount.h
index 04965889..2c3901c4 100644
--- a/common/amount.h
+++ b/common/amount.h
@@ -232,6 +232,9 @@ const char *fmt_amount_msat_btc(const tal_t *ctx,
/* => 1234msat */
char *fmt_amount_msat(const tal_t *ctx, struct amount_msat msat);
+/* => 1234.12sat */
+char *fmt_amount_m_as_sat(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,
diff --git a/common/test/run-amount.c b/common/test/run-amount.c
index f76484ef..751ff6c6 100644
--- a/common/test/run-amount.c
+++ b/common/test/run-amount.c
@@ -347,6 +347,57 @@ int main(int argc, char *argv[])
/* Overflowingly big. */
FAIL_SAT(&sat, "21000000000000000000000000.00000000btc");
+ const char *partial_sats[] =
+ {
+ "10.111sat",
+ "10.11sat",
+ "10.1sat",
+ "10sat",
+ "10.001sat",
+ "10.01sat",
+ "10.1sat",
+ "1.111sat",
+ "1.11sat",
+ "1.1sat",
+ "1sat",
+ "0.111sat",
+ "0.011sat",
+ "0.001sat",
+ "0sat",
+ NULL,
+ };
+
+ u64 msat_amnts[] =
+ {
+ 10111,
+ 10110,
+ 10100,
+ 10000,
+ 10001,
+ 10010,
+ 10100,
+ 1111,
+ 1110,
+ 1100,
+ 1000,
+ 111,
+ 11,
+ 1,
+ 0,
+ };
+
+ assert(sizeof(partial_sats) / sizeof(partial_sats[0]) - 1
+ == sizeof(msat_amnts) / sizeof(msat_amnts[0]));
+
+ for (int i = 0; partial_sats[i]; i++) {
+ msat.millisatoshis = msat_amnts[i];
+ printf("Does '%s' equal '%s'\n",
+ fmt_amount_m_as_sat(tmpctx, msat),
+ partial_sats[i]);
+ assert(streq(fmt_amount_m_as_sat(tmpctx, msat),
+ partial_sats[i]));
+ }
+
/* Test fmt_amount_msat_btc, fmt_amount_msat */
for (u64 i = 0; i <= UINT64_MAX / 10; i = i ? i * 10 : 1) {
const char *with, *without;
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.