mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
sphinx: Integrate sphinx OR with lightningd
Now replaces the old cleartext onion routing with the sphinx implementation.
This commit is contained in:
parent
7bb5c279a8
commit
1d3737055a
@ -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
|
||||
|
50
daemon/pay.c
50
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 <ccan/str/hex/hex.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <inttypes.h>
|
||||
#include <sodium/randombytes.h>
|
||||
|
||||
/* 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);
|
||||
|
@ -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 <inttypes.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
@ -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);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user