From 1d3737055a4d7dbb6f87b0edad51f50dc116d0fe Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Thu, 6 Oct 2016 22:06:20 +0200 Subject: [PATCH] sphinx: Integrate sphinx OR with lightningd Now replaces the old cleartext onion routing with the sphinx implementation. --- daemon/Makefile | 4 +-- daemon/pay.c | 50 +++++++++++++++++++++++-------- daemon/peer.c | 78 ++++++++++++++++++++++++++++++++----------------- daemon/peer.h | 1 + 4 files changed, 93 insertions(+), 40 deletions(-) diff --git a/daemon/Makefile b/daemon/Makefile index b904dd18d..0274c7d17 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -30,7 +30,6 @@ DAEMON_SRC := \ daemon/jsonrpc.c \ daemon/lightningd.c \ daemon/netaddr.c \ - daemon/onion.c \ daemon/opt_time.c \ daemon/output_to_htlc.c \ daemon/packets.c \ @@ -38,6 +37,7 @@ DAEMON_SRC := \ daemon/peer.c \ daemon/routing.c \ daemon/secrets.c \ + daemon/sphinx.c \ daemon/timeout.c \ daemon/wallet.c \ daemon/watch.c \ @@ -79,7 +79,6 @@ DAEMON_HEADERS := \ daemon/lightningd.h \ daemon/log.h \ daemon/netaddr.h \ - daemon/onion.h \ daemon/opt_time.h \ daemon/output_to_htlc.h \ daemon/packets.h \ @@ -88,6 +87,7 @@ DAEMON_HEADERS := \ daemon/pseudorand.h \ daemon/routing.h \ daemon/secrets.h \ + daemon/sphinx.h \ daemon/timeout.h \ daemon/wallet.h \ daemon/watch.h diff --git a/daemon/pay.c b/daemon/pay.c index 46821625f..25f936354 100644 --- a/daemon/pay.c +++ b/daemon/pay.c @@ -4,13 +4,14 @@ #include "jsonrpc.h" #include "lightningd.h" #include "log.h" -#include "onion.h" #include "pay.h" #include "peer.h" #include "routing.h" +#include "sphinx.h" #include #include #include +#include /* Outstanding "pay" commands. */ struct pay_command { @@ -293,7 +294,6 @@ static void json_sendpay(struct command *cmd, const char *buffer, const jsmntok_t *params) { struct pubkey *ids; - u64 *amounts; jsmntok_t *routetok, *rhashtok; const jsmntok_t *t, *end; unsigned int delay; @@ -303,8 +303,12 @@ static void json_sendpay(struct command *cmd, struct pay_command *pc; bool replacing = false; const u8 *onion; + u8 sessionkey[32]; enum fail_error error_code; const char *err; + struct hoppayload *hoppayloads; + u64 amount, lastamount; + struct onionpacket *packet; if (!json_get_params(buffer, params, "route", &routetok, @@ -332,8 +336,8 @@ static void json_sendpay(struct command *cmd, end = json_next(routetok); n_hops = 0; - amounts = tal_arr(cmd, u64, n_hops); ids = tal_arr(cmd, struct pubkey, n_hops); + hoppayloads = tal_arr(cmd, struct hoppayload, 0); for (t = routetok + 1; t < end; t = json_next(t)) { const jsmntok_t *amttok, *idtok, *delaytok; @@ -353,12 +357,26 @@ static void json_sendpay(struct command *cmd, return; } - tal_resize(&amounts, n_hops+1); - if (!json_tok_u64(buffer, amttok, &amounts[n_hops])) { - command_fail(cmd, "route %zu invalid msatoshi", n_hops); - return; + if (n_hops == 0) { + /* What we will send */ + if (!json_tok_u64(buffer, amttok, &amount)) { + command_fail(cmd, "route %zu invalid msatoshi", n_hops); + return; + } + lastamount = amount; + } else{ + /* What that hop will forward */ + tal_resize(&hoppayloads, n_hops); + memset(&hoppayloads[n_hops-1], 0, sizeof(struct hoppayload)); + if (!json_tok_u64(buffer, amttok, &hoppayloads[n_hops-1].amount)) { + command_fail(cmd, "route %zu invalid msatoshi", n_hops); + return; + } + lastamount = hoppayloads[n_hops-1].amount; } + tal_resize(&ids, n_hops+1); + memset(&ids[n_hops], 0, sizeof(ids[n_hops])); if (!pubkey_from_hexstr(cmd->dstate->secpctx, buffer + idtok->start, idtok->end - idtok->start, @@ -374,6 +392,10 @@ static void json_sendpay(struct command *cmd, n_hops++; } + /* Add payload for final hop */ + tal_resize(&hoppayloads, n_hops); + memset(&hoppayloads[n_hops-1], 0, sizeof(struct hoppayload)); + if (n_hops == 0) { command_fail(cmd, "Empty route"); return; @@ -392,7 +414,7 @@ static void json_sendpay(struct command *cmd, size_t old_nhops = tal_count(pc->ids); log_add(cmd->dstate->base_log, "... succeeded"); /* Must match successful payment parameters. */ - if (pc->msatoshi != amounts[n_hops-1]) { + if (pc->msatoshi != lastamount) { command_fail(cmd, "already succeeded with amount %" PRIu64, pc->msatoshi); @@ -420,9 +442,13 @@ static void json_sendpay(struct command *cmd, return; } + randombytes_buf(&sessionkey, sizeof(sessionkey)); + /* Onion will carry us from first peer onwards. */ - onion = onion_create(cmd, cmd->dstate->secpctx, ids+1, amounts+1, - n_hops-1); + packet = create_onionpacket( + cmd, cmd->dstate->secpctx, ids, hoppayloads, + sessionkey, (u8*)"", 0); + onion = serialize_onionpacket(cmd, cmd->dstate->secpctx, packet); if (pc) pc->ids = tal_free(pc->ids); @@ -432,10 +458,10 @@ static void json_sendpay(struct command *cmd, pc->rhash = rhash; pc->rval = NULL; pc->ids = tal_steal(pc, ids); - pc->msatoshi = amounts[n_hops-1]; + pc->msatoshi = lastamount; /* Expiry for HTLCs is absolute. And add one to give some margin. */ - err = command_htlc_add(peer, amounts[0], + err = command_htlc_add(peer, amount, delay + get_block_height(cmd->dstate) + 1, &rhash, NULL, onion, &error_code, &pc->htlc); diff --git a/daemon/peer.c b/daemon/peer.c index e8b824543..bf71d35b3 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -13,7 +13,6 @@ #include "log.h" #include "names.h" #include "netaddr.h" -#include "onion.h" #include "output_to_htlc.h" #include "packets.h" #include "pay.h" @@ -24,6 +23,7 @@ #include "remove_dust.h" #include "routing.h" #include "secrets.h" +#include "sphinx.h" #include "state.h" #include "timeout.h" #include "utils.h" @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -199,6 +200,19 @@ struct peer *find_peer(struct lightningd_state *dstate, const struct pubkey *id) return NULL; } +struct peer *find_peer_by_pkhash(struct lightningd_state *dstate, const u8 *pkhash) +{ + struct peer *peer; + u8 addr[20]; + + list_for_each(&dstate->peers, peer, list) { + pubkey_hash160(dstate->secpctx, addr, peer->id); + if (memcmp(addr, pkhash, sizeof(addr)) == 0) + return peer; + } + return NULL; +} + void debug_dump_peers(struct lightningd_state *dstate) { struct peer *peer; @@ -438,11 +452,10 @@ static void set_htlc_fail(struct peer *peer, static void route_htlc_onwards(struct peer *peer, struct htlc *htlc, u64 msatoshi, - const BitcoinPubkey *pb_id, + const u8 *pb_id, const u8 *rest_of_route, const struct peer *only_dest) { - struct pubkey id; struct peer *next; struct htlc *newhtlc; enum fail_error error_code; @@ -454,19 +467,10 @@ static void route_htlc_onwards(struct peer *peer, log_add(peer->log, " (id %"PRIu64")", htlc->id); } - if (!proto_to_pubkey(peer->dstate->secpctx, pb_id, &id)) { - log_unusual(peer->log, - "Malformed pubkey for HTLC %"PRIu64, htlc->id); - command_htlc_set_fail(peer, htlc, BAD_REQUEST_400, - "Malformed pubkey"); - return; - } - - next = find_peer(peer->dstate, &id); + next = find_peer_by_pkhash(peer->dstate, pb_id); if (!next || !next->nc) { log_unusual(peer->log, "Can't route HTLC %"PRIu64": no %speer ", htlc->id, next ? "ready " : ""); - log_add_struct(peer->log, "%s", struct pubkey, &id); if (!peer->dstate->dev_never_routefail) command_htlc_set_fail(peer, htlc, NOT_FOUND_404, "Unknown peer"); @@ -505,9 +509,10 @@ static void route_htlc_onwards(struct peer *peer, static void their_htlc_added(struct peer *peer, struct htlc *htlc, struct peer *only_dest) { - RouteStep *step; - const u8 *rest_of_route; struct invoice *invoice; + struct privkey pk; + struct onionpacket *packet; + struct route_step *step = NULL; if (abs_locktime_is_seconds(&htlc->expiry)) { log_unusual(peer->log, "HTLC %"PRIu64" is in seconds", htlc->id); @@ -536,8 +541,13 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc, return; } - step = onion_unwrap(peer, htlc->routing, tal_count(htlc->routing), - &rest_of_route); + //FIXME: dirty trick to retrieve unexported state + memcpy(&pk, peer->dstate->secret, sizeof(pk)); + packet = parse_onionpacket(peer, peer->dstate->secpctx, + htlc->routing, tal_count(htlc->routing)); + if (packet) + step = process_onionpacket(peer, peer->dstate->secpctx, packet, &pk); + if (!step) { log_unusual(peer->log, "Bad onion, failing HTLC %"PRIu64, htlc->id); @@ -546,8 +556,8 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc, return; } - switch (step->next_case) { - case ROUTE_STEP__NEXT_END: + switch (step->nextcase) { + case ONION_END: if (only_dest) return; invoice = find_unpaid(peer->dstate, &htlc->rhash); @@ -584,19 +594,20 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc, command_htlc_fulfill(peer, htlc); goto free_rest; - case ROUTE_STEP__NEXT_BITCOIN: - route_htlc_onwards(peer, htlc, step->amount, step->bitcoin, - rest_of_route, only_dest); + case ONION_FORWARD: + printf("FORWARDING %lu\n", step->hoppayload->amount); + route_htlc_onwards(peer, htlc, step->hoppayload->amount, step->next->nexthop, + serialize_onionpacket(step, peer->dstate->secpctx, step->next), only_dest); goto free_rest; default: - log_info(peer->log, "Unknown step type %u", step->next_case); + log_info(peer->log, "Unknown step type %u", step->nextcase); command_htlc_set_fail(peer, htlc, VERSION_NOT_SUPPORTED_505, "unknown step type"); goto free_rest; } free_rest: - tal_free(rest_of_route); + tal_free(step); } static void our_htlc_failed(struct peer *peer, struct htlc *htlc) @@ -4396,6 +4407,11 @@ static void json_newhtlc(struct command *cmd, struct htlc *htlc; const char *err; enum fail_error error_code; + struct hoppayload *hoppayloads; + u8 sessionkey[32]; + struct onionpacket *packet; + u8 *onion; + struct pubkey *path = tal_arrz(cmd, struct pubkey, 1); if (!json_get_params(buffer, params, "peerid", &peeridtok, @@ -4445,10 +4461,20 @@ static void json_newhtlc(struct command *cmd, return; } + tal_arr(cmd, struct pubkey, 1); + hoppayloads = tal_arrz(cmd, struct hoppayload, 1); + memcpy(&path[0], peer->id, sizeof(struct pubkey)); + randombytes_buf(&sessionkey, sizeof(sessionkey)); + packet = create_onionpacket( + cmd, + cmd->dstate->secpctx, + path, + hoppayloads, sessionkey, (u8*)"", 0); + onion = serialize_onionpacket(cmd, cmd->dstate->secpctx, packet); + log_debug(peer->log, "JSON command to add new HTLC"); err = command_htlc_add(peer, msatoshi, expiry, &rhash, NULL, - onion_create(cmd, cmd->dstate->secpctx, - NULL, NULL, 0), + onion, &error_code, &htlc); if (err) { command_fail(cmd, "could not add htlc: %u:%s", error_code, err); diff --git a/daemon/peer.h b/daemon/peer.h index 6a580447e..344ccd239 100644 --- a/daemon/peer.h +++ b/daemon/peer.h @@ -240,6 +240,7 @@ struct peer_address { void setup_listeners(struct lightningd_state *dstate, unsigned int portnum); struct peer *find_peer(struct lightningd_state *dstate, const struct pubkey *id); +struct peer *find_peer_by_pkhash(struct lightningd_state *dstate, const u8 *pkhash); struct peer *new_peer(struct lightningd_state *dstate, struct log *log,