Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Self-pay support. #6399

Merged
merged 10 commits into from
Jul 25, 2023
13 changes: 3 additions & 10 deletions common/coin_mvt.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,7 @@ static struct chain_coin_mvt *new_chain_coin_mvt(const tal_t *ctx,
{
struct chain_coin_mvt *mvt = tal(ctx, struct chain_coin_mvt);

if (account_name)
mvt->account_name = tal_strdup(mvt, account_name);
else
mvt->account_name = NULL;

mvt->account_name = tal_strdup_or_null(mvt, account_name);
mvt->tx_txid = tx_txid;
mvt->outpoint = outpoint;
mvt->originating_acct = NULL;
Expand Down Expand Up @@ -393,11 +389,8 @@ struct coin_mvt *finalize_chain_mvt(const tal_t *ctx,
struct coin_mvt *mvt = tal(ctx, struct coin_mvt);

mvt->account_id = tal_strdup(mvt, chain_mvt->account_name);
if (chain_mvt->originating_acct)
mvt->originating_acct =
tal_strdup(mvt, chain_mvt->originating_acct);
else
mvt->originating_acct = NULL;
mvt->originating_acct =
tal_strdup_or_null(mvt, chain_mvt->originating_acct);
mvt->hrp_name = tal_strdup(mvt, hrp_name);
mvt->type = CHAIN_MVT;

Expand Down
5 changes: 1 addition & 4 deletions common/configvar.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ struct configvar *configvar_new(const tal_t *ctx,
const char *configline)
{
struct configvar *cv = tal(ctx, struct configvar);
if (file)
cv->file = tal_strdup(cv, file);
else
cv->file = NULL;
cv->file = tal_strdup_or_null(cv, file);
cv->src = src;
cv->linenum = linenum;
cv->configline = tal_strdup(cv, configline);
Expand Down
10 changes: 10 additions & 0 deletions common/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,16 @@ char *utf8_str(const tal_t *ctx, const u8 *buf TAKES, size_t buflen)
return ret;
}

char *tal_strdup_or_null(const tal_t *ctx, const char *str)
{
if (!str) {
/* You might have taken NULL; that's legal! Release now. */
taken(str);
return NULL;
}
return tal_strdup(ctx, str);
}

int tmpdir_mkstemp(const tal_t *ctx, const char *template TAKES, char **created)
{
char *tmpdir = getenv("TMPDIR");
Expand Down
3 changes: 3 additions & 0 deletions common/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ bool utf8_check(const void *buf, size_t buflen);
/* Check it's UTF-8, return copy (or same if TAKES), or NULL if not valid. */
char *utf8_str(const tal_t *ctx, const u8 *buf TAKES, size_t buflen);

/* Strdup, or pass through NULL */
char *tal_strdup_or_null(const tal_t *ctx, const char *str);

/* Use the POSIX C locale. */
void setup_locale(void);

Expand Down
35 changes: 26 additions & 9 deletions db/bindings.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,17 @@ char *db_col_strdup(const tal_t *ctx,
return tal_strdup(ctx, (char *)stmt->db->config->column_text_fn(stmt, col));
}

char *db_col_strdup_optional(const tal_t *ctx,
struct db_stmt *stmt,
const char *colname)
{
size_t col = db_query_colnum(stmt, colname);
if (db_column_is_null(stmt, col))
return NULL;

return tal_strdup(ctx, (char *)stmt->db->config->column_text_fn(stmt, col));
}

void db_col_preimage(struct db_stmt *stmt, const char *colname,
struct preimage *preimage)
{
Expand Down Expand Up @@ -346,17 +357,22 @@ void db_col_node_id(struct db_stmt *stmt, const char *colname, struct node_id *d
memcpy(dest->k, db_column_blob(stmt, col), sizeof(dest->k));
}

/* We don't assume sizeof(struct node_id) == sizeof(struct node_id.k),
* otherwise this would simply be a call to db_col_arr!
* Thanks ARM! */
struct node_id *db_col_node_id_arr(const tal_t *ctx, struct db_stmt *stmt,
const char *colname)
const char *colname)
{
size_t col = db_query_colnum(stmt, colname);
struct node_id *ret;
size_t n = db_column_bytes(stmt, col) / sizeof(ret->k);
const u8 *arr = db_column_blob(stmt, col);
assert(n * sizeof(ret->k) == (size_t)db_column_bytes(stmt, col));
ret = tal_arr(ctx, struct node_id, n);

db_column_null_warn(stmt, colname, col);
if (db_column_is_null(stmt, col))
return NULL;

ret = tal_arr(ctx, struct node_id, n);
for (size_t i = 0; i < n; i++)
memcpy(ret[i].k, arr + i * sizeof(ret[i].k), sizeof(ret[i].k));

Expand Down Expand Up @@ -399,7 +415,9 @@ db_col_short_channel_id_arr(const tal_t *ctx, struct db_stmt *stmt, const char *
size_t len;
struct short_channel_id *ret;

db_column_null_warn(stmt, colname, col);
if (db_column_is_null(stmt, col))
return NULL;

ser = db_column_blob(stmt, col);
len = db_column_bytes(stmt, col);
ret = tal_arr(ctx, struct short_channel_id, 0);
Expand Down Expand Up @@ -516,15 +534,14 @@ void db_col_amount_msat_or_default(struct db_stmt *stmt,
msat->millisatoshis = db_col_u64(stmt, colname); /* Raw: low level function */
}

void db_col_amount_msat(struct db_stmt *stmt, const char *colname,
struct amount_msat *msat)
struct amount_msat db_col_amount_msat(struct db_stmt *stmt, const char *colname)
{
msat->millisatoshis = db_col_u64(stmt, colname); /* Raw: low level function */
return amount_msat(db_col_u64(stmt, colname));
}

void db_col_amount_sat(struct db_stmt *stmt, const char *colname, struct amount_sat *sat)
struct amount_sat db_col_amount_sat(struct db_stmt *stmt, const char *colname)
{
sat->satoshis = db_col_u64(stmt, colname); /* Raw: low level function */
return amount_sat(db_col_u64(stmt, colname));
}

struct json_escape *db_col_json_escape(const tal_t *ctx,
Expand Down
8 changes: 6 additions & 2 deletions db/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,13 @@ const void* db_col_blob(struct db_stmt *stmt, const char *colname);
char *db_col_strdup(const tal_t *ctx,
struct db_stmt *stmt,
const char *colname);
/* string or NULL */
char *db_col_strdup_optional(const tal_t *ctx,
struct db_stmt *stmt,
const char *colname);
void db_col_preimage(struct db_stmt *stmt, const char *colname, struct preimage *preimage);
void db_col_amount_msat(struct db_stmt *stmt, const char *colname, struct amount_msat *msat);
void db_col_amount_sat(struct db_stmt *stmt, const char *colname, struct amount_sat *sat);
struct amount_msat db_col_amount_msat(struct db_stmt *stmt, const char *colname);
struct amount_sat db_col_amount_sat(struct db_stmt *stmt, const char *colname);
struct json_escape *db_col_json_escape(const tal_t *ctx, struct db_stmt *stmt, const char *colname);
void db_col_sha256(struct db_stmt *stmt, const char *colname, struct sha256 *sha);
void db_col_sha256d(struct db_stmt *stmt, const char *colname, struct sha256_double *shad);
Expand Down
2 changes: 1 addition & 1 deletion doc/lightning-pay.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ The following error codes may occur:
- 201: Already paid with this *hash* using different amount or
destination.
- 203: Permanent failure at destination. The *data* field of the error
will be routing failure object.
will be routing failure object (except for self-payment, which currently returns the error directly from lightning-sendpay(7)).
- 205: Unable to find a route.
- 206: Route too expensive. Either the fee or the needed total
locktime for the route exceeds your *maxfeepercent* or *maxdelay*
Expand Down
11 changes: 6 additions & 5 deletions doc/lightning-sendpay.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,19 @@ route.

Generally, a client would call lightning-getroute(7) to resolve a route,
then use **sendpay** to send it. If it fails, it would call
lightning-getroute(7) again to retry.
lightning-getroute(7) again to retry. If the route is empty, a payment-to-self is attempted.

The response will occur when the payment is on its way to the
destination. The **sendpay** RPC command does not wait for definite
success or definite failure of the payment. Instead, use the
success or definite failure of the payment (except for already-succeeded
payments, or to-self payments). Instead, use the
**waitsendpay** RPC command to poll or wait for definite success or
definite failure.

The *label* and *bolt11* parameters, if provided, will be returned in
*waitsendpay* and *listsendpays* results.

The *amount\_msat* amount must be provided if *partid* is non-zero, otherwise
The *amount\_msat* amount must be provided if *partid* is non-zero, or the payment is to-self, otherwise
it must be equal to the final
amount to the destination. By default 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
Expand All @@ -39,10 +40,10 @@ accept the payment, as defined by the `payment_data` field in BOLT 4
and the `s` field in the BOLT 11 invoice format. It is required if
*partid* is non-zero.

The *partid* value, if provided and non-zero, allows for multiple parallel
The *partid* value must not be provided for self-payments. If provided and non-zero, allows for multiple parallel
partial payments with the same *payment\_hash*. The *amount\_msat* amount
(which must be provided) for each **sendpay** with matching
*payment\_hash* must be equal, and **sendpay** will fail if there are
*payment\_hash* must be equal, and **sendpay** will fail if there are differing values given.

The *localinvreqid* value indicates that this payment is being made for a local
invoice\_request: this ensures that we only send a payment for a single-use
Expand Down
8 changes: 2 additions & 6 deletions lightningd/chaintopology.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,7 @@ static void rebroadcast_txs(struct chain_topology *topo)

tal_arr_expand(&txs->txs, fmt_bitcoin_tx(txs->txs, otx->tx));
tal_arr_expand(&txs->allowhighfees, otx->allowhighfees);
tal_arr_expand(&txs->cmd_id,
otx->cmd_id ? tal_strdup(txs, otx->cmd_id) : NULL);
tal_arr_expand(&txs->cmd_id, tal_strdup_or_null(txs, otx->cmd_id));
}
tal_free(cleanup_ctx);

Expand Down Expand Up @@ -277,10 +276,7 @@ void broadcast_tx_(struct chain_topology *topo,
otx->cbarg = cbarg;
if (taken(otx->cbarg))
tal_steal(otx, otx->cbarg);
if (cmd_id)
otx->cmd_id = tal_strdup(otx, cmd_id);
else
otx->cmd_id = NULL;
otx->cmd_id = tal_strdup_or_null(otx, cmd_id);

/* Note that if the minimum block is N, we broadcast it when
* we have block N-1! */
Expand Down
5 changes: 4 additions & 1 deletion lightningd/htlc_set.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <common/features.h>
#include <common/timeout.h>
#include <common/type_to_string.h>
#include <lightningd/channel.h>
#include <lightningd/htlc_set.h>
#include <lightningd/invoice.h>
#include <lightningd/lightningd.h>
Expand Down Expand Up @@ -101,6 +102,7 @@ void htlc_set_add(struct lightningd *ld,
{
struct htlc_set *set;
const struct invoice_details *details;
const char *err;

/* BOLT #4:
* The final node:
Expand All @@ -109,8 +111,9 @@ void htlc_set_add(struct lightningd *ld,
* - Note: "amount paid" specified there is the `total_msat` field.
*/
details = invoice_check_payment(tmpctx, ld, &hin->payment_hash,
total_msat, payment_secret);
total_msat, payment_secret, &err);
if (!details) {
log_debug(hin->key.channel->log, "payment failed: %s", err);
local_fail_in_htlc(hin,
take(failmsg_incorrect_or_unknown(NULL, ld, hin)));
return;
Expand Down
42 changes: 22 additions & 20 deletions lightningd/invoice.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,8 @@ invoice_check_payment(const tal_t *ctx,
struct lightningd *ld,
const struct sha256 *payment_hash,
const struct amount_msat msat,
const struct secret *payment_secret)
const struct secret *payment_secret,
const char **err)
{
u64 inv_dbid;
const struct invoice_details *details;
Expand All @@ -382,11 +383,12 @@ invoice_check_payment(const tal_t *ctx,
* - MUST return an `incorrect_or_unknown_payment_details` error.
*/
if (!invoices_find_unpaid(ld->wallet->invoices, &inv_dbid, payment_hash)) {
log_debug(ld->log, "Unknown paid invoice %s",
type_to_string(tmpctx, struct sha256, payment_hash));
if (invoices_find_by_rhash(ld->wallet->invoices, &inv_dbid, payment_hash)) {
log_debug(ld->log, "ALREADY paid invoice %s",
type_to_string(tmpctx, struct sha256, payment_hash));
*err = tal_fmt(ctx, "Already paid or expired invoice %s",
type_to_string(tmpctx, struct sha256, payment_hash));
} else {
*err = tal_fmt(ctx, "Unknown invoice %s",
type_to_string(tmpctx, struct sha256, payment_hash));
}
Comment on lines 386 to 392
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can write the if without {...} here just to be consistent with the our code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, if there is multiline code I prefer {} for clarity. It's fine to omit for simple cases, ofc.

return NULL;
}
Expand All @@ -401,8 +403,8 @@ invoice_check_payment(const tal_t *ctx,
*/
if (feature_is_set(details->features, COMPULSORY_FEATURE(OPT_VAR_ONION))
&& !payment_secret) {
log_debug(ld->log, "Attept to pay %s without secret",
type_to_string(tmpctx, struct sha256, &details->rhash));
*err = tal_fmt(ctx, "Attempt to pay %s without secret",
type_to_string(tmpctx, struct sha256, &details->rhash));
return tal_free(details);
}

Expand All @@ -414,9 +416,9 @@ invoice_check_payment(const tal_t *ctx,
else
invoice_secret(&details->r, &expected);
if (!secret_eq_consttime(payment_secret, &expected)) {
log_debug(ld->log, "Attept to pay %s with wrong secret",
type_to_string(tmpctx, struct sha256,
&details->rhash));
*err = tal_fmt(ctx, "Attempt to pay %s with wrong secret",
type_to_string(tmpctx, struct sha256,
&details->rhash));
return tal_free(details);
}
}
Expand All @@ -432,21 +434,21 @@ invoice_check_payment(const tal_t *ctx,
struct amount_msat twice;

if (amount_msat_less(msat, *details->msat)) {
log_debug(ld->log, "Attept to pay %s with amount %s < %s",
type_to_string(tmpctx, struct sha256,
&details->rhash),
type_to_string(tmpctx, struct amount_msat, &msat),
type_to_string(tmpctx, struct amount_msat, details->msat));
*err = tal_fmt(ctx, "Attempt to pay %s with amount %s < %s",
type_to_string(tmpctx, struct sha256,
&details->rhash),
type_to_string(tmpctx, struct amount_msat, &msat),
type_to_string(tmpctx, struct amount_msat, details->msat));
return tal_free(details);
}

if (amount_msat_add(&twice, *details->msat, *details->msat)
&& amount_msat_greater(msat, twice)) {
log_debug(ld->log, "Attept to pay %s with amount %s > %s",
type_to_string(tmpctx, struct sha256,
&details->rhash),
type_to_string(tmpctx, struct amount_msat, &msat),
type_to_string(tmpctx, struct amount_msat, &twice));
*err = tal_fmt(ctx, "Attempt to pay %s with amount %s > %s",
type_to_string(tmpctx, struct sha256,
&details->rhash),
type_to_string(tmpctx, struct amount_msat, &msat),
type_to_string(tmpctx, struct amount_msat, &twice));
/* BOLT #4:
*
* - if the amount paid is more than twice the amount
Expand Down
4 changes: 3 additions & 1 deletion lightningd/invoice.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct invoice_details {
* @payment_hash: hash of preimage they want.
* @msat: amount they offer to pay.
* @payment_secret: they payment secret they sent, if any.
* @err: error string if it returns NULL.
*
* Returns NULL if there's a problem, otherwise returns the invoice details.
*/
Expand All @@ -55,7 +56,8 @@ invoice_check_payment(const tal_t *ctx,
struct lightningd *ld,
const struct sha256 *payment_hash,
const struct amount_msat msat,
const struct secret *payment_secret);
const struct secret *payment_secret,
const char **err);

/**
* invoice_try_pay - process payment for these incoming payments.
Expand Down
Loading
Loading