db.c: database API.

These tables could use a rework, as they largely reflect our internal
state.  But it's a start.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2016-08-18 14:25:13 +09:30
parent be38d3f507
commit 71b8a07c56
16 changed files with 1703 additions and 8 deletions

View file

@ -6,6 +6,7 @@ You will need several development libraries:
* protobuf-c: version 1.1.0 or above. * protobuf-c: version 1.1.0 or above.
* libsodium: for crypto. * libsodium: for crypto.
* libbase58: for bitcoin's base58 encoding. * libbase58: for bitcoin's base58 encoding.
* libsqlite3: for database support.
You will also need a version of bitcoind with segregated witness support, You will also need a version of bitcoind with segregated witness support,
such as the 0.13 or above. such as the 0.13 or above.
@ -15,7 +16,7 @@ To Build on Ubuntu 16.04
Get dependencies: Get dependencies:
``` ```
sudo apt-get install libprotobuf-c-dev libsodium-dev libbase58-dev sudo apt-get install libprotobuf-c-dev libsodium-dev libbase58-dev libsqlite3-dev
``` ```
Clone lightning and initialize submodules: Clone lightning and initialize submodules:

View file

@ -176,7 +176,7 @@ CWARNFLAGS := -Werror -Wall -Wundef -Wmissing-prototypes -Wmissing-declarations
CDEBUGFLAGS := -g -fstack-protector CDEBUGFLAGS := -g -fstack-protector
CFLAGS := $(CWARNFLAGS) $(CDEBUGFLAGS) -I $(CCANDIR) -I secp256k1/include/ -I . $(FEATURES) CFLAGS := $(CWARNFLAGS) $(CDEBUGFLAGS) -I $(CCANDIR) -I secp256k1/include/ -I . $(FEATURES)
LDLIBS := -lprotobuf-c -lgmp -lsodium -lbase58 LDLIBS := -lprotobuf-c -lgmp -lsodium -lbase58 -lsqlite3
$(PROGRAMS): CFLAGS+=-I. $(PROGRAMS): CFLAGS+=-I.
default: $(PROGRAMS) daemon-all default: $(PROGRAMS) daemon-all

View file

@ -20,6 +20,7 @@ DAEMON_SRC := \
daemon/commit_tx.c \ daemon/commit_tx.c \
daemon/controlled_time.c \ daemon/controlled_time.c \
daemon/cryptopkt.c \ daemon/cryptopkt.c \
daemon/db.c \
daemon/dns.c \ daemon/dns.c \
daemon/htlc.c \ daemon/htlc.c \
daemon/jsonrpc.c \ daemon/jsonrpc.c \
@ -58,6 +59,7 @@ DAEMON_HEADERS := \
daemon/configdir.h \ daemon/configdir.h \
daemon/controlled_time.h \ daemon/controlled_time.h \
daemon/cryptopkt.h \ daemon/cryptopkt.h \
daemon/db.h \
daemon/dns.h \ daemon/dns.h \
daemon/htlc.h \ daemon/htlc.h \
daemon/htlc_state.h \ daemon/htlc_state.h \

1531
daemon/db.c Normal file

File diff suppressed because it is too large Load diff

46
daemon/db.h Normal file
View file

