channeld: generate error messages instead of having master do it.

The master now hands channeld either an error code, and channeld
generates the error message, or an error message relayed from another
node to pass through.

This doesn't fill in the channel_update yet: we need to wire up gossipd
to give us that.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-11-28 15:34:20 +10:30 committed by Christian Decker
parent ee8274b7a1
commit 2bed246e10
4 changed files with 154 additions and 105 deletions

View File

@ -1985,20 +1985,118 @@ static void handle_preimage(struct peer *peer, const u8 *inmsg)
abort();
}
static u8 *foreign_channel_update(const tal_t *ctx,
struct peer *peer,
const struct short_channel_id *scid)
{
/* FIXME! */
return NULL;
}
static u8 *make_failmsg(const tal_t *ctx,
struct peer *peer,
const struct htlc *htlc,
enum onion_type failcode,
const struct short_channel_id *scid)
{
u8 *msg, *channel_update = NULL;
u32 cltv_expiry = abs_locktime_to_blocks(&htlc->expiry);
switch (failcode) {
case WIRE_INVALID_REALM:
msg = towire_invalid_realm(ctx);
goto done;
case WIRE_TEMPORARY_NODE_FAILURE:
msg = towire_temporary_node_failure(ctx);
goto done;
case WIRE_PERMANENT_NODE_FAILURE:
msg = towire_permanent_node_failure(ctx);
goto done;
case WIRE_REQUIRED_NODE_FEATURE_MISSING:
msg = towire_required_node_feature_missing(ctx);
goto done;
case WIRE_TEMPORARY_CHANNEL_FAILURE:
channel_update = foreign_channel_update(ctx, peer, scid);
msg = towire_temporary_channel_failure(ctx, channel_update);
goto done;
case WIRE_CHANNEL_DISABLED:
msg = towire_channel_disabled(ctx);
goto done;
case WIRE_PERMANENT_CHANNEL_FAILURE:
msg = towire_permanent_channel_failure(ctx);
goto done;
case WIRE_REQUIRED_CHANNEL_FEATURE_MISSING:
msg = towire_required_channel_feature_missing(ctx);
goto done;
case WIRE_UNKNOWN_NEXT_PEER:
msg = towire_unknown_next_peer(ctx);
goto done;
case WIRE_AMOUNT_BELOW_MINIMUM:
channel_update = foreign_channel_update(ctx, peer, scid);
msg = towire_amount_below_minimum(ctx, htlc->msatoshi,
channel_update);
goto done;
case WIRE_FEE_INSUFFICIENT:
channel_update = foreign_channel_update(ctx, peer, scid);
msg = towire_fee_insufficient(ctx, htlc->msatoshi,
channel_update);
goto done;
case WIRE_INCORRECT_CLTV_EXPIRY:
channel_update = foreign_channel_update(ctx, peer, scid);
msg = towire_incorrect_cltv_expiry(ctx, cltv_expiry,
channel_update);
goto done;
case WIRE_EXPIRY_TOO_SOON:
channel_update = foreign_channel_update(ctx, peer, scid);
msg = towire_expiry_too_soon(ctx, channel_update);
goto done;
case WIRE_EXPIRY_TOO_FAR:
msg = towire_expiry_too_far(ctx);
goto done;
case WIRE_UNKNOWN_PAYMENT_HASH:
msg = towire_unknown_payment_hash(ctx);
goto done;
case WIRE_INCORRECT_PAYMENT_AMOUNT:
msg = towire_incorrect_payment_amount(ctx);
goto done;
case WIRE_FINAL_EXPIRY_TOO_SOON:
msg = towire_final_expiry_too_soon(ctx);
goto done;
case WIRE_FINAL_INCORRECT_CLTV_EXPIRY:
msg = towire_final_incorrect_cltv_expiry(ctx, cltv_expiry);
goto done;
case WIRE_FINAL_INCORRECT_HTLC_AMOUNT:
msg = towire_final_incorrect_htlc_amount(ctx, htlc->msatoshi);
goto done;
case WIRE_INVALID_ONION_VERSION:
case WIRE_INVALID_ONION_HMAC:
case WIRE_INVALID_ONION_KEY:
break;
}
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Asked to create failmsg %u (%s)",
failcode, onion_type_name(failcode));
done:
tal_free(channel_update);
return msg;
}
static void handle_fail(struct peer *peer, const u8 *inmsg)
{
u8 *msg;
u64 id;
u8 *errpkt;
u16 failcode;
struct short_channel_id scid;
enum channel_remove_err e;
struct htlc *h;
if (!fromwire_channel_fail_htlc(inmsg, inmsg, NULL, &id, &errpkt,
&failcode))
&failcode, &scid))
master_badmsg(WIRE_CHANNEL_FAIL_HTLC, inmsg);
if ((failcode & BADONION) && tal_len(errpkt))
if (failcode && tal_len(errpkt))
status_failed(STATUS_FAIL_MASTER_IO,
"Invalid channel_fail_htlc: %s with errpkt?",
onion_type_name(failcode));
@ -2017,8 +2115,13 @@ static void handle_fail(struct peer *peer, const u8 *inmsg)
id, &sha256_of_onion,
failcode);
} else {
u8 *reply = wrap_onionreply(inmsg, h->shared_secret,
errpkt);
u8 *reply;
if (failcode)
errpkt = make_failmsg(inmsg, peer, h,
failcode, &scid);
reply = wrap_onionreply(inmsg, h->shared_secret,
errpkt);
msg = towire_update_fail_htlc(peer, &peer->channel_id,
id, reply);
}

