mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 18:11:28 +01:00
69cb158edd
We use libsecp256k1 to convert signatures to DER; we were creating a temporary one, but we really should be handing the one we have in dstate through. This does that, everywhere. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
139 lines
3.3 KiB
C
139 lines
3.3 KiB
C
#include "chaintopology.h"
|
|
#include "jsonrpc.h"
|
|
#include "lightningd.h"
|
|
#include "log.h"
|
|
#include "onion.h"
|
|
#include "pay.h"
|
|
#include "peer.h"
|
|
#include "routing.h"
|
|
#include <ccan/str/hex/hex.h>
|
|
#include <inttypes.h>
|
|
|
|
/* Outstanding "pay" commands. */
|
|
struct pay_command {
|
|
struct list_node list;
|
|
struct htlc *htlc;
|
|
struct command *cmd;
|
|
};
|
|
|
|
void complete_pay_command(struct peer *peer, struct htlc *htlc)
|
|
{
|
|
struct pay_command *i;
|
|
|
|
list_for_each(&peer->pay_commands, i, list) {
|
|
if (i->htlc == htlc) {
|
|
if (htlc->r) {
|
|
struct json_result *response;
|
|
|
|
response = new_json_result(i->cmd);
|
|
json_object_start(response, NULL);
|
|
json_add_hex(response, "preimage",
|
|
htlc->r, sizeof(*htlc->r));
|
|
json_object_end(response);
|
|
command_success(i->cmd, response);
|
|
} else {
|
|
command_fail(i->cmd, "htlc failed");
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Can happen if RPC connection goes away. */
|
|
log_unusual(peer->log, "No command for HTLC %"PRIu64" %s",
|
|
htlc->id, htlc->r ? "fulfill" : "fail");
|
|
}
|
|
|
|
static void remove_from_list(struct pay_command *pc)
|
|
{
|
|
list_del(&pc->list);
|
|
}
|
|
|
|
static void json_pay(struct command *cmd,
|
|
const char *buffer, const jsmntok_t *params)
|
|
{
|
|
struct pubkey id;
|
|
jsmntok_t *idtok, *msatoshistok, *rhashtok;
|
|
unsigned int expiry;
|
|
int i;
|
|
u64 msatoshis;
|
|
s64 fee;
|
|
struct sha256 rhash;
|
|
struct node_connection **route;
|
|
struct peer *peer;
|
|
struct pay_command *pc;
|
|
const u8 *onion;
|
|
|
|
if (!json_get_params(buffer, params,
|
|
"id", &idtok,
|
|
"msatoshis", &msatoshistok,
|
|
"rhash", &rhashtok,
|
|
NULL)) {
|
|
command_fail(cmd, "Need id, msatoshis and rhash");
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* FIXME: Add fee param, check for excessive fee. */
|
|
peer = find_route(cmd->dstate, &id, msatoshis, &fee, &route);
|
|
if (!peer) {
|
|
command_fail(cmd, "no route found");
|
|
return;
|
|
}
|
|
|
|
expiry = 0;
|
|
for (i = tal_count(route) - 1; i >= 0; i--) {
|
|
expiry += route[i]->delay;
|
|
if (expiry < route[i]->min_blocks)
|
|
expiry = route[i]->min_blocks;
|
|
}
|
|
expiry += peer->nc->delay;
|
|
if (expiry < peer->nc->min_blocks)
|
|
expiry = peer->nc->min_blocks;
|
|
|
|
/* Expiry for HTLCs is absolute. And add one to give some margin. */
|
|
expiry += get_block_height(cmd->dstate) + 1;
|
|
|
|
onion = onion_create(cmd, cmd->dstate->secpctx, route, msatoshis, fee);
|
|
pc = tal(cmd, struct pay_command);
|
|
pc->cmd = cmd;
|
|
pc->htlc = command_htlc_add(peer, msatoshis + fee, expiry, &rhash, NULL,
|
|
onion);
|
|
if (!pc->htlc) {
|
|
command_fail(cmd, "could not add htlc");
|
|
return;
|
|
}
|
|
|
|
/* Wait until we get response. */
|
|
list_add_tail(&peer->pay_commands, &pc->list);
|
|
tal_add_destructor(pc, remove_from_list);
|
|
}
|
|
|
|
const struct json_command pay_command = {
|
|
"pay",
|
|
json_pay,
|
|
"Send {id} {msatoshis} in return for preimage of {rhash}",
|
|
"Returns an empty result on success"
|
|
};
|