JSON: allow any number of decimal points when parsing 'btc' suffix.

I tried to fundchannel 0.01btc, and of course it wanted 8 decimals exactly.
If I can't get this right, it's probably a bad idea.

I still don't allow whole number of btc though, since that's probably a mistake
and you're not supposed to put that much in c-lightning yet :)

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2019-02-23 11:35:51 +10:30
parent 9f3627f09d
commit f5dc8b9d52
14 changed files with 74 additions and 69 deletions

View File

@ -15,10 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- lightning-cli: `help <cmd>` finds man pages even if `make install` not run.
- JSON API: `getroute`, `invoice`, `sendpay` and `pay` commands `msatoshi`
parameter can have suffixes `msat`, `sat` (optionally with 3 decimals) or `btc`
(with 8 or 11 decimals).
(with 1 to 11 decimal places).
- JSON API: `fundchannel` and `withdraw` commands `satoshi`
parameter can have suffixes `msat` (must end in `000`), `sat` or `btc`
(with 8 decimals).
(with 1 to 8 decimal places).
- JSON API: `decodepay`, `getroute`, `sendpay`, `pay`, `listpeers`, `listfunds`, `listchannels` and
all invoice commands now return an `amount_msat` field which has an `msat` suffix.
- JSON API: `listfunds` `channels` now has `_msat` fields for each existing raw amount field, with `msat` suffix.

View File

@ -103,7 +103,7 @@ static bool breakup(const char *str, size_t slen,
return true;
}
static bool from_number(u64 *res, const char *s, size_t len, u64 multipler)
static bool from_number(u64 *res, const char *s, size_t len, int tens_factor)
{
if (len == 0)
return false;
@ -118,19 +118,25 @@ static bool from_number(u64 *res, const char *s, size_t len, u64 multipler)
return false;
*res += s[i] - '0';
}
if (mul_overflows_u64(*res, multipler))
return false;
*res *= multipler;
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, u64 multipler1,
const char *s2, size_t len2, u64 multipler2)
const char *s1, size_t len1, int tens_factor,
const char *s2, size_t len2)
{
u64 p1, p2;
if (!from_number(&p1, s1, len1, multipler1)
|| !from_number(&p2, s2, len2, multipler2))
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))
@ -144,8 +150,7 @@ static bool from_numbers(u64 *res,
* [0-9]+ => millisatoshi.
* [0-9]+msat => millisatoshi.
* [0-9]+sat => *1000 -> millisatopshi.
* [0-9]+.[0-9]{8}btc => *1000 -> millisatoshi.
* [0-9]+.[0-9]{11}btc => millisatoshi.
* [0-9]+.[0-9]{1,11}btc => millisatoshi.
*/
bool parse_amount_msat(struct amount_msat *msat, const char *s, size_t slen)
{
@ -158,25 +163,15 @@ bool parse_amount_msat(struct amount_msat *msat, const char *s, size_t slen)
return false;
if (!post_decimal_ptr && !suffix_ptr)
return from_number(&msat->millisatoshis, s, whole_number_len, 1);
return from_number(&msat->millisatoshis, s, whole_number_len, 0);
if (!post_decimal_ptr && memeqstr(suffix_ptr, suffix_len, "msat"))
return from_number(&msat->millisatoshis, s, whole_number_len, 1);
return from_number(&msat->millisatoshis, s, whole_number_len, 0);
if (!post_decimal_ptr && memeqstr(suffix_ptr, suffix_len, "sat"))
return from_number(&msat->millisatoshis, s, whole_number_len,
MSAT_PER_SAT);
if (post_decimal_ptr && post_decimal_len == 8
&& memeqstr(suffix_ptr, suffix_len, "btc"))
return from_number(&msat->millisatoshis, s, whole_number_len, 3);
if (post_decimal_ptr && memeqstr(suffix_ptr, suffix_len, "btc"))
return from_numbers(&msat->millisatoshis,
s, whole_number_len,
MSAT_PER_BTC,
post_decimal_ptr, post_decimal_len,
MSAT_PER_SAT);
if (post_decimal_ptr && post_decimal_len == 11
&& memeqstr(suffix_ptr, suffix_len, "btc"))
return from_numbers(&msat->millisatoshis,
s, whole_number_len,
MSAT_PER_BTC,
post_decimal_ptr, post_decimal_len, 1);
s, whole_number_len, 11,
post_decimal_ptr, post_decimal_len);
return false;
}
@ -184,7 +179,7 @@ bool parse_amount_msat(struct amount_msat *msat, const char *s, size_t slen)
* [0-9]+ => satoshi.
* [0-9]+sat => satoshi.
* [0-9]+000msat => satoshi.
* [0-9]+.[0-9]{8}btc => satoshi.
* [0-9]+.[0-9]{1,8}btc => satoshi.
*/
bool parse_amount_sat(struct amount_sat *sat, const char *s, size_t slen)
{
@ -197,21 +192,18 @@ bool parse_amount_sat(struct amount_sat *sat, const char *s, size_t slen)
return false;
if (!post_decimal_ptr && !suffix_ptr)
return from_number(&sat->satoshis, s, whole_number_len, 1);
return from_number(&sat->satoshis, s, whole_number_len, 0);
if (!post_decimal_ptr && memeqstr(suffix_ptr, suffix_len, "sat"))
return from_number(&sat->satoshis, s, whole_number_len, 1);
return from_number(&sat->satoshis, s, whole_number_len, 0);
if (!post_decimal_ptr && memeqstr(suffix_ptr, suffix_len, "msat")) {
if (!memends(s, whole_number_len, "000", strlen("000")))
return false;
return from_number(&sat->satoshis, s, whole_number_len - 3, 1);
return from_number(&sat->satoshis, s, whole_number_len - 3, 0);
}
if (post_decimal_ptr && post_decimal_len == 8
&& memeqstr(suffix_ptr, suffix_len, "btc"))
if (post_decimal_ptr && memeqstr(suffix_ptr, suffix_len, "btc"))
return from_numbers(&sat->satoshis,
s, whole_number_len,
SAT_PER_BTC,
post_decimal_ptr, post_decimal_len,
1);
s, whole_number_len, 8,
post_decimal_ptr, post_decimal_len);
return false;
}

