#include "chaintopology.h" #include "failure.h" #include "jsonrpc.h" #include "lightningd.h" #include "log.h" #include "onion.h" #include "pay.h" #include "peer.h" #include "routing.h" #include #include #include /* Outstanding "pay" commands. */ struct pay_command { struct list_node list; struct sha256 rhash; u64 msatoshis; struct pubkey id; /* Set if this is in progress. */ struct htlc *htlc; /* Preimage if this succeeded. */ struct rval *rval; struct command *cmd; }; static void json_pay_success(struct command *cmd, const struct rval *rval) { struct json_result *response; response = new_json_result(cmd); json_object_start(response, NULL); json_add_hex(response, "preimage", rval, sizeof(*rval)); json_object_end(response); command_success(cmd, response); } static void handle_json(struct command *cmd, const struct htlc *htlc) { FailInfo *f; struct pubkey id; const char *idstr = "INVALID"; if (htlc->r) { json_pay_success(cmd, htlc->r); return; } f = failinfo_unwrap(cmd, htlc->fail, tal_count(htlc->fail)); if (!f) { command_fail(cmd, "failed (bad message)"); return; } if (proto_to_pubkey(cmd->dstate->secpctx, f->id, &id)) idstr = pubkey_to_hexstr(cmd, cmd->dstate->secpctx, &id); command_fail(cmd, "failed: error code %u node %s reason %s", f->error_code, idstr, f->reason ? f->reason : "unknown"); } void complete_pay_command(struct lightningd_state *dstate, const struct htlc *htlc) { struct pay_command *i; list_for_each(&dstate->pay_commands, i, list) { if (i->htlc == htlc) { if (htlc->r) i->rval = tal_dup(i, struct rval, htlc->r); i->htlc = NULL; /* Can be NULL if JSON RPC goes away. */ if (i->cmd) handle_json(i->cmd, htlc); return; } } /* Can happen if RPC connection goes away. */ log_unusual(dstate->base_log, "No command for HTLC %"PRIu64" %s", htlc->id, htlc->r ? "fulfill" : "fail"); } /* When JSON RPC goes away, cmd is freed: detach from any running paycommand */ static void remove_cmd_from_pc(struct command *cmd) { struct pay_command *pc; list_for_each(&cmd->dstate->pay_commands, pc, list) { if (pc->cmd == cmd) { pc->cmd = NULL; return; } } /* We can reach here, in the case where another pay command * re-uses the pc->cmd before we get around to cleaning up. */ } static struct pay_command *find_pay_command(struct lightningd_state *dstate, const struct sha256 *rhash) { struct pay_command *pc; list_for_each(&dstate->pay_commands, pc, list) { if (structeq(rhash, &pc->rhash)) return pc; } return NULL; } static void json_add_route(struct json_result *response, secp256k1_context *secpctx, const struct pubkey *id, u64 amount, unsigned int delay) { json_object_start(response, NULL); json_add_pubkey(response, secpctx, "id", id); json_add_u64(response, "msatoshis", amount); json_add_num(response, "delay", delay); json_object_end(response); } static void json_getroute(struct command *cmd, const char *buffer, const jsmntok_t *params) { struct pubkey id; jsmntok_t *idtok, *msatoshistok; struct json_result *response; int i; u64 msatoshis; s64 fee; struct node_connection **route; struct peer *peer; u64 *amounts, total_amount; unsigned int total_delay, *delays; if (!json_get_params(buffer, params, "id", &idtok, "msatoshis", &msatoshistok, NULL)) { command_fail(cmd, "Need id and msatoshis"); return; } if (!pubkey_from_hexstr(cmd->dstate->secpctx, buffer + idtok->start, idtok->end - idtok->start, &id)) { command_fail(cmd, "Invalid id"); return; } if (!json_tok_u64(buffer, msatoshistok, &msatoshis)) { command_fail(cmd, "'%.*s' is not a valid number", (int)(msatoshistok->end - msatoshistok->start), buffer + msatoshistok->start); return; } peer = find_route(cmd->dstate, &id, msatoshis, &fee, &route); if (!peer) { command_fail(cmd, "no route found"); return; } /* Fees, delays need to be calculated backwards along route. */ amounts = tal_arr(cmd, u64, tal_count(route)+1); delays = tal_arr(cmd, unsigned int, tal_count(route)+1); total_amount = msatoshis; total_delay = 0; for (i = tal_count(route) - 1; i >= 0; i--) { amounts[i+1] = total_amount; total_amount += connection_fee(route[i], total_amount); total_delay += route[i]->delay; if (total_delay < route[i]->min_blocks) total_delay = route[i]->min_blocks; delays[i+1] = total_delay; } /* We don't charge ourselves any fees. */ amounts[0] = total_amount; /* We do require delay though. */ total_delay += peer->nc->delay; if (total_delay < peer->nc->min_blocks) total_delay = peer->nc->min_blocks; delays[0] = total_delay; response = new_json_result(cmd); json_object_start(response, NULL); json_array_start(response, "route"); json_add_route(response, cmd->dstate->secpctx, peer->id, amounts[0], delays[0]); for (i = 0; i < tal_count(route); i++) json_add_route(response, cmd->dstate->secpctx, &route[i]->dst->id, amounts[i+1], delays[i+1]); json_array_end(response); json_object_end(response); command_success(cmd, response); } const struct json_command getroute_command = { "getroute", json_getroute, "Return route for {msatoshis} to {id}", "Returns a {route} array of {id} {msatoshis} {delay}: msatoshis and delay (in blocks) is cumulative." }; 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; size_t n_hops; struct sha256 rhash; struct peer *peer; struct pay_command *pc; const u8 *onion; enum fail_error error_code; const char *err; if (!json_get_params(buffer, params, "route", &routetok, "rhash", &rhashtok, NULL)) { command_fail(cmd, "Need route and rhash"); return; } if (!hex_decode(buffer + rhashtok->start, rhashtok->end - rhashtok->start, &rhash, sizeof(rhash))) { command_fail(cmd, "'%.*s' is not a valid sha256 hash", (int)(rhashtok->end - rhashtok->start), buffer + rhashtok->start); return; } if (routetok->type != JSMN_ARRAY) { command_fail(cmd, "'%.*s' is not an array", (int)(routetok->end - routetok->start), buffer + routetok->start); return; } end = json_next(routetok); n_hops = 0; amounts = tal_arr(cmd, u64, n_hops); ids = tal_arr(cmd, struct pubkey, n_hops); for (t = routetok + 1; t < end; t = json_next(t)) { const jsmntok_t *amttok, *idtok, *delaytok; if (t->type != JSMN_OBJECT) { command_fail(cmd, "route %zu '%.*s' is not an object", n_hops, (int)(t->end - t->start), buffer + t->start); return; } amttok = json_get_member(buffer, t, "msatoshis"); idtok = json_get_member(buffer, t, "id"); delaytok = json_get_member(buffer, t, "delay"); if (!amttok || !idtok || !delaytok) { command_fail(cmd, "route %zu needs msatoshis/id/delay", n_hops); return; } tal_resize(&amounts, n_hops+1); if (!json_tok_u64(buffer, amttok, &amounts[n_hops])) { command_fail(cmd, "route %zu invalid msatoshis", n_hops); return; } tal_resize(&ids, n_hops+1); if (!pubkey_from_hexstr(cmd->dstate->secpctx, buffer + idtok->start, idtok->end - idtok->start, &ids[n_hops])) { command_fail(cmd, "route %zu invalid id", n_hops); return; } /* Only need first delay. */ if (n_hops == 0 && !json_tok_number(buffer, delaytok, &delay)) { command_fail(cmd, "route %zu invalid delay", n_hops); return; } n_hops++; } if (n_hops == 0) { command_fail(cmd, "Empty route"); return; } pc = find_pay_command(cmd->dstate, &rhash); if (pc) { log_debug(cmd->dstate->base_log, "json_sendpay: found previous"); if (pc->htlc) { log_add(cmd->dstate->base_log, "... still in progress"); command_fail(cmd, "still in progress"); return; } if (pc->rval) { log_add(cmd->dstate->base_log, "... succeeded"); /* Must match successful payment parameters. */ if (pc->msatoshis != amounts[n_hops-1]) { command_fail(cmd, "already succeeded with amount %" PRIu64, pc->msatoshis); return; } if (!structeq(&pc->id, &ids[n_hops-1])) { char *previd; previd = pubkey_to_hexstr(cmd, cmd->dstate->secpctx, &pc->id); command_fail(cmd, "already succeeded to %s", previd); return; } json_pay_success(cmd, pc->rval); return; } log_add(cmd->dstate->base_log, "... retrying"); } peer = find_peer(cmd->dstate, &ids[0]); if (!peer) { command_fail(cmd, "no connection to first peer found"); return; } /* Onion will carry us from first peer onwards. */ onion = onion_create(cmd, cmd->dstate->secpctx, ids+1, amounts+1, n_hops-1); if (!pc) pc = tal(cmd->dstate, struct pay_command); pc->cmd = cmd; pc->rhash = rhash; pc->rval = NULL; pc->id = ids[n_hops-1]; pc->msatoshis = amounts[n_hops-1]; /* Expiry for HTLCs is absolute. And add one to give some margin. */ err = command_htlc_add(peer, amounts[0], delay + get_block_height(cmd->dstate) + 1, &rhash, NULL, onion, &error_code, &pc->htlc); if (err) { command_fail(cmd, "could not add htlc: %u: %s", error_code, err); return; } /* Wait until we get response. */ list_add_tail(&cmd->dstate->pay_commands, &pc->list); tal_add_destructor(cmd, remove_cmd_from_pc); } const struct json_command sendpay_command = { "sendpay", json_sendpay, "Send along {route} in return for preimage of {rhash}", "Returns the {preimage} on success" };