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.
* libsodium: for crypto.
* libbase58: for bitcoin's base58 encoding.
* libsqlite3: for database support.
You will also need a version of bitcoind with segregated witness support,
such as the 0.13 or above.
@ -15,7 +16,7 @@ To Build on Ubuntu 16.04
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:

View file

@ -176,7 +176,7 @@ CWARNFLAGS := -Werror -Wall -Wundef -Wmissing-prototypes -Wmissing-declarations
CDEBUGFLAGS := -g -fstack-protector
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.
default: $(PROGRAMS) daemon-all

View file

@ -20,6 +20,7 @@ DAEMON_SRC := \
daemon/commit_tx.c \
daemon/controlled_time.c \
daemon/cryptopkt.c \
daemon/db.c \
daemon/dns.c \
daemon/htlc.c \
daemon/jsonrpc.c \
@ -58,6 +59,7 @@ DAEMON_HEADERS := \
daemon/configdir.h \
daemon/controlled_time.h \
daemon/cryptopkt.h \
daemon/db.h \
daemon/dns.h \
daemon/htlc.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";
}
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. */
static const int per_state_bits[] = {
[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);
enum htlc_state htlc_state_from_name(const char *name);
void htlc_changestate(struct htlc *h,
enum htlc_state oldstate,
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;
}
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) {
assert((htlc_state_flags(h->state)
if (state < RCVD_ADD_HTLC) {
assert((htlc_state_flags(state)
& (HTLC_REMOTE_F_OWNER|HTLC_LOCAL_F_OWNER))
== HTLC_LOCAL_F_OWNER);
return LOCAL;
} else {
assert((htlc_state_flags(h->state)
assert((htlc_state_flags(state)
& (HTLC_REMOTE_F_OWNER|HTLC_LOCAL_F_OWNER))
== HTLC_REMOTE_F_OWNER);
return REMOTE;
}
}
static inline enum htlc_side htlc_owner(const struct htlc *h)
{
return htlc_state_owner(h->state);
}
/* FIXME: Transitional function. */
static inline enum channel_side htlc_channel_side(const struct htlc *h)
{

View file

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

View file

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

View file

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

View file

@ -5,12 +5,14 @@
#include "log.h"
#include "peer.h"
#include "secrets.h"
#include "utils.h"
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/crypto/shachain/shachain.h>
#include <ccan/mem/mem.h>
#include <ccan/noerr/noerr.h>
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/short_types/short_types.h>
#include <ccan/tal/str/str.h>
#include <errno.h>
#include <fcntl.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));
}
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)
{
int fd;

View file

@ -45,6 +45,16 @@ void peer_sign_steal_input(const struct peer *peer,
const u8 *witnessscript,
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_get_revocation_hash(const struct peer *peer, u64 index,

View file

@ -21,6 +21,26 @@ struct wallet {
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,
struct privkey *privkey, struct pubkey *pubkey)
{

View file

@ -7,6 +7,9 @@ struct lightningd_state;
struct bitcoin_tx;
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,
const struct wallet *w,
struct bitcoin_tx *tx,

12
names.c
View file

@ -1,4 +1,5 @@
#include "names.h"
#include <ccan/str/str.h>
/* Indented for 'check-source' because it has to be included after names.h */
#include "gen_state_names.h"
#include "gen_pkt_names.h"
@ -13,6 +14,17 @@ const char *state_name(enum state s)
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)
{
size_t i;

View file

@ -5,6 +5,7 @@
#include "state_types.h"
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 *pkt_name(Pkt__PktCase pkt);
#endif /* LIGHTNING_NAMES_H */