Browse Source

lightningd: send message on HTLC failure, relay to peer.

We don't do the encryption wrapping we're supposed to do yet.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
f3dbc75eb3
  1. 2
      lightningd/Makefile
  2. 51
      lightningd/channel/channel.c
  3. 66
      lightningd/peer_control.c
  4. 1
      lightningd/test/test-basic

2
lightningd/Makefile

@ -126,7 +126,7 @@ check-makefile: check-lightningd-makefile
check-lightningd-makefile:
@for f in lightningd/*.h lightningd/*/*.h; do if ! echo $(LIGHTNINGD_HEADERS_NOGEN) $(LIGHTNINGD_HEADERS_GEN) "" | grep -q "$$f "; then echo $$f not mentioned in LIGHTNINGD_HEADERS_NOGEN or LIGHTNINGD_HEADERS_GEN >&2; exit 1; fi; done
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_OLD_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(CCAN_OBJS) $(CCAN_SHACHAIN48_OBJ) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIBBASE58_OBJS) $(LIGHTNINGD_OPENING_CONTROL_OBJS) $(LIGHTNINGD_CHANNEL_CONTROL_OBJS) libsecp256k1.a libsodium.a libwallycore.a
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_OLD_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(WIRE_ONION_OBJS) $(CCAN_OBJS) $(CCAN_SHACHAIN48_OBJ) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIBBASE58_OBJS) $(LIGHTNINGD_OPENING_CONTROL_OBJS) $(LIGHTNINGD_CHANNEL_CONTROL_OBJS) libsecp256k1.a libsodium.a libwallycore.a
clean: lightningd-clean

51
lightningd/channel/channel.c

@ -722,6 +722,44 @@ static void handle_peer_fulfill_htlc(struct peer *peer, const u8 *msg)
abort();
}
static void handle_peer_fail_htlc(struct peer *peer, const u8 *msg)
{
struct channel_id channel_id;
u64 id;
enum channel_remove_err e;
u8 *reason;
if (!fromwire_update_fail_htlc(msg, msg, NULL,
&channel_id, &id, &reason)) {
peer_failed(io_conn_fd(peer->peer_conn),
&peer->pcs.cs,
&peer->channel_id,
WIRE_CHANNEL_PEER_BAD_MESSAGE,
"Bad update_fulfill_htlc %s", tal_hex(msg, msg));
}
e = channel_fail_htlc(peer->channel, LOCAL, id);
switch (e) {
case CHANNEL_ERR_REMOVE_OK:
msg = towire_channel_failed_htlc(msg, id, reason);
daemon_conn_send(&peer->master, take(msg));
start_commit_timer(peer);
return;
case CHANNEL_ERR_NO_SUCH_ID:
case CHANNEL_ERR_ALREADY_FULFILLED:
case CHANNEL_ERR_HTLC_UNCOMMITTED:
case CHANNEL_ERR_HTLC_NOT_IRREVOCABLE:
case CHANNEL_ERR_BAD_PREIMAGE:
peer_failed(io_conn_fd(peer->peer_conn),
&peer->pcs.cs,
&peer->channel_id,
WIRE_CHANNEL_PEER_BAD_MESSAGE,
"Bad update_fail_htlc: failed to remove %"
PRIu64 " error %u", id, e);
}
abort();
}
static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg)
{
enum wire_type type = fromwire_peektype(msg);
@ -767,6 +805,9 @@ static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg)
case WIRE_UPDATE_FULFILL_HTLC:
handle_peer_fulfill_htlc(peer, msg);
goto done;
case WIRE_UPDATE_FAIL_HTLC:
handle_peer_fail_htlc(peer, msg);
goto done;
case WIRE_INIT:
case WIRE_ERROR:
case WIRE_OPEN_CHANNEL:
@ -777,7 +818,6 @@ static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg)
case WIRE_SHUTDOWN:
case WIRE_CLOSING_SIGNED:
case WIRE_UPDATE_FAIL_HTLC:
case WIRE_UPDATE_FAIL_MALFORMED_HTLC:
case WIRE_UPDATE_FEE:
peer_failed(io_conn_fd(peer->peer_conn),
@ -1011,12 +1051,14 @@ static void handle_fail(struct peer *peer, const u8 *inmsg)
u8 *msg;
u64 id;
u8 *errpkt;
enum channel_remove_err e;
if (!fromwire_channel_fail_htlc(inmsg, inmsg, NULL, &id, &errpkt))
status_failed(WIRE_CHANNEL_BAD_COMMAND,
"Invalid channel_fail_htlc");
switch (channel_fail_htlc(peer->channel, REMOTE, id)) {
e = channel_fail_htlc(peer->channel, REMOTE, id);
switch (e) {
case CHANNEL_ERR_REMOVE_OK:
msg = towire_update_fail_htlc(peer, &peer->channel_id,
id, errpkt);
@ -1032,7 +1074,7 @@ static void handle_fail(struct peer *peer, const u8 *inmsg)
case CHANNEL_ERR_HTLC_NOT_IRREVOCABLE:
case CHANNEL_ERR_BAD_PREIMAGE:
status_failed(WIRE_CHANNEL_BAD_COMMAND,
"HTLC %"PRIu64" preimage failed", id);
"HTLC %"PRIu64" removal failed: %i", id, e);
}
abort();
}
@ -1080,7 +1122,8 @@ static struct io_plan *req_in(struct io_conn *conn, struct daemon_conn *master)
case WIRE_CHANNEL_PEER_BAD_MESSAGE:
break;
}
status_failed(WIRE_CHANNEL_BAD_COMMAND, "%s", strerror(errno));
status_failed(WIRE_CHANNEL_BAD_COMMAND, "%u %s", t,
channel_wire_type_name(t));
}
out:

