mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-21 16:14:23 +01:00
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>
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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`
|
||||
|
||||
Reference in New Issue
Block a user