View File

@ -124,8 +124,7 @@ const char *fmt_amount_sat(const tal_t *ctx, const struct amount_sat *sat);
* [0-9]+ => millisatoshi.
* [0-9]+msat => millisatoshi.
* [0-9]+sat => *1000 -> millisatopshi.
* [0-9]+.[0-9]{8}btc => *1000 -> millisatoshi.
* [0-9]+.[0-9]{11}btc => millisatoshi.
* [0-9]+.[0-9]{1,11}btc => millisatoshi.
*/
bool parse_amount_msat(struct amount_msat *msat, const char *s, size_t slen);
@ -133,7 +132,7 @@ bool parse_amount_msat(struct amount_msat *msat, const char *s, size_t slen);
* [0-9]+ => satoshi.
* [0-9]+sat => satoshi.
* [0-9]+000msat => satoshi.
* [0-9]+.[0-9]{8}btc => satoshi.
* [0-9]+.[0-9]{1,8}btc => satoshi.
*/
bool parse_amount_sat(struct amount_sat *sat, const char *s, size_t slen);

View File

@ -52,11 +52,19 @@ int main(void)
PASS_MSAT(&msat, "0.00000000000btc", 0);
PASS_MSAT(&msat, "0.00000001btc", 1000);
PASS_MSAT(&msat, "0.00000000001btc", 1);
PASS_MSAT(&msat, "1.2btc", 120000000000);
PASS_MSAT(&msat, "1.23btc", 123000000000);
PASS_MSAT(&msat, "1.234btc", 123400000000);
PASS_MSAT(&msat, "1.2345btc", 123450000000);
PASS_MSAT(&msat, "1.23456btc", 123456000000);
PASS_MSAT(&msat, "1.234567btc", 123456700000);
PASS_MSAT(&msat, "1.2345678btc", 123456780000);
PASS_MSAT(&msat, "1.23456789btc", 123456789000);
PASS_MSAT(&msat, "1.234567890btc", 123456789000);
PASS_MSAT(&msat, "1.2345678901btc", 123456789010);
PASS_MSAT(&msat, "1.23456789012btc", 123456789012);
FAIL_MSAT(&msat, "1btc");
FAIL_MSAT(&msat, "1.0000000btc");
FAIL_MSAT(&msat, "1.000000000btc");
FAIL_MSAT(&msat, "1.000000000000btc");
FAIL_MSAT(&msat, "-1.23456789btc");
FAIL_MSAT(&msat, "-1.23456789012btc");
@ -95,10 +103,16 @@ int main(void)
PASS_SAT(&sat, "0.00000001btc", 1);
FAIL_SAT(&sat, "0.00000000001btc");
PASS_SAT(&sat, "1.23456789btc", 123456789);
FAIL_SAT(&sat, "1.23456789012btc");
PASS_SAT(&sat, "1.2btc", 120000000);
PASS_SAT(&sat, "1.23btc", 123000000);
PASS_SAT(&sat, "1.234btc", 123400000);
PASS_SAT(&sat, "1.2345btc", 123450000);
PASS_SAT(&sat, "1.23456btc", 123456000);
PASS_SAT(&sat, "1.234567btc", 123456700);
PASS_SAT(&sat, "1.2345678btc", 123456780);
PASS_SAT(&sat, "1.23456789btc", 123456789);
FAIL_SAT(&sat, "1.234567890btc");
FAIL_SAT(&sat, "1btc");
FAIL_SAT(&sat, "1.0000000btc");
FAIL_SAT(&sat, "1.000000000btc");
FAIL_SAT(&sat, "-1.23456789btc");
/* Overflowingly big. */

