mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 07:34:24 +01:00
db: save and restore accepted payments.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
76
daemon/db.c
76
daemon/db.c
@@ -8,6 +8,7 @@
|
|||||||
#include "names.h"
|
#include "names.h"
|
||||||
#include "netaddr.h"
|
#include "netaddr.h"
|
||||||
#include "pay.h"
|
#include "pay.h"
|
||||||
|
#include "payment.h"
|
||||||
#include "routing.h"
|
#include "routing.h"
|
||||||
#include "secrets.h"
|
#include "secrets.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
@@ -1071,6 +1072,40 @@ static void db_load_pay(struct lightningd_state *dstate)
|
|||||||
tal_free(ctx);
|
tal_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void db_load_payment(struct lightningd_state *dstate)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
sqlite3_stmt *stmt;
|
||||||
|
char *ctx = tal(dstate, char);
|
||||||
|
|
||||||
|
err = sqlite3_prepare_v2(dstate->db->sql, "SELECT * FROM payment;", -1,
|
||||||
|
&stmt, NULL);
|
||||||
|
|
||||||
|
if (err != SQLITE_OK)
|
||||||
|
fatal("db_load_payment:prepare gave %s:%s",
|
||||||
|
sqlite3_errstr(err), sqlite3_errmsg(dstate->db->sql));
|
||||||
|
|
||||||
|
while ((err = sqlite3_step(stmt)) != SQLITE_DONE) {
|
||||||
|
struct rval r;
|
||||||
|
u64 msatoshis;
|
||||||
|
bool complete;
|
||||||
|
|
||||||
|
if (err != SQLITE_ROW)
|
||||||
|
fatal("db_load_payment:step gave %s:%s",
|
||||||
|
sqlite3_errstr(err),
|
||||||
|
sqlite3_errmsg(dstate->db->sql));
|
||||||
|
if (sqlite3_column_count(stmt) != 3)
|
||||||
|
fatal("db_load_pay:step gave %i cols, not 3",
|
||||||
|
sqlite3_column_count(stmt));
|
||||||
|
|
||||||
|
from_sql_blob(stmt, 0, &r, sizeof(r));
|
||||||
|
msatoshis = sqlite3_column_int64(stmt, 1);
|
||||||
|
complete = sqlite3_column_int(stmt, 2);
|
||||||
|
payment_add(dstate, &r, msatoshis, complete);
|
||||||
|
}
|
||||||
|
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;
|
||||||
@@ -1112,6 +1147,7 @@ static void db_load(struct lightningd_state *dstate)
|
|||||||
db_load_addresses(dstate);
|
db_load_addresses(dstate);
|
||||||
db_load_peers(dstate);
|
db_load_peers(dstate);
|
||||||
db_load_pay(dstate);
|
db_load_pay(dstate);
|
||||||
|
db_load_payment(dstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void db_init(struct lightningd_state *dstate)
|
void db_init(struct lightningd_state *dstate)
|
||||||
@@ -1158,6 +1194,9 @@ void db_init(struct lightningd_state *dstate)
|
|||||||
SQL_BLOB(ids), SQL_PUBKEY(htlc_peer),
|
SQL_BLOB(ids), SQL_PUBKEY(htlc_peer),
|
||||||
SQL_U64(htlc_id), SQL_R(r), SQL_FAIL(fail),
|
SQL_U64(htlc_id), SQL_R(r), SQL_FAIL(fail),
|
||||||
"PRIMARY KEY(rhash)")
|
"PRIMARY KEY(rhash)")
|
||||||
|
TABLE(payment,
|
||||||
|
SQL_R(r), SQL_U64(msatoshis), SQL_BOOL(complete),
|
||||||
|
"PRIMARY KEY(r)")
|
||||||
TABLE(anchors,
|
TABLE(anchors,
|
||||||
SQL_PUBKEY(peer),
|
SQL_PUBKEY(peer),
|
||||||
SQL_TXID(txid), SQL_U32(idx), SQL_U64(amount),
|
SQL_TXID(txid), SQL_U32(idx), SQL_U64(amount),
|
||||||
@@ -1886,3 +1925,40 @@ bool db_complete_pay_command(struct lightningd_state *dstate,
|
|||||||
tal_free(ctx);
|
tal_free(ctx);
|
||||||
return !errmsg;
|
return !errmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool db_new_payment(struct lightningd_state *dstate,
|
||||||
|
u64 msatoshis,
|
||||||
|
const struct rval *r)
|
||||||
|
{
|
||||||
|
const char *errmsg, *ctx = tal(dstate, char);
|
||||||
|
|
||||||
|
log_debug(dstate->base_log, "%s", __func__);
|
||||||
|
|
||||||
|
assert(!dstate->db->in_transaction);
|
||||||
|
|
||||||
|
errmsg = db_exec(ctx, dstate, "INSERT INTO payment VALUES (x'%s', %"PRIu64", %s);",
|
||||||
|
tal_hexstr(ctx, r, sizeof(*r)),
|
||||||
|
msatoshis,
|
||||||
|
sql_bool(false));
|
||||||
|
if (errmsg)
|
||||||
|
log_broken(dstate->base_log, "%s:%s", __func__, errmsg);
|
||||||
|
tal_free(ctx);
|
||||||
|
return !errmsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool db_resolve_payment(struct lightningd_state *dstate, const struct rval *r)
|
||||||
|
{
|
||||||
|
const char *errmsg, *ctx = tal(dstate, char);
|
||||||
|
|
||||||
|
log_debug(dstate->base_log, "%s", __func__);
|
||||||
|
|
||||||
|
assert(dstate->db->in_transaction);
|
||||||
|
|
||||||
|
errmsg = db_exec(ctx, dstate, "UPDATE payment SET complete=%s WHERE r=x'%s';",
|
||||||
|
sql_bool(true),
|
||||||
|
tal_hexstr(ctx, r, sizeof(*r)));
|
||||||
|
if (errmsg)
|
||||||
|
log_broken(dstate->base_log, "%s:%s", __func__, errmsg);
|
||||||
|
tal_free(ctx);
|
||||||
|
return !errmsg;
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ bool db_replace_pay_command(struct lightningd_state *dstate,
|
|||||||
const struct pubkey *ids,
|
const struct pubkey *ids,
|
||||||
u64 msatoshis,
|
u64 msatoshis,
|
||||||
const struct htlc *htlc);
|
const struct htlc *htlc);
|
||||||
|
bool db_new_payment(struct lightningd_state *dstate,
|
||||||
|
u64 msatoshis,
|
||||||
|
const struct rval *r);
|
||||||
|
|
||||||
/* 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. */
|
||||||
@@ -46,8 +49,9 @@ 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,
|
bool db_complete_pay_command(struct lightningd_state *dstate,
|
||||||
const struct htlc *htlc);
|
const struct htlc *htlc);
|
||||||
|
bool db_resolve_payment(struct lightningd_state *dstate, const struct rval *r);
|
||||||
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);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "db.h"
|
||||||
#include "jsonrpc.h"
|
#include "jsonrpc.h"
|
||||||
#include "lightningd.h"
|
#include "lightningd.h"
|
||||||
#include "payment.h"
|
#include "payment.h"
|
||||||
@@ -17,6 +18,20 @@ struct payment *find_payment(struct lightningd_state *dstate,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void payment_add(struct lightningd_state *dstate,
|
||||||
|
const struct rval *r,
|
||||||
|
u64 msatoshis,
|
||||||
|
bool complete)
|
||||||
|
{
|
||||||
|
struct payment *payment = tal(dstate, struct payment);
|
||||||
|
|
||||||
|
payment->msatoshis = msatoshis;
|
||||||
|
payment->r = *r;
|
||||||
|
payment->complete = complete;
|
||||||
|
sha256(&payment->rhash, payment->r.r, sizeof(payment->r.r));
|
||||||
|
list_add(&dstate->payments, &payment->list);
|
||||||
|
}
|
||||||
|
|
||||||
static void json_accept_payment(struct command *cmd,
|
static void json_accept_payment(struct command *cmd,
|
||||||
const char *buffer, const jsmntok_t *params)
|
const char *buffer, const jsmntok_t *params)
|
||||||
{
|
{
|
||||||
@@ -57,7 +72,12 @@ static void json_accept_payment(struct command *cmd,
|
|||||||
buffer + msatoshis->start);
|
buffer + msatoshis->start);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
payment->complete = false;
|
||||||
|
|
||||||
|
if (!db_new_payment(cmd->dstate, payment->msatoshis, &payment->r)) {
|
||||||
|
command_fail(cmd, "database error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* OK, connect it to main state, respond with hash */
|
/* OK, connect it to main state, respond with hash */
|
||||||
tal_steal(cmd->dstate, payment);
|
tal_steal(cmd->dstate, payment);
|
||||||
list_add(&cmd->dstate->payments, &payment->list);
|
list_add(&cmd->dstate->payments, &payment->list);
|
||||||
|
|||||||
@@ -10,8 +10,15 @@ struct payment {
|
|||||||
u64 msatoshis;
|
u64 msatoshis;
|
||||||
struct rval r;
|
struct rval r;
|
||||||
struct sha256 rhash;
|
struct sha256 rhash;
|
||||||
|
bool complete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* From database */
|
||||||
|
void payment_add(struct lightningd_state *dstate,
|
||||||
|
const struct rval *r,
|
||||||
|
u64 msatoshis,
|
||||||
|
bool complete);
|
||||||
|
|
||||||
struct payment *find_payment(struct lightningd_state *dstate,
|
struct payment *find_payment(struct lightningd_state *dstate,
|
||||||
const struct sha256 *rhash);
|
const struct sha256 *rhash);
|
||||||
|
|
||||||
|
|||||||
@@ -560,9 +560,28 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is a courtesy: we could simply take your money! */
|
||||||
|
if (payment->complete) {
|
||||||
|
log_unusual(peer->log,
|
||||||
|
"Repeated payment for HTLC %"PRIu64,
|
||||||
|
htlc->id);
|
||||||
|
command_htlc_set_fail(peer, htlc,
|
||||||
|
UNAUTHORIZED_401,
|
||||||
|
"already received payment");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log_info(peer->log, "Immediately resolving HTLC %"PRIu64,
|
log_info(peer->log, "Immediately resolving HTLC %"PRIu64,
|
||||||
htlc->id);
|
htlc->id);
|
||||||
|
|
||||||
|
if (!db_resolve_payment(peer->dstate, &payment->r)) {
|
||||||
|
command_htlc_set_fail(peer, htlc,
|
||||||
|
INTERNAL_SERVER_ERROR_500,
|
||||||
|
"database error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
payment->complete = true;
|
||||||
set_htlc_rval(peer, htlc, &payment->r);
|
set_htlc_rval(peer, htlc, &payment->r);
|
||||||
command_htlc_fulfill(peer, htlc);
|
command_htlc_fulfill(peer, htlc);
|
||||||
goto free_rest;
|
goto free_rest;
|
||||||
|
|||||||
@@ -386,9 +386,10 @@ EOF
|
|||||||
cp $DIR2/config $DIR3/config
|
cp $DIR2/config $DIR3/config
|
||||||
|
|
||||||
if [ x"$RECONNECT" = xrestart ]; then
|
if [ x"$RECONNECT" = xrestart ]; then
|
||||||
# Make sure node2 restarts on same port, by setting in config.
|
# Make sure node2 & 3 restart on same port, by setting in config.
|
||||||
# Find a free TCP port.
|
# Find a free TCP port.
|
||||||
echo port=`findport 4000` >> $DIR2/config
|
echo port=`findport 4000` >> $DIR2/config
|
||||||
|
echo port=`findport 4010` >> $DIR3/config
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$DIFFERENT_FEES" ]; then
|
if [ -n "$DIFFERENT_FEES" ]; then
|
||||||
@@ -418,7 +419,8 @@ else
|
|||||||
LIGHTNINGD2="$PREFIX $LIGHTNINGD2"
|
LIGHTNINGD2="$PREFIX $LIGHTNINGD2"
|
||||||
$LIGHTNINGD2 > $REDIR2 2> $REDIRERR2 &
|
$LIGHTNINGD2 > $REDIR2 2> $REDIRERR2 &
|
||||||
fi
|
fi
|
||||||
$PREFIX ../lightningd --lightning-dir=$DIR3 > $DIR3/output 2> $DIR3/errors &
|
LIGHTNINGD3="$PREFIX $(readlink -f `pwd`/../lightningd) --lightning-dir=$DIR3"
|
||||||
|
$LIGHTNINGD3 > $DIR3/output 2> $DIR3/errors &
|
||||||
|
|
||||||
if ! check "$LCLI1 getlog 2>/dev/null | $FGREP Hello"; then
|
if ! check "$LCLI1 getlog 2>/dev/null | $FGREP Hello"; then
|
||||||
echo Failed to start daemon 1 >&2
|
echo Failed to start daemon 1 >&2
|
||||||
@@ -1028,6 +1030,15 @@ if [ ! -n "$MANUALCOMMIT" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# If restarting, make sure node3 remembers incoming payment.
|
||||||
|
if [ "$RECONNECT" = restart ]; then
|
||||||
|
$LCLI3 -- dev-restart $LIGHTNINGD3 >/dev/null 2>&1 || true
|
||||||
|
if ! check "$LCLI3 getpeers | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then
|
||||||
|
echo "Failed to reconnect!">&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Pay correctly.
|
# Pay correctly.
|
||||||
lcli1 sendpay "$ROUTE" $RHASH5
|
lcli1 sendpay "$ROUTE" $RHASH5
|
||||||
|
|
||||||
@@ -1035,6 +1046,25 @@ if [ ! -n "$MANUALCOMMIT" ]; then
|
|||||||
# Note that it is delayed a little, since node2 fulfils as soon as fulfill
|
# Note that it is delayed a little, since node2 fulfils as soon as fulfill
|
||||||
# starts.
|
# starts.
|
||||||
check lcli3 "getpeers | $FGREP \"\\\"our_amount\\\" : $(($HTLC_AMOUNT - $NO_HTLCS_FEE / 2))\""
|
check lcli3 "getpeers | $FGREP \"\\\"our_amount\\\" : $(($HTLC_AMOUNT - $NO_HTLCS_FEE / 2))\""
|
||||||
|
|
||||||
|
# If restarting, make sure node3 remembers completed payment.
|
||||||
|
if [ "$RECONNECT" = restart ]; then
|
||||||
|
echo RESTARTING NODE3
|
||||||
|
$LCLI3 -- dev-restart $LIGHTNINGD3 >/dev/null 2>&1 || true
|
||||||
|
if ! check "$LCLI3 getpeers 2>/dev/null | tr -s '\012\011\" ' ' ' | fgrep -q 'connected : true'"; then
|
||||||
|
echo "Failed to reconnect!">&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Can't pay twice (try from node2)
|
||||||
|
ROUTE2=`lcli2 getroute $ID3 $HTLC_AMOUNT`
|
||||||
|
ROUTE2=`echo $ROUTE2 | sed 's/^{ "route" : \(.*\) }$/\1/'`
|
||||||
|
if lcli2 sendpay "$ROUTE2" $RHASH5; then
|
||||||
|
echo "Paying twice worked?" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
lcli3 close $ID2
|
lcli3 close $ID2
|
||||||
|
|
||||||
# Re-send should be a noop (doesn't matter that node3 is down!)
|
# Re-send should be a noop (doesn't matter that node3 is down!)
|
||||||
|
|||||||
Reference in New Issue
Block a user