66
lightningd/peer_control.c

@ -635,11 +635,24 @@ struct decoding_htlc {
u8 shared_secret[32];
};
static void fail_htlc(struct peer *peer, u64 htlc_id, enum onion_type failcode)
static void fail_htlc(struct peer *peer, u64 htlc_id, const u8 *msg)
{
log_broken(peer->log, "failed htlc %"PRIu64" code 0x%04x",
htlc_id, failcode);
/* FIXME: implement */
enum onion_type failcode = fromwire_peektype(msg);
log_broken(peer->log, "failed htlc %"PRIu64" code 0x%04x (%s)",
htlc_id, failcode, onion_type_name(failcode));
/* We don't do BADONION here */
assert(!(failcode & BADONION));
if (failcode & UPDATE) {
/* FIXME: Ask gossip daemon for channel_update. */
}
/* FIXME: encrypt msg! */
subd_send_msg(peer->owner,
take(towire_channel_fail_htlc(peer, htlc_id, msg)));
if (taken(msg))
tal_free(msg);
}
static void handle_localpay(struct htlc_end *hend,
@ -651,7 +664,8 @@ static void handle_localpay(struct htlc_end *hend,
payment_hash);
if (!invoice) {
fail_htlc(hend->peer, hend->htlc_id, WIRE_UNKNOWN_PAYMENT_HASH);
fail_htlc(hend->peer, hend->htlc_id,
take(towire_unknown_payment_hash(hend)));
tal_free(hend);
return;
}
@ -666,11 +680,11 @@ static void handle_localpay(struct htlc_end *hend,
*/
if (hend->msatoshis < invoice->msatoshi) {
fail_htlc(hend->peer, hend->htlc_id,
WIRE_INCORRECT_PAYMENT_AMOUNT);
take(towire_incorrect_payment_amount(hend)));
return;
} else if (hend->msatoshis > invoice->msatoshi * 2) {
fail_htlc(hend->peer, hend->htlc_id,
WIRE_INCORRECT_PAYMENT_AMOUNT);
take(towire_incorrect_payment_amount(hend)));
return;
}
@ -685,7 +699,8 @@ static void handle_localpay(struct htlc_end *hend,
cltv_expiry,
get_block_height(hend->peer->ld->topology),
hend->peer->ld->dstate.config.deadline_blocks);
fail_htlc(hend->peer, hend->htlc_id, WIRE_FINAL_EXPIRY_TOO_SOON);
fail_htlc(hend->peer, hend->htlc_id,
take(towire_final_expiry_too_soon(hend)));
tal_free(hend);
return;
}
@ -773,6 +788,40 @@ static int peer_fulfilled_htlc(struct peer *peer, const u8 *msg)
return 0;
}
static int peer_failed_htlc(struct peer *peer, const u8 *msg)
{
u64 id;
u8 *reason;
struct htlc_end *hend;
enum onion_type failcode;
if (!fromwire_channel_failed_htlc(msg, msg, NULL, &id, &reason)) {
log_broken(peer->log, "bad fromwire_channel_failed_htlc %s",
tal_hex(peer, msg));
return -1;
}
hend = find_htlc_end(&peer->ld->htlc_ends, peer, id, HTLC_DST);
if (!hend) {
log_broken(peer->log,
"channel_failed_htlc unknown htlc %"PRIu64,
id);
return -1;
}
/* FIXME: Decrypt reason. */
failcode = fromwire_peektype(reason);
log_info(peer->log, "htlc %"PRIu64" failed with code 0x%04x (%s)",
id, failcode, onion_type_name(failcode));
/* FIXME: Forward! */
assert(!hend->other_end);
tal_free(hend);
return 0;
}
static int channel_msg(struct subd *sd, const u8 *msg, const int *unused)
{
enum channel_wire_type t = fromwire_peektype(msg);
@ -789,6 +838,7 @@ static int channel_msg(struct subd *sd, const u8 *msg, const int *unused)
case WIRE_CHANNEL_FULFILLED_HTLC:
return peer_fulfilled_htlc(sd->peer, msg);
case WIRE_CHANNEL_FAILED_HTLC:
return peer_failed_htlc(sd->peer, msg);
case WIRE_CHANNEL_MALFORMED_HTLC:
/* FIXME: Forward. */
abort();

1
lightningd/test/test-basic

@ -63,6 +63,7 @@ check "lcli1 getlog debug | $FGREP 'Sending commit_sig with 0 htlc sigs'"
check "lcli2 getlog debug | $FGREP 'their htlc 0 locked'"
check "lcli2 getpeers info | $FGREP 'failed htlc 0 code 0x400f'"
check "lcli1 getpeers info | $FGREP 'htlc 0 failed with code 0x400f'"
# This one isn't dust.
RHASH=`lcli2 invoice 100000000 testpayment1 | get_field rhash`

Loading…
Cancel
Save