mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-22 00:24:19 +01:00
db: save and restore "sendpay" commands.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
183
daemon/db.c
183
daemon/db.c
@@ -7,6 +7,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "names.h"
|
#include "names.h"
|
||||||
#include "netaddr.h"
|
#include "netaddr.h"
|
||||||
|
#include "pay.h"
|
||||||
#include "routing.h"
|
#include "routing.h"
|
||||||
#include "secrets.h"
|
#include "secrets.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
@@ -953,6 +954,109 @@ static void db_load_peers(struct lightningd_state *dstate)
|
|||||||
connect_htlc_src(dstate);
|
connect_htlc_src(dstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *pubkeys_to_hex(const tal_t *ctx,
|
||||||
|
secp256k1_context *secpctx,
|
||||||
|
const struct pubkey *ids)
|
||||||
|
{
|
||||||
|
u8 *ders = tal_arr(ctx, u8, PUBKEY_DER_LEN * tal_count(ids));
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < tal_count(ids); i++)
|
||||||
|
pubkey_to_der(secpctx, ders + i * PUBKEY_DER_LEN, &ids[i]);
|
||||||
|
|
||||||
|
return tal_hexstr(ctx, ders, tal_count(ders));
|
||||||
|
}
|
||||||
|
static struct pubkey *pubkeys_from_arr(const tal_t *ctx,
|
||||||
|
secp256k1_context *secpctx,
|
||||||
|
const void *blob, size_t len)
|
||||||
|
{
|
||||||
|
struct pubkey *ids;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (len % PUBKEY_DER_LEN)
|
||||||
|
fatal("ids array bad length %zu", len);
|
||||||
|
|
||||||
|
ids = tal_arr(ctx, struct pubkey, len / PUBKEY_DER_LEN);
|
||||||
|
for (i = 0; i < tal_count(ids); i++) {
|
||||||
|
if (!pubkey_from_der(secpctx, blob, PUBKEY_DER_LEN, &ids[i]))
|
||||||
|
fatal("ids array invalid %zu", i);
|
||||||
|
blob = (const u8 *)blob + PUBKEY_DER_LEN;
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void db_load_pay(struct lightningd_state *dstate)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
sqlite3_stmt *stmt;
|
||||||
|
char *ctx = tal(dstate, char);
|
||||||
|
|
||||||
|
err = sqlite3_prepare_v2(dstate->db->sql, "SELECT * FROM pay;", -1,
|
||||||
|
&stmt, NULL);
|
||||||
|
|
||||||
|
if (err != SQLITE_OK)
|
||||||
|
fatal("db_load_pay:prepare gave %s:%s",
|
||||||
|
sqlite3_errstr(err), sqlite3_errmsg(dstate->db->sql));
|
||||||
|
|
||||||
|
/* CREATE TABLE pay (rhash "SQL_RHASH", msatoshis INT, ids BLOB, htlc_peer "SQL_PUBKEY", htlc_id INT, r "SQL_R", fail BLOB, PRIMARY KEY(rhash)); */
|
||||||
|
while ((err = sqlite3_step(stmt)) != SQLITE_DONE) {
|
||||||
|
struct sha256 rhash;
|
||||||
|
struct htlc *htlc;
|
||||||
|
struct pubkey *peer_id;
|
||||||
|
u64 htlc_id, msatoshis;
|
||||||
|
struct pubkey *ids;
|
||||||
|
struct rval *r;
|
||||||
|
void *fail;
|
||||||
|
|
||||||
|
if (err != SQLITE_ROW)
|
||||||
|
fatal("db_load_pay:step gave %s:%s",
|
||||||
|
sqlite3_errstr(err),
|
||||||
|
sqlite3_errmsg(dstate->db->sql));
|
||||||
|
if (sqlite3_column_count(stmt) != 7)
|
||||||
|
fatal("db_load_pay:step gave %i cols, not 7",
|
||||||
|
sqlite3_column_count(stmt));
|
||||||
|
|
||||||
|
sha256_from_sql(stmt, 0, &rhash);
|
||||||
|
msatoshis = sqlite3_column_int64(stmt, 1);
|
||||||
|
ids = pubkeys_from_arr(ctx, dstate->secpctx,
|
||||||
|
sqlite3_column_blob(stmt, 2),
|
||||||
|
sqlite3_column_bytes(stmt, 2));
|
||||||
|
if (sqlite3_column_type(stmt, 3) == SQLITE_NULL)
|
||||||
|
peer_id = NULL;
|
||||||
|
else {
|
||||||
|
peer_id = tal(ctx, struct pubkey);
|
||||||
|
pubkey_from_sql(dstate->secpctx, stmt, 3, peer_id);
|
||||||
|
}
|
||||||
|
htlc_id = sqlite3_column_int64(stmt, 4);
|
||||||
|
if (sqlite3_column_type(stmt, 5) == SQLITE_NULL)
|
||||||
|
r = NULL;
|
||||||
|
else {
|
||||||
|
r = tal(ctx, struct rval);
|
||||||
|
from_sql_blob(stmt, 5, r, sizeof(*r));
|
||||||
|
}
|
||||||
|
fail = tal_sql_blob(ctx, stmt, 6);
|
||||||
|
/* Exactly one of these must be set. */
|
||||||
|
if (!fail + !peer_id + !r != 2)
|
||||||
|
fatal("db_load_pay: not exactly one set:"
|
||||||
|
" fail=%p peer_id=%p r=%p",
|
||||||
|
fail, peer_id, r);
|
||||||
|
if (peer_id) {
|
||||||
|
struct peer *peer = find_peer(dstate, peer_id);
|
||||||
|
if (!peer)
|
||||||
|
fatal("db_load_pay: unknown peer");
|
||||||
|
htlc = htlc_get(&peer->htlcs, htlc_id, LOCAL);
|
||||||
|
if (!htlc)
|
||||||
|
fatal("db_load_pay: unknown htlc");
|
||||||
|
} else
|
||||||
|
htlc = NULL;
|
||||||
|
|
||||||
|
if (!pay_add(dstate, &rhash, msatoshis, ids, htlc, fail, r))
|
||||||
|
fatal("db_load_pay: could not add pay");
|
||||||
|
}
|
||||||
|
tal_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
static void db_load_addresses(struct lightningd_state *dstate)
|
static void db_load_addresses(struct lightningd_state *dstate)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
@@ -993,6 +1097,7 @@ static void db_load(struct lightningd_state *dstate)
|
|||||||
db_load_wallet(dstate);
|
db_load_wallet(dstate);
|
||||||
db_load_addresses(dstate);
|
db_load_addresses(dstate);
|
||||||
db_load_peers(dstate);
|
db_load_peers(dstate);
|
||||||
|
db_load_pay(dstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void db_init(struct lightningd_state *dstate)
|
void db_init(struct lightningd_state *dstate)
|
||||||
@@ -1033,6 +1138,7 @@ void db_init(struct lightningd_state *dstate)
|
|||||||
/* Set up tables. */
|
/* Set up tables. */
|
||||||
errmsg = db_exec(dstate, dstate,
|
errmsg = db_exec(dstate, dstate,
|
||||||
"CREATE TABLE wallet (privkey "SQL_PRIVKEY");"
|
"CREATE TABLE wallet (privkey "SQL_PRIVKEY");"
|
||||||
|
"CREATE TABLE pay (rhash "SQL_RHASH", msatoshis INT, ids BLOB, htlc_peer "SQL_PUBKEY", htlc_id INT, r "SQL_R", fail BLOB, PRIMARY KEY(rhash));"
|
||||||
"CREATE TABLE anchors (peer "SQL_PUBKEY", txid "SQL_TXID", idx INT, amount INT, ok_depth INT, min_depth INT, bool ours, PRIMARY KEY(peer));"
|
"CREATE TABLE anchors (peer "SQL_PUBKEY", txid "SQL_TXID", idx INT, amount INT, ok_depth INT, min_depth INT, bool ours, PRIMARY KEY(peer));"
|
||||||
/* FIXME: state in primary key is overkill: just need side */
|
/* FIXME: state in primary key is overkill: just need side */
|
||||||
"CREATE TABLE htlcs (peer "SQL_PUBKEY", id INT, state TEXT, msatoshis INT, expiry INT, rhash "SQL_RHASH", r "SQL_R", routing "SQL_ROUTING", src_peer "SQL_PUBKEY", src_id INT, fail BLOB, PRIMARY KEY(peer, id, state));"
|
"CREATE TABLE htlcs (peer "SQL_PUBKEY", id INT, state TEXT, msatoshis INT, expiry INT, rhash "SQL_RHASH", r "SQL_R", routing "SQL_ROUTING", src_peer "SQL_PUBKEY", src_id INT, fail BLOB, PRIMARY KEY(peer, id, state));"
|
||||||
@@ -1654,3 +1760,80 @@ bool db_update_their_closing(struct peer *peer)
|
|||||||
tal_free(ctx);
|
tal_free(ctx);
|
||||||
return !errmsg;
|
return !errmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool db_new_pay_command(struct lightningd_state *dstate,
|
||||||
|
const struct sha256 *rhash,
|
||||||
|
const struct pubkey *ids,
|
||||||
|
u64 msatoshis,
|
||||||
|
const struct htlc *htlc)
|
||||||
|
{
|
||||||
|
const char *errmsg, *ctx = tal(dstate, char);
|
||||||
|
|
||||||
|
log_debug(dstate->base_log, "%s", __func__);
|
||||||
|
log_add_struct(dstate->base_log, "(%s)", struct sha256, rhash);
|
||||||
|
|
||||||
|
assert(!dstate->db->in_transaction);
|
||||||
|
/* CREATE TABLE pay (rhash "SQL_RHASH", msatoshis INT, ids BLOB, htlc_peer "SQL_PUBKEY", htlc_id INT, r "SQL_R", fail BLOB, PRIMARY KEY(rhash)); */
|
||||||
|
errmsg = db_exec(ctx, dstate, "INSERT INTO pay VALUES (x'%s', %"PRIu64", x'%s', x'%s', %"PRIu64", NULL, NULL);",
|
||||||
|
tal_hexstr(ctx, rhash, sizeof(*rhash)),
|
||||||
|
msatoshis,
|
||||||
|
pubkeys_to_hex(ctx, dstate->secpctx, ids),
|
||||||
|
pubkey_to_hexstr(ctx, dstate->secpctx, htlc->peer->id),
|
||||||
|
htlc->id);
|
||||||
|
if (errmsg)
|
||||||
|
log_broken(dstate->base_log, "%s:%s", __func__, errmsg);
|
||||||
|
tal_free(ctx);
|
||||||
|
return !errmsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool db_replace_pay_command(struct lightningd_state *dstate,
|
||||||
|
const struct sha256 *rhash,
|
||||||
|
const struct pubkey *ids,
|
||||||
|
u64 msatoshis,
|
||||||
|
const struct htlc *htlc)
|
||||||
|
{
|
||||||
|
const char *errmsg, *ctx = tal(dstate, char);
|
||||||
|
|
||||||
|
log_debug(dstate->base_log, "%s", __func__);
|
||||||
|
log_add_struct(dstate->base_log, "(%s)", struct sha256, rhash);
|
||||||
|
|
||||||
|
assert(!dstate->db->in_transaction);
|
||||||
|
/* CREATE TABLE pay (rhash "SQL_RHASH", msatoshis INT, ids BLOB, htlc_peer "SQL_PUBKEY", htlc_id INT, r "SQL_R", fail BLOB, PRIMARY KEY(rhash)); */
|
||||||
|
errmsg = db_exec(ctx, dstate, "UPDATE pay SET msatoshis=%"PRIu64", ids=x'%s', htlc_peer=x'%s', htlc_id=%"PRIu64", r=NULL, fail=NULL WHERE rhash=x'%s';",
|
||||||
|
msatoshis,
|
||||||
|
pubkeys_to_hex(ctx, dstate->secpctx, ids),
|
||||||
|
pubkey_to_hexstr(ctx, dstate->secpctx, htlc->peer->id),
|
||||||
|
htlc->id,
|
||||||
|
tal_hexstr(ctx, rhash, sizeof(*rhash)));
|
||||||
|
if (errmsg)
|
||||||
|
log_broken(dstate->base_log, "%s:%s", __func__, errmsg);
|
||||||
|
tal_free(ctx);
|
||||||
|
return !errmsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool db_complete_pay_command(struct lightningd_state *dstate,
|
||||||
|
const struct htlc *htlc)
|
||||||
|
{
|
||||||
|
const char *errmsg, *ctx = tal(dstate, char);
|
||||||
|
|
||||||
|
log_debug(dstate->base_log, "%s", __func__);
|
||||||
|
log_add_struct(dstate->base_log, "(%s)", struct sha256, &htlc->rhash);
|
||||||
|
|
||||||
|
assert(dstate->db->in_transaction);
|
||||||
|
/* CREATE TABLE pay (rhash "SQL_RHASH", msatoshis INT, ids BLOB, htlc_peer "SQL_PUBKEY", htlc_id INT, r "SQL_R", fail BLOB, PRIMARY KEY(rhash)); */
|
||||||
|
if (htlc->r)
|
||||||
|
errmsg = db_exec(ctx, dstate,
|
||||||
|
"UPDATE pay SET r=x'%s', htlc_peer=NULL WHERE rhash=x'%s';",
|
||||||
|
tal_hexstr(ctx, htlc->r, sizeof(*htlc->r)),
|
||||||
|
tal_hexstr(ctx, &htlc->rhash, sizeof(htlc->rhash)));
|
||||||
|
else
|
||||||
|
errmsg = db_exec(ctx, dstate,
|
||||||
|
"UPDATE pay SET fail=x'%s', htlc_peer=NULL WHERE rhash=x'%s';",
|
||||||
|
tal_hexstr(ctx, htlc->fail, tal_count(htlc->fail)),
|
||||||
|
tal_hexstr(ctx, &htlc->rhash, sizeof(htlc->rhash)));
|
||||||
|
|
||||||
|
if (errmsg)
|
||||||
|
log_broken(dstate->base_log, "%s:%s", __func__, errmsg);
|
||||||
|
tal_free(ctx);
|
||||||
|
return !errmsg;
|
||||||
|
}
|
||||||
|
|||||||
12
daemon/db.h
12
daemon/db.h
@@ -27,6 +27,16 @@ bool db_set_our_closing_script(struct peer *peer);
|
|||||||
bool db_set_their_closing_script(struct peer *peer);
|
bool db_set_their_closing_script(struct peer *peer);
|
||||||
bool db_update_our_closing(struct peer *peer);
|
bool db_update_our_closing(struct peer *peer);
|
||||||
bool db_update_their_closing(struct peer *peer);
|
bool db_update_their_closing(struct peer *peer);
|
||||||
|
bool db_new_pay_command(struct lightningd_state *dstate,
|
||||||
|
const struct sha256 *rhash,
|
||||||
|
const struct pubkey *ids,
|
||||||
|
u64 msatoshis,
|
||||||
|
const struct htlc *htlc);
|
||||||
|
bool db_replace_pay_command(struct lightningd_state *dstate,
|
||||||
|
const struct sha256 *rhash,
|
||||||
|
const struct pubkey *ids,
|
||||||
|
u64 msatoshis,
|
||||||
|
const struct htlc *htlc);
|
||||||
|
|
||||||
/* FIXME: save error handling until db_commit_transaction for calls
|
/* FIXME: save error handling until db_commit_transaction for calls
|
||||||
* which have to be inside transaction anyway. */
|
* which have to be inside transaction anyway. */
|
||||||
@@ -36,6 +46,8 @@ bool db_new_htlc(struct peer *peer, const struct htlc *htlc);
|
|||||||
bool db_new_feechange(struct peer *peer, const struct feechange *feechange);
|
bool db_new_feechange(struct peer *peer, const struct feechange *feechange);
|
||||||
bool db_update_htlc_state(struct peer *peer, const struct htlc *htlc,
|
bool db_update_htlc_state(struct peer *peer, const struct htlc *htlc,
|
||||||
enum htlc_state oldstate);
|
enum htlc_state oldstate);
|
||||||
|
bool db_complete_pay_command(struct lightningd_state *state,
|
||||||
|
const struct htlc *htlc);
|
||||||
bool db_update_feechange_state(struct peer *peer,
|
bool db_update_feechange_state(struct peer *peer,
|
||||||
const struct feechange *f,
|
const struct feechange *f,
|
||||||
enum htlc_state oldstate);
|
enum htlc_state oldstate);
|
||||||
|
|||||||
103
daemon/pay.c
103
daemon/pay.c
@@ -1,4 +1,5 @@
|
|||||||
#include "chaintopology.h"
|
#include "chaintopology.h"
|
||||||
|
#include "db.h"
|
||||||
#include "failure.h"
|
#include "failure.h"
|
||||||
#include "jsonrpc.h"
|
#include "jsonrpc.h"
|
||||||
#include "lightningd.h"
|
#include "lightningd.h"
|
||||||
@@ -15,15 +16,14 @@
|
|||||||
struct pay_command {
|
struct pay_command {
|
||||||
struct list_node list;
|
struct list_node list;
|
||||||
struct sha256 rhash;
|
struct sha256 rhash;
|
||||||
u64 msatoshis;
|
u64 msatoshi;
|
||||||
struct pubkey *ids;
|
const struct pubkey *ids;
|
||||||
/* Set if this is in progress. */
|
/* Set if this is in progress. */
|
||||||
struct htlc *htlc;
|
struct htlc *htlc;
|
||||||
/* Preimage if this succeeded. */
|
/* Preimage if this succeeded. */
|
||||||
struct rval *rval;
|
const struct rval *rval;
|
||||||
struct command *cmd;
|
struct command *cmd;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void json_pay_success(struct command *cmd, const struct rval *rval)
|
static void json_pay_success(struct command *cmd, const struct rval *rval)
|
||||||
{
|
{
|
||||||
struct json_result *response;
|
struct json_result *response;
|
||||||
@@ -101,6 +101,9 @@ void complete_pay_command(struct lightningd_state *dstate,
|
|||||||
list_for_each(&dstate->pay_commands, i, list) {
|
list_for_each(&dstate->pay_commands, i, list) {
|
||||||
if (i->htlc == htlc) {
|
if (i->htlc == htlc) {
|
||||||
FailInfo *f = NULL;
|
FailInfo *f = NULL;
|
||||||
|
|
||||||
|
db_complete_pay_command(dstate, htlc);
|
||||||
|
|
||||||
if (htlc->r)
|
if (htlc->r)
|
||||||
i->rval = tal_dup(i, struct rval, htlc->r);
|
i->rval = tal_dup(i, struct rval, htlc->r);
|
||||||
else {
|
else {
|
||||||
@@ -119,7 +122,7 @@ void complete_pay_command(struct lightningd_state *dstate,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Can happen if RPC connection goes away. */
|
/* Can happen with testing low-level commands. */
|
||||||
log_unusual(dstate->base_log, "No command for HTLC %"PRIu64" %s",
|
log_unusual(dstate->base_log, "No command for HTLC %"PRIu64" %s",
|
||||||
htlc->id, htlc->r ? "fulfill" : "fail");
|
htlc->id, htlc->r ? "fulfill" : "fail");
|
||||||
}
|
}
|
||||||
@@ -151,6 +154,35 @@ static struct pay_command *find_pay_command(struct lightningd_state *dstate,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For database restore. */
|
||||||
|
bool pay_add(struct lightningd_state *dstate,
|
||||||
|
const struct sha256 *rhash,
|
||||||
|
u64 msatoshi,
|
||||||
|
const struct pubkey *ids,
|
||||||
|
struct htlc *htlc,
|
||||||
|
const u8 *fail UNNEEDED,
|
||||||
|
const struct rval *r)
|
||||||
|
{
|
||||||
|
struct pay_command *pc;
|
||||||
|
|
||||||
|
if (find_pay_command(dstate, rhash))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pc = tal(dstate, struct pay_command);
|
||||||
|
pc->rhash = *rhash;
|
||||||
|
pc->msatoshi = msatoshi;
|
||||||
|
pc->ids = tal_dup_arr(pc, struct pubkey, ids, tal_count(ids), 0);
|
||||||
|
pc->htlc = htlc;
|
||||||
|
if (r)
|
||||||
|
pc->rval = tal_dup(pc, struct rval, r);
|
||||||
|
else
|
||||||
|
pc->rval = NULL;
|
||||||
|
pc->cmd = NULL;
|
||||||
|
|
||||||
|
list_add_tail(&dstate->pay_commands, &pc->list);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void json_add_route(struct json_result *response,
|
static void json_add_route(struct json_result *response,
|
||||||
secp256k1_context *secpctx,
|
secp256k1_context *secpctx,
|
||||||
const struct pubkey *id,
|
const struct pubkey *id,
|
||||||
@@ -158,7 +190,7 @@ static void json_add_route(struct json_result *response,
|
|||||||
{
|
{
|
||||||
json_object_start(response, NULL);
|
json_object_start(response, NULL);
|
||||||
json_add_pubkey(response, secpctx, "id", id);
|
json_add_pubkey(response, secpctx, "id", id);
|
||||||
json_add_u64(response, "msatoshis", amount);
|
json_add_u64(response, "msatoshi", amount);
|
||||||
json_add_num(response, "delay", delay);
|
json_add_num(response, "delay", delay);
|
||||||
json_object_end(response);
|
json_object_end(response);
|
||||||
}
|
}
|
||||||
@@ -167,10 +199,10 @@ static void json_getroute(struct command *cmd,
|
|||||||
const char *buffer, const jsmntok_t *params)
|
const char *buffer, const jsmntok_t *params)
|
||||||
{
|
{
|
||||||
struct pubkey id;
|
struct pubkey id;
|
||||||
jsmntok_t *idtok, *msatoshistok;
|
jsmntok_t *idtok, *msatoshitok;
|
||||||
struct json_result *response;
|
struct json_result *response;
|
||||||
int i;
|
int i;
|
||||||
u64 msatoshis;
|
u64 msatoshi;
|
||||||
s64 fee;
|
s64 fee;
|
||||||
struct node_connection **route;
|
struct node_connection **route;
|
||||||
struct peer *peer;
|
struct peer *peer;
|
||||||
@@ -179,9 +211,9 @@ static void json_getroute(struct command *cmd,
|
|||||||
|
|
||||||
if (!json_get_params(buffer, params,
|
if (!json_get_params(buffer, params,
|
||||||
"id", &idtok,
|
"id", &idtok,
|
||||||
"msatoshis", &msatoshistok,
|
"msatoshi", &msatoshitok,
|
||||||
NULL)) {
|
NULL)) {
|
||||||
command_fail(cmd, "Need id and msatoshis");
|
command_fail(cmd, "Need id and msatoshi");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,14 +224,14 @@ static void json_getroute(struct command *cmd,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!json_tok_u64(buffer, msatoshistok, &msatoshis)) {
|
if (!json_tok_u64(buffer, msatoshitok, &msatoshi)) {
|
||||||
command_fail(cmd, "'%.*s' is not a valid number",
|
command_fail(cmd, "'%.*s' is not a valid number",
|
||||||
(int)(msatoshistok->end - msatoshistok->start),
|
(int)(msatoshitok->end - msatoshitok->start),
|
||||||
buffer + msatoshistok->start);
|
buffer + msatoshitok->start);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
peer = find_route(cmd->dstate, &id, msatoshis, &fee, &route);
|
peer = find_route(cmd->dstate, &id, msatoshi, &fee, &route);
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
command_fail(cmd, "no route found");
|
command_fail(cmd, "no route found");
|
||||||
return;
|
return;
|
||||||
@@ -208,7 +240,7 @@ static void json_getroute(struct command *cmd,
|
|||||||
/* Fees, delays need to be calculated backwards along route. */
|
/* Fees, delays need to be calculated backwards along route. */
|
||||||
amounts = tal_arr(cmd, u64, tal_count(route)+1);
|
amounts = tal_arr(cmd, u64, tal_count(route)+1);
|
||||||
delays = tal_arr(cmd, unsigned int, tal_count(route)+1);
|
delays = tal_arr(cmd, unsigned int, tal_count(route)+1);
|
||||||
total_amount = msatoshis;
|
total_amount = msatoshi;
|
||||||
|
|
||||||
total_delay = 0;
|
total_delay = 0;
|
||||||
for (i = tal_count(route) - 1; i >= 0; i--) {
|
for (i = tal_count(route) - 1; i >= 0; i--) {
|
||||||
@@ -244,8 +276,8 @@ static void json_getroute(struct command *cmd,
|
|||||||
const struct json_command getroute_command = {
|
const struct json_command getroute_command = {
|
||||||
"getroute",
|
"getroute",
|
||||||
json_getroute,
|
json_getroute,
|
||||||
"Return route for {msatoshis} to {id}",
|
"Return route for {msatoshi} to {id}",
|
||||||
"Returns a {route} array of {id} {msatoshis} {delay}: msatoshis and delay (in blocks) is cumulative."
|
"Returns a {route} array of {id} {msatoshi} {delay}: msatoshi and delay (in blocks) is cumulative."
|
||||||
};
|
};
|
||||||
|
|
||||||
static void json_sendpay(struct command *cmd,
|
static void json_sendpay(struct command *cmd,
|
||||||
@@ -260,6 +292,7 @@ static void json_sendpay(struct command *cmd,
|
|||||||
struct sha256 rhash;
|
struct sha256 rhash;
|
||||||
struct peer *peer;
|
struct peer *peer;
|
||||||
struct pay_command *pc;
|
struct pay_command *pc;
|
||||||
|
bool replacing = false;
|
||||||
const u8 *onion;
|
const u8 *onion;
|
||||||
enum fail_error error_code;
|
enum fail_error error_code;
|
||||||
const char *err;
|
const char *err;
|
||||||
@@ -302,18 +335,18 @@ static void json_sendpay(struct command *cmd,
|
|||||||
buffer + t->start);
|
buffer + t->start);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
amttok = json_get_member(buffer, t, "msatoshis");
|
amttok = json_get_member(buffer, t, "msatoshi");
|
||||||
idtok = json_get_member(buffer, t, "id");
|
idtok = json_get_member(buffer, t, "id");
|
||||||
delaytok = json_get_member(buffer, t, "delay");
|
delaytok = json_get_member(buffer, t, "delay");
|
||||||
if (!amttok || !idtok || !delaytok) {
|
if (!amttok || !idtok || !delaytok) {
|
||||||
command_fail(cmd, "route %zu needs msatoshis/id/delay",
|
command_fail(cmd, "route %zu needs msatoshi/id/delay",
|
||||||
n_hops);
|
n_hops);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tal_resize(&amounts, n_hops+1);
|
tal_resize(&amounts, n_hops+1);
|
||||||
if (!json_tok_u64(buffer, amttok, &amounts[n_hops])) {
|
if (!json_tok_u64(buffer, amttok, &amounts[n_hops])) {
|
||||||
command_fail(cmd, "route %zu invalid msatoshis", n_hops);
|
command_fail(cmd, "route %zu invalid msatoshi", n_hops);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tal_resize(&ids, n_hops+1);
|
tal_resize(&ids, n_hops+1);
|
||||||
@@ -339,6 +372,7 @@ static void json_sendpay(struct command *cmd,
|
|||||||
|
|
||||||
pc = find_pay_command(cmd->dstate, &rhash);
|
pc = find_pay_command(cmd->dstate, &rhash);
|
||||||
if (pc) {
|
if (pc) {
|
||||||
|
replacing = true;
|
||||||
log_debug(cmd->dstate->base_log, "json_sendpay: found previous");
|
log_debug(cmd->dstate->base_log, "json_sendpay: found previous");
|
||||||
if (pc->htlc) {
|
if (pc->htlc) {
|
||||||
log_add(cmd->dstate->base_log, "... still in progress");
|
log_add(cmd->dstate->base_log, "... still in progress");
|
||||||
@@ -349,10 +383,10 @@ static void json_sendpay(struct command *cmd,
|
|||||||
size_t old_nhops = tal_count(pc->ids);
|
size_t old_nhops = tal_count(pc->ids);
|
||||||
log_add(cmd->dstate->base_log, "... succeeded");
|
log_add(cmd->dstate->base_log, "... succeeded");
|
||||||
/* Must match successful payment parameters. */
|
/* Must match successful payment parameters. */
|
||||||
if (pc->msatoshis != amounts[n_hops-1]) {
|
if (pc->msatoshi != amounts[n_hops-1]) {
|
||||||
command_fail(cmd,
|
command_fail(cmd,
|
||||||
"already succeeded with amount %"
|
"already succeeded with amount %"
|
||||||
PRIu64, pc->msatoshis);
|
PRIu64, pc->msatoshi);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!structeq(&pc->ids[old_nhops-1], &ids[n_hops-1])) {
|
if (!structeq(&pc->ids[old_nhops-1], &ids[n_hops-1])) {
|
||||||
@@ -389,7 +423,7 @@ static void json_sendpay(struct command *cmd,
|
|||||||
pc->rhash = rhash;
|
pc->rhash = rhash;
|
||||||
pc->rval = NULL;
|
pc->rval = NULL;
|
||||||
pc->ids = tal_steal(pc, ids);
|
pc->ids = tal_steal(pc, ids);
|
||||||
pc->msatoshis = amounts[n_hops-1];
|
pc->msatoshi = amounts[n_hops-1];
|
||||||
|
|
||||||
/* Expiry for HTLCs is absolute. And add one to give some margin. */
|
/* Expiry for HTLCs is absolute. And add one to give some margin. */
|
||||||
err = command_htlc_add(peer, amounts[0],
|
err = command_htlc_add(peer, amounts[0],
|
||||||
@@ -398,9 +432,32 @@ static void json_sendpay(struct command *cmd,
|
|||||||
onion, &error_code, &pc->htlc);
|
onion, &error_code, &pc->htlc);
|
||||||
if (err) {
|
if (err) {
|
||||||
command_fail(cmd, "could not add htlc: %u: %s", error_code, err);
|
command_fail(cmd, "could not add htlc: %u: %s", error_code, err);
|
||||||
|
tal_free(pc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (replacing) {
|
||||||
|
if (!db_replace_pay_command(cmd->dstate, &pc->rhash,
|
||||||
|
pc->ids, pc->msatoshi,
|
||||||
|
pc->htlc)) {
|
||||||
|
command_fail(cmd, "database error");
|
||||||
|
/* We could reconnect, but db error is *bad*. */
|
||||||
|
peer_fail(peer, __func__);
|
||||||
|
tal_free(pc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!db_new_pay_command(cmd->dstate, &pc->rhash,
|
||||||
|
pc->ids, pc->msatoshi,
|
||||||
|
pc->htlc)) {
|
||||||
|
command_fail(cmd, "database error");
|
||||||
|
/* We could reconnect, but db error is *bad*. */
|
||||||
|
peer_fail(peer, __func__);
|
||||||
|
tal_free(pc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Wait until we get response. */
|
/* Wait until we get response. */
|
||||||
list_add_tail(&cmd->dstate->pay_commands, &pc->list);
|
list_add_tail(&cmd->dstate->pay_commands, &pc->list);
|
||||||
tal_add_destructor(cmd, remove_cmd_from_pc);
|
tal_add_destructor(cmd, remove_cmd_from_pc);
|
||||||
|
|||||||
@@ -8,4 +8,12 @@ struct htlc;
|
|||||||
void complete_pay_command(struct lightningd_state *dstate,
|
void complete_pay_command(struct lightningd_state *dstate,
|
||||||
const struct htlc *htlc);
|
const struct htlc *htlc);
|
||||||
|
|
||||||
|
bool pay_add(struct lightningd_state *dstate,
|
||||||
|
const struct sha256 *rhash,
|
||||||
|
u64 msatoshi,
|
||||||
|
const struct pubkey *ids,
|
||||||
|
struct htlc *htlc,
|
||||||
|
const u8 *fail,
|
||||||
|
const struct rval *r);
|
||||||
|
|
||||||
#endif /* LIGHTNING_DAEMON_PAY_H */
|
#endif /* LIGHTNING_DAEMON_PAY_H */
|
||||||
|
|||||||
@@ -1010,9 +1010,6 @@ if [ ! -n "$MANUALCOMMIT" ]; then
|
|||||||
lcli1 add-route $ID2 $ID3 546000 10 36 36
|
lcli1 add-route $ID2 $ID3 546000 10 36 36
|
||||||
RHASH5=`lcli3 accept-payment $HTLC_AMOUNT | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
|
RHASH5=`lcli3 accept-payment $HTLC_AMOUNT | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
|
||||||
|
|
||||||
# FIXME: We don't save payments in db yet!
|
|
||||||
DO_RECONNECT=""
|
|
||||||
|
|
||||||
# Get route.
|
# Get route.
|
||||||
ROUTE=`lcli1 getroute $ID3 $HTLC_AMOUNT`
|
ROUTE=`lcli1 getroute $ID3 $HTLC_AMOUNT`
|
||||||
ROUTE=`echo $ROUTE | sed 's/^{ "route" : \(.*\) }$/\1/'`
|
ROUTE=`echo $ROUTE | sed 's/^{ "route" : \(.*\) }$/\1/'`
|
||||||
@@ -1061,8 +1058,6 @@ if [ ! -n "$MANUALCOMMIT" ]; then
|
|||||||
echo "Pay to node3 didn't fail instantly second time" >&2
|
echo "Pay to node3 didn't fail instantly second time" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DO_RECONNECT=$RECONNECT
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
lcli1 close $ID2
|
lcli1 close $ID2
|
||||||
|
|||||||
Reference in New Issue
Block a user