mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
lightningd/channel: inter-daemon messages for HTLC handling.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
9b6753173c
commit
7919279367
@ -7,6 +7,7 @@
|
|||||||
#include <ccan/io/io.h>
|
#include <ccan/io/io.h>
|
||||||
#include <ccan/structeq/structeq.h>
|
#include <ccan/structeq/structeq.h>
|
||||||
#include <ccan/take/take.h>
|
#include <ccan/take/take.h>
|
||||||
|
#include <ccan/tal/str/str.h>
|
||||||
#include <ccan/time/time.h>
|
#include <ccan/time/time.h>
|
||||||
#include <daemon/routing.h>
|
#include <daemon/routing.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -28,6 +29,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <type_to_string.h>
|
#include <type_to_string.h>
|
||||||
#include <version.h>
|
#include <version.h>
|
||||||
|
#include <wire/gen_onion_wire.h>
|
||||||
#include <wire/gen_peer_wire.h>
|
#include <wire/gen_peer_wire.h>
|
||||||
#include <wire/wire.h>
|
#include <wire/wire.h>
|
||||||
#include <wire/wire_io.h>
|
#include <wire/wire_io.h>
|
||||||
@ -53,6 +55,13 @@ struct peer {
|
|||||||
/* Our shaseed for generating per-commitment-secrets. */
|
/* Our shaseed for generating per-commitment-secrets. */
|
||||||
struct sha256 shaseed;
|
struct sha256 shaseed;
|
||||||
|
|
||||||
|
/* BOLT #2:
|
||||||
|
*
|
||||||
|
* A sending node MUST set `id` to 0 for the first HTLC it offers, and
|
||||||
|
* increase the value by 1 for each successive offer.
|
||||||
|
*/
|
||||||
|
u64 htlc_id;
|
||||||
|
|
||||||
struct channel_id channel_id;
|
struct channel_id channel_id;
|
||||||
struct channel *channel;
|
struct channel *channel;
|
||||||
|
|
||||||
@ -274,32 +283,219 @@ static void init_channel(struct peer *peer, const u8 *msg)
|
|||||||
peer_conn_broken, peer);
|
peer_conn_broken, peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_funding_locked(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
if (!fromwire_channel_funding_locked(msg, NULL,
|
||||||
|
&peer->short_channel_ids[LOCAL]))
|
||||||
|
status_failed(WIRE_CHANNEL_BAD_COMMAND, "%s", tal_hex(msg, msg));
|
||||||
|
|
||||||
|
msg = towire_funding_locked(peer,
|
||||||
|
&peer->channel_id,
|
||||||
|
&peer->next_per_commit[LOCAL]);
|
||||||
|
msg_enqueue(&peer->peer_out, take(msg));
|
||||||
|
peer->funding_locked[LOCAL] = true;
|
||||||
|
|
||||||
|
if (peer->funding_locked[REMOTE]) {
|
||||||
|
send_channel_announcement(peer);
|
||||||
|
send_channel_update(peer, false);
|
||||||
|
daemon_conn_send(&peer->master,
|
||||||
|
take(towire_channel_normal_operation(peer)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_funding_announce_depth(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
status_trace("Exchanging announcement signatures.");
|
||||||
|
send_announcement_signatures(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_commit_timer(struct peer *peer)
|
||||||
|
{
|
||||||
|
/* FIXME! */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
|
||||||
|
{
|
||||||
|
u8 *msg;
|
||||||
|
u32 amount_msat, cltv_expiry;
|
||||||
|
struct sha256 payment_hash;
|
||||||
|
u8 onion_routing_packet[1254];
|
||||||
|
enum onion_type failcode;
|
||||||
|
/* Subtle: must be tal_arr since we marshal using tal_len() */
|
||||||
|
const char *failmsg;
|
||||||
|
|
||||||
|
if (!peer->funding_locked[LOCAL] || !peer->funding_locked[REMOTE])
|
||||||
|
status_failed(WIRE_CHANNEL_BAD_COMMAND, "funding not locked");
|
||||||
|
|
||||||
|
if (!fromwire_channel_offer_htlc(inmsg, NULL, &amount_msat,
|
||||||
|
&cltv_expiry, &payment_hash,
|
||||||
|
onion_routing_packet))
|
||||||
|
status_failed(WIRE_CHANNEL_BAD_COMMAND,
|
||||||
|
"bad offer_htlc message %s",
|
||||||
|
tal_hex(inmsg, inmsg));
|
||||||
|
|
||||||
|
switch (channel_add_htlc(peer->channel, LOCAL, peer->htlc_id,
|
||||||
|
amount_msat, cltv_expiry, &payment_hash,
|
||||||
|
onion_routing_packet)) {
|
||||||
|
case CHANNEL_ERR_ADD_OK:
|
||||||
|
/* Tell the peer. */
|
||||||
|
msg = towire_update_add_htlc(peer, &peer->channel_id,
|
||||||
|
peer->htlc_id, amount_msat,
|
||||||
|
cltv_expiry, &payment_hash,
|
||||||
|
onion_routing_packet);
|
||||||
|
msg_enqueue(&peer->peer_out, take(msg));
|
||||||
|
peer->funding_locked[LOCAL] = true;
|
||||||
|
start_commit_timer(peer);
|
||||||
|
/* Tell the master. */
|
||||||
|
msg = towire_channel_offer_htlc_reply(inmsg, peer->htlc_id,
|
||||||
|
0, NULL);
|
||||||
|
daemon_conn_send(&peer->master, take(msg));
|
||||||
|
peer->htlc_id++;
|
||||||
|
return;
|
||||||
|
case CHANNEL_ERR_INVALID_EXPIRY:
|
||||||
|
failcode = WIRE_INCORRECT_CLTV_EXPIRY;
|
||||||
|
failmsg = tal_fmt(inmsg, "Invalid cltv_expiry %u", cltv_expiry);
|
||||||
|
goto failed;
|
||||||
|
case CHANNEL_ERR_DUPLICATE:
|
||||||
|
case CHANNEL_ERR_DUPLICATE_ID_DIFFERENT:
|
||||||
|
status_failed(WIRE_CHANNEL_BAD_COMMAND,
|
||||||
|
"Duplicate HTLC %"PRIu64, peer->htlc_id);
|
||||||
|
|
||||||
|
/* FIXME: Fuzz the boundaries a bit to avoid probing? */
|
||||||
|
case CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED:
|
||||||
|
/* FIXME: We should advertise this? */
|
||||||
|
failcode = WIRE_TEMPORARY_CHANNEL_FAILURE;
|
||||||
|
failmsg = tal_fmt(inmsg, "Maximum value exceeded");
|
||||||
|
goto failed;
|
||||||
|
case CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED:
|
||||||
|
failcode = WIRE_TEMPORARY_CHANNEL_FAILURE;
|
||||||
|
failmsg = tal_fmt(inmsg, "Capacity exceeded");
|
||||||
|
goto failed;
|
||||||
|
case CHANNEL_ERR_HTLC_BELOW_MINIMUM:
|
||||||
|
failcode = WIRE_AMOUNT_BELOW_MINIMUM;
|
||||||
|
failmsg = tal_fmt(inmsg, "HTLC too small (%u minimum)",
|
||||||
|
htlc_minimum_msat(peer->channel, REMOTE));
|
||||||
|
goto failed;
|
||||||
|
case CHANNEL_ERR_TOO_MANY_HTLCS:
|
||||||
|
failcode = WIRE_TEMPORARY_CHANNEL_FAILURE;
|
||||||
|
failmsg = tal_fmt(inmsg, "Too many HTLCs");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
/* Shouldn't return anything else! */
|
||||||
|
abort();
|
||||||
|
|
||||||
|
failed:
|
||||||
|
msg = towire_channel_offer_htlc_reply(inmsg, 0, failcode, (u8*)failmsg);
|
||||||
|
daemon_conn_send(&peer->master, take(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_preimage(struct peer *peer, const u8 *inmsg)
|
||||||
|
{
|
||||||
|
u8 *msg;
|
||||||
|
u64 id;
|
||||||
|
struct preimage preimage;
|
||||||
|
|
||||||
|
if (!fromwire_channel_fulfill_htlc(inmsg, NULL, &id, &preimage))
|
||||||
|
status_failed(WIRE_CHANNEL_BAD_COMMAND,
|
||||||
|
"Invalid channel_fulfill_htlc");
|
||||||
|
|
||||||
|
switch (channel_fulfill_htlc(peer->channel, REMOTE, id, &preimage)) {
|
||||||
|
case CHANNEL_ERR_REMOVE_OK:
|
||||||
|
msg = towire_update_fulfill_htlc(peer, &peer->channel_id,
|
||||||
|
id, &preimage);
|
||||||
|
msg_enqueue(&peer->peer_out, take(msg));
|
||||||
|
start_commit_timer(peer);
|
||||||
|
return;
|
||||||
|
/* These shouldn't happen, because any offered HTLC (which would give
|
||||||
|
* us the preimage) should have timed out long before. If we
|
||||||
|
* were to get preimages from other sources, this could happen. */
|
||||||
|
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:
|
||||||
|
status_failed(WIRE_CHANNEL_BAD_COMMAND,
|
||||||
|
"HTLC %"PRIu64" preimage failed", id);
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_fail(struct peer *peer, const u8 *inmsg)
|
||||||
|
{
|
||||||
|
u8 *msg;
|
||||||
|
u64 id;
|
||||||
|
u8 *errpkt;
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
case CHANNEL_ERR_REMOVE_OK:
|
||||||
|
msg = towire_update_fail_htlc(peer, &peer->channel_id,
|
||||||
|
id, errpkt);
|
||||||
|
msg_enqueue(&peer->peer_out, take(msg));
|
||||||
|
start_commit_timer(peer);
|
||||||
|
return;
|
||||||
|
/* These shouldn't happen, because any offered HTLC (which would give
|
||||||
|
* us the preimage) should have timed out long before. If we
|
||||||
|
* were to get preimages from other sources, this could happen. */
|
||||||
|
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:
|
||||||
|
status_failed(WIRE_CHANNEL_BAD_COMMAND,
|
||||||
|
"HTLC %"PRIu64" preimage failed", id);
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
static struct io_plan *req_in(struct io_conn *conn, struct daemon_conn *master)
|
static struct io_plan *req_in(struct io_conn *conn, struct daemon_conn *master)
|
||||||
{
|
{
|
||||||
struct peer *peer = container_of(master, struct peer, master);
|
struct peer *peer = container_of(master, struct peer, master);
|
||||||
|
|
||||||
if (!peer->channel)
|
if (!peer->channel)
|
||||||
init_channel(peer, master->msg_in);
|
init_channel(peer, master->msg_in);
|
||||||
else if (fromwire_channel_funding_locked(master->msg_in, NULL,
|
else {
|
||||||
&peer->short_channel_ids[LOCAL])) {
|
enum channel_wire_type t = fromwire_peektype(master->msg_in);
|
||||||
u8 *msg = towire_funding_locked(peer,
|
|
||||||
&peer->channel_id,
|
|
||||||
&peer->next_per_commit[LOCAL]);
|
|
||||||
msg_enqueue(&peer->peer_out, take(msg));
|
|
||||||
peer->funding_locked[LOCAL] = true;
|
|
||||||
|
|
||||||
if (peer->funding_locked[REMOTE]) {
|
switch (t) {
|
||||||
send_channel_announcement(peer);
|
case WIRE_CHANNEL_FUNDING_LOCKED:
|
||||||
send_channel_update(peer, false);
|
handle_funding_locked(peer, master->msg_in);
|
||||||
daemon_conn_send(master,
|
goto out;
|
||||||
take(towire_channel_normal_operation(peer)));
|
case WIRE_CHANNEL_FUNDING_ANNOUNCE_DEPTH:
|
||||||
|
handle_funding_announce_depth(peer, master->msg_in);
|
||||||
|
goto out;
|
||||||
|
case WIRE_CHANNEL_OFFER_HTLC:
|
||||||
|
handle_offer_htlc(peer, master->msg_in);
|
||||||
|
goto out;
|
||||||
|
case WIRE_CHANNEL_FULFILL_HTLC:
|
||||||
|
handle_preimage(peer, master->msg_in);
|
||||||
|
goto out;
|
||||||
|
case WIRE_CHANNEL_FAIL_HTLC:
|
||||||
|
handle_fail(peer, master->msg_in);
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
case WIRE_CHANNEL_BAD_COMMAND:
|
||||||
|
case WIRE_CHANNEL_HSM_FAILED:
|
||||||
|
case WIRE_CHANNEL_PEER_WRITE_FAILED:
|
||||||
|
case WIRE_CHANNEL_PEER_READ_FAILED:
|
||||||
|
case WIRE_CHANNEL_RECEIVED_FUNDING_LOCKED:
|
||||||
|
case WIRE_CHANNEL_NORMAL_OPERATION:
|
||||||
|
case WIRE_CHANNEL_INIT:
|
||||||
|
case WIRE_CHANNEL_OFFER_HTLC_REPLY:
|
||||||
|
case WIRE_CHANNEL_ACCEPTED_HTLC:
|
||||||
|
case WIRE_CHANNEL_FULFILLED_HTLC:
|
||||||
|
case WIRE_CHANNEL_FAILED_HTLC:
|
||||||
|
case WIRE_CHANNEL_MALFORMED_HTLC:
|
||||||
|
case WIRE_CHANNEL_PEER_BAD_MESSAGE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if(fromwire_channel_funding_announce_depth(master->msg_in, NULL)) {
|
|
||||||
status_trace("Exchanging announcement signatures.");
|
|
||||||
send_announcement_signatures(peer);
|
|
||||||
} else
|
|
||||||
status_failed(WIRE_CHANNEL_BAD_COMMAND, "%s", strerror(errno));
|
status_failed(WIRE_CHANNEL_BAD_COMMAND, "%s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
return daemon_conn_read_next(conn, master);
|
return daemon_conn_read_next(conn, master);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,6 +518,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
daemon_conn_init(peer, &peer->master, REQ_FD, req_in);
|
daemon_conn_init(peer, &peer->master, REQ_FD, req_in);
|
||||||
peer->channel = NULL;
|
peer->channel = NULL;
|
||||||
|
peer->htlc_id = 0;
|
||||||
|
|
||||||
status_setup_async(&peer->master);
|
status_setup_async(&peer->master);
|
||||||
msg_queue_init(&peer->peer_out, peer);
|
msg_queue_init(&peer->peer_out, peer);
|
||||||
|
@ -43,4 +43,61 @@ channel_funding_locked,2
|
|||||||
channel_funding_locked,0,short_channel_id,struct short_channel_id
|
channel_funding_locked,0,short_channel_id,struct short_channel_id
|
||||||
|
|
||||||
# Tell the channel that we may announce the channel's existence
|
# Tell the channel that we may announce the channel's existence
|
||||||
channel_funding_announce_depth,3
|
channel_funding_announce_depth,3
|
||||||
|
|
||||||
|
# Tell channel to offer this htlc
|
||||||
|
channel_offer_htlc,4
|
||||||
|
channel_offer_htlc,0,amount_msat,4
|
||||||
|
channel_offer_htlc,0,cltv_expiry,4
|
||||||
|
channel_offer_htlc,0,payment_hash,32
|
||||||
|
channel_offer_htlc,0,onion_routing_packet,1254*u8
|
||||||
|
|
||||||
|
# Reply; synchronous since IDs have to increment.
|
||||||
|
channel_offer_htlc_reply,104
|
||||||
|
channel_offer_htlc_reply,0,id,8
|
||||||
|
# Zero failure code means success.
|
||||||
|
channel_offer_htlc_reply,0,failure_code,2
|
||||||
|
channel_offer_htlc_reply,0,failurestrlen,2
|
||||||
|
channel_offer_htlc_reply,0,failurestr,failurestrlen*u8
|
||||||
|
|
||||||
|
# Main daemon found out the preimage for an htlc
|
||||||
|
#include <bitcoin/preimage.h>
|
||||||
|
channel_fulfill_htlc,5
|
||||||
|
channel_fulfill_htlc,0,id,8
|
||||||
|
channel_fulfill_htlc,0,payment_preimage,struct preimage
|
||||||
|
|
||||||
|
# Main daemon says HTLC failed
|
||||||
|
channel_fail_htlc,6
|
||||||
|
channel_fail_htlc,0,id,8
|
||||||
|
channel_fail_htlc,0,len,2
|
||||||
|
channel_fail_htlc,0,error_pkt,len*u8
|
||||||
|
|
||||||
|
# Peer and I are irrevocably committed to this HTLC.
|
||||||
|
channel_accepted_htlc,7
|
||||||
|
channel_accepted_htlc,0,id,8
|
||||||
|
channel_accepted_htlc,0,amount_msat,4
|
||||||
|
channel_accepted_htlc,0,cltv_expiry,4
|
||||||
|
channel_accepted_htlc,0,payment_hash,32
|
||||||
|
channel_accepted_htlc,0,next_onion,1254*u8
|
||||||
|
channel_accepted_htlc,0,forward,bool
|
||||||
|
channel_accepted_htlc,0,amt_to_forward,u64
|
||||||
|
channel_accepted_htlc,0,outgoing_cltv_value,u32
|
||||||
|
|
||||||
|
# FIXME: Add code to commit current channel state!
|
||||||
|
|
||||||
|
# The HTLC preimage was given.
|
||||||
|
channel_fulfilled_htlc,8
|
||||||
|
channel_fulfilled_htlc,0,id,8
|
||||||
|
channel_fulfilled_htlc,0,payment_preimage,struct preimage
|
||||||
|
|
||||||
|
# This HTLC failed
|
||||||
|
channel_failed_htlc,9
|
||||||
|
channel_failed_htlc,0,id,8
|
||||||
|
channel_failed_htlc,0,len,2
|
||||||
|
channel_failed_htlc,0,reason,len*u8
|
||||||
|
|
||||||
|
# This HTLC was returned malformed
|
||||||
|
channel_malformed_htlc,10
|
||||||
|
channel_malformed_htlc,0,id,8
|
||||||
|
channel_malformed_htlc,0,sha256_of_onion,32
|
||||||
|
channel_malformed_htlc,0,failure_code,2
|
||||||
|
|
@ -629,6 +629,14 @@ static size_t update_channel_status(struct subd *sd,
|
|||||||
case WIRE_CHANNEL_NORMAL_OPERATION:
|
case WIRE_CHANNEL_NORMAL_OPERATION:
|
||||||
peer_set_condition(sd->peer, "Normal operation");
|
peer_set_condition(sd->peer, "Normal operation");
|
||||||
break;
|
break;
|
||||||
|
case WIRE_CHANNEL_ACCEPTED_HTLC:
|
||||||
|
case WIRE_CHANNEL_FULFILLED_HTLC:
|
||||||
|
case WIRE_CHANNEL_FAILED_HTLC:
|
||||||
|
case WIRE_CHANNEL_MALFORMED_HTLC:
|
||||||
|
/* FIXME: Forward. */
|
||||||
|
abort();
|
||||||
|
break;
|
||||||
|
|
||||||
/* We never see fatal ones. */
|
/* We never see fatal ones. */
|
||||||
case WIRE_CHANNEL_BAD_COMMAND:
|
case WIRE_CHANNEL_BAD_COMMAND:
|
||||||
case WIRE_CHANNEL_HSM_FAILED:
|
case WIRE_CHANNEL_HSM_FAILED:
|
||||||
@ -639,6 +647,11 @@ static size_t update_channel_status(struct subd *sd,
|
|||||||
case WIRE_CHANNEL_INIT:
|
case WIRE_CHANNEL_INIT:
|
||||||
case WIRE_CHANNEL_FUNDING_LOCKED:
|
case WIRE_CHANNEL_FUNDING_LOCKED:
|
||||||
case WIRE_CHANNEL_FUNDING_ANNOUNCE_DEPTH:
|
case WIRE_CHANNEL_FUNDING_ANNOUNCE_DEPTH:
|
||||||
|
case WIRE_CHANNEL_OFFER_HTLC:
|
||||||
|
case WIRE_CHANNEL_FULFILL_HTLC:
|
||||||
|
case WIRE_CHANNEL_FAIL_HTLC:
|
||||||
|
/* Replies go to requests. */
|
||||||
|
case WIRE_CHANNEL_OFFER_HTLC_REPLY:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user