Browse Source

pay: Save nodes and channels used on route to payment.

ppa-0.6.1
ZmnSCPxj 7 years ago
committed by Rusty Russell
parent
commit
299b280f78
  1. 8
      lightningd/pay.c
  2. 102
      wallet/db.c
  3. 10
      wallet/db.h
  4. 18
      wallet/wallet.c
  5. 3
      wallet/wallet.h

8
lightningd/pay.c

@ -131,6 +131,7 @@ static bool send_payment(struct command *cmd,
struct pubkey *ids = tal_arr(tmpctx, struct pubkey, n_hops); struct pubkey *ids = tal_arr(tmpctx, struct pubkey, n_hops);
struct wallet_payment *payment = NULL; struct wallet_payment *payment = NULL;
struct htlc_out *hout; struct htlc_out *hout;
struct short_channel_id *channels;
/* Expiry for HTLCs is absolute. And add one to give some margin. */ /* Expiry for HTLCs is absolute. And add one to give some margin. */
base_expiry = get_block_height(cmd->ld->topology) + 1; base_expiry = get_block_height(cmd->ld->topology) + 1;
@ -213,6 +214,11 @@ static bool send_payment(struct command *cmd,
return false; return false;
} }
/* Copy channels used along the route. */
channels = tal_arr(tmpctx, struct short_channel_id, n_hops);
for (i = 0; i < n_hops; ++i)
channels[i] = route[i].channel_id;
/* If hout fails, payment should be freed too. */ /* If hout fails, payment should be freed too. */
payment = tal(hout, struct wallet_payment); payment = tal(hout, struct wallet_payment);
payment->id = 0; payment->id = 0;
@ -223,6 +229,8 @@ static bool send_payment(struct command *cmd,
payment->timestamp = time_now().ts.tv_sec; payment->timestamp = time_now().ts.tv_sec;
payment->payment_preimage = NULL; payment->payment_preimage = NULL;
payment->path_secrets = tal_steal(payment, path_secrets); payment->path_secrets = tal_steal(payment, path_secrets);
payment->route_nodes = tal_steal(payment, ids);
payment->route_channels = tal_steal(payment, channels);
/* We write this into db when HTLC is actually sent. */ /* We write this into db when HTLC is actually sent. */
wallet_payment_setup(cmd->ld->wallet, payment); wallet_payment_setup(cmd->ld->wallet, payment);

102
wallet/db.c

@ -183,6 +183,12 @@ char *dbmigrations[] = {
"UPDATE invoices" "UPDATE invoices"
" SET paid_timestamp = strftime('%s', 'now')" " SET paid_timestamp = strftime('%s', 'now')"
" WHERE state = 1;", " WHERE state = 1;",
/* We need to keep the route node pubkeys and short channel ids to
* correctly mark routing failures. We separate short channel ids
* because we cannot safely save them as blobs due to byteorder
* concerns. */
"ALTER TABLE payments ADD COLUMN route_nodes BLOB;",
"ALTER TABLE payments ADD COLUMN route_channels TEXT;",
NULL, NULL,
}; };
@ -454,6 +460,56 @@ bool sqlite3_column_short_channel_id(sqlite3_stmt *stmt, int col,
size_t sourcelen = sqlite3_column_bytes(stmt, col); size_t sourcelen = sqlite3_column_bytes(stmt, col);
return short_channel_id_from_str(source, sourcelen, dest); return short_channel_id_from_str(source, sourcelen, dest);
} }
bool sqlite3_bind_short_channel_id_array(sqlite3_stmt *stmt, int col,
const struct short_channel_id *id)
{
u8 *ser;
size_t num;
size_t i;
/* Handle nulls early. */
if (!id) {
sqlite3_bind_null(stmt, col);
return true;
}
ser = tal_arr(NULL, u8, 0);
num = tal_count(id);
for (i = 0; i < num; ++i)
towire_short_channel_id(&ser, &id[i]);
sqlite3_bind_blob(stmt, col, ser, tal_len(ser), SQLITE_TRANSIENT);
tal_free(ser);
return true;
}
struct short_channel_id *
sqlite3_column_short_channel_id_array(const tal_t *ctx,
sqlite3_stmt *stmt, int col)
{
const u8 *ser;
size_t len;
struct short_channel_id *ret;
size_t n;
/* Handle nulls early. */
if (sqlite3_column_type(stmt, col) == SQLITE_NULL)
return NULL;
ser = sqlite3_column_blob(stmt, col);
len = sqlite3_column_bytes(stmt, col);
ret = tal_arr(ctx, struct short_channel_id, 0);
n = 0;
while (len != 0) {
tal_resize(&ret, n + 1);
fromwire_short_channel_id(&ser, &len, &ret[n]);
++n;
}
return ret;
}
bool sqlite3_bind_tx(sqlite3_stmt *stmt, int col, const struct bitcoin_tx *tx) bool sqlite3_bind_tx(sqlite3_stmt *stmt, int col, const struct bitcoin_tx *tx)
{ {
@ -503,6 +559,52 @@ bool sqlite3_bind_pubkey(sqlite3_stmt *stmt, int col, const struct pubkey *pk)
return true; return true;
} }
bool sqlite3_bind_pubkey_array(sqlite3_stmt *stmt, int col,
const struct pubkey *pks)
{
size_t n;
size_t i;
u8 *ders;
if (!pks) {
sqlite3_bind_null(stmt, col);
return true;
}
n = tal_count(pks);
ders = tal_arr(NULL, u8, n * PUBKEY_DER_LEN);
for (i = 0; i < n; ++i)
pubkey_to_der(&ders[i * PUBKEY_DER_LEN], &pks[i]);
sqlite3_bind_blob(stmt, col, ders, tal_len(ders), SQLITE_TRANSIENT);
tal_free(ders);
return true;
}
struct pubkey *sqlite3_column_pubkey_array(const tal_t *ctx,
sqlite3_stmt *stmt, int col)
{
size_t i;
size_t n;
struct pubkey *ret;
const u8 *ders;
if (sqlite3_column_type(stmt, col) == SQLITE_NULL)
return NULL;
n = sqlite3_column_bytes(stmt, col) / PUBKEY_DER_LEN;
assert(n * PUBKEY_DER_LEN == sqlite3_column_bytes(stmt, col));
ret = tal_arr(ctx, struct pubkey, n);
ders = sqlite3_column_blob(stmt, col);
for (i = 0; i < n; ++i) {
if (!pubkey_from_der(&ders[i * PUBKEY_DER_LEN], PUBKEY_DER_LEN, &ret[i]))
return tal_free(ret);
}
return ret;
}
bool sqlite3_column_preimage(sqlite3_stmt *stmt, int col, struct preimage *dest) bool sqlite3_column_preimage(sqlite3_stmt *stmt, int col, struct preimage *dest)
{ {
assert(sqlite3_column_bytes(stmt, col) == sizeof(struct preimage)); assert(sqlite3_column_bytes(stmt, col) == sizeof(struct preimage));

10
wallet/db.h

@ -117,6 +117,11 @@ bool sqlite3_bind_short_channel_id(sqlite3_stmt *stmt, int col,
const struct short_channel_id *id); const struct short_channel_id *id);
bool sqlite3_column_short_channel_id(sqlite3_stmt *stmt, int col, bool sqlite3_column_short_channel_id(sqlite3_stmt *stmt, int col,
struct short_channel_id *dest); struct short_channel_id *dest);
bool sqlite3_bind_short_channel_id_array(sqlite3_stmt *stmt, int col,
const struct short_channel_id *id);
struct short_channel_id *
sqlite3_column_short_channel_id_array(const tal_t *ctx,
sqlite3_stmt *stmt, int col);
bool sqlite3_bind_tx(sqlite3_stmt *stmt, int col, const struct bitcoin_tx *tx); bool sqlite3_bind_tx(sqlite3_stmt *stmt, int col, const struct bitcoin_tx *tx);
struct bitcoin_tx *sqlite3_column_tx(const tal_t *ctx, sqlite3_stmt *stmt, struct bitcoin_tx *sqlite3_column_tx(const tal_t *ctx, sqlite3_stmt *stmt,
int col); int col);
@ -126,6 +131,11 @@ bool sqlite3_column_signature(sqlite3_stmt *stmt, int col, secp256k1_ecdsa_signa
bool sqlite3_column_pubkey(sqlite3_stmt *stmt, int col, struct pubkey *dest); bool sqlite3_column_pubkey(sqlite3_stmt *stmt, int col, struct pubkey *dest);
bool sqlite3_bind_pubkey(sqlite3_stmt *stmt, int col, const struct pubkey *pk); bool sqlite3_bind_pubkey(sqlite3_stmt *stmt, int col, const struct pubkey *pk);
bool sqlite3_bind_pubkey_array(sqlite3_stmt *stmt, int col,
const struct pubkey *pks);
struct pubkey *sqlite3_column_pubkey_array(const tal_t *ctx,
sqlite3_stmt *stmt, int col);
bool sqlite3_column_preimage(sqlite3_stmt *stmt, int col, struct preimage *dest); bool sqlite3_column_preimage(sqlite3_stmt *stmt, int col, struct preimage *dest);
bool sqlite3_bind_preimage(sqlite3_stmt *stmt, int col, const struct preimage *p); bool sqlite3_bind_preimage(sqlite3_stmt *stmt, int col, const struct preimage *p);

18
wallet/wallet.c

@ -1295,8 +1295,10 @@ void wallet_payment_store(struct wallet *wallet,
" destination," " destination,"
" msatoshi," " msatoshi,"
" timestamp," " timestamp,"
" path_secrets" " path_secrets,"
") VALUES (?, ?, ?, ?, ?, ?);"); " route_nodes,"
" route_channels"
") VALUES (?, ?, ?, ?, ?, ?, ?, ?);");
sqlite3_bind_int(stmt, 1, payment->status); sqlite3_bind_int(stmt, 1, payment->status);
sqlite3_bind_sha256(stmt, 2, &payment->payment_hash); sqlite3_bind_sha256(stmt, 2, &payment->payment_hash);
@ -1306,6 +1308,9 @@ void wallet_payment_store(struct wallet *wallet,
sqlite3_bind_blob(stmt, 6, payment->path_secrets, sqlite3_bind_blob(stmt, 6, payment->path_secrets,
tal_len(payment->path_secrets), tal_len(payment->path_secrets),
SQLITE_TRANSIENT); SQLITE_TRANSIENT);
sqlite3_bind_pubkey_array(stmt, 7, payment->route_nodes);
sqlite3_bind_short_channel_id_array(stmt, 8,
payment->route_channels);
db_exec_prepared(wallet->db, stmt); db_exec_prepared(wallet->db, stmt);
@ -1353,6 +1358,11 @@ static struct wallet_payment *wallet_stmt2payment(const tal_t *ctx,
/* Can be NULL for old db! */ /* Can be NULL for old db! */
payment->path_secrets = sqlite3_column_secrets(payment, stmt, 7); payment->path_secrets = sqlite3_column_secrets(payment, stmt, 7);
payment->route_nodes = sqlite3_column_pubkey_array(payment, stmt, 8);
payment->route_channels
= sqlite3_column_short_channel_id_array(payment, stmt, 9);
return payment; return payment;
} }
@ -1371,7 +1381,7 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet,
stmt = db_prepare(wallet->db, stmt = db_prepare(wallet->db,
"SELECT id, status, destination," "SELECT id, status, destination,"
"msatoshi, payment_hash, timestamp, payment_preimage, " "msatoshi, payment_hash, timestamp, payment_preimage, "
"path_secrets " "path_secrets, route_nodes, route_channels "
"FROM payments " "FROM payments "
"WHERE payment_hash = ?"); "WHERE payment_hash = ?");
@ -1463,7 +1473,7 @@ wallet_payment_list(const tal_t *ctx,
wallet->db, wallet->db,
"SELECT id, status, destination, " "SELECT id, status, destination, "
"msatoshi, payment_hash, timestamp, payment_preimage, " "msatoshi, payment_hash, timestamp, payment_preimage, "
"path_secrets " "path_secrets, route_nodes, route_channels "
"FROM payments;"); "FROM payments;");
} }

3
wallet/wallet.h

@ -93,7 +93,10 @@ struct wallet_payment {
u64 msatoshi; u64 msatoshi;
/* If and only if PAYMENT_COMPLETE */ /* If and only if PAYMENT_COMPLETE */
struct preimage *payment_preimage; struct preimage *payment_preimage;
/* Needed for recovering from routing failures. */
struct secret *path_secrets; struct secret *path_secrets;
struct pubkey *route_nodes;
struct short_channel_id *route_channels;
}; };
/** /**

Loading…
Cancel
Save