@ -0,0 +1,46 @@
#ifndef LIGHTNING_DAEMON_DB_H
#define LIGHTNING_DAEMON_DB_H
#include "config.h"
#include "peer.h"
#include <stdbool.h>
void db_init(struct lightningd_state *dstate);
bool db_create_peer(struct peer *peer);
bool db_set_anchor(struct peer *peer);
bool db_set_visible_state(struct peer *peer);
bool db_start_transaction(struct peer *peer);
void db_abort_transaction(struct peer *peer);
bool db_commit_transaction(struct peer *peer);
void db_add_wallet_privkey(struct lightningd_state *dstate,
const struct privkey *privkey);
/* Must NOT be inside transaction. */
bool db_htlc_fulfilled(struct peer *peer, const struct htlc *htlc);
bool db_set_our_closing_script(struct peer *peer);
bool db_set_their_closing_script(struct peer *peer);
bool db_update_our_closing(struct peer *peer);
bool db_update_their_closing(struct peer *peer);
/* FIXME: save error handling until db_commit_transaction for calls
* which have to be inside transaction anyway. */
/* Must be inside transaction. */
bool db_new_htlc(struct peer *peer, const struct htlc *htlc);
bool db_update_htlc_state(struct peer *peer, const struct htlc *htlc,
enum htlc_state oldstate);
bool db_new_commit_info(struct peer *peer, enum channel_side side,
const struct sha256 *prev_rhash);
bool db_remove_their_prev_revocation_hash(struct peer *peer);
bool db_update_next_revocation_hash(struct peer *peer);
bool db_save_shachain(struct peer *peer);
bool db_update_state(struct peer *peer);
bool db_begin_shutdown(struct peer *peer);
bool db_add_commit_map(struct peer *peer,
const struct sha256_double *txid, u64 commit_num);
void db_forget_peer(struct peer *peer);
#endif /* LIGHTNING_DAEMON_DB_H */

View file

