mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-04 13:44:22 +01:00
wallet: Implement loading of stored channels from DB
Ugliest code I've written in a while, but it seems to do the trick.
This commit is contained in:
committed by
Rusty Russell
parent
ca00ec0bb8
commit
a5b425faad
196
wallet/wallet.c
196
wallet/wallet.c
@@ -4,6 +4,8 @@
|
||||
#include <ccan/str/hex/hex.h>
|
||||
#include <inttypes.h>
|
||||
#include <lightningd/lightningd.h>
|
||||
#include <lightningd/peer_control.h>
|
||||
#include <lightningd/peer_htlcs.h>
|
||||
|
||||
#define SQLITE_MAX_UINT 0x7FFFFFFFFFFFFFFF
|
||||
|
||||
@@ -343,6 +345,200 @@ bool wallet_shachain_load(struct wallet *wallet, u64 id,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sqlite3_column_short_channel_id(sqlite3_stmt *stmt, int col,
|
||||
struct short_channel_id *dest)
|
||||
{
|
||||
const char *source = sqlite3_column_blob(stmt, col);
|
||||
size_t sourcelen = sqlite3_column_bytes(stmt, col);
|
||||
return short_channel_id_from_str(source, sourcelen, dest);
|
||||
}
|
||||
|
||||
static bool sqlite3_column_sig(sqlite3_stmt *stmt, int col, secp256k1_ecdsa_signature *sig)
|
||||
{
|
||||
u8 buf[64];
|
||||
if (!sqlite3_column_hexval(stmt, col, buf, sizeof(buf)))
|
||||
return false;
|
||||
return secp256k1_ecdsa_signature_parse_compact(secp256k1_ctx, sig, buf) == 1;
|
||||
}
|
||||
|
||||
static bool sqlite3_column_pubkey(sqlite3_stmt *stmt, int col, struct pubkey *dest)
|
||||
{
|
||||
u8 buf[PUBKEY_DER_LEN];
|
||||
if (!sqlite3_column_hexval(stmt, col, buf, sizeof(buf)))
|
||||
return false;
|
||||
return pubkey_from_der(buf, sizeof(buf), dest);
|
||||
}
|
||||
|
||||
static u8 *sqlite3_column_varhexblob(tal_t *ctx, sqlite3_stmt *stmt, int col)
|
||||
{
|
||||
const u8 *source = sqlite3_column_blob(stmt, col);
|
||||
size_t sourcelen = sqlite3_column_bytes(stmt, col);
|
||||
return tal_hexdata(ctx, source, sourcelen);
|
||||
}
|
||||
|
||||
static bool wallet_peer_load(struct wallet *w, const u64 id, struct peer *peer)
|
||||
{
|
||||
bool ok = true;
|
||||
sqlite3_stmt *stmt = db_query(__func__, w->db, "SELECT id, node_id FROM peers WHERE id=%"PRIu64";", id);
|
||||
if (!stmt || sqlite3_step(stmt) != SQLITE_ROW) {
|
||||
sqlite3_finalize(stmt);
|
||||
return false;
|
||||
}
|
||||
peer->unique_id = sqlite3_column_int64(stmt, 0);
|
||||
ok &= sqlite3_column_pubkey(stmt, 1, &peer->id);
|
||||
sqlite3_finalize(stmt);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* wallet_stmt2channel - Helper to populate a wallet_channel from a sqlite3_stmt
|
||||
*
|
||||
* Returns true on success.
|
||||
*/
|
||||
static bool wallet_stmt2channel(struct wallet *w, sqlite3_stmt *stmt,
|
||||
struct wallet_channel *chan)
|
||||
{
|
||||
bool ok = true;
|
||||
int col = 0;
|
||||
struct channel_info *channel_info;
|
||||
struct sha256_double temphash;
|
||||
struct short_channel_id scid;
|
||||
|
||||
if (!chan->peer) {
|
||||
chan->peer = talz(chan, struct peer);
|
||||
}
|
||||
chan->peer->unique_id = sqlite3_column_int64(stmt, col++);
|
||||
chan->peer_id = sqlite3_column_int64(stmt, col++);
|
||||
wallet_peer_load(w, chan->peer_id, chan->peer);
|
||||
|
||||
if (sqlite3_column_short_channel_id(stmt, col++, &scid)) {
|
||||
chan->peer->scid = tal(chan->peer, struct short_channel_id);
|
||||
*chan->peer->scid = scid;
|
||||
} else {
|
||||
chan->peer->scid = NULL;
|
||||
}
|
||||
|
||||
/* TODO(cdecker) Load channel configs into chan */
|
||||
col += 2;
|
||||
|
||||
chan->peer->state = sqlite3_column_int(stmt, col++);
|
||||
chan->peer->funder = sqlite3_column_int(stmt, col++);
|
||||
chan->peer->channel_flags = sqlite3_column_int(stmt, col++);
|
||||
chan->peer->minimum_depth = sqlite3_column_int(stmt, col++);
|
||||
chan->peer->next_index[LOCAL] = sqlite3_column_int64(stmt, col++);
|
||||
chan->peer->next_index[REMOTE] = sqlite3_column_int64(stmt, col++);
|
||||
chan->peer->num_revocations_received =
|
||||
sqlite3_column_int64(stmt, col++);
|
||||
chan->peer->next_htlc_id = sqlite3_column_int64(stmt, col++);
|
||||
|
||||
if (sqlite3_column_hexval(stmt, col++, &temphash, sizeof(temphash))) {
|
||||
chan->peer->funding_txid = tal(chan->peer, struct sha256_double);
|
||||
*chan->peer->funding_txid = temphash;
|
||||
} else {
|
||||
chan->peer->funding_txid = NULL;
|
||||
}
|
||||
|
||||
chan->peer->funding_outnum = sqlite3_column_int(stmt, col++);
|
||||
chan->peer->funding_satoshi = sqlite3_column_int64(stmt, col++);
|
||||
chan->peer->remote_funding_locked =
|
||||
sqlite3_column_int(stmt, col++) != 0;
|
||||
chan->peer->push_msat = sqlite3_column_int64(stmt, col++);
|
||||
|
||||
if (sqlite3_column_type(stmt, col) != SQLITE_NULL) {
|
||||
chan->peer->our_msatoshi = tal(chan->peer, u64);
|
||||
*chan->peer->our_msatoshi = sqlite3_column_int64(stmt, col);
|
||||
}else {
|
||||
chan->peer->our_msatoshi = tal_free(chan->peer->our_msatoshi);
|
||||
}
|
||||
col++;
|
||||
|
||||
/* See if we have a valid commit_sig indicating the presence
|
||||
* of channel_info */
|
||||
if (sqlite3_column_type(stmt, col) != SQLITE_NULL) {
|
||||
/* OK, so we have a valid sig, instantiate and/or fill
|
||||
* in channel_info */
|
||||
if (!chan->peer->channel_info)
|
||||
chan->peer->channel_info = tal(chan->peer, struct channel_info);
|
||||
channel_info = chan->peer->channel_info;
|
||||
|
||||
/* Populate channel_info */
|
||||
ok &= sqlite3_column_sig(stmt, col++, &chan->peer->channel_info->commit_sig);
|
||||
ok &= sqlite3_column_pubkey(stmt, col++, &chan->peer->channel_info->remote_fundingkey);
|
||||
ok &= sqlite3_column_pubkey(stmt, col++, &channel_info->theirbase.revocation);
|
||||
ok &= sqlite3_column_pubkey(stmt, col++, &channel_info->theirbase.payment);
|
||||
ok &= sqlite3_column_pubkey(stmt, col++, &channel_info->theirbase.delayed_payment);
|
||||
ok &= sqlite3_column_pubkey(stmt, col++, &channel_info->remote_per_commit);
|
||||
ok &= sqlite3_column_pubkey(stmt, col++, &channel_info->old_remote_per_commit);
|
||||
channel_info->feerate_per_kw = sqlite3_column_int64(stmt, col++);
|
||||
} else {
|
||||
/* No channel_info, skip positions in the result */
|
||||
col += 8;
|
||||
}
|
||||
|
||||
/* Load shachain */
|
||||
u64 shachain_id = sqlite3_column_int64(stmt, col++);
|
||||
ok &= wallet_shachain_load(w, shachain_id, &chan->peer->their_shachain);
|
||||
|
||||
/* Do we have a non-null remote_shutdown_scriptpubkey? */
|
||||
if (sqlite3_column_type(stmt, col) != SQLITE_NULL) {
|
||||
chan->peer->remote_shutdown_scriptpubkey = sqlite3_column_varhexblob(chan->peer, stmt, col++);
|
||||
chan->peer->local_shutdown_idx = sqlite3_column_int64(stmt, col++);
|
||||
} else {
|
||||
chan->peer->remote_shutdown_scriptpubkey = tal_free(chan->peer->remote_shutdown_scriptpubkey);
|
||||
chan->peer->local_shutdown_idx = 0;
|
||||
col += 2;
|
||||
}
|
||||
|
||||
/* Do we have a last_sent_commit, if yes, populate */
|
||||
if (sqlite3_column_type(stmt, col) != SQLITE_NULL) {
|
||||
if (!chan->peer->last_sent_commit) {
|
||||
chan->peer->last_sent_commit = tal(chan->peer, struct changed_htlc);
|
||||
}
|
||||
chan->peer->last_sent_commit->newstate = sqlite3_column_int64(stmt, col++);
|
||||
chan->peer->last_sent_commit->id = sqlite3_column_int64(stmt, col++);
|
||||
} else {
|
||||
chan->peer->last_sent_commit = tal_free(chan->peer->last_sent_commit);
|
||||
col += 2;
|
||||
}
|
||||
assert(col == 32);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool wallet_channel_load(struct wallet *w, const u64 id,
|
||||
struct wallet_channel *chan)
|
||||
{
|
||||
bool ok;
|
||||
/* The explicit query that matches the columns and their order in
|
||||
* wallet_stmt2channel. */
|
||||
const char *channel_query =
|
||||
"SELECT id, peer_id, short_channel_id, channel_config_local, "
|
||||
"channel_config_remote, state, funder, channel_flags, "
|
||||
"minimum_depth, "
|
||||
"next_index_local, next_index_remote, num_revocations_received, "
|
||||
"next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, "
|
||||
"funding_locked_remote, push_msatoshi, msatoshi_local, "
|
||||
"commit_sig_remote, "
|
||||
"fundingkey_remote, revocation_basepoint_remote, "
|
||||
"payment_basepoint_remote, "
|
||||
"delayed_payment_basepoint_remote, per_commit_remote, "
|
||||
"old_per_commit_remote, feerate_per_kw, shachain_remote_id, "
|
||||
"shutdown_scriptpubkey_remote, shutdown_keyidx_local, "
|
||||
"last_sent_commit_state, last_sent_commit_id FROM channels WHERE "
|
||||
"id=%" PRIu64 ";";
|
||||
|
||||
sqlite3_stmt *stmt = db_query(__func__, w->db, channel_query, id);
|
||||
if (!stmt || sqlite3_step(stmt) != SQLITE_ROW) {
|
||||
sqlite3_finalize(stmt);
|
||||
return false;
|
||||
}
|
||||
ok = wallet_stmt2channel(w, stmt, chan);
|
||||
chan->id = id;
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* wallet_shachain_delete - Drop the shachain from the database
|
||||
*
|
||||
|
||||
@@ -47,6 +47,14 @@ struct wallet_shachain {
|
||||
struct shachain chain;
|
||||
};
|
||||
|
||||
/* A database backed peer struct. Like wallet_shachain, it is writethrough. */
|
||||
/* TODO(cdecker) Separate peer from channel */
|
||||
struct wallet_channel {
|
||||
u64 id;
|
||||
u64 peer_id;
|
||||
struct peer *peer;
|
||||
};
|
||||
|
||||
/**
|
||||
* wallet_new - Constructor for a new sqlite3 based wallet
|
||||
*
|
||||
@@ -154,4 +162,6 @@ static inline bool wallet_shachain_get_hash(struct wallet *w,
|
||||
bool wallet_shachain_load(struct wallet *wallet, u64 id,
|
||||
struct wallet_shachain *chain);
|
||||
|
||||
bool wallet_channel_load(struct wallet *w, const u64 id,
|
||||
struct wallet_channel *chan);
|
||||
#endif /* WALLET_WALLET_H */
|
||||
|
||||
Reference in New Issue
Block a user