diff --git a/lightningd/channel/channel.c b/lightningd/channel/channel.c index d74dee74d..ba9e84978 100644 --- a/lightningd/channel/channel.c +++ b/lightningd/channel/channel.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +55,13 @@ struct peer { /* Our shaseed for generating per-commitment-secrets. */ 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 *channel; @@ -274,32 +283,219 @@ static void init_channel(struct peer *peer, const u8 *msg) 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) { struct peer *peer = container_of(master, struct peer, master); if (!peer->channel) init_channel(peer, master->msg_in); - else if (fromwire_channel_funding_locked(master->msg_in, NULL, - &peer->short_channel_ids[LOCAL])) { - 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; + else { + enum channel_wire_type t = fromwire_peektype(master->msg_in); - if (peer->funding_locked[REMOTE]) { - send_channel_announcement(peer); - send_channel_update(peer, false); - daemon_conn_send(master, - take(towire_channel_normal_operation(peer))); + switch (t) { + case WIRE_CHANNEL_FUNDING_LOCKED: + handle_funding_locked(peer, master->msg_in); + goto out; + 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)); + } +out: 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); peer->channel = NULL; + peer->htlc_id = 0; status_setup_async(&peer->master); msg_queue_init(&peer->peer_out, peer); diff --git a/lightningd/channel/channel_wire.csv b/lightningd/channel/channel_wire.csv index 1c4f36329..12e31c827 100644 --- a/lightningd/channel/channel_wire.csv +++ b/lightningd/channel/channel_wire.csv @@ -43,4 +43,61 @@ channel_funding_locked,2 channel_funding_locked,0,short_channel_id,struct short_channel_id # Tell the channel that we may announce the channel's existence -channel_funding_announce_depth,3 \ No newline at end of file +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 +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 diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 3f12709f8..290ca6ed7 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -629,6 +629,14 @@ static size_t update_channel_status(struct subd *sd, case WIRE_CHANNEL_NORMAL_OPERATION: peer_set_condition(sd->peer, "Normal operation"); 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. */ case WIRE_CHANNEL_BAD_COMMAND: 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_FUNDING_LOCKED: 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; }