From 25f1cba3cfe3a0629185563444d3bdd3ea6ffd66 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Sun, 30 Apr 2017 23:49:15 +0200 Subject: [PATCH] routing: Ask gossipd to resolve channel_id and forward HTLCs Since we now use the short_channel_id to identify the next hop we need to resolve the channel_id to the pubkey of the next hop. This is done by calling out to `gossipd` and stuffing the necessary information into `htlc_end` and recovering it from there once we receive a reply. --- lightningd/channel/channel.c | 3 +- lightningd/channel/channel_wire.csv | 2 +- lightningd/gossip/gossip.c | 32 ++++++++++++ lightningd/gossip/gossip_wire.csv | 8 +++ lightningd/gossip_control.c | 2 + lightningd/htlc_end.h | 11 +++- lightningd/peer_control.c | 78 +++++++++++++++++------------ 7 files changed, 101 insertions(+), 35 deletions(-) diff --git a/lightningd/channel/channel.c b/lightningd/channel/channel.c index a69d47aba..47189faff 100644 --- a/lightningd/channel/channel.c +++ b/lightningd/channel/channel.c @@ -636,7 +636,6 @@ static void their_htlc_locked(const struct htlc *htlc, struct peer *peer) goto remove_htlc; } - u8 dummy_next_hop[20]; memset(dummy_next_hop, 0, 20); /* Tell master to deal with it. */ msg = towire_channel_accepted_htlc(tmpctx, htlc->id, htlc->msatoshi, abs_locktime_to_blocks(&htlc->expiry), @@ -646,7 +645,7 @@ static void their_htlc_locked(const struct htlc *htlc, struct peer *peer) rs->nextcase == ONION_FORWARD, rs->hop_data.amt_forward, rs->hop_data.outgoing_cltv, - dummy_next_hop); + &rs->hop_data.channel_id); daemon_conn_send(&peer->master, take(msg)); tal_free(tmpctx); return; diff --git a/lightningd/channel/channel_wire.csv b/lightningd/channel/channel_wire.csv index 3edd86bf6..ad90d1ff6 100644 --- a/lightningd/channel/channel_wire.csv +++ b/lightningd/channel/channel_wire.csv @@ -85,7 +85,7 @@ channel_accepted_htlc,0,next_onion,1366*u8 channel_accepted_htlc,0,forward,bool channel_accepted_htlc,0,amt_to_forward,u64 channel_accepted_htlc,0,outgoing_cltv_value,u32 -channel_accepted_htlc,0,nexthop,20*u8 +channel_accepted_htlc,0,next_channel,struct short_channel_id # FIXME: Add code to commit current channel state! diff --git a/lightningd/gossip/gossip.c b/lightningd/gossip/gossip.c index 6c5bf9531..7de2decfb 100644 --- a/lightningd/gossip/gossip.c +++ b/lightningd/gossip/gossip.c @@ -633,6 +633,34 @@ static struct io_plan *gossip_init(struct daemon_conn *master, return daemon_conn_read_next(master->conn, master); } +static struct io_plan *resolve_channel_req(struct io_conn *conn, + struct daemon *daemon, const u8 *msg) +{ + struct short_channel_id scid; + struct node_connection *nc; + u8 *reply; + struct pubkey *nullkey = talz(msg, struct pubkey); + if (!fromwire_gossip_resolve_channel_request(msg, NULL, &scid)) { + status_trace("Unable to parse resolver request"); + reply = towire_gossip_resolve_channel_reply(msg, 1, nullkey, + nullkey); + } else { + status_trace("Attempting to resolce channel %d/%d/%d", + scid.blocknum, scid.txnum, scid.outnum); + + nc = get_connection_by_scid(daemon->rstate, &scid, 0); + if (!nc) { + reply = towire_gossip_resolve_channel_reply( + msg, 2, nullkey, nullkey); + } else { + reply = towire_gossip_resolve_channel_reply( + msg, 0, &nc->src->id, &nc->dst->id); + } + } + daemon_conn_send(&daemon->master, reply); + return daemon_conn_read_next(conn, &daemon->master); +} + static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master) { struct daemon *daemon = container_of(master, struct daemon, master); @@ -662,11 +690,15 @@ static struct io_plan *recv_req(struct io_conn *conn, struct daemon_conn *master case WIRE_GOSSIP_PING: return ping_req(conn, daemon, daemon->master.msg_in); + case WIRE_GOSSIP_RESOLVE_CHANNEL_REQUEST: + return resolve_channel_req(conn, daemon, daemon->master.msg_in); + case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY: case WIRE_GOSSIP_GETNODES_REPLY: case WIRE_GOSSIP_GETROUTE_REPLY: case WIRE_GOSSIP_GETCHANNELS_REPLY: case WIRE_GOSSIP_PING_REPLY: + case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY: case WIRE_GOSSIPSTATUS_INIT_FAILED: case WIRE_GOSSIPSTATUS_BAD_NEW_PEER_REQUEST: case WIRE_GOSSIPSTATUS_BAD_RELEASE_REQUEST: diff --git a/lightningd/gossip/gossip_wire.csv b/lightningd/gossip/gossip_wire.csv index 3e5c3ae8d..a78c70b6d 100644 --- a/lightningd/gossip/gossip_wire.csv +++ b/lightningd/gossip/gossip_wire.csv @@ -91,3 +91,11 @@ gossip_ping,0,len,u16 gossip_ping_reply,108 gossip_ping_reply,0,totlen,u16 +# Given a short_channel_id, return the endpoints +gossip_resolve_channel_request,9 +gossip_resolve_channel_request,0,channel_id,struct short_channel_id + +gossip_resolve_channel_reply,109 +gossip_resolve_channel_reply,0,error,u8 +gossip_resolve_channel_reply,1,node_id_1,struct pubkey +gossip_resolve_channel_reply,34,node_id_2,struct pubkey diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 9ba1c3a6d..776d854a0 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -147,12 +147,14 @@ static int gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIP_GETROUTE_REQUEST: case WIRE_GOSSIP_GETCHANNELS_REQUEST: case WIRE_GOSSIP_PING: + case WIRE_GOSSIP_RESOLVE_CHANNEL_REQUEST: /* This is a reply, so never gets through to here. */ case WIRE_GOSSIPCTL_RELEASE_PEER_REPLY: case WIRE_GOSSIP_GETNODES_REPLY: case WIRE_GOSSIP_GETROUTE_REPLY: case WIRE_GOSSIP_GETCHANNELS_REPLY: case WIRE_GOSSIP_PING_REPLY: + case WIRE_GOSSIP_RESOLVE_CHANNEL_REPLY: break; case WIRE_GOSSIPSTATUS_PEER_BAD_MSG: peer_bad_message(gossip, msg); diff --git a/lightningd/htlc_end.h b/lightningd/htlc_end.h index 150dee694..98d5391a7 100644 --- a/lightningd/htlc_end.h +++ b/lightningd/htlc_end.h @@ -3,6 +3,7 @@ #include "config.h" #include #include +#include /* A HTLC has a source and destination: if other is NULL, it's this node. * @@ -14,11 +15,19 @@ struct htlc_end { enum htlc_end_type which_end; struct peer *peer; u64 htlc_id; - u64 msatoshis; + u32 msatoshis; struct htlc_end *other_end; /* If this is driven by a command. */ struct pay_command *pay_command; + + /* Temporary information, while we resolve the next hop */ + u8 next_onion[TOTAL_PACKET_SIZE]; + struct short_channel_id next_channel; + u64 amt_to_forward; + u32 outgoing_cltv_value; + u32 cltv_expiry; + struct sha256 payment_hash; }; static inline const struct htlc_end *keyof_htlc_end(const struct htlc_end *e) diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 4539501b5..c9be4a7ed 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -875,14 +875,11 @@ fail: tal_free(hend); } -static struct peer *peer_by_pkhash(struct lightningd *ld, const u8 pkhash[20]) +static struct peer *peer_by_pubkey(struct lightningd *ld, const struct pubkey *id) { struct peer *peer; - u8 addr[20]; - list_for_each(&ld->peers, peer, list) { - pubkey_hash160(addr, peer->id); - if (memcmp(addr, pkhash, sizeof(addr)) == 0) + if (pubkey_cmp(id, peer->id) == 0) return peer; } return NULL; @@ -945,13 +942,13 @@ static void forward_htlc(struct htlc_end *hend, const struct sha256 *payment_hash, u64 amt_to_forward, u32 outgoing_cltv_value, - const u8 next_hop[20], + const struct pubkey *next_hop, const u8 next_onion[TOTAL_PACKET_SIZE]) { u8 *err, *msg; u64 fee; struct lightningd *ld = hend->peer->ld; - struct peer *next = peer_by_pkhash(ld, next_hop); + struct peer *next = peer_by_pubkey(ld, next_hop); if (!next) { err = towire_unknown_next_peer(hend); @@ -1035,44 +1032,63 @@ fail: tal_free(hend); } +/* We received a resolver reply, which gives us the node_ids of the + * channel we want to forward over */ +static bool channel_resolve_reply(struct subd *gossip, const u8 *msg, + const int *fds, struct htlc_end *hend) +{ + struct pubkey node_id_1, node_id_2, peer_id; + u8 error; + fromwire_gossip_resolve_channel_reply(msg, NULL, &error, &node_id_1, + &node_id_2); + + /* Get the other peer matching the id that is not us */ + if (pubkey_cmp(&node_id_1, &gossip->ld->dstate.id) == 0) { + peer_id = node_id_2; + } else { + peer_id = node_id_1; + } + + forward_htlc(hend, hend->cltv_expiry, &hend->payment_hash, + hend->amt_to_forward, hend->outgoing_cltv_value, &peer_id, + hend->next_onion); + /* FIXME(cdecker) Cleanup things we stuffed into hend before (maybe?) */ + return true; +} + static int peer_accepted_htlc(struct peer *peer, const u8 *msg) { - u64 id; - u32 cltv_expiry, amount_msat; - struct sha256 payment_hash; - u8 next_onion[TOTAL_PACKET_SIZE]; - u8 next_hop[20]; bool forward; - u64 amt_to_forward; - u32 outgoing_cltv_value; struct htlc_end *hend; - - if (!fromwire_channel_accepted_htlc(msg, NULL, &id, &amount_msat, - &cltv_expiry, &payment_hash, - next_onion, &forward, - &amt_to_forward, - &outgoing_cltv_value, - next_hop)) { + u8 *req; + + hend = tal(msg, struct htlc_end); + if (!fromwire_channel_accepted_htlc(msg, NULL, + &hend->htlc_id, &hend->msatoshis, + &hend->cltv_expiry, &hend->payment_hash, + hend->next_onion, &forward, + &hend->amt_to_forward, + &hend->outgoing_cltv_value, + &hend->next_channel)) { log_broken(peer->log, "bad fromwire_channel_accepted_htlc %s", tal_hex(peer, msg)); return -1; } - hend = tal(peer, struct htlc_end); + tal_steal(peer, hend); hend->which_end = HTLC_SRC; hend->peer = peer; - hend->htlc_id = id; hend->other_end = NULL; hend->pay_command = NULL; - hend->msatoshis = amount_msat; - if (forward) - forward_htlc(hend, cltv_expiry, &payment_hash, - amt_to_forward, outgoing_cltv_value, - next_hop, next_onion); - else - handle_localpay(hend, cltv_expiry, &payment_hash, - amt_to_forward, outgoing_cltv_value); + if (forward) { + req = towire_gossip_resolve_channel_request(msg, &hend->next_channel); + log_broken(peer->log, "Asking gossip to resolve channel %d/%d/%d", hend->next_channel.blocknum, hend->next_channel.txnum, hend->next_channel.outnum); + subd_req(hend, peer->ld->gossip, req, -1, 0, channel_resolve_reply, hend); + /* FIXME(cdecker) Stuff all this info into hend */ + } else + handle_localpay(hend, hend->cltv_expiry, &hend->payment_hash, + hend->amt_to_forward, hend->outgoing_cltv_value); return 0; }