mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
lightningd: Load persisted channels on startup
This is the big one, and it's completely anticlimactic: it loads all channels that have reached opening and are not marked as closingd_complete into memory, that's it. Signed-off-by: Christian Decker <decker.christian@gmail.com>
This commit is contained in:
parent
4e6f9787b6
commit
e51d261f51
@ -267,6 +267,15 @@ int main(int argc, char *argv[])
|
||||
/* FIXME: Load from peers. */
|
||||
0);
|
||||
|
||||
/* Load peers from database */
|
||||
wallet_channels_load_active(ld->wallet, &ld->peers);
|
||||
struct peer *peer;
|
||||
list_for_each(&ld->peers, peer, list) {
|
||||
populate_peer(ld, peer);
|
||||
peer->seed = tal(peer, struct privkey);
|
||||
derive_peer_seed(ld, peer->seed, &peer->id);
|
||||
}
|
||||
|
||||
/* Create RPC socket (if any) */
|
||||
setup_jsonrpc(&ld->dstate, ld->dstate.rpc_filename);
|
||||
|
||||
|
@ -550,6 +550,23 @@ static struct wallet_channel *peer_channel_new(struct wallet *w,
|
||||
return wc;
|
||||
}
|
||||
|
||||
void populate_peer(struct lightningd *ld, struct peer *peer)
|
||||
{
|
||||
const char *idname;
|
||||
struct pubkey *id = &peer->id;
|
||||
idname = type_to_string(peer, struct pubkey, id);
|
||||
|
||||
peer->ld = ld;
|
||||
|
||||
/* Max 128k per peer. */
|
||||
peer->log_book = new_log_book(peer, 128*1024,
|
||||
get_log_level(ld->dstate.log_book));
|
||||
peer->log = new_log(peer, peer->log_book, "peer %s:", idname);
|
||||
set_log_outfn(peer->log_book, copy_to_parent_log, peer);
|
||||
tal_free(idname);
|
||||
tal_add_destructor(peer, destroy_peer);
|
||||
}
|
||||
|
||||
void add_peer(struct lightningd *ld, u64 unique_id,
|
||||
int fd, const struct pubkey *id,
|
||||
const struct crypto_state *cs)
|
||||
@ -598,14 +615,6 @@ void add_peer(struct lightningd *ld, u64 unique_id,
|
||||
/* peer->channel gets populated as soon as we start opening a channel */
|
||||
peer->channel = NULL;
|
||||
|
||||
idname = type_to_string(peer, struct pubkey, id);
|
||||
|
||||
/* Max 128k per peer. */
|
||||
peer->log_book = new_log_book(peer, 128*1024,
|
||||
get_log_level(ld->dstate.log_book));
|
||||
peer->log = new_log(peer, peer->log_book, "peer %s:", idname);
|
||||
set_log_outfn(peer->log_book, copy_to_parent_log, peer);
|
||||
|
||||
/* FIXME: Don't assume protocol here! */
|
||||
if (!netaddr_from_fd(fd, SOCK_STREAM, IPPROTO_TCP, &peer->netaddr)) {
|
||||
log_unusual(ld->log, "Failed to get netaddr for outgoing: %s",
|
||||
@ -613,11 +622,14 @@ void add_peer(struct lightningd *ld, u64 unique_id,
|
||||
tal_free(peer);
|
||||
return;
|
||||
}
|
||||
list_add_tail(&ld->peers, &peer->list);
|
||||
populate_peer(ld, peer);
|
||||
|
||||
idname = type_to_string(peer, struct pubkey, id);
|
||||
netname = netaddr_name(idname, &peer->netaddr);
|
||||
log_info(peer->log, "Connected from %s", netname);
|
||||
|
||||
tal_free(idname);
|
||||
list_add_tail(&ld->peers, &peer->list);
|
||||
tal_add_destructor(peer, destroy_peer);
|
||||
|
||||
/* Let gossip handle it from here. */
|
||||
peer->owner = peer->ld->gossip;
|
||||
|
@ -158,6 +158,18 @@ void add_peer(struct lightningd *ld, u64 unique_id,
|
||||
int fd, const struct pubkey *id,
|
||||
const struct crypto_state *cs);
|
||||
|
||||
/**
|
||||
* populate_peer -- Populate daemon fields in a peer
|
||||
*
|
||||
* @ld: the daemon to wire the peer into
|
||||
* @peer: the peer to populate
|
||||
*
|
||||
* Creating a new peer, or loading a peer from the database we need to
|
||||
* populate a number of fields, e.g., the logging handler and the
|
||||
* pointer to the daemon. populate_peer does exactly that.
|
||||
*/
|
||||
void populate_peer(struct lightningd *ld, struct peer *peer);
|
||||
|
||||
/* Could be configurable. */
|
||||
#define OUR_CHANNEL_FLAGS CHANNEL_FLAGS_ANNOUNCE_CHANNEL
|
||||
|
||||
|
@ -47,10 +47,10 @@ def setupBitcoind():
|
||||
bitcoind.rpc.generate(1)
|
||||
|
||||
|
||||
def wait_for(success, timeout=30):
|
||||
def wait_for(success, timeout=30, interval=0.1):
|
||||
start_time = time.time()
|
||||
while not success() and time.time() < start_time + timeout:
|
||||
pass
|
||||
time.sleep(interval)
|
||||
if time.time() > start_time + timeout:
|
||||
raise ValueError("Error waiting for {}", success)
|
||||
|
||||
@ -875,17 +875,21 @@ class LightningDTests(BaseLightningDTests):
|
||||
for n in (l1, l2):
|
||||
assert(n.db_query('SELECT COUNT(id) as count FROM channels;')[0]['count'] == 1)
|
||||
|
||||
l1.daemon.stop()
|
||||
|
||||
# Let the other side notice, then stop it
|
||||
wait_for(lambda: not l2.rpc.getpeers()['peers'][0]['connected'])
|
||||
l2.daemon.stop()
|
||||
|
||||
# Let the other side notice, then stop it
|
||||
wait_for(lambda: not l1.rpc.getpeers()['peers'][0]['connected'])
|
||||
#l1.daemon.stop()
|
||||
|
||||
# Now restart l1 and it should reload peers/channels from the DB
|
||||
l1.daemon.start()
|
||||
l2.daemon.start()
|
||||
wait_for(lambda: len(l2.rpc.getpeers()['peers']) == 1)
|
||||
|
||||
#wait_for(lambda: len(l1.rpc.getpeers()['peers']) == 1)
|
||||
wait_for(lambda: len([p for p in l1.rpc.getpeers()['peers'] if p['connected']]), interval=1)
|
||||
wait_for(lambda: len([p for p in l2.rpc.getpeers()['peers'] if p['connected']]), interval=1)
|
||||
|
||||
# Now make sure this is really functional by sending a payment
|
||||
self.pay(l1, l2, 10000)
|
||||
|
||||
class LegacyLightningDTests(BaseLightningDTests):
|
||||
|
||||
|
@ -591,6 +591,27 @@ bool wallet_channel_load(struct wallet *w, const u64 id,
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool wallet_channels_load_active(struct wallet *w, struct list_head *peers)
|
||||
{
|
||||
bool ok = true;
|
||||
/* Channels are active if they have reached at least the
|
||||
* opening state and they are not marked as complete */
|
||||
sqlite3_stmt *stmt = db_query(
|
||||
__func__, w->db, "SELECT %s FROM channels WHERE state >= %d AND state != %d;",
|
||||
channel_fields, OPENINGD, CLOSINGD_COMPLETE);
|
||||
|
||||
int count = 0;
|
||||
while (ok && stmt && sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
struct wallet_channel *c = talz(w, struct wallet_channel);
|
||||
ok &= wallet_stmt2channel(w, stmt, c);
|
||||
list_add(peers, &c->peer->list);
|
||||
count++;
|
||||
}
|
||||
log_debug(w->log, "Loaded %d channels from DB", count);
|
||||
sqlite3_finalize(stmt);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static char* db_serialize_signature(const tal_t *ctx, secp256k1_ecdsa_signature* sig)
|
||||
{
|
||||
u8 buf[64];
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "config.h"
|
||||
#include "db.h"
|
||||
#include <ccan/crypto/shachain/shachain.h>
|
||||
#include <ccan/list/list.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <lightningd/channel_config.h>
|
||||
#include <lightningd/utxo.h>
|
||||
@ -197,4 +198,16 @@ bool wallet_channel_config_load(struct wallet *w, const u64 id,
|
||||
*/
|
||||
bool wallet_peer_by_nodeid(struct wallet *w, const struct pubkey *nodeid,
|
||||
struct peer *peer);
|
||||
|
||||
/**
|
||||
* wlalet_channels_load_active -- Load persisted active channels into the peers
|
||||
*
|
||||
* @w: wallet to load from
|
||||
* @peers: list_head to load channels/peers into
|
||||
*
|
||||
* Be sure to call this only once on startup since it'll append peers
|
||||
* loaded from the database to the list without checking.
|
||||
*/
|
||||
bool wallet_channels_load_active(struct wallet *w, struct list_head *peers);
|
||||
|
||||
#endif /* WALLET_WALLET_H */
|
||||
|
Loading…
Reference in New Issue
Block a user