Skip to content

Commit

Permalink
pay: Save nodes and channels used on route to payment.
Browse files Browse the repository at this point in the history
  • Loading branch information
ZmnSCPxj committed Jan 20, 2018
1 parent e2c4997 commit b5d16e6
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 4 deletions.
8 changes: 8 additions & 0 deletions lightningd/pay.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ static bool send_payment(struct command *cmd,
struct pubkey *ids = tal_arr(tmpctx, struct pubkey, n_hops);
struct wallet_payment *payment = NULL;
struct htlc_out *hout;
struct short_channel_id *channels;

/* Expiry for HTLCs is absolute. And add one to give some margin. */
base_expiry = get_block_height(cmd->ld->topology) + 1;
Expand Down Expand Up @@ -213,6 +214,11 @@ static bool send_payment(struct command *cmd,
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. */
payment = tal(hout, struct wallet_payment);
payment->id = 0;
Expand All @@ -223,6 +229,8 @@ static bool send_payment(struct command *cmd,
payment->timestamp = time_now().ts.tv_sec;
payment->payment_preimage = NULL;
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. */
wallet_payment_setup(cmd->ld->wallet, payment);
Expand Down
140 changes: 140 additions & 0 deletions wallet/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ char *dbmigrations[] = {
"UPDATE invoices"
" SET paid_timestamp = strftime('%s', 'now')"
" 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,
};

Expand Down Expand Up @@ -454,6 +460,86 @@ bool sqlite3_column_short_channel_id(sqlite3_stmt *stmt, int col,
size_t sourcelen = sqlite3_column_bytes(stmt, col);
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)
{
const tal_t *tmpctx;
char *allser;
char *ser;
size_t num;
size_t i;
bool res;

/* Handle nulls early. */
if (!id) {
sqlite3_bind_null(stmt, col);
return true;
}

tmpctx = tal_tmpctx(id);
allser = tal_strdup(tmpctx, "");
num = tal_count(id);

for (i = 0; i < num; ++i) {
ser = short_channel_id_to_str(tmpctx, id);
if (i == 0)
res = tal_append_fmt(&allser, "%s", ser);
else
res = tal_append_fmt(&allser, ",%s", ser);
if (!res) {
tal_free(tmpctx);
return false;
}
}

sqlite3_bind_blob(stmt, col, allser, strlen(allser), SQLITE_TRANSIENT);

tal_free(tmpctx);
return true;
}
struct short_channel_id *
sqlite3_column_short_channel_id_array(const tal_t *ctx,
sqlite3_stmt *stmt, int col)
{
const tal_t *tmpctx;
const char *scan;
const char *start;
const char *end;
struct short_channel_id *ret;
size_t n;

/* Handle nulls early. */
if (sqlite3_column_type(stmt, col) == SQLITE_NULL)
return NULL;

tmpctx = tal_tmpctx(ctx);
scan = sqlite3_column_blob(stmt, col);
end = scan + sqlite3_column_bytes(stmt, col);
ret = NULL;
n = 0;

/* Scan for comma-separated scid strings. */
while (scan != end) {
ret = tal_dup_arr (tmpctx, struct short_channel_id,
take(ret), n, 1);
if (!ret) {
tal_free(tmpctx);
return NULL;
}
start = scan;
while (scan != end && *scan != ',')
++scan;
if (!short_channel_id_from_str(start, scan - start, &ret[n])) {
tal_free(tmpctx);
return NULL;
}
++n;
}

ret = tal_steal(ctx, ret);
tal_free(tmpctx);
return ret;
}

bool sqlite3_bind_tx(sqlite3_stmt *stmt, int col, const struct bitcoin_tx *tx)
{
Expand Down Expand Up @@ -503,6 +589,60 @@ bool sqlite3_bind_pubkey(sqlite3_stmt *stmt, int col, const struct pubkey *pk)
return true;
}

bool sqlite3_bind_pubkey_array(sqlite3_stmt *stmt, int col,
const struct pubkey *pks)
{
const tal_t *tmpctx;
size_t n;
size_t i;
u8 *ders;

if (!pks) {
sqlite3_bind_null(stmt, col);
return true;
}

tmpctx = tal_tmpctx(pks);
n = tal_count(pks);
ders = tal_arr(tmpctx, 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(tmpctx);
return true;
}
struct pubkey *sqlite3_column_pubkey_array(const tal_t *ctx,
sqlite3_stmt *stmt, int col)
{
const tal_t *tmpctx;
size_t i;
size_t n;
struct pubkey *ret;
const u8 *ders;

if (sqlite3_column_type(stmt, col) == SQLITE_NULL)
return NULL;

tmpctx = tal_tmpctx(ctx);
n = sqlite3_column_bytes(stmt, col) / PUBKEY_DER_LEN;
assert(n * PUBKEY_DER_LEN == sqlite3_column_bytes(stmt, col));
ret = tal_arr(tmpctx, 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])) {
tal_free(tmpctx);
return NULL;
}
}

ret = tal_steal(ctx, ret);
tal_free(tmpctx);
return ret;
}

bool sqlite3_column_preimage(sqlite3_stmt *stmt, int col, struct preimage *dest)
{
assert(sqlite3_column_bytes(stmt, col) == sizeof(struct preimage));
Expand Down
10 changes: 10 additions & 0 deletions wallet/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ bool sqlite3_bind_short_channel_id(sqlite3_stmt *stmt, int col,
const struct short_channel_id *id);
bool sqlite3_column_short_channel_id(sqlite3_stmt *stmt, int col,
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);
struct bitcoin_tx *sqlite3_column_tx(const tal_t *ctx, sqlite3_stmt *stmt,
int col);
Expand All @@ -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_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_bind_preimage(sqlite3_stmt *stmt, int col, const struct preimage *p);

Expand Down
18 changes: 14 additions & 4 deletions wallet/wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1288,8 +1288,10 @@ void wallet_payment_store(struct wallet *wallet,
" destination,"
" msatoshi,"
" timestamp,"
" path_secrets"
") VALUES (?, ?, ?, ?, ?, ?);");
" path_secrets,"
" route_nodes,"
" route_channels"
") VALUES (?, ?, ?, ?, ?, ?, ?, ?);");

sqlite3_bind_int(stmt, 1, payment->status);
sqlite3_bind_sha256(stmt, 2, &payment->payment_hash);
Expand All @@ -1299,6 +1301,9 @@ void wallet_payment_store(struct wallet *wallet,
sqlite3_bind_blob(stmt, 6, payment->path_secrets,
tal_len(payment->path_secrets),
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);

Expand Down Expand Up @@ -1346,6 +1351,11 @@ static struct wallet_payment *wallet_stmt2payment(const tal_t *ctx,

/* Can be NULL for old db! */
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;
}

Expand All @@ -1364,7 +1374,7 @@ wallet_payment_by_hash(const tal_t *ctx, struct wallet *wallet,
stmt = db_prepare(wallet->db,
"SELECT id, status, destination,"
"msatoshi, payment_hash, timestamp, payment_preimage, "
"path_secrets "
"path_secrets, route_nodes, route_channels "
"FROM payments "
"WHERE payment_hash = ?");

Expand Down Expand Up @@ -1456,7 +1466,7 @@ wallet_payment_list(const tal_t *ctx,
wallet->db,
"SELECT id, status, destination, "
"msatoshi, payment_hash, timestamp, payment_preimage, "
"path_secrets "
"path_secrets, route_nodes, route_channels "
"FROM payments;");
}

Expand Down
3 changes: 3 additions & 0 deletions wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ struct wallet_payment {
u64 msatoshi;
/* Iff PAYMENT_COMPLETE */
struct preimage *payment_preimage;
/* Needed for recovering from routing failures. */
struct secret *path_secrets;
struct pubkey *route_nodes;
struct short_channel_id *route_channels;
};

/**
Expand Down

0 comments on commit b5d16e6

Please sign in to comment.