Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions lightningd/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,8 @@ void payment_failed(struct lightningd *ld,
fail ? fail->erring_channel : NULL,
NULL,
failstr,
fail ? fail->channel_dir : 0);
fail ? fail->channel_dir : 0,
fail ? fail->msg : NULL);

tell_waiters_failed(ld, payment_hash, payment, pay_errcode,
failonion, fail, failstr);
Expand All @@ -675,6 +676,7 @@ static struct command_result *wait_payment(struct lightningd *ld,
struct short_channel_id *failchannel;
u8 *failupdate;
char *faildetail;
u8 *failmsg;
struct routing_failure *fail;
int faildirection;
enum jsonrpc_errcode rpcerrorcode;
Expand Down Expand Up @@ -715,7 +717,8 @@ static struct command_result *wait_payment(struct lightningd *ld,
&failchannel,
&failupdate,
&faildetail,
&faildirection);
&faildirection,
&failmsg);
/* Old DB might not save failure information */
if (!failonionreply && !failnode) {
return command_fail(cmd, PAY_UNSPECIFIED_ERROR,
Expand Down Expand Up @@ -745,8 +748,7 @@ static struct command_result *wait_payment(struct lightningd *ld,
fail->erring_channel = NULL;
}

/* FIXME: We don't store this! */
fail->msg = NULL;
fail->msg = tal_dup_talarr(fail, u8, failmsg);

/* Peers which fail directly can hit this! */
if (failcode & BADONION)
Expand Down Expand Up @@ -1530,7 +1532,7 @@ static struct command_result *self_payment(struct lightningd *ld,
fail->failcode, fail->erring_node,
NULL, NULL,
err,
0);
0, NULL);
/* We do this even though there really can't be any waiters,
* since we didn't block. */
tell_waiters_failed(ld, rhash, payment, PAY_DESTINATION_PERM_FAIL,
Expand Down
9 changes: 9 additions & 0 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -2861,6 +2861,15 @@ def test_error_returns_blockheight(node_factory, bitcoind):
assert (err.value.error['data']['raw_message']
== '400f{:016x}{:08x}'.format(100, bitcoind.rpc.getblockcount()))

# A second waitsendpay replays the failure from the database (the
# path a waitsendpay racing the failure takes): raw_message must
# survive that round trip too.
with pytest.raises(RpcError, match=r"INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS.*'erring_index': 1") as err:
l1.rpc.waitsendpay('00' * 32, TIMEOUT)

assert (err.value.error['data']['raw_message']
== '400f{:016x}{:08x}'.format(100, bitcoind.rpc.getblockcount()))


@unittest.skipIf(TEST_NETWORK != 'regtest', "Invoice is network specific")
def test_pay_no_secret(node_factory, bitcoind):
Expand Down
5 changes: 5 additions & 0 deletions wallet/migrations.c
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,11 @@ static const struct db_migration dbmigrations[] = {
{SQL("ALTER TABLE offers ADD COLUMN force_paths INTEGER DEFAULT 0;"), NULL,
SQL("ALTER TABLE offers DROP COLUMN force_paths"), NULL},
/* ^v26.04 */

/* Raw BOLT4 failure message, so waitsendpay can report it even
* after the failure was recorded (issue #9341). */
{SQL("ALTER TABLE payments ADD failmsg BLOB;"), NULL,
SQL("ALTER TABLE payments DROP COLUMN failmsg"), NULL},
};

const struct db_migration *get_db_migrations(size_t *num)
Expand Down
14 changes: 12 additions & 2 deletions wallet/wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -4351,7 +4351,8 @@ void wallet_payment_get_failinfo(const tal_t *ctx,
struct short_channel_id **failchannel,
u8 **failupdate,
char **faildetail,
int *faildirection)
int *faildirection,
u8 **failmsg)
{
struct db_stmt *stmt;
bool resb;
Expand All @@ -4361,6 +4362,7 @@ void wallet_payment_get_failinfo(const tal_t *ctx,
", failindex, failcode"
", failnode, failscid"
", failupdate, faildetail, faildirection"
", failmsg"
" FROM payments"
" WHERE payment_hash=? AND partid=? AND groupid=?;"));
db_bind_sha256(stmt, payment_hash);
Expand Down Expand Up @@ -4395,6 +4397,10 @@ void wallet_payment_get_failinfo(const tal_t *ctx,
*faildetail = db_col_strdup(ctx, stmt, "faildetail");
else
*faildetail = NULL;
if (db_col_is_null(stmt, "failmsg"))
*failmsg = NULL;
else
*failmsg = db_col_arr(ctx, stmt, "failmsg", u8);

tal_free(stmt);
}
Expand All @@ -4410,7 +4416,8 @@ void wallet_payment_set_failinfo(struct wallet *wallet,
const struct short_channel_id *failchannel,
const u8 *failupdate /*tal_arr*/,
const char *faildetail,
int faildirection)
int faildirection,
const u8 *failmsg /*tal_arr*/)
{
struct db_stmt *stmt;

Expand All @@ -4424,6 +4431,7 @@ void wallet_payment_set_failinfo(struct wallet *wallet,
" , faildirection=?"
" , failupdate=?"
" , faildetail=?"
" , failmsg=?"
" WHERE payment_hash=?"
" AND partid=?;"));
if (failonionreply)
Expand Down Expand Up @@ -4454,6 +4462,8 @@ void wallet_payment_set_failinfo(struct wallet *wallet,
else
db_bind_null(stmt);

db_bind_talarr(stmt, failmsg);

db_bind_sha256(stmt, payment_hash);
db_bind_u64(stmt, partid);

Expand Down
6 changes: 4 additions & 2 deletions wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,8 @@ void wallet_payment_get_failinfo(const tal_t *ctx,
struct short_channel_id **failchannel,
u8 **failupdate,
char **faildetail,
int *faildirection);
int *faildirection,
u8 **failmsg);
/**
* wallet_payment_set_failinfo - Set failure information for a given
* `payment_hash`.
Expand All @@ -1075,7 +1076,8 @@ void wallet_payment_set_failinfo(struct wallet *wallet,
const struct short_channel_id *failchannel,
const u8 *failupdate,
const char *faildetail,
int faildirection);
int faildirection,
const u8 *failmsg);

/**
* payments_first: get first payment, optionally filtering by status
Expand Down
Loading