@ -15,6 +15,16 @@ const char *htlc_state_name(enum htlc_state s)
return "unknown"; return "unknown";
} }
enum htlc_state htlc_state_from_name(const char *name)
{
size_t i;
for (i = 0; enum_htlc_state_names[i].name; i++)
if (streq(enum_htlc_state_names[i].name, name))
return enum_htlc_state_names[i].v;
return HTLC_STATE_INVALID;
}
/* This is the flags for each state. */ /* This is the flags for each state. */
static const int per_state_bits[] = { static const int per_state_bits[] = {
[SENT_ADD_HTLC] = HTLC_ADDING + HTLC_LOCAL_F_OWNER [SENT_ADD_HTLC] = HTLC_ADDING + HTLC_LOCAL_F_OWNER

View file

@ -72,6 +72,7 @@ struct htlc {
}; };
const char *htlc_state_name(enum htlc_state s); const char *htlc_state_name(enum htlc_state s);
enum htlc_state htlc_state_from_name(const char *name);
void htlc_changestate(struct htlc *h, void htlc_changestate(struct htlc *h,
enum htlc_state oldstate, enum htlc_state oldstate,
enum htlc_state newstate); enum htlc_state newstate);
@ -82,21 +83,26 @@ static inline bool htlc_has(const struct htlc *h, int flag)
return htlc_state_flags(h->state) & flag; return htlc_state_flags(h->state) & flag;
} }
static inline enum htlc_side htlc_owner(const struct htlc *h) static inline enum htlc_side htlc_state_owner(enum htlc_state state)
{ {
if (h->state < RCVD_ADD_HTLC) { if (state < RCVD_ADD_HTLC) {
assert((htlc_state_flags(h->state) assert((htlc_state_flags(state)
& (HTLC_REMOTE_F_OWNER|HTLC_LOCAL_F_OWNER)) & (HTLC_REMOTE_F_OWNER|HTLC_LOCAL_F_OWNER))
== HTLC_LOCAL_F_OWNER); == HTLC_LOCAL_F_OWNER);
return LOCAL; return LOCAL;
} else { } else {
assert((htlc_state_flags(h->state) assert((htlc_state_flags(state)
& (HTLC_REMOTE_F_OWNER|HTLC_LOCAL_F_OWNER)) & (HTLC_REMOTE_F_OWNER|HTLC_LOCAL_F_OWNER))
== HTLC_REMOTE_F_OWNER); == HTLC_REMOTE_F_OWNER);
return REMOTE; return REMOTE;
} }
} }
static inline enum htlc_side htlc_owner(const struct htlc *h)
{
return htlc_state_owner(h->state);
}
/* FIXME: Transitional function. */ /* FIXME: Transitional function. */
static inline enum channel_side htlc_channel_side(const struct htlc *h) static inline enum channel_side htlc_channel_side(const struct htlc *h)
{ {

View file

@ -29,6 +29,8 @@ enum htlc_state {
SENT_REMOVE_COMMIT, SENT_REMOVE_COMMIT,
RCVD_REMOVE_REVOCATION, RCVD_REMOVE_REVOCATION,
RCVD_REMOVE_ACK_COMMIT, RCVD_REMOVE_ACK_COMMIT,
SENT_REMOVE_ACK_REVOCATION SENT_REMOVE_ACK_REVOCATION,
HTLC_STATE_INVALID
}; };
#endif /* LIGHTNING_DAEMON_HTLC_STATE_H */ #endif /* LIGHTNING_DAEMON_HTLC_STATE_H */

View file

@ -2,6 +2,7 @@
#include "chaintopology.h" #include "chaintopology.h"
#include "configdir.h" #include "configdir.h"
#include "controlled_time.h" #include "controlled_time.h"
#include "db.h"
#include "jsonrpc.h" #include "jsonrpc.h"
#include "lightningd.h" #include "lightningd.h"
#include "log.h" #include "log.h"
@ -330,6 +331,9 @@ int main(int argc, char *argv[])
secrets_init(dstate); secrets_init(dstate);
new_node(dstate, &dstate->id); new_node(dstate, &dstate->id);
/* Read or create database. */
db_init(dstate);
/* Initialize block topology. */ /* Initialize block topology. */
setup_topology(dstate); setup_topology(dstate);

View file

@ -72,6 +72,9 @@ struct lightningd_state {
/* Configuration settings. */ /* Configuration settings. */
struct config config; struct config config;
/* The database where we keep our stuff. */
struct db *db;
/* Any pending timers. */ /* Any pending timers. */
struct timers timers; struct timers timers;

View file

@ -5,12 +5,14 @@
#include "log.h" #include "log.h"
#include "peer.h" #include "peer.h"
#include "secrets.h" #include "secrets.h"
#include "utils.h"
#include <ccan/crypto/sha256/sha256.h> #include <ccan/crypto/sha256/sha256.h>
#include <ccan/crypto/shachain/shachain.h> #include <ccan/crypto/shachain/shachain.h>
#include <ccan/mem/mem.h> #include <ccan/mem/mem.h>
#include <ccan/noerr/noerr.h> #include <ccan/noerr/noerr.h>
#include <ccan/read_write_all/read_write_all.h> #include <ccan/read_write_all/read_write_all.h>
#include <ccan/short_types/short_types.h> #include <ccan/short_types/short_types.h>
#include <ccan/tal/str/str.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <secp256k1.h> #include <secp256k1.h>
@ -175,6 +177,48 @@ void peer_get_revocation_hash(const struct peer *peer, u64 index,
sha256(rhash, preimage.u.u8, sizeof(preimage.u.u8)); sha256(rhash, preimage.u.u8, sizeof(preimage.u.u8));
} }
const char *peer_secrets_for_db(const tal_t *ctx, struct peer *peer)
{
const struct peer_secrets *ps = peer->secrets;
return tal_fmt(ctx, "x'%s', x'%s', x'%s'",
tal_hexstr(ctx, &ps->commit, sizeof(ps->commit)),
tal_hexstr(ctx, &ps->final, sizeof(ps->final)),
tal_hexstr(ctx, &ps->revocation_seed,
sizeof(ps->revocation_seed)));
}
void peer_set_secrets_from_db(struct peer *peer,
const void *commit_privkey,
size_t commit_privkey_len,
const void *final_privkey,
size_t final_privkey_len,
const void *revocation_seed,
size_t revocation_seed_len)
{
struct peer_secrets *ps = tal(peer, struct peer_secrets);
assert(!peer->secrets);
peer->secrets = ps;
if (commit_privkey_len != sizeof(ps->commit)
|| final_privkey_len != sizeof(ps->final)
|| revocation_seed_len != sizeof(ps->revocation_seed))
fatal("peer_set_secrets_from_db: bad lengths %zu/%zu/%zu",
commit_privkey_len, final_privkey_len,
revocation_seed_len);
memcpy(&ps->commit, commit_privkey, commit_privkey_len);
memcpy(&ps->final, final_privkey, final_privkey_len);
memcpy(&ps->revocation_seed, revocation_seed, revocation_seed_len);
if (!pubkey_from_privkey(peer->dstate->secpctx, &ps->commit,
&peer->local.commitkey))
fatal("peer_set_secrets_from_db:bad commit privkey");
if (!pubkey_from_privkey(peer->dstate->secpctx, &ps->final,
&peer->local.finalkey))
fatal("peer_set_secrets_from_db:bad final privkey");
}
void secrets_init(struct lightningd_state *dstate) void secrets_init(struct lightningd_state *dstate)
{ {
int fd; int fd;

View file

@ -45,6 +45,16 @@ void peer_sign_steal_input(const struct peer *peer,
const u8 *witnessscript, const u8 *witnessscript,
struct signature *sig); struct signature *sig);
const char *peer_secrets_for_db(const tal_t *ctx, struct peer *peer);
void peer_set_secrets_from_db(struct peer *peer,
const void *commit_privkey,
size_t commit_privkey_len,
const void *final_privkey,
size_t final_privkey_len,
const void *revocation_seed,
size_t revocation_seed_len);
void peer_secrets_init(struct peer *peer); void peer_secrets_init(struct peer *peer);
void peer_get_revocation_hash(const struct peer *peer, u64 index, void peer_get_revocation_hash(const struct peer *peer, u64 index,

View file

@ -21,6 +21,26 @@ struct wallet {
struct ripemd160 p2sh; struct ripemd160 p2sh;
}; };
bool restore_wallet_address(struct lightningd_state *dstate,
const struct privkey *privkey)
{
struct wallet *w = tal(dstate, struct wallet);
u8 *redeemscript;
struct sha256 h;
w->privkey = *privkey;
if (!pubkey_from_privkey(dstate->secpctx, &w->privkey, &w->pubkey))
return false;
redeemscript = bitcoin_redeem_p2wpkh(w, dstate->secpctx, &w->pubkey);
sha256(&h, redeemscript, tal_count(redeemscript));
ripemd160(&w->p2sh, h.u.u8, sizeof(h));
list_add_tail(&dstate->wallet, &w->list);
tal_free(redeemscript);
return true;
}
static void new_keypair(struct lightningd_state *dstate, static void new_keypair(struct lightningd_state *dstate,
struct privkey *privkey, struct pubkey *pubkey) struct privkey *privkey, struct pubkey *pubkey)
{ {

View file

@ -7,6 +7,9 @@ struct lightningd_state;
struct bitcoin_tx; struct bitcoin_tx;
struct bitcoin_tx_output; struct bitcoin_tx_output;
bool restore_wallet_address(struct lightningd_state *dstate,
const struct privkey *privkey);
void wallet_add_signed_input(struct lightningd_state *dstate, void wallet_add_signed_input(struct lightningd_state *dstate,
const struct wallet *w, const struct wallet *w,
struct bitcoin_tx *tx, struct bitcoin_tx *tx,

12
names.c
View file

@ -1,4 +1,5 @@
#include "names.h" #include "names.h"
#include <ccan/str/str.h>
/* Indented for 'check-source' because it has to be included after names.h */ /* Indented for 'check-source' because it has to be included after names.h */
#include "gen_state_names.h" #include "gen_state_names.h"
#include "gen_pkt_names.h" #include "gen_pkt_names.h"
@ -13,6 +14,17 @@ const char *state_name(enum state s)
return "unknown"; return "unknown";
} }
enum state name_to_state(const char *name)
{
size_t i;
for (i = 0; enum_state_names[i].name; i++)
if (streq(name, enum_state_names[i].name))
return enum_state_names[i].v;
return STATE_MAX;
}
const char *input_name(enum state_input in) const char *input_name(enum state_input in)
{ {
size_t i; size_t i;

View file

@ -5,6 +5,7 @@
#include "state_types.h" #include "state_types.h"
const char *state_name(enum state s); const char *state_name(enum state s);
enum state name_to_state(const char *name);
const char *input_name(enum state_input in); const char *input_name(enum state_input in);
const char *pkt_name(Pkt__PktCase pkt); const char *pkt_name(Pkt__PktCase pkt);
#endif /* LIGHTNING_NAMES_H */ #endif /* LIGHTNING_NAMES_H */