mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 23:24:27 +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 "netaddr.h"
|
||||
#include "pay.h"
|
||||
#include "payment.h"
|
||||
#include "routing.h"
|
||||
#include "secrets.h"
|
||||
#include "utils.h"
|
||||
@@ -1071,6 +1072,40 @@ static void db_load_pay(struct lightningd_state *dstate)
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
@@ -1112,6 +1147,7 @@ static void db_load(struct lightningd_state *dstate)
|
||||
db_load_addresses(dstate);
|
||||
db_load_peers(dstate);
|
||||
db_load_pay(dstate);
|
||||
db_load_payment(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_U64(htlc_id), SQL_R(r), SQL_FAIL(fail),
|
||||
"PRIMARY KEY(rhash)")
|
||||
TABLE(payment,
|
||||
SQL_R(r), SQL_U64(msatoshis), SQL_BOOL(complete),
|
||||
"PRIMARY KEY(r)")
|
||||
TABLE(anchors,
|
||||
SQL_PUBKEY(peer),
|
||||
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);
|
||||
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,
|
||||
u64 msatoshis,
|
||||
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
|
||||
* 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_update_htlc_state(struct peer *peer, const struct htlc *htlc,
|
||||
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);
|
||||
bool db_resolve_payment(struct lightningd_state *dstate, const struct rval *r);
|
||||
bool db_update_feechange_state(struct peer *peer,
|
||||
const struct feechange *f,
|
||||
enum htlc_state oldstate);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "db.h"
|
||||
#include "jsonrpc.h"
|
||||
#include "lightningd.h"
|
||||
#include "payment.h"
|
||||
@@ -17,6 +18,20 @@ struct payment *find_payment(struct lightningd_state *dstate,
|
||||
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,
|
||||
const char *buffer, const jsmntok_t *params)
|
||||
{
|
||||
@@ -57,7 +72,12 @@ static void json_accept_payment(struct command *cmd,
|
||||
buffer + msatoshis->start);
|
||||
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 */
|
||||
tal_steal(cmd->dstate, payment);
|
||||
list_add(&cmd->dstate->payments, &payment->list);
|
||||
|
||||
@@ -10,8 +10,15 @@ struct payment {
|
||||
u64 msatoshis;
|
||||
struct rval r;
|
||||
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,
|
||||
const struct sha256 *rhash);
|
||||
|
||||
|
||||
@@ -560,9 +560,28 @@ static void their_htlc_added(struct peer *peer, struct htlc *htlc,
|
||||
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,
|
||||
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);
|
||||
command_htlc_fulfill(peer, htlc);
|
||||
goto free_rest;
|
||||
|
||||
@@ -386,9 +386,10 @@ EOF
|
||||
cp $DIR2/config $DIR3/config
|
||||
|
||||
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.
|
||||
echo port=`findport 4000` >> $DIR2/config
|
||||
echo port=`findport 4010` >> $DIR3/config
|
||||
fi
|
||||
|
||||
if [ -n "$DIFFERENT_FEES" ]; then
|
||||
@@ -418,7 +419,8 @@ else
|
||||
LIGHTNINGD2="$PREFIX $LIGHTNINGD2"
|
||||
$LIGHTNINGD2 > $REDIR2 2> $REDIRERR2 &
|
||||
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
|
||||
echo Failed to start daemon 1 >&2
|
||||
@@ -1028,6 +1030,15 @@ if [ ! -n "$MANUALCOMMIT" ]; then
|
||||
exit 1
|
||||
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.
|
||||
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
|
||||
# starts.
|
||||
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
|
||||
|
||||
# Re-send should be a noop (doesn't matter that node3 is down!)
|
||||
|
||||
Reference in New Issue
Block a user