mirror of
https://github.com/aljazceru/lightning.git
synced 2026-01-22 23:34:21 +01:00
htlc: save fail message in HTLC.
It's not currently encrypted, but at least you get some idea now why an HTLC failed. We (ab)use HTTP error codes for the moment. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
172
daemon/peer.c
172
daemon/peer.c
@@ -57,6 +57,8 @@ struct json_connecting {
|
||||
struct anchor_input *input;
|
||||
};
|
||||
|
||||
static bool command_htlc_set_fail(struct peer *peer, struct htlc *htlc,
|
||||
enum fail_error error_code, const char *why);
|
||||
static bool command_htlc_fail(struct peer *peer, struct htlc *htlc);
|
||||
static bool command_htlc_fulfill(struct peer *peer, struct htlc *htlc);
|
||||
static void try_commit(struct peer *peer);
|
||||
@@ -409,10 +411,20 @@ void set_htlc_rval(struct peer *peer,
|
||||
struct htlc *htlc, const struct rval *rval)
|
||||
{
|
||||
assert(!htlc->r);
|
||||
assert(!htlc->fail);
|
||||
htlc->r = tal_dup(htlc, struct rval, rval);
|
||||
db_htlc_fulfilled(peer, htlc);
|
||||
}
|
||||
|
||||
void set_htlc_fail(struct peer *peer,
|
||||
struct htlc *htlc, const void *fail, size_t len)
|
||||
{
|
||||
assert(!htlc->r);
|
||||
assert(!htlc->fail);
|
||||
htlc->fail = tal_dup_arr(htlc, u8, fail, len, 0);
|
||||
db_htlc_failed(peer, htlc);
|
||||
}
|
||||
|
||||
static void route_htlc_onwards(struct peer *peer,
|
||||
struct htlc *htlc,
|
||||
u64 msatoshis,
|
||||
@@ -422,6 +434,9 @@ static void route_htlc_onwards(struct peer *peer,
|
||||
{
|
||||
struct pubkey id;
|
||||
struct peer *next;
|
||||
struct htlc *newhtlc;
|
||||
enum fail_error error_code;
|
||||
const char *err;
|
||||
|
||||
if (!only_dest) {
|
||||
log_debug_struct(peer->log, "Forwarding HTLC %s",
|
||||
@@ -432,7 +447,8 @@ static void route_htlc_onwards(struct peer *peer,
|
||||
if (!proto_to_pubkey(peer->dstate->secpctx, pb_id, &id)) {
|
||||
log_unusual(peer->log,
|
||||
"Malformed pubkey for HTLC %"PRIu64, htlc->id);
|
||||
command_htlc_fail(peer, htlc);
|
||||
command_htlc_set_fail(peer, htlc, BAD_REQUEST_400,
|
||||
"Malformed pubkey");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -442,7 +458,8 @@ static void route_htlc_onwards(struct peer *peer,
|
||||
htlc->id, next ? "ready " : "");
|
||||
log_add_struct(peer->log, "%s", struct pubkey, &id);
|
||||
if (!peer->dstate->dev_never_routefail)
|
||||
command_htlc_fail(peer, htlc);
|
||||
command_htlc_set_fail(peer, htlc, NOT_FOUND_404,
|
||||
"Unknown peer");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -456,7 +473,8 @@ static void route_htlc_onwards(struct peer *peer,
|
||||
": %"PRIi64" on %"PRIu64,
|
||||
htlc->id, htlc->msatoshis - msatoshis,
|
||||
msatoshis);
|
||||
command_htlc_fail(peer, htlc);
|
||||
command_htlc_set_fail(peer, htlc, PAYMENT_REQUIRED_402,
|
||||
"Insufficent fee");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -464,13 +482,13 @@ static void route_htlc_onwards(struct peer *peer,
|
||||
struct pubkey, next->id);
|
||||
|
||||
/* This checks the HTLC itself is possible. */
|
||||
if (!command_htlc_add(next, msatoshis,
|
||||
abs_locktime_to_blocks(&htlc->expiry)
|
||||
- next->nc->delay,
|
||||
&htlc->rhash, htlc, rest_of_route)) {
|
||||
command_htlc_fail(peer, htlc);
|
||||
return;
|
||||
}
|
||||
err = command_htlc_add(next, msatoshis,
|
||||
abs_locktime_to_blocks(&htlc->expiry)
|
||||
- next->nc->delay,
|
||||
&htlc->rhash, htlc, rest_of_route,
|
||||
&error_code, &newhtlc);
|
||||
if (err)
|
||||
command_htlc_set_fail(peer, htlc, error_code, err);
|
||||
}
|
||||
|
||||
static void their_htlc_added(struct peer *peer, struct htlc *htlc,
|
||||
@@ -482,7 +500,8 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
|
||||
|
||||
if (abs_locktime_is_seconds(&htlc->expiry)) {
|
||||
log_unusual(peer->log, "HTLC %"PRIu64" is in seconds", htlc->id);
|
||||
command_htlc_fail(peer, htlc);
|
||||
command_htlc_set_fail(peer, htlc, BAD_REQUEST_400,
|
||||
"bad locktime");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -491,7 +510,8 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
|
||||
log_unusual(peer->log, "HTLC %"PRIu64" expires too soon:"
|
||||
" block %u",
|
||||
htlc->id, abs_locktime_to_blocks(&htlc->expiry));
|
||||
command_htlc_fail(peer, htlc);
|
||||
command_htlc_set_fail(peer, htlc, BAD_REQUEST_400,
|
||||
"expiry too soon");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -500,7 +520,8 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
|
||||
log_unusual(peer->log, "HTLC %"PRIu64" expires too far:"
|
||||
" block %u",
|
||||
htlc->id, abs_locktime_to_blocks(&htlc->expiry));
|
||||
command_htlc_fail(peer, htlc);
|
||||
command_htlc_set_fail(peer, htlc, BAD_REQUEST_400,
|
||||
"expiry too far");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -509,7 +530,8 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
|
||||
if (!step) {
|
||||
log_unusual(peer->log, "Bad onion, failing HTLC %"PRIu64,
|
||||
htlc->id);
|
||||
command_htlc_fail(peer, htlc);
|
||||
command_htlc_set_fail(peer, htlc, BAD_REQUEST_400,
|
||||
"invalid onion");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -524,7 +546,9 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
|
||||
log_add_struct(peer->log, " rhash=%s",
|
||||
struct sha256, &htlc->rhash);
|
||||
if (unlikely(!peer->dstate->dev_never_routefail))
|
||||
command_htlc_fail(peer, htlc);
|
||||
command_htlc_set_fail(peer, htlc,
|
||||
UNAUTHORIZED_401,
|
||||
"unknown rhash");
|
||||
goto free_rest;
|
||||
}
|
||||
|
||||
@@ -534,7 +558,9 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
|
||||
htlc->id,
|
||||
htlc->msatoshis,
|
||||
payment->msatoshis);
|
||||
command_htlc_fail(peer, htlc);
|
||||
command_htlc_set_fail(peer, htlc,
|
||||
UNAUTHORIZED_401,
|
||||
"incorrect amount");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -551,7 +577,8 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
|
||||
goto free_rest;
|
||||
default:
|
||||
log_info(peer->log, "Unknown step type %u", step->next_case);
|
||||
command_htlc_fail(peer, htlc);
|
||||
command_htlc_set_fail(peer, htlc, VERSION_NOT_SUPPORTED_505,
|
||||
"unknown step type");
|
||||
goto free_rest;
|
||||
}
|
||||
|
||||
@@ -561,9 +588,12 @@ free_rest:
|
||||
|
||||
static void our_htlc_failed(struct peer *peer, struct htlc *htlc)
|
||||
{
|
||||
if (htlc->src)
|
||||
assert(htlc_owner(htlc) == LOCAL);
|
||||
if (htlc->src) {
|
||||
set_htlc_fail(htlc->src->peer, htlc->src,
|
||||
htlc->fail, tal_count(htlc->fail));
|
||||
command_htlc_fail(htlc->src->peer, htlc->src);
|
||||
else
|
||||
} else
|
||||
complete_pay_command(peer, htlc);
|
||||
}
|
||||
|
||||
@@ -709,7 +739,7 @@ static void check_both_committed(struct peer *peer, struct htlc *h)
|
||||
switch (h->state) {
|
||||
case RCVD_REMOVE_ACK_REVOCATION:
|
||||
/* If it was fulfilled, we handled it immediately. */
|
||||
if (!h->r)
|
||||
if (h->fail)
|
||||
our_htlc_failed(peer, h);
|
||||
break;
|
||||
case RCVD_ADD_ACK_REVOCATION:
|
||||
@@ -1599,7 +1629,17 @@ static const struct bitcoin_tx *htlc_fulfill_tx(const struct peer *peer,
|
||||
return tx;
|
||||
}
|
||||
|
||||
/* FIXME: Reason! */
|
||||
static bool command_htlc_set_fail(struct peer *peer, struct htlc *htlc,
|
||||
enum fail_error error_code, const char *why)
|
||||
{
|
||||
const u8 *fail = failinfo_create(htlc, peer->dstate->secpctx,
|
||||
&peer->dstate->id, error_code, why);
|
||||
|
||||
set_htlc_fail(peer, htlc, fail, tal_count(fail));
|
||||
tal_free(fail);
|
||||
return command_htlc_fail(peer, htlc);
|
||||
}
|
||||
|
||||
static bool command_htlc_fail(struct peer *peer, struct htlc *htlc)
|
||||
{
|
||||
/* If onchain, nothing we can do. */
|
||||
@@ -1670,31 +1710,35 @@ static bool command_htlc_fulfill(struct peer *peer, struct htlc *htlc)
|
||||
return true;
|
||||
}
|
||||
|
||||
struct htlc *command_htlc_add(struct peer *peer, u64 msatoshis,
|
||||
unsigned int expiry,
|
||||
const struct sha256 *rhash,
|
||||
struct htlc *src,
|
||||
const u8 *route)
|
||||
const char *command_htlc_add(struct peer *peer, u64 msatoshis,
|
||||
unsigned int expiry,
|
||||
const struct sha256 *rhash,
|
||||
struct htlc *src,
|
||||
const u8 *route,
|
||||
u32 *error_code,
|
||||
struct htlc **htlc)
|
||||
{
|
||||
struct channel_state *cstate;
|
||||
struct abs_locktime locktime;
|
||||
struct htlc *htlc;
|
||||
|
||||
if (!blocks_to_abs_locktime(expiry, &locktime)) {
|
||||
log_unusual(peer->log, "add_htlc: fail: bad expiry %u", expiry);
|
||||
return NULL;
|
||||
*error_code = BAD_REQUEST_400;
|
||||
return "bad expiry";
|
||||
}
|
||||
|
||||
if (expiry < get_block_height(peer->dstate) + peer->dstate->config.min_htlc_expiry) {
|
||||
log_unusual(peer->log, "add_htlc: fail: expiry %u is too soon",
|
||||
expiry);
|
||||
return NULL;
|
||||
*error_code = BAD_REQUEST_400;
|
||||
return "expiry too soon";
|
||||
}
|
||||
|
||||
if (expiry > get_block_height(peer->dstate) + peer->dstate->config.max_htlc_expiry) {
|
||||
log_unusual(peer->log, "add_htlc: fail: expiry %u is too far",
|
||||
expiry);
|
||||
return NULL;
|
||||
*error_code = BAD_REQUEST_400;
|
||||
return "expiry too far";
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
@@ -1704,18 +1748,20 @@ struct htlc *command_htlc_add(struct peer *peer, u64 msatoshis,
|
||||
*/
|
||||
if (peer->remote.staging_cstate->side[OURS].num_htlcs == 300) {
|
||||
log_unusual(peer->log, "add_htlc: fail: already at limit");
|
||||
return NULL;
|
||||
*error_code = SERVICE_UNAVAILABLE_503;
|
||||
return "channel full";
|
||||
}
|
||||
|
||||
if (!state_can_add_htlc(peer->state)) {
|
||||
log_unusual(peer->log, "add_htlc: fail: peer state %s",
|
||||
state_name(peer->state));
|
||||
return NULL;
|
||||
*error_code = NOT_FOUND_404;
|
||||
return "peer not available";
|
||||
}
|
||||
|
||||
htlc = peer_new_htlc(peer, peer->htlc_id_counter,
|
||||
msatoshis, rhash, expiry, route, tal_count(route),
|
||||
src, SENT_ADD_HTLC);
|
||||
*htlc = peer_new_htlc(peer, peer->htlc_id_counter,
|
||||
msatoshis, rhash, expiry, route, tal_count(route),
|
||||
src, SENT_ADD_HTLC);
|
||||
|
||||
/* FIXME: BOLT is not correct here: we should say IFF we cannot
|
||||
* afford it in remote at its own current proposed fee-rate. */
|
||||
@@ -1725,20 +1771,24 @@ struct htlc *command_htlc_add(struct peer *peer, u64 msatoshis,
|
||||
* the remote commitment transaction at the current `fee_rate`
|
||||
*/
|
||||
cstate = copy_cstate(peer, peer->remote.staging_cstate);
|
||||
if (!cstate_add_htlc(cstate, htlc)) {
|
||||
if (!cstate_add_htlc(cstate, *htlc)) {
|
||||
log_unusual(peer->log, "add_htlc: fail: Cannot afford %"PRIu64
|
||||
" milli-satoshis in their commit tx",
|
||||
msatoshis);
|
||||
return tal_free(htlc);
|
||||
*htlc = tal_free(*htlc);
|
||||
*error_code = SERVICE_UNAVAILABLE_503;
|
||||
return "cannot afford htlc";
|
||||
}
|
||||
tal_free(cstate);
|
||||
|
||||
cstate = copy_cstate(peer, peer->local.staging_cstate);
|
||||
if (!cstate_add_htlc(cstate, htlc)) {
|
||||
if (!cstate_add_htlc(cstate, *htlc)) {
|
||||
log_unusual(peer->log, "add_htlc: fail: Cannot afford %"PRIu64
|
||||
" milli-satoshis in our commit tx",
|
||||
msatoshis);
|
||||
return tal_free(htlc);
|
||||
*htlc = tal_free(*htlc);
|
||||
*error_code = SERVICE_UNAVAILABLE_503;
|
||||
return "cannot afford htlc";
|
||||
}
|
||||
tal_free(cstate);
|
||||
|
||||
@@ -1747,17 +1797,17 @@ struct htlc *command_htlc_add(struct peer *peer, u64 msatoshis,
|
||||
* The sending node MUST add the HTLC addition to the unacked
|
||||
* changeset for its remote commitment
|
||||
*/
|
||||
if (!cstate_add_htlc(peer->remote.staging_cstate, htlc))
|
||||
if (!cstate_add_htlc(peer->remote.staging_cstate, *htlc))
|
||||
fatal("Could not add HTLC?");
|
||||
|
||||
remote_changes_pending(peer);
|
||||
|
||||
queue_pkt_htlc_add(peer, htlc);
|
||||
queue_pkt_htlc_add(peer, *htlc);
|
||||
|
||||
/* Make sure we never offer the same one twice. */
|
||||
peer->htlc_id_counter++;
|
||||
|
||||
return htlc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct io_plan *pkt_out(struct io_conn *conn, struct peer *peer)
|
||||
@@ -2463,6 +2513,7 @@ struct htlc *peer_new_htlc(struct peer *peer,
|
||||
h->msatoshis = msatoshis;
|
||||
h->rhash = *rhash;
|
||||
h->r = NULL;
|
||||
h->fail = NULL;
|
||||
if (!blocks_to_abs_locktime(expiry, &h->expiry))
|
||||
fatal("Invalid HTLC expiry %u", expiry);
|
||||
h->routing = tal_dup_arr(h, u8, route, routelen, 0);
|
||||
@@ -2891,7 +2942,8 @@ static void check_htlc_expiry(struct peer *peer)
|
||||
continue;
|
||||
|
||||
/* This can fail only if we're in an error state. */
|
||||
if (!command_htlc_fail(peer, h))
|
||||
if (!command_htlc_set_fail(peer, h,
|
||||
REQUEST_TIMEOUT_408, "timed out"))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3132,6 +3184,14 @@ static const struct bitcoin_tx *irrevocably_resolved(struct peer *peer)
|
||||
return peer->onchain.tx;
|
||||
}
|
||||
|
||||
/* We usually don't fail HTLCs we offered, but if the peer breaks down
|
||||
* before we've confirmed it, this is exactly what happens. */
|
||||
static void fail_own_htlc(struct peer *peer, struct htlc *htlc)
|
||||
{
|
||||
set_htlc_fail(peer, htlc, "peer closed", strlen("peer closed"));
|
||||
our_htlc_failed(peer, htlc);
|
||||
}
|
||||
|
||||
/* We've spent an HTLC output to get our funds back. There's still a
|
||||
* chance that they could also spend the HTLC output (using the preimage),
|
||||
* so we need to wait for some confirms.
|
||||
@@ -3149,7 +3209,7 @@ static enum watch_result our_htlc_timeout_depth(struct peer *peer,
|
||||
return KEEP_WATCHING;
|
||||
if (depth + 1 < peer->dstate->config.min_htlc_expiry)
|
||||
return KEEP_WATCHING;
|
||||
our_htlc_failed(peer, htlc);
|
||||
fail_own_htlc(peer, htlc);
|
||||
return DELETE_WATCH;
|
||||
}
|
||||
|
||||
@@ -3291,7 +3351,7 @@ static enum watch_result our_unilateral_depth(struct peer *peer,
|
||||
log_debug(peer->log,
|
||||
"%s:failing uncommitted htlc %"PRIu64,
|
||||
__func__, h->id);
|
||||
our_htlc_failed(peer, h);
|
||||
fail_own_htlc(peer, h);
|
||||
}
|
||||
}
|
||||
return DELETE_WATCH;
|
||||
@@ -3728,7 +3788,7 @@ static enum watch_result anchor_spent(struct peer *peer,
|
||||
h;
|
||||
h = htlc_map_next(&peer->htlcs, &it)) {
|
||||
if (h->state == SENT_ADD_HTLC) {
|
||||
our_htlc_failed(peer, h);
|
||||
fail_own_htlc(peer, h);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4302,6 +4362,8 @@ static void json_newhtlc(struct command *cmd,
|
||||
struct sha256 rhash;
|
||||
struct json_result *response = new_json_result(cmd);
|
||||
struct htlc *htlc;
|
||||
const char *err;
|
||||
enum fail_error error_code;
|
||||
|
||||
if (!json_get_params(buffer, params,
|
||||
"peerid", &peeridtok,
|
||||
@@ -4352,10 +4414,11 @@ static void json_newhtlc(struct command *cmd,
|
||||
}
|
||||
|
||||
log_debug(peer->log, "JSON command to add new HTLC");
|
||||
htlc = command_htlc_add(peer, msatoshis, expiry, &rhash, NULL,
|
||||
dummy_single_route(cmd, peer, msatoshis));
|
||||
if (!htlc) {
|
||||
command_fail(cmd, "could not add htlc");
|
||||
err = command_htlc_add(peer, msatoshis, expiry, &rhash, NULL,
|
||||
dummy_single_route(cmd, peer, msatoshis),
|
||||
&error_code, &htlc);
|
||||
if (err) {
|
||||
command_fail(cmd, "could not add htlc: %u:%s", error_code, err);
|
||||
return;
|
||||
}
|
||||
log_debug(peer->log, "JSON new HTLC is %"PRIu64, htlc->id);
|
||||
@@ -4467,15 +4530,16 @@ static void json_failhtlc(struct command *cmd,
|
||||
const char *buffer, const jsmntok_t *params)
|
||||
{
|
||||
struct peer *peer;
|
||||
jsmntok_t *peeridtok, *idtok;
|
||||
jsmntok_t *peeridtok, *idtok, *reasontok;
|
||||
u64 id;
|
||||
struct htlc *htlc;
|
||||
|
||||
if (!json_get_params(buffer, params,
|
||||
"peerid", &peeridtok,
|
||||
"id", &idtok,
|
||||
"reason", &reasontok,
|
||||
NULL)) {
|
||||
command_fail(cmd, "Need peerid and id");
|
||||
command_fail(cmd, "Need peerid, id and reason");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4514,6 +4578,8 @@ static void json_failhtlc(struct command *cmd,
|
||||
return;
|
||||
}
|
||||
|
||||
set_htlc_fail(peer, htlc, buffer + reasontok->start,
|
||||
reasontok->end - reasontok->start);
|
||||
if (command_htlc_fail(peer, htlc))
|
||||
command_success(cmd, null_response(cmd));
|
||||
else
|
||||
@@ -4525,7 +4591,7 @@ static void json_failhtlc(struct command *cmd,
|
||||
const struct json_command failhtlc_command = {
|
||||
"failhtlc",
|
||||
json_failhtlc,
|
||||
"Fail htlc proposed by {peerid} which has {id}",
|
||||
"Fail htlc proposed by {peerid} which has {id}, using {reason}",
|
||||
"Returns an empty result on success"
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user