View File

@ -97,6 +97,8 @@ channel_fail_htlc,,len,u16
channel_fail_htlc,,error_pkt,len*u8
# If it errcode is != 0, it's a local error, otherwise we're passing thru.
channel_fail_htlc,,errcode,u16
# If errcode & UPDATE, this says which outgoing channel failed.
channel_fail_htlc,,which_channel,struct short_channel_id
# Ping/pong test.
channel_ping,1011

1 # Received and sent funding_locked
97 channel_ping_reply,,totlen,u16 channel_ping,,len,u16
98 # Channeld tells the master to announce the channel (with first update) channel_ping_reply,1111
99 channel_announce,1012 channel_ping_reply,,totlen,u16
100 # Channeld tells the master to announce the channel (with first update)
101 channel_announce,1012
102 channel_announce,,announce_len,u16
103 channel_announce,,announce,announce_len*u8
104 channel_announce,,update_len,u16

View File

@ -35,11 +35,15 @@ struct htlc_in {
/* If a local error, this is non-zero. */
enum onion_type failcode;
/* Either a remote error, or local error if !(failure & BADONION). */
/* For a remote error. */
const u8 *failuremsg;
/* If failcode & UPDATE, this is the channel which failed. */
struct short_channel_id failoutchannel;
/* If they fulfilled, here's the preimage. */
struct preimage *preimage;
};
struct htlc_out {
@ -61,7 +65,7 @@ struct htlc_out {
/* If a local error, this is non-zero. */
enum onion_type failcode;
/* Either a remote error, or local error if !(failure & BADONION). */
/* For a remote error. */
const u8 *failuremsg;
/* If we fulfilled, here's the preimage. */

View File

@ -79,7 +79,8 @@ static bool htlc_out_update_state(struct peer *peer,
static void fail_in_htlc(struct htlc_in *hin,
enum onion_type failcode,
const u8 *failuremsg)
const u8 *failuremsg,
const struct short_channel_id *out_channelid)
{
assert(!hin->preimage);
@ -88,6 +89,12 @@ static void fail_in_htlc(struct htlc_in *hin,
if (failuremsg)
hin->failuremsg = tal_dup_arr(hin, u8, failuremsg, tal_len(failuremsg), 0);
/* We need this set, since we send it to channeld. */
if (hin->failcode & UPDATE)
hin->failoutchannel = *out_channelid;
else
memset(&hin->failoutchannel, 0, sizeof(hin->failoutchannel));
/* We update state now to signal it's in progress, for persistence. */
htlc_in_update_state(hin->key.peer, hin, SENT_REMOVE_HTLC);
@ -95,93 +102,22 @@ static void fail_in_htlc(struct htlc_in *hin,
if (!hin->key.peer->owner)
return;
if (!hin->failuremsg) {
subd_send_msg(hin->key.peer->owner,
take(towire_channel_fail_htlc(hin,
hin->key.id,
NULL,
hin->failcode)));
} else {
subd_send_msg(hin->key.peer->owner,
take(towire_channel_fail_htlc(hin, hin->key.id,
hin->failuremsg,
0)));
}
}
static u8 *make_failmsg(const tal_t *ctx,
struct log *log,
u64 msatoshi,
enum onion_type failcode,
const u8 *channel_update)
{
switch (failcode) {
case WIRE_INVALID_REALM:
return towire_invalid_realm(ctx);
case WIRE_TEMPORARY_NODE_FAILURE:
return towire_temporary_node_failure(ctx);
case WIRE_PERMANENT_NODE_FAILURE:
return towire_permanent_node_failure(ctx);
case WIRE_REQUIRED_NODE_FEATURE_MISSING:
return towire_required_node_feature_missing(ctx);
case WIRE_TEMPORARY_CHANNEL_FAILURE:
return towire_temporary_channel_failure(ctx, channel_update);
case WIRE_CHANNEL_DISABLED:
return towire_channel_disabled(ctx);
case WIRE_PERMANENT_CHANNEL_FAILURE:
return towire_permanent_channel_failure(ctx);
case WIRE_REQUIRED_CHANNEL_FEATURE_MISSING:
return towire_required_channel_feature_missing(ctx);
case WIRE_UNKNOWN_NEXT_PEER:
return towire_unknown_next_peer(ctx);
case WIRE_AMOUNT_BELOW_MINIMUM:
return towire_amount_below_minimum(ctx, msatoshi, channel_update);
case WIRE_FEE_INSUFFICIENT:
return towire_fee_insufficient(ctx, msatoshi, channel_update);
case WIRE_INCORRECT_CLTV_EXPIRY:
/* FIXME: cltv! */
return towire_incorrect_cltv_expiry(ctx, 0, channel_update);
case WIRE_EXPIRY_TOO_SOON:
return towire_expiry_too_soon(ctx, channel_update);
case WIRE_EXPIRY_TOO_FAR:
return towire_expiry_too_far(ctx);
case WIRE_UNKNOWN_PAYMENT_HASH:
return towire_unknown_payment_hash(ctx);
case WIRE_INCORRECT_PAYMENT_AMOUNT:
return towire_incorrect_payment_amount(ctx);
case WIRE_FINAL_EXPIRY_TOO_SOON:
return towire_final_expiry_too_soon(ctx);
case WIRE_FINAL_INCORRECT_CLTV_EXPIRY:
/* FIXME: cltv! */
return towire_final_incorrect_cltv_expiry(ctx, 0);
case WIRE_FINAL_INCORRECT_HTLC_AMOUNT:
return towire_final_incorrect_htlc_amount(ctx, msatoshi);
case WIRE_INVALID_ONION_VERSION:
case WIRE_INVALID_ONION_HMAC:
case WIRE_INVALID_ONION_KEY:
/* We don't have anything to add for these; code is enough */
return NULL;
}
log_broken(log, "Asked to create unknown failmsg %u:"
" using temp node failure instead", failcode);
return towire_temporary_node_failure(ctx);
subd_send_msg(hin->key.peer->owner,
take(towire_channel_fail_htlc(hin,
hin->key.id,
hin->failuremsg,
hin->failcode,
&hin->failoutchannel)));
}
/* This is used for cases where we can immediately fail the HTLC. */
static void local_fail_htlc(struct htlc_in *hin, enum onion_type failcode)
static void local_fail_htlc(struct htlc_in *hin, enum onion_type failcode,
const struct short_channel_id *out_channel)
{
u8 *msg;
log_info(hin->key.peer->log, "failed htlc %"PRIu64" code 0x%04x (%s)",
hin->key.id, failcode, onion_type_name(failcode));
/* FIXME: Get update! */
msg = make_failmsg(hin, hin->key.peer->log,
hin->msatoshi, failcode, NULL);
fail_in_htlc(hin, failcode, msg);
tal_free(msg);
fail_in_htlc(hin, failcode, NULL, out_channel);
}
/* localfail are for handing to the local payer if it's local. */
@ -190,7 +126,8 @@ static void fail_out_htlc(struct htlc_out *hout, const char *localfail)
htlc_out_check(hout, __func__);
assert(hout->failcode || hout->failuremsg);
if (hout->in) {
fail_in_htlc(hout->in, hout->failcode, hout->failuremsg);
fail_in_htlc(hout->in, hout->failcode, hout->failuremsg,
hout->key.peer->scid);
} else {
payment_failed(hout->key.peer->ld, hout, localfail);
}
@ -364,7 +301,9 @@ static void handle_localpay(struct htlc_in *hin,
return;
fail:
local_fail_htlc(hin, failcode);
/* Final hop never sends an UPDATE. */
assert(!(failcode & UPDATE));
local_fail_htlc(hin, failcode, NULL);
}
/*
@ -378,10 +317,7 @@ static void hout_subd_died(struct htlc_out *hout)
"Failing HTLC %"PRIu64" due to peer death",
hout->key.id);
hout->failuremsg = make_failmsg(hout, hout->key.peer->log,
hout->msatoshi,
WIRE_TEMPORARY_CHANNEL_FAILURE,
NULL);
hout->failcode = WIRE_TEMPORARY_CHANNEL_FAILURE;
fail_out_htlc(hout, "Outgoing subdaemon died");
}
@ -410,7 +346,8 @@ static void rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds,
(const char *)failurestr);
payment_failed(hout->key.peer->ld, hout, localfail);
} else
local_fail_htlc(hout->in, failure_code);
local_fail_htlc(hout->in, failure_code,
hout->key.peer->scid);
return;
}
@ -480,9 +417,10 @@ static void forward_htlc(struct htlc_in *hin,
struct lightningd *ld = hin->key.peer->ld;
struct peer *next = peer_by_id(ld, next_hop);
if (!next) {
failcode = WIRE_UNKNOWN_NEXT_PEER;
goto fail;
/* Unknown peer, or peer not ready. */
if (!next || !next->scid) {
local_fail_htlc(hin, WIRE_UNKNOWN_NEXT_PEER, NULL);
return;
}
/* BOLT #7:
@ -551,7 +489,7 @@ static void forward_htlc(struct htlc_in *hin,
return;
fail:
local_fail_htlc(hin, failcode);
local_fail_htlc(hin, failcode, next->scid);
}
/* Temporary information, while we resolve the next hop */
@ -578,7 +516,7 @@ static void channel_resolve_reply(struct subd *gossip, const u8 *msg,
}
if (tal_count(nodes) == 0) {
local_fail_htlc(gr->hin, WIRE_UNKNOWN_NEXT_PEER);
local_fail_htlc(gr->hin, WIRE_UNKNOWN_NEXT_PEER, NULL);
return;
} else if (tal_count(nodes) != 2) {
log_broken(gossip->log,
@ -826,12 +764,10 @@ void onchain_failed_our_htlc(const struct peer *peer,
struct htlc_out *hout = find_htlc_out_by_ripemd(peer, &htlc->ripemd);
/* Don't fail twice! */
if (hout->failuremsg)
if (hout->failuremsg || hout->failcode)
return;
hout->failuremsg = make_failmsg(hout, peer->log, hout->msatoshi,
WIRE_PERMANENT_CHANNEL_FAILURE,
NULL);
hout->failcode = WIRE_PERMANENT_CHANNEL_FAILURE;
if (!hout->in) {
char *localfail = tal_fmt(peer, "%s: %s",
@ -840,7 +776,8 @@ void onchain_failed_our_htlc(const struct peer *peer,
payment_failed(hout->key.peer->ld, hout, localfail);
tal_free(localfail);
} else
local_fail_htlc(hout->in, WIRE_PERMANENT_CHANNEL_FAILURE);
local_fail_htlc(hout->in, WIRE_PERMANENT_CHANNEL_FAILURE,
hout->key.peer->scid);
}
static void remove_htlc_in(struct peer *peer, struct htlc_in *hin)
@ -1294,8 +1231,11 @@ void peer_got_revoke(struct peer *peer, const u8 *msg)
if (!failcodes[i])
continue;
/* These are all errors before finding next hop. */
assert(!(failcodes[i] & UPDATE));
hin = find_htlc_in(&peer->ld->htlcs_in, peer, changed[i].id);
local_fail_htlc(hin, failcodes[i]);
local_fail_htlc(hin, failcodes[i], NULL);
}
wallet_channel_save(peer->ld->wallet, peer->channel);
}