Browse Source

db: save and restore accepted payments.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
ab125f709b
  1. 76
      daemon/db.c
  2. 6
      daemon/db.h
  3. 20
      daemon/payment.c
  4. 7
      daemon/payment.h
  5. 19
      daemon/peer.c
  6. 34
      daemon/test/test.sh

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;
}

6
daemon/db.h

@ -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);

20
daemon/payment.c

@ -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);

7
daemon/payment.h

@ -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);

19
daemon/peer.c

@ -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;

34
daemon/test/test.sh

@ -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!)

Loading…
Cancel
Save