View File

@ -2,12 +2,12 @@
.\" Title: lightning-fundchannel
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 02/18/2019
.\" Date: 02/23/2019
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "LIGHTNING\-FUNDCHANN" "7" "02/18/2019" "\ \&" "\ \&"
.TH "LIGHTNING\-FUNDCHANN" "7" "02/23/2019" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -38,7 +38,7 @@ The \fBfundchannel\fR RPC command opens a payment channel with a peer by committ
.sp
\fIid\fR is the peer id obtained from \fBconnect\fR\&.
.sp
\fIsatoshi\fR is the amount in satoshis taken from the internal wallet to fund the channel\&. The string \fIall\fR can be used to specify all available funds (or 16777215 satoshi if more is available)\&. Otherwise, it is in satoshi precision; it can be a whole number, a whole number ending in \fIsat\fR, a whole number ending in \fI000msat\fR, or a number with 8 decimal places ending in \fIbtc\fR\&. The value cannot be less than the dust limit, currently set to 546, nor more than 16777215 satoshi\&.
\fIsatoshi\fR is the amount in satoshis taken from the internal wallet to fund the channel\&. The string \fIall\fR can be used to specify all available funds (or 16777215 satoshi if more is available)\&. Otherwise, it is in satoshi precision; it can be a whole number, a whole number ending in \fIsat\fR, a whole number ending in \fI000msat\fR, or a number with 1 to 8 decimal places ending in \fIbtc\fR\&. The value cannot be less than the dust limit, currently set to 546, nor more than 16777215 satoshi\&.
.sp
\fIfeerate\fR is an optional feerate used for the opening transaction and as initial feerate for commitment and HTLC transactions\&. It can be one of the strings \fIurgent\fR, \fInormal\fR or \fIslow\fR to use lightningd\(cqs internal estimates: \fInormal\fR is the default\&.
.sp

View File

@ -24,7 +24,7 @@ for the channel.
'satoshi' is the amount in satoshis taken from the internal wallet to fund the channel.
The string 'all' can be used to specify all available funds (or 16777215 satoshi if more is available).
Otherwise, it is in satoshi precision; it can be a whole number, a whole number ending in 'sat', a whole number ending in '000msat', or a number with 8 decimal places ending in 'btc'.
Otherwise, it is in satoshi precision; it can be a whole number, a whole number ending in 'sat', a whole number ending in '000msat', or a number with 1 to 8 decimal places ending in 'btc'.
The value cannot be less than the dust limit, currently set to 546, nor more
than 16777215 satoshi.

View File

@ -2,12 +2,12 @@
.\" Title: lightning-invoice
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 02/18/2019
.\" Date: 02/23/2019
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "LIGHTNING\-INVOICE" "7" "02/18/2019" "\ \&" "\ \&"
.TH "LIGHTNING\-INVOICE" "7" "02/23/2019" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -36,7 +36,7 @@ lightning-invoice \- Command for accepting payments\&.
.sp
The \fBinvoice\fR RPC command creates the expectation of a payment of a given amount of milli\-satoshi: it returns a unique token which another lightning daemon can use to pay this invoice\&. This token includes a \fIroute hint\fR description of an incoming channel with capacity to pay the invoice, if any exists\&.
.sp
The \fImsatoshi\fR parameter can be the string "any", which creates an invoice that can be paid with any amount\&. Otherwise it is in millisatoshi precision; it can be a whole number, or a whole number ending in \fImsat\fR or \fIsat\fR, or a number with three decimal places ending in \fIsat\fR, or a number with 8 or 11 decimal places ending in \fIbtc\fR\&.
The \fImsatoshi\fR parameter can be the string "any", which creates an invoice that can be paid with any amount\&. Otherwise it is in millisatoshi precision; it can be a whole number, or a whole number ending in \fImsat\fR or \fIsat\fR, or a number with three decimal places ending in \fIsat\fR, or a number with 1 to 11 decimal places ending in \fIbtc\fR\&.
.sp
The \fIlabel\fR must be a unique string or number (which is treated as a string, so "01" is different from "1"); it is never revealed to other nodes on the lightning network, but it can be used to query the status of this invoice\&.
.sp

View File

@ -22,7 +22,7 @@ The 'msatoshi' parameter can be the string "any", which creates an invoice
that can be paid with any amount. Otherwise it is in millisatoshi
precision; it can be a whole number, or a whole number ending in 'msat' or
'sat', or a number with three decimal places ending in 'sat', or a number
with 8 or 11 decimal places ending in 'btc'.
with 1 to 11 decimal places ending in 'btc'.
The 'label' must be a unique string or number (which is treated as a
string, so "01" is different from "1"); it is never revealed to other

View File

@ -2,12 +2,12 @@
.\" Title: lightning-pay
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 02/18/2019
.\" Date: 02/23/2019
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "LIGHTNING\-PAY" "7" "02/18/2019" "\ \&" "\ \&"
.TH "LIGHTNING\-PAY" "7" "02/23/2019" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -34,7 +34,7 @@ lightning-pay \- Command for sending a payment to a BOLT11 invoice
\fBpay\fR \fIbolt11\fR [\fImsatoshi\fR] [\fIdescription\fR] [\fIriskfactor\fR] [\fImaxfeepercent\fR] [\fIretry_for\fR] [\fImaxdelay\fR] [\fIexemptfee\fR]
.SH "DESCRIPTION"
.sp
The \fBpay\fR RPC command attempts to find a route to the given destination, and send the funds it asks for\&. If the \fIbolt11\fR does not contain an amount, \fImsatoshi\fR is required, otherwise if it is specified it must be \fInull\fR\&. \fImsatoshi\fR is in millisatoshi precision; it can be a whole number, or a whole number with suffix \fImsat\fR, \fIsat\fR, or \fIbtc\fR, or a three decimal point number with suffix \fIsat\fR, or an 8 or 11 decimal point number postfixed by \fIbtc\fR\&.
The \fBpay\fR RPC command attempts to find a route to the given destination, and send the funds it asks for\&. If the \fIbolt11\fR does not contain an amount, \fImsatoshi\fR is required, otherwise if it is specified it must be \fInull\fR\&. \fImsatoshi\fR is in millisatoshi precision; it can be a whole number, or a whole number with suffix \fImsat\fR or \fIsat\fR, or a three decimal point number with suffix \fIsat\fR, or an 1 to 11 decimal point number suffixed by \fIbtc\fR\&.
.sp
If \fIbolt11\fR contains a description hash (\fIh\fR field) \fIdescription\fR is required, otherwise it is unused\&. The \fIriskfactor\fR is described in detail in lightning\-getroute(7), and defaults to 10\&. The \fImaxfeepercent\fR limits the money paid in fees, and defaults to 0\&.5\&. The maxfeepercent\*(Aq is a percentage of the amount that is to be paid\&. The `exemptfee option can be used for tiny payments which would be dominated by the fee leveraged by forwarding nodes\&. Setting exemptfee allows the maxfeepercent check to be skipped on fees that are smaller than exemptfee (default: 5000 millisatoshi)\&.
.sp

View File

@ -17,9 +17,9 @@ The *pay* RPC command attempts to find a route to the given destination,
and send the funds it asks for. If the 'bolt11' does not contain an amount,
'msatoshi' is required, otherwise if it is specified it must be 'null'.
'msatoshi' is in millisatoshi precision; it can be a whole number, or
a whole number with suffix 'msat', 'sat', or 'btc', or a three decimal
point number with suffix 'sat', or an 8 or 11 decimal point number
postfixed by 'btc'.
a whole number with suffix 'msat' or 'sat', or a three decimal
point number with suffix 'sat', or an 1 to 11 decimal point number
suffixed by 'btc'.
If 'bolt11' contains a description hash ('h' field) 'description' is
required, otherwise it is unused. The 'riskfactor' is described in detail

View File

@ -2,12 +2,12 @@
.\" Title: lightning-sendpay
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 02/18/2019
.\" Date: 02/23/2019
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "LIGHTNING\-SENDPAY" "7" "02/18/2019" "\ \&" "\ \&"
.TH "LIGHTNING\-SENDPAY" "7" "02/23/2019" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -42,7 +42,7 @@ The response will occur when the payment is on its way to the destination\&. The
.sp
The \fIdescription\fR parameter, if provided, will be returned in \fIwaitsendpay\fR and \fIlistpayments\fR results\&.
.sp
The \fImsatoshi\fR amount, if provided, is the amount that will be recorded as the target payment value\&. If not specified, it will be the final amount to the destination\&. If specified, then the final amount at the destination must be from the specified \fImsatoshi\fR to twice the specified \fImsatoshi\fR, inclusive\&. This is intended to obscure payments by overpaying slightly at the destination; the actual target payment is what should be specified as the \fImsatoshi\fR argument\&. \fImsatoshi\fR is in millisatoshi precision; it can be a whole number, or a whole number ending in \fImsat\fR or \fIsat\fR, or a number with three decimal places ending in \fIsat\fR, or a number with 8 or 11 decimal places ending in \fIbtc\fR\&.
The \fImsatoshi\fR amount, if provided, is the amount that will be recorded as the target payment value\&. If not specified, it will be the final amount to the destination\&. If specified, then the final amount at the destination must be from the specified \fImsatoshi\fR to twice the specified \fImsatoshi\fR, inclusive\&. This is intended to obscure payments by overpaying slightly at the destination; the actual target payment is what should be specified as the \fImsatoshi\fR argument\&. \fImsatoshi\fR is in millisatoshi precision; it can be a whole number, or a whole number ending in \fImsat\fR or \fIsat\fR, or a number with three decimal places ending in \fIsat\fR, or a number with 1 to 11 decimal places ending in \fIbtc\fR\&.
.sp
Once a payment has succeeded, calls to \fBsendpay\fR with the same \fIpayment_hash\fR but a different \fImsatoshi\fR or destination will fail; this prevents accidental multiple payments\&. Calls to \fBsendpay\fR with the same \fIpayment_hash\fR, \fImsatoshi\fR, and destination as a previous successful payment (even if a different route) will return immediately with success\&.
.SH "RETURN VALUE"

View File

@ -41,8 +41,8 @@ the destination;
the actual target payment is what should be specified as the
'msatoshi' argument. 'msatoshi' is in millisatoshi precision; it can
be a whole number, or a whole number ending in 'msat' or 'sat', or a
number with three decimal places ending in 'sat', or a number with 8
or 11 decimal places ending in 'btc'.
number with three decimal places ending in 'sat', or a number with 1
to 11 decimal places ending in 'btc'.
Once a payment has succeeded, calls to *sendpay* with the same 'payment_hash'

View File

@ -2,12 +2,12 @@
.\" Title: lightning-withdraw
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 02/18/2019
.\" Date: 02/23/2019
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "LIGHTNING\-WITHDRAW" "7" "02/18/2019" "\ \&" "\ \&"
.TH "LIGHTNING\-WITHDRAW" "7" "02/23/2019" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -38,7 +38,7 @@ The \fBwithdraw\fR RPC command sends funds from c\-lightning\(cqs internal walle
.sp
The address can be of any Bitcoin accepted type, including bech32\&.
.sp
\fIsatoshi\fR is the amount to be withdrawn from the internal wallet (expressed, as name suggests, in satoshi)\&. The string \fIall\fR can be used to specify withdrawal of all available funds\&. Otherwise, it is in satoshi precision; it can be a whole number, a whole number ending in \fIsat\fR, a whole number ending in \fI000msat\fR, or a number with 8 decimal places ending in \fIbtc\fR\&.
\fIsatoshi\fR is the amount to be withdrawn from the internal wallet (expressed, as name suggests, in satoshi)\&. The string \fIall\fR can be used to specify withdrawal of all available funds\&. Otherwise, it is in satoshi precision; it can be a whole number, a whole number ending in \fIsat\fR, a whole number ending in \fI000msat\fR, or a number with 1 to 8 decimal places ending in \fIbtc\fR\&.
.sp
\fIfeerate\fR is an optional feerate to use\&. It can be one of the strings \fIurgent\fR, \fInormal\fR or \fIslow\fR to use lightningd\(cqs internal estimates: \fInormal\fR is the default\&.
.sp

View File

@ -22,7 +22,7 @@ including bech32.
'satoshi' is the amount to be withdrawn from the internal
wallet (expressed, as name suggests, in satoshi).
The string 'all' can be used to specify withdrawal of all
available funds. Otherwise, it is in satoshi precision; it can be a whole number, a whole number ending in 'sat', a whole number ending in '000msat', or a number with 8 decimal places ending in 'btc'.
available funds. Otherwise, it is in satoshi precision; it can be a whole number, a whole number ending in 'sat', a whole number ending in '000msat', or a number with 1 to 8 decimal places ending in 'btc'.
'feerate' is an optional feerate to use. It can be one of the strings
'urgent', 'normal' or 'slow' to use lightningd's internal estimates: