#include "config.h"
#include "common/json_filter.c"
#include "test_utils.h"

#include "plugins/libplugin.c"

#include <bitcoin/tx.h>
#include <ccan/tal/str/str.h>
#include <common/coin_mvt.h>
#include <common/fee_states.h>
#include <common/htlc.h>
#include <common/json_stream.h>
#include <common/setup.h>
#include <common/utils.h>
#include <db/common.h>
#include <plugins/bkpr/account.h>
#include <plugins/bkpr/account_entry.h>
#include <plugins/bkpr/chain_event.h>
#include <plugins/bkpr/channel_event.h>
#include <plugins/bkpr/onchain_fee.h>
#include <plugins/bkpr/recorder.h>
#include <stdio.h>
#include <unistd.h>
#include <wire/wire.h>

#include "plugins/bkpr/db.c"


/* AUTOGENERATED MOCKS START */
/* Generated stub for account_entry_tag_str */
const char *account_entry_tag_str(enum account_entry_tag tag UNNEEDED)
{ fprintf(stderr, "account_entry_tag_str called!\n"); abort(); }
/* Generated stub for daemon_maybe_debug */
void daemon_maybe_debug(char *argv[])
{ fprintf(stderr, "daemon_maybe_debug called!\n"); abort(); }
/* Generated stub for daemon_setup */
void daemon_setup(const char *argv0 UNNEEDED,
		  void (*backtrace_print)(const char *fmt UNNEEDED, ...) UNNEEDED,
		  void (*backtrace_exit)(void))
{ fprintf(stderr, "daemon_setup called!\n"); abort(); }
/* Generated stub for first_fee_state */
enum htlc_state first_fee_state(enum side opener UNNEEDED)
{ fprintf(stderr, "first_fee_state called!\n"); abort(); }
/* Generated stub for fmt_wireaddr_without_port */
char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED)
{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); }
/* Generated stub for fromwire */
const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED)
{ fprintf(stderr, "fromwire called!\n"); abort(); }
/* Generated stub for fromwire_bool */
bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_bool called!\n"); abort(); }
/* Generated stub for fromwire_fail */
void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_fail called!\n"); abort(); }
/* Generated stub for fromwire_secp256k1_ecdsa_signature */
void fromwire_secp256k1_ecdsa_signature(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
					secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "fromwire_secp256k1_ecdsa_signature called!\n"); abort(); }
/* Generated stub for fromwire_sha256 */
void fromwire_sha256(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sha256 *sha256 UNNEEDED)
{ fprintf(stderr, "fromwire_sha256 called!\n"); abort(); }
/* Generated stub for fromwire_tal_arrn */
u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED,
		       const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_tal_arrn called!\n"); abort(); }
/* Generated stub for fromwire_u16 */
u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); }
/* Generated stub for fromwire_u32 */
u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); }
/* Generated stub for fromwire_u64 */
u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); }
/* Generated stub for fromwire_u8 */
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
/* Generated stub for fromwire_u8_array */
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); }
/* Generated stub for fromwire_wirestring */
char *fromwire_wirestring(const tal_t *ctx UNNEEDED, const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_wirestring called!\n"); abort(); }
/* Generated stub for htlc_state_flags */
int htlc_state_flags(enum htlc_state state UNNEEDED)
{ fprintf(stderr, "htlc_state_flags called!\n"); abort(); }
/* Generated stub for htlc_state_name */
const char *htlc_state_name(enum htlc_state s UNNEEDED)
{ fprintf(stderr, "htlc_state_name called!\n"); abort(); }
/* Generated stub for json_get_id */
const char *json_get_id(const tal_t *ctx UNNEEDED,
			const char *buffer UNNEEDED, const jsmntok_t *obj UNNEEDED)
{ fprintf(stderr, "json_get_id called!\n"); abort(); }
/* Generated stub for json_get_member */
const jsmntok_t *json_get_member(const char *buffer UNNEEDED, const jsmntok_t tok[] UNNEEDED,
				 const char *label UNNEEDED)
{ fprintf(stderr, "json_get_member called!\n"); abort(); }
/* Generated stub for json_next */
const jsmntok_t *json_next(const jsmntok_t *tok UNNEEDED)
{ fprintf(stderr, "json_next called!\n"); abort(); }
/* Generated stub for json_parse_input */
bool json_parse_input(jsmn_parser *parser UNNEEDED,
		      jsmntok_t **toks UNNEEDED,
		      const char *input UNNEEDED, int len UNNEEDED,
		      bool *complete UNNEEDED)
{ fprintf(stderr, "json_parse_input called!\n"); abort(); }
/* Generated stub for json_parse_simple */
jsmntok_t *json_parse_simple(const tal_t *ctx UNNEEDED, const char *input UNNEEDED, int len UNNEEDED)
{ fprintf(stderr, "json_parse_simple called!\n"); abort(); }
/* Generated stub for json_scan */
const char *json_scan(const tal_t *ctx UNNEEDED,
		      const char *buffer UNNEEDED,
		      const jsmntok_t *tok UNNEEDED,
		      const char *guide UNNEEDED,
		      ...)
{ fprintf(stderr, "json_scan called!\n"); abort(); }
/* Generated stub for json_scanv */
const char *json_scanv(const tal_t *ctx UNNEEDED,
		       const char *buffer UNNEEDED,
		       const jsmntok_t *tok UNNEEDED,
		       const char *guide UNNEEDED,
		       va_list ap UNNEEDED)
{ fprintf(stderr, "json_scanv called!\n"); abort(); }
/* Generated stub for json_strdup */
char *json_strdup(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED)
{ fprintf(stderr, "json_strdup called!\n"); abort(); }
/* Generated stub for json_to_bool */
bool json_to_bool(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, bool *b UNNEEDED)
{ fprintf(stderr, "json_to_bool called!\n"); abort(); }
/* Generated stub for json_to_int */
bool json_to_int(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, int *num UNNEEDED)
{ fprintf(stderr, "json_to_int called!\n"); abort(); }
/* Generated stub for json_to_msat */
bool json_to_msat(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
		  struct amount_msat *msat UNNEEDED)
{ fprintf(stderr, "json_to_msat called!\n"); abort(); }
/* Generated stub for json_to_node_id */
bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
			       struct node_id *id UNNEEDED)
{ fprintf(stderr, "json_to_node_id called!\n"); abort(); }
/* Generated stub for json_to_number */
bool json_to_number(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
		    unsigned int *num UNNEEDED)
{ fprintf(stderr, "json_to_number called!\n"); abort(); }
/* Generated stub for json_to_secret */
bool json_to_secret(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, struct secret *dest UNNEEDED)
{ fprintf(stderr, "json_to_secret called!\n"); abort(); }
/* Generated stub for json_to_short_channel_id */
bool json_to_short_channel_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
			      struct short_channel_id *scid UNNEEDED)
{ fprintf(stderr, "json_to_short_channel_id called!\n"); abort(); }
/* Generated stub for json_to_txid */
bool json_to_txid(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
		  struct bitcoin_txid *txid UNNEEDED)
{ fprintf(stderr, "json_to_txid called!\n"); abort(); }
/* Generated stub for json_to_u16 */
bool json_to_u16(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
                 uint16_t *num UNNEEDED)
{ fprintf(stderr, "json_to_u16 called!\n"); abort(); }
/* Generated stub for json_tok_bin_from_hex */
u8 *json_tok_bin_from_hex(const tal_t *ctx UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED)
{ fprintf(stderr, "json_tok_bin_from_hex called!\n"); abort(); }
/* Generated stub for json_tok_full */
const char *json_tok_full(const char *buffer UNNEEDED, const jsmntok_t *t UNNEEDED)
{ fprintf(stderr, "json_tok_full called!\n"); abort(); }
/* Generated stub for json_tok_full_len */
int json_tok_full_len(const jsmntok_t *t UNNEEDED)
{ fprintf(stderr, "json_tok_full_len called!\n"); abort(); }
/* Generated stub for json_tok_streq */
bool json_tok_streq(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, const char *str UNNEEDED)
{ fprintf(stderr, "json_tok_streq called!\n"); abort(); }
/* Generated stub for last_fee_state */
enum htlc_state last_fee_state(enum side opener UNNEEDED)
{ fprintf(stderr, "last_fee_state called!\n"); abort(); }
/* Generated stub for log_level_name */
const char *log_level_name(enum log_level level UNNEEDED)
{ fprintf(stderr, "log_level_name called!\n"); abort(); }
/* Generated stub for new_channel_event */
struct channel_event *new_channel_event(const tal_t *ctx UNNEEDED,
					const char *tag UNNEEDED,
					struct amount_msat credit UNNEEDED,
					struct amount_msat debit UNNEEDED,
					struct amount_msat fees UNNEEDED,
					const char *currency UNNEEDED,
					struct sha256 *payment_id STEALS UNNEEDED,
					u32 part_id UNNEEDED,
					u64 timestamp UNNEEDED)
{ fprintf(stderr, "new_channel_event called!\n"); abort(); }
/* Generated stub for toks_alloc */
jsmntok_t *toks_alloc(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "toks_alloc called!\n"); abort(); }
/* Generated stub for toks_reset */
void toks_reset(jsmntok_t *toks UNNEEDED)
{ fprintf(stderr, "toks_reset called!\n"); abort(); }
/* Generated stub for towire */
void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED)
{ fprintf(stderr, "towire called!\n"); abort(); }
/* Generated stub for towire_bool */
void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED)
{ fprintf(stderr, "towire_bool called!\n"); abort(); }
/* Generated stub for towire_secp256k1_ecdsa_signature */
void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED,
			      const secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "towire_secp256k1_ecdsa_signature called!\n"); abort(); }
/* Generated stub for towire_sha256 */
void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED)
{ fprintf(stderr, "towire_sha256 called!\n"); abort(); }
/* Generated stub for towire_u16 */
void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED)
{ fprintf(stderr, "towire_u16 called!\n"); abort(); }
/* Generated stub for towire_u32 */
void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
{ fprintf(stderr, "towire_u32 called!\n"); abort(); }
/* Generated stub for towire_u64 */
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
/* Generated stub for towire_u8 */
void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
{ fprintf(stderr, "towire_u8 called!\n"); abort(); }
/* Generated stub for towire_u8_array */
void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "towire_u8_array called!\n"); abort(); }
/* Generated stub for towire_wirestring */
void towire_wirestring(u8 **pptr UNNEEDED, const char *str UNNEEDED)
{ fprintf(stderr, "towire_wirestring called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */

static char *tmp_dsn(const tal_t *ctx)
{
	char *dsn, *filename;
	int fd = tmpdir_mkstemp(ctx, "lacct-db-XXXXXX", &filename);
	if (fd == -1)
		return NULL;
	close(fd);

	dsn = tal_fmt(ctx, "sqlite3://%s", filename);
	tal_free(filename);

	return dsn;
}

static bool accountseq(struct account *a1, struct account *a2)
{
	CHECK(a1->db_id == a2->db_id);
	CHECK(streq(a1->name, a2->name));
	CHECK((a1->peer_id != NULL) == (a2->peer_id != NULL));
	if (a1->peer_id)
		CHECK(node_id_eq(a1->peer_id, a2->peer_id));
	CHECK(a1->is_wallet == a2->is_wallet);
	CHECK(a1->we_opened == a2->we_opened);
	CHECK(a1->leased == a2->leased);
	CHECK(a1->onchain_resolved_block == a2->onchain_resolved_block);

	CHECK((a1->open_event_db_id != NULL) == (a2->open_event_db_id != NULL));
	if (a1->open_event_db_id)
		CHECK(*a1->open_event_db_id == *a2->open_event_db_id);

	CHECK((a1->closed_event_db_id != NULL) == (a2->closed_event_db_id != NULL));
	if (a1->closed_event_db_id)
		CHECK(*a1->closed_event_db_id == *a2->closed_event_db_id);

	CHECK(a1->closed_count == a2->closed_count);

	return true;
}

static bool channel_events_eq(struct channel_event *e1, struct channel_event *e2)
{
	CHECK(e1->db_id == e2->db_id);
	CHECK(e1->acct_db_id == e2->acct_db_id);
	CHECK(streq(e1->tag, e2->tag));
	CHECK(amount_msat_eq(e1->credit, e2->credit));
	CHECK(amount_msat_eq(e1->debit, e2->debit));
	CHECK(amount_msat_eq(e1->fees, e2->fees));
	CHECK((e1->rebalance_id != NULL) == (e2->rebalance_id != NULL));
	if (e1->rebalance_id)
		CHECK(*e1->rebalance_id == *e2->rebalance_id);
	CHECK(streq(e1->currency, e2->currency));
	CHECK((e1->payment_id != NULL) == (e2->payment_id != NULL));
	if (e1->payment_id)
		CHECK(sha256_eq(e1->payment_id, e2->payment_id));
	CHECK(e1->part_id == e2->part_id);
	CHECK(e1->timestamp == e2->timestamp);

	CHECK((e1->desc != NULL) == (e2->desc != NULL));
	if (e1->desc)
		CHECK(streq(e1->desc, e2->desc));

	return true;
}

static bool chain_events_eq(struct chain_event *e1, struct chain_event *e2)
{
	CHECK(e1->db_id == e2->db_id);
	CHECK(e1->acct_db_id == e2->acct_db_id);
	CHECK((e1->origin_acct != NULL) == (e2->origin_acct != NULL));
	if (e1->origin_acct)
		CHECK(streq(e1->origin_acct, e2->origin_acct));
	CHECK(streq(e1->tag, e2->tag));
	CHECK(amount_msat_eq(e1->credit, e2->credit));
	CHECK(amount_msat_eq(e1->debit, e2->debit));
	CHECK(amount_msat_eq(e1->output_value, e2->output_value));
	CHECK(streq(e1->currency, e2->currency));
	CHECK(e1->timestamp == e2->timestamp);
	CHECK(e1->blockheight == e2->blockheight);
	CHECK(e1->stealable == e2->stealable);
	CHECK(e1->ignored == e2->ignored);
	CHECK(bitcoin_outpoint_eq(&e1->outpoint, &e2->outpoint));

	CHECK((e1->spending_txid != NULL) == (e2->spending_txid != NULL));
	if (e1->spending_txid)
		CHECK(bitcoin_txid_eq(e1->spending_txid, e2->spending_txid));

	CHECK((e1->payment_id != NULL) == (e2->payment_id != NULL));
	if (e1->payment_id)
		CHECK(sha256_eq(e1->payment_id, e2->payment_id));

	CHECK((e1->desc != NULL) == (e2->desc != NULL));
	if (e1->desc)
		CHECK(streq(e1->desc, e2->desc));

	return true;
}

static struct channel_event *make_channel_event(const tal_t *ctx,
						char *tag,
						struct amount_msat credit,
						struct amount_msat debit,
						char payment_char)
{
	struct channel_event *ev = tal(ctx, struct channel_event);

	ev->payment_id = tal(ev, struct sha256);
	memset(ev->payment_id, payment_char, sizeof(struct sha256));
	ev->credit = credit;
	ev->debit = debit;
	ev->fees = AMOUNT_MSAT(104);
	ev->currency = "btc";
	ev->timestamp = 1919191;
	ev->part_id = 19;
	ev->tag = tag;
	ev->desc = tal_fmt(ev, "description");
	ev->rebalance_id = NULL;
	return ev;
}

static struct chain_event *make_chain_event(const tal_t *ctx,
					    char *tag,
					    struct amount_msat credit,
					    struct amount_msat debit,
					    struct amount_msat output_val,
					    u32 blockheight,
					    char outpoint_char,
					    u32 outnum,
					    /* Note that '*' is magic */
					    char spend_char)


{
	struct chain_event *ev = tal(ctx, struct chain_event);

	/* This event spends the second inserted event */
	ev->tag = tal_fmt(ctx, "%s", tag);
	ev->origin_acct = NULL;
	ev->credit = credit;
	ev->debit = debit;
	ev->output_value = output_val;
	ev->currency = "btc";
	ev->timestamp = 1919191;
	ev->blockheight = blockheight;
	ev->ignored = false;
	ev->stealable = false;
	ev->desc = tal_fmt(ev, "hello hello");
	memset(&ev->outpoint.txid, outpoint_char, sizeof(struct bitcoin_txid));
	ev->outpoint.n = outnum;

	if (spend_char != '*') {
		ev->spending_txid = tal(ctx, struct bitcoin_txid);
		memset(ev->spending_txid, spend_char,
		       sizeof(struct bitcoin_txid));
	} else
		ev->spending_txid = NULL;

	ev->payment_id = NULL;

	return ev;
}

static bool test_onchain_fee_wallet_spend(const tal_t *ctx, struct plugin *p)
{
	bool created;
	struct db *db = db_setup(ctx, p, tmp_dsn(ctx), &created);
	struct node_id node_id, peer_id;
	struct account *wal_acct, *ext_acct;
	struct bitcoin_txid txid;
	struct onchain_fee **ofs;
	u32 blockheight = 100000;

	memset(&node_id, 2, sizeof(struct node_id));
	memset(&peer_id, 3, sizeof(struct node_id));

	wal_acct = new_account(ctx, tal_fmt(ctx, "wallet"), &peer_id);
	ext_acct = new_account(ctx, tal_fmt(ctx, "external"), &peer_id);
	memset(&txid, '1', sizeof(struct bitcoin_txid));

	db_begin_transaction(db);
	account_add(db, wal_acct);
	account_add(db, ext_acct);
	db_commit_transaction(db);


	/* Send funds to an external address
	 * tag     utxo_id vout    txid    debits  credits acct_id
	 * withdr  XXXX    0       1111    1000            wallet
	 * deposit 1111    1                        200    wallet
	 * deposit 1111    0                        700    external
	 */
	db_begin_transaction(db);
	log_chain_event(db, wal_acct,
		make_chain_event(ctx, "withdrawal",
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(1000),
				 AMOUNT_MSAT(1000),
				 blockheight,
				 'X', 0, '1'));
	maybe_update_onchain_fees(ctx, db, &txid);

	log_chain_event(db, wal_acct,
		make_chain_event(ctx, "deposit",
				 AMOUNT_MSAT(200),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(200),
				 blockheight,
				 '1', 1, '*'));
	maybe_update_onchain_fees(ctx, db, &txid);

	log_chain_event(db, ext_acct,
		make_chain_event(ctx, "deposit",
				 AMOUNT_MSAT(700),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(700),
				 blockheight,
				 '1', 0, '*'));
	maybe_update_onchain_fees(ctx, db, &txid);
	db_commit_transaction(db);

	db_begin_transaction(db);
	ofs = list_chain_fees(ctx, db);
	db_commit_transaction(db);

	CHECK(tal_count(ofs) == 2);

	/* we expect 800, then -700 */
	CHECK(amount_msat_eq(ofs[0]->credit, AMOUNT_MSAT(800)));
	CHECK(amount_msat_zero(ofs[0]->debit));
	CHECK(ofs[0]->update_count == 1);

	CHECK(amount_msat_zero(ofs[1]->credit));
	CHECK(amount_msat_eq(ofs[1]->debit, AMOUNT_MSAT(700)));
	CHECK(ofs[1]->update_count == 2);

	return true;
}

static bool test_onchain_fee_chan_close(const tal_t *ctx, struct plugin *p)
{
	bool created;
	struct db *db = db_setup(ctx, p, tmp_dsn(ctx), &created);
	struct node_id node_id, peer_id;
	struct account *acct, *wal_acct, *ext_acct;
	struct onchain_fee **ofs, **ofs1;
	struct bitcoin_txid txid;
	struct chain_event *ev;
	enum mvt_tag *tags;
	u32 close_output_count;
	u32 blockheight = 100000;
	char *err;

	memset(&node_id, 2, sizeof(struct node_id));
	memset(&peer_id, 3, sizeof(struct node_id));
	/* to_us, to_them, 1 htlc, 2 anchors */
	close_output_count = 5;

	wal_acct = new_account(ctx, tal_fmt(ctx, "wallet"), &peer_id);
	ext_acct = new_account(ctx, tal_fmt(ctx, "external"), &peer_id);
	acct = new_account(ctx, tal_fmt(ctx, "chan-1"), &peer_id);

	db_begin_transaction(db);
	account_add(db, wal_acct);
	account_add(db, ext_acct);
	account_add(db, acct);
	db_commit_transaction(db);

	/* Close a channel */
	/* tag     utxo_id vout    txid    debits  credits acct_id
	 * close   XXXX    0       1111    1000            wallet
	 * delay   1111    1                        200    chan-1
	 * anchor  1111    0                         30    chan-1
	 * anchor  1111    4                         30    external
	 * to_wall 1111    1       2222     200            chan-1
	 * htlc_tim1111    2                        600    chan-1
	 * htlc_tim1111    2       3333     600            chan-1
	 * to_them 1111    3                        300    external
	 * deposit 2222    0                        150    chan-1
	 * htlc_tx 3333    0                        450    chan-1
	 * to_wall 3333    0       4444     450            chan-1
	 * deposit 4444    0                        350    wallet
	 */
	tags = tal_arr(ctx, enum mvt_tag, 1);
	db_begin_transaction(db);
	ev = make_chain_event(ctx, "channel_open",
				    AMOUNT_MSAT(1000),
				    AMOUNT_MSAT(0),
				    AMOUNT_MSAT(1660),
				    blockheight,
				    'X', 0, '*');
	log_chain_event(db, acct, ev);
	tags[0] = CHANNEL_OPEN;
	maybe_update_account(db, acct, ev, tags, 0, NULL);

	ev = make_chain_event(ctx, "channel_close",
				    AMOUNT_MSAT(0),
				    AMOUNT_MSAT(1000),
				    AMOUNT_MSAT(1660),
				    blockheight,
				    'X', 0, '1');
	log_chain_event(db, acct, ev);

	/* Update the account to have the right info! */
	tags[0] = CHANNEL_CLOSE;
	maybe_update_account(db, acct, ev, tags, close_output_count, NULL);

	log_chain_event(db, acct,
		make_chain_event(ctx, "delayed_to_us",
				 AMOUNT_MSAT(200),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(200),
				 blockheight,
				 '1', 1, '*'));
	memset(&txid, '1', sizeof(struct bitcoin_txid));
	maybe_update_onchain_fees(ctx, db, &txid);

	log_chain_event(db, wal_acct,
		make_chain_event(ctx, "anchor",
				 AMOUNT_MSAT(30),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(30),
				 blockheight,
				 '1', 0, '*'));
	log_chain_event(db, ext_acct,
		make_chain_event(ctx, "anchor",
				 AMOUNT_MSAT(30),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(30),
				 blockheight,
				 '1', 4, '*'));
	memset(&txid, '1', sizeof(struct bitcoin_txid));
	maybe_update_onchain_fees(ctx, db, &txid);

	/* Should be no fees yet */
	ofs = list_chain_fees(ctx, db);
	CHECK(tal_count(ofs) == 0);

	log_chain_event(db, acct,
		make_chain_event(ctx, "htlc_timeout",
				 AMOUNT_MSAT(600),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(600),
				 blockheight,
				 '1', 2, '*'));

	log_chain_event(db, ext_acct,
		make_chain_event(ctx, "to_them",
				 AMOUNT_MSAT(300),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(300),
				 blockheight,
				 '1', 3, '*'));

	memset(&txid, '1', sizeof(struct bitcoin_txid));
	maybe_update_onchain_fees(ctx, db, &txid);
	db_commit_transaction(db);

	/* txid 2222 */
	db_begin_transaction(db);
	log_chain_event(db, acct,
		make_chain_event(ctx, "to_wallet",
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(200),
				 AMOUNT_MSAT(200),
				 blockheight + 1,
				 '1', 1, '2'));

	log_chain_event(db, wal_acct,
		make_chain_event(ctx, "deposit",
				 AMOUNT_MSAT(150),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(150),
				 blockheight + 1,
				 '2', 0, '*'));
	memset(&txid, '2', sizeof(struct bitcoin_txid));
	maybe_update_onchain_fees(ctx, db, &txid);
	CHECK(acct->onchain_resolved_block == 0);

	maybe_mark_account_onchain(db, acct);
	CHECK(acct->onchain_resolved_block == 0);
	db_commit_transaction(db);

	/* Expect: 1 onchain fee records, all for chan-1 */
	db_begin_transaction(db);
	ofs = list_chain_fees(ctx, db);
	ofs1 = account_onchain_fees(ctx, db, acct);
	db_commit_transaction(db);

	CHECK(tal_count(ofs) == tal_count(ofs1));
	CHECK(tal_count(ofs) == 1);

	/* txid 4444 */
	db_begin_transaction(db);
	log_chain_event(db, wal_acct,
		make_chain_event(ctx, "deposit",
				 AMOUNT_MSAT(350),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(350),
				 blockheight + 2,
				 '4', 0, '*'));

	memset(&txid, '4', sizeof(struct bitcoin_txid));
	maybe_update_onchain_fees(ctx, db, &txid);

	/* txid 3333 */
	log_chain_event(db, acct,
		make_chain_event(ctx, "htlc_timeout",
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(600),
				 AMOUNT_MSAT(600),
				 blockheight + 2,
				 '1', 2, '3'));

	maybe_mark_account_onchain(db, acct);
	CHECK(acct->onchain_resolved_block == 0);

	log_chain_event(db, acct,
		make_chain_event(ctx, "htlc_tx",
				 AMOUNT_MSAT(450),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(450),
				 blockheight + 2,
				 '3', 0, '*'));

	memset(&txid, '3', sizeof(struct bitcoin_txid));
	maybe_update_onchain_fees(ctx, db, &txid);

	log_chain_event(db, acct,
		make_chain_event(ctx, "to_wallet",
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(450),
				 AMOUNT_MSAT(450),
				 blockheight + 2,
				 '3', 0, '4'));

	memset(&txid, '4', sizeof(struct bitcoin_txid));
	maybe_update_onchain_fees(ctx, db, &txid);

	db_commit_transaction(db);

	/* Expect: onchain fee records for tx except channel close */
	db_begin_transaction(db);
	ofs = list_chain_fees(ctx, db);
	ofs1 = account_onchain_fees(ctx, db, acct);
	db_commit_transaction(db);

	CHECK(tal_count(ofs) == tal_count(ofs1));
	CHECK(tal_count(ofs) == 3);

	/* Now we update the channel's onchain fees */
	CHECK(acct->onchain_resolved_block == 0);
	db_begin_transaction(db);
	maybe_mark_account_onchain(db, acct);
	CHECK(acct->onchain_resolved_block == blockheight + 2);
	err = update_channel_onchain_fees(ctx, db, acct);
	CHECK_MSG(!err, err);
	ofs = account_onchain_fees(ctx, db, acct);
	db_commit_transaction(db);

	/* Expect: fees as follows
	 *
	 * chan-1, 1111, 200 (anchor outs ignored)
	 * chan-1, 2222,  50
	 * chan-1, 3333, 150
	 * chan-1, 4444, 100
	 */
	CHECK(tal_count(ofs) == 4);
	for (size_t i = 0; i < tal_count(ofs); i++) {
		CHECK(ofs[i]->acct_db_id == acct->db_id);
		CHECK(streq(ofs[i]->currency, "btc"));

		memset(&txid, '1', sizeof(struct bitcoin_txid));
		if (bitcoin_txid_eq(&txid, &ofs[i]->txid)) {
			CHECK(ofs[i]->update_count == 1);
			CHECK(amount_msat_eq(ofs[i]->credit, AMOUNT_MSAT(200)));
			CHECK(amount_msat_zero(ofs[i]->debit));
			continue;
		}
		memset(&txid, '2', sizeof(struct bitcoin_txid));
		if (bitcoin_txid_eq(&txid, &ofs[i]->txid)) {
			CHECK(ofs[i]->update_count == 1);
			CHECK(amount_msat_eq(ofs[i]->credit, AMOUNT_MSAT(50)));
			CHECK(amount_msat_zero(ofs[i]->debit));
			continue;
		}
		memset(&txid, '3', sizeof(struct bitcoin_txid));
		if (bitcoin_txid_eq(&txid, &ofs[i]->txid)) {
			CHECK(ofs[i]->update_count == 1);
			CHECK(amount_msat_eq(ofs[i]->credit, AMOUNT_MSAT(150)));
			CHECK(amount_msat_zero(ofs[i]->debit));
			continue;
		}
		memset(&txid, '4', sizeof(struct bitcoin_txid));
		if (bitcoin_txid_eq(&txid, &ofs[i]->txid)) {
			CHECK(ofs[i]->update_count == 1);
			CHECK(amount_msat_eq(ofs[i]->credit, AMOUNT_MSAT(100)));
			CHECK(amount_msat_zero(ofs[i]->debit));
			continue;
		}

		CHECK_MSG(false, "txid didn't match");
	}

	return true;
}

static bool test_onchain_fee_chan_open(const tal_t *ctx, struct plugin *p)
{
	bool created;
	struct db *db = db_setup(ctx, p, tmp_dsn(ctx), &created);
	struct node_id node_id, peer_id;
	struct account *acct, *acct2, *wal_acct, *ext_acct;
	struct bitcoin_txid txid;
	struct onchain_fee **ofs;
	u32 blockheight = 100000;

	memset(&node_id, 2, sizeof(struct node_id));
	memset(&peer_id, 3, sizeof(struct node_id));

	wal_acct = new_account(ctx, tal_fmt(ctx, "wallet"), &peer_id);
	ext_acct = new_account(ctx, tal_fmt(ctx, "external"), &peer_id);
	acct = new_account(ctx, tal_fmt(ctx, "chan-1"), &peer_id);
	acct2 = new_account(ctx, tal_fmt(ctx, "chan-2"), &peer_id);

	db_begin_transaction(db);
	account_add(db, wal_acct);
	account_add(db, ext_acct);
	account_add(db, acct);
	account_add(db, acct2);
	db_commit_transaction(db);

	/* Assumption that we rely on later */
	CHECK(acct->db_id < acct2->db_id);

	/* Open two channels from wallet */
	/* tag     utxo_id vout    txid    debits  credits acct_id
	 * withd   XXXX    0       AAAA    1000            wallet
	 * withd   YYYY    0       AAAA    3001            wallet
	 * open    AAAA    0                        500    chan-1
	 * open    AAAA    1                       1000    chan-2
	 * depo    AAAA    2                       2200    wallet
	 */
	memset(&txid, 'A', sizeof(struct bitcoin_txid));
	db_begin_transaction(db);
	log_chain_event(db, wal_acct,
		make_chain_event(ctx, "withdrawal",
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(1000),
				 AMOUNT_MSAT(1000),
				 blockheight,
				 'X', 0, 'A'));
	log_chain_event(db, wal_acct,
		make_chain_event(ctx, "withdrawal",
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(3001),
				 AMOUNT_MSAT(3001),
				 blockheight,
				 'Y', 0, 'A'));

	log_chain_event(db, acct,
		make_chain_event(ctx, "deposit",
				 AMOUNT_MSAT(500),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(500),
				 blockheight,
				 'A', 0, '*'));
	maybe_update_onchain_fees(ctx, db, &txid);

	log_chain_event(db, acct2,
		make_chain_event(ctx, "deposit",
				 AMOUNT_MSAT(1000),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(1000),
				 blockheight,
				 'A', 1, '*'));
	maybe_update_onchain_fees(ctx, db, &txid);

	log_chain_event(db, wal_acct,
		make_chain_event(ctx, "deposit",
				 AMOUNT_MSAT(2200),
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(2200),
				 blockheight,
				 'A', 2, '*'));
	maybe_update_onchain_fees(ctx, db, &txid);

	maybe_update_onchain_fees(ctx, db, &txid);
	db_commit_transaction(db);

	/* Expect: 5 onchain fee records, totaling to 151/150msat ea,
	 * none for wallet */
	db_begin_transaction(db);
	ofs = list_chain_fees(ctx, db);
	db_commit_transaction(db);

	CHECK(tal_count(ofs) == 5);

	struct exp_result {
		u32 credit;
		u32 debit;
		u32 update_count;
	};

	struct exp_result exp_results[] = {
		{ .credit = 3501, .debit = 0, .update_count = 1 },
		{ .credit = 0, .debit = 2250, .update_count = 2 },
		{ .credit = 0, .debit = 1100, .update_count = 3 },
		{ .credit = 1250, .debit = 0, .update_count = 1 },
		{ .credit = 0, .debit = 1100, .update_count = 2 },
	};

	/* Since these are sorted on fetch,
	 * this *should* be stable */
	for (size_t i = 0; i < tal_count(ofs); i++) {
		CHECK(i < ARRAY_SIZE(exp_results));
		CHECK(amount_msat_eq(ofs[i]->credit,
				     amount_msat(exp_results[i].credit)));
		CHECK(amount_msat_eq(ofs[i]->debit,
				     amount_msat(exp_results[i].debit)));
		CHECK(ofs[i]->update_count == exp_results[i].update_count);

		CHECK(streq(ofs[i]->currency, "btc"));
		CHECK(bitcoin_txid_eq(&ofs[i]->txid, &txid));
	}

	return true;
}

static bool test_channel_rebalances(const tal_t *ctx, struct plugin *p)
{
	bool created;
	struct db *db = db_setup(ctx, p, tmp_dsn(ctx), &created);
	struct channel_event *ev1, *ev2, *ev3, **chan_evs;
	struct rebalance **rebals;
	struct account *acct1, *acct2, *acct3;
	struct node_id peer_id;

	memset(&peer_id, 3, sizeof(struct node_id));
	acct1 = new_account(ctx, tal_fmt(ctx, "one"), &peer_id);
	acct2 = new_account(ctx, tal_fmt(ctx, "two"), &peer_id);
	acct3 = new_account(ctx, tal_fmt(ctx, "three"), &peer_id);

	db_begin_transaction(db);

	account_add(db, acct1);
	account_add(db, acct2);
	account_add(db, acct3);

	/* Simulate a rebalance of 100msats, w/ a 12msat fee */
	ev1 = make_channel_event(ctx, "invoice",
		           AMOUNT_MSAT(100),
			   AMOUNT_MSAT(0),
			   'A');
	ev1->fees = AMOUNT_MSAT(0);
	log_channel_event(db, acct1, ev1);

	ev2 = make_channel_event(ctx, "invoice",
				 AMOUNT_MSAT(0),
				 AMOUNT_MSAT(112),
				 'A');
	ev2->fees = AMOUNT_MSAT(12);
	log_channel_event(db, acct2, ev2);

	/* Third event w/ same preimage but diff amounts */
	ev3 = make_channel_event(ctx, "invoice",
				 AMOUNT_MSAT(105),
				 AMOUNT_MSAT(0),
				 'A');
	log_channel_event(db, acct3, ev3);
	db_commit_transaction(db);

	db_begin_transaction(db);
	chan_evs = account_get_channel_events(ctx, db, acct1);
	CHECK(tal_count(chan_evs) == 1 && !chan_evs[0]->rebalance_id);

	chan_evs = account_get_channel_events(ctx, db, acct2);
	CHECK(tal_count(chan_evs) == 1 && !chan_evs[0]->rebalance_id);

	chan_evs = account_get_channel_events(ctx, db, acct3);
	CHECK(tal_count(chan_evs) == 1 && !chan_evs[0]->rebalance_id);

	maybe_record_rebalance(db, ev2);
	CHECK(ev2->rebalance_id != NULL);

	/* Both events should be marked as rebalance */
	chan_evs = account_get_channel_events(ctx, db, acct1);
	CHECK(tal_count(chan_evs) == 1 && chan_evs[0]->rebalance_id);

	chan_evs = account_get_channel_events(ctx, db, acct2);
	CHECK(tal_count(chan_evs) == 1 && chan_evs[0]->rebalance_id);

	/* Third event is not a rebalance though */
	chan_evs = account_get_channel_events(ctx, db, acct3);
	CHECK(tal_count(chan_evs) == 1 && !chan_evs[0]->rebalance_id);

	/* Did we get an accurate rebalances entry? */
	rebals = list_rebalances(ctx, db);

	CHECK(tal_count(rebals) == 1);

	CHECK(rebals[0]->in_ev_id == ev1->db_id);
	CHECK(rebals[0]->out_ev_id == ev2->db_id);
	CHECK(streq(rebals[0]->in_acct_name, "one"));
	CHECK(streq(rebals[0]->out_acct_name, "two"));
	CHECK(amount_msat_eq(rebals[0]->rebal_msat, AMOUNT_MSAT(100)));
	CHECK(amount_msat_eq(rebals[0]->fee_msat, AMOUNT_MSAT(12)));

	db_commit_transaction(db);

	return true;
}

static bool test_channel_event_crud(const tal_t *ctx, struct plugin *p)
{
	bool created;
	struct db *db = db_setup(ctx, p, tmp_dsn(ctx), &created);
	struct node_id peer_id;
	struct account *acct, *acct2;
	struct channel_event *ev1, *ev2, *ev3, **chan_evs;

	memset(&peer_id, 3, sizeof(struct node_id));

	acct = new_account(ctx, tal_fmt(ctx, "example"), &peer_id);
	acct2 = new_account(ctx, tal_fmt(ctx, "wallet"), &peer_id);
	db_begin_transaction(db);
	account_add(db, acct);
	account_add(db, acct2);
	db_commit_transaction(db);

	ev1 = tal(ctx, struct channel_event);
	ev1->payment_id = tal(ev1, struct sha256);
	memset(ev1->payment_id, 'B', sizeof(struct sha256));
	ev1->credit = AMOUNT_MSAT(100);
	ev1->debit = AMOUNT_MSAT(102);
	ev1->fees = AMOUNT_MSAT(104);
	ev1->currency = "btc";
	ev1->timestamp = 11111;
	ev1->part_id = 19;
	ev1->desc = tal_strdup(ev1, "hello desc1");
	ev1->rebalance_id = NULL;

	/* Passing unknown tags in should be ok */
	ev1->tag = "hello";
	ev1->desc = tal_fmt(ev1, "desc");

	ev2 = tal(ctx, struct channel_event);
	ev2->payment_id = tal(ev2, struct sha256);
	memset(ev2->payment_id, 'C', sizeof(struct sha256));
	ev2->credit = AMOUNT_MSAT(200);
	ev2->debit = AMOUNT_MSAT(202);
	ev2->fees = AMOUNT_MSAT(204);
	ev2->currency = "brct";
	ev2->timestamp = 22222;
	ev2->part_id = 0;
	ev2->tag = tal_fmt(ev2, "deposit");
	ev2->desc = NULL;
	ev2->rebalance_id = tal(ev2, u64);
	*ev2->rebalance_id = 1;

	ev3 = tal(ctx, struct channel_event);
	ev3->payment_id = tal(ev3, struct sha256);
	memset(ev3->payment_id, 'D', sizeof(struct sha256));
	ev3->credit = AMOUNT_MSAT(300);
	ev3->debit = AMOUNT_MSAT(302);
	ev3->fees = AMOUNT_MSAT(304);
	ev3->currency = "brct";
	ev3->timestamp = 33333;
	ev3->part_id = 5;
	ev3->tag = tal_fmt(ev3, "routed");
	ev3->desc = NULL;
	ev3->rebalance_id = NULL;

	db_begin_transaction(db);
	log_channel_event(db, acct, ev1);
	log_channel_event(db, acct, ev2);

	/* log a channel event to a different acct */
	log_channel_event(db, acct2, ev3);

	/* log a channel event without a payment id */
	ev3->payment_id = NULL;
	log_channel_event(db, acct2, ev3);

	db_commit_transaction(db);

	db_begin_transaction(db);
	chan_evs = account_get_channel_events(ctx, db, acct);
	db_commit_transaction(db);

	CHECK(streq(acct->name, chan_evs[0]->acct_name));
	CHECK(streq(acct->name, chan_evs[1]->acct_name));

	CHECK(tal_count(chan_evs) == 2);
	channel_events_eq(ev1, chan_evs[0]);
	channel_events_eq(ev2, chan_evs[1]);

	return true;
}

static bool test_chain_event_crud(const tal_t *ctx, struct plugin *p)
{
	bool created;
	struct db *db = db_setup(ctx, p, tmp_dsn(ctx), &created);
	struct node_id peer_id;
	struct account *acct, *acct2;
	struct chain_event *ev1, *ev2, *ev3, **chain_evs;
	char *name = tal_fmt(ctx, "example");

	ev2 = tal(ctx, struct chain_event);
	memset(&peer_id, 3, sizeof(struct node_id));

	acct = new_account(ctx, name, &peer_id);
	acct2 = new_account(ctx, tal_fmt(ctx, "wallet"), &peer_id);
	db_begin_transaction(db);
	account_add(db, acct);
	account_add(db, acct2);
	db_commit_transaction(db);

	/* This event spends the second inserted event */
	ev1 = tal(ctx, struct chain_event);
	ev1->tag = tal_fmt(ev1, "withdrawal");
	ev1->origin_acct = NULL;
	ev1->credit = AMOUNT_MSAT(100);
	ev1->debit = AMOUNT_MSAT(102);
	ev1->output_value = AMOUNT_MSAT(104);
	ev1->currency = "btc";
	ev1->timestamp = 1919191;
	ev1->blockheight = 1919191;
	ev1->ignored = false;
	ev1->stealable  = false;
	memset(&ev1->outpoint.txid, 'D', sizeof(struct bitcoin_txid));
	ev1->outpoint.n = 1;
	ev1->spending_txid = tal(ctx, struct bitcoin_txid);
	memset(ev1->spending_txid, 'C', sizeof(struct bitcoin_txid));
	ev1->payment_id = NULL;
	ev1->desc = tal_fmt(ev1, "description");

	db_begin_transaction(db);
	log_chain_event(db, acct, ev1);
	db_commit_transaction(db);

	ev2->tag = tal_fmt(ctx, "deposit");
	ev2->origin_acct = tal_fmt(ctx, "wallet");
	ev2->credit = AMOUNT_MSAT(200);
	ev2->debit = AMOUNT_MSAT(202);
	ev2->output_value = AMOUNT_MSAT(104);
	ev2->currency = "btc";
	ev2->timestamp = 1919191;
	ev2->blockheight = 1919191;
	ev2->ignored = false;
	ev2->stealable = false;
	memset(&ev2->outpoint.txid, 'D', sizeof(struct bitcoin_txid));
	ev2->outpoint.n = 1;
	ev2->spending_txid = NULL;
	ev2->payment_id = tal(ctx, struct sha256);
	ev2->desc = NULL;
	memset(ev2->payment_id, 'B', sizeof(struct sha256));

	/* Dummy event, logged to separate account */
	ev3 = tal(ctx, struct chain_event);
	ev3->tag = tal_fmt(ev3, "deposit");
	ev3->origin_acct = NULL;
	ev3->credit = AMOUNT_MSAT(300);
	ev3->debit = AMOUNT_MSAT(302);
	ev3->output_value = AMOUNT_MSAT(304);
	ev3->currency = "btc";
	ev3->timestamp = 3939393;
	ev3->blockheight = 3939393;
	ev3->ignored = false;
	ev3->stealable = false;
	memset(&ev3->outpoint.txid, 'E', sizeof(struct bitcoin_txid));
	ev3->outpoint.n = 1;
	ev3->spending_txid = tal(ctx, struct bitcoin_txid);
	memset(ev3->spending_txid, 'D', sizeof(struct bitcoin_txid));
	ev3->payment_id = NULL;
	ev3->desc = NULL;

	db_begin_transaction(db);
	log_chain_event(db, acct, ev2);

	/* log new event to a different account.. */
	log_chain_event(db, acct2, ev3);
	db_commit_transaction(db);

	/* Try to add an already exiting event */
	db_begin_transaction(db);
	log_chain_event(db, acct, ev2);
	db_commit_transaction(db);

	/* Ok now we ge the list, there should only be two */
	db_begin_transaction(db);
	chain_evs = account_get_chain_events(ctx, db, acct);
	db_commit_transaction(db);
	CHECK(tal_count(chain_evs) == 2);

	CHECK(streq(acct->name, chain_evs[0]->acct_name));
	CHECK(streq(acct->name, chain_evs[1]->acct_name));
	chain_events_eq(ev1, chain_evs[0]);
	chain_events_eq(ev2, chain_evs[1]);

	/* Now insert a utxo create and spend, in that order */
	ev1->db_id = 0;
	memset(&ev1->outpoint.txid, 'A', sizeof(struct bitcoin_txid));
	ev1->outpoint.n = 10;
	ev1->spending_txid = tal_free(ev1->spending_txid);

	ev2->db_id = 0;
	memset(&ev2->outpoint.txid, 'A', sizeof(struct bitcoin_txid));
	ev2->outpoint.n = 10;
	ev2->spending_txid = tal(ctx, struct bitcoin_txid);
	memset(ev2->spending_txid, 'B', sizeof(struct bitcoin_txid));


	db_begin_transaction(db);
	log_chain_event(db, acct, ev1);
	log_chain_event(db, acct, ev2);
	chain_evs = account_get_chain_events(ctx, db, acct);
	db_commit_transaction(db);

	/* There should be four now */
	CHECK(tal_count(chain_evs) == 4);

	chain_events_eq(ev1, chain_evs[2]);
	chain_events_eq(ev2, chain_evs[3]);

	return true;
}

static bool test_account_balances(const tal_t *ctx, struct plugin *p)
{
	bool created;
	struct db *db = db_setup(ctx, p, tmp_dsn(ctx), &created);
	struct node_id peer_id;
	struct account *acct, *acct2;
	struct chain_event *ev1;
	struct acct_balance **balances;
	bool exists;
	char *err;

	memset(&peer_id, 3, sizeof(struct node_id));

	acct = new_account(ctx, tal_fmt(ctx, "example"), &peer_id);
	acct2 = new_account(ctx, tal_fmt(ctx, "wallet"), &peer_id);

	db_begin_transaction(db);
	/* Check that account does not exist yet */
	err = account_get_balance(ctx, db, acct->name, true, false,
				  &balances, &exists);

	CHECK(!err);
	CHECK_MSG(!exists, "expected account not to exist");

	account_add(db, acct);
	account_add(db, acct2);

	/* +1000btc */
	log_chain_event(db, acct,
			make_chain_event(ctx, "one",
					 AMOUNT_MSAT(1000),
					 AMOUNT_MSAT(0),
					 AMOUNT_MSAT(1000),
					 1019,
					 'A', 1, '*'));
	ev1 = make_chain_event(ctx, "two",
			       AMOUNT_MSAT(0), AMOUNT_MSAT(999),
			       AMOUNT_MSAT(999),
			       1020, 'A', 2, '*');

	/* Make this an ignored event */
	ev1->ignored = true;

	/* -999btc */
	log_chain_event(db, acct, ev1);

	/* -440btc */
	log_channel_event(db, acct,
			  make_channel_event(ctx, "chan",
					     AMOUNT_MSAT(0),
					     AMOUNT_MSAT(440),
					     'C'));

	/* 500btc */
	log_channel_event(db, acct,
			  make_channel_event(ctx, "chan",
					     AMOUNT_MSAT(500),
					     AMOUNT_MSAT(0),
					     'D'));

	/* +5000chf */
	ev1 = make_chain_event(ctx, "two",
			       AMOUNT_MSAT(5000), AMOUNT_MSAT(0),
			       AMOUNT_MSAT(5000), 1999,
			       'A', 3, '*');
	ev1->currency = "chf";
	log_chain_event(db, acct, ev1);

	/* Add same chain event to a different account, shouldn't show */
	log_chain_event(db, acct2, ev1);

	err = account_get_balance(ctx, db, acct->name, true, false,
				  &balances, NULL);
	CHECK_MSG(!err, err);
	db_commit_transaction(db);

	/* Should have 2 balances */
	CHECK(tal_count(balances) == 2);
	CHECK(streq(balances[0]->currency, "btc"));
	CHECK(amount_msat_eq(balances[0]->balance, AMOUNT_MSAT(500 - 440 + 1)));
	CHECK(streq(balances[1]->currency, "chf"));
	CHECK(amount_msat_eq(balances[1]->balance, AMOUNT_MSAT(5000)));

	/* Should error if account balance is negative */
	db_begin_transaction(db);
	/* -5001chf */
	ev1 = make_chain_event(ctx, "two",
			       AMOUNT_MSAT(0), AMOUNT_MSAT(5001),
			       AMOUNT_MSAT(5001), 2020,
			       'A', 4, '*');
	ev1->currency = "chf";
	log_chain_event(db, acct, ev1);

	err = account_get_balance(ctx, db, acct->name, true, false,
				  &balances, &exists);
	CHECK_MSG(err != NULL, "Expected err message");
	CHECK(streq(err, "chf channel balance is negative? 5000msat - 5001msat"));
	CHECK_MSG(exists, "expected account to exist");

	err = account_get_balance(ctx, db, acct->name, false, false,
				  &balances, NULL);
	CHECK_MSG(!err, err);

	/* Now with ignored events */
	err = account_get_balance(ctx, db, acct->name, true, true,
				  &balances, NULL);
	CHECK(streq(balances[0]->currency, "btc"));
	CHECK(amount_msat_eq(balances[0]->balance,
			     AMOUNT_MSAT(500 - 440 + 1000)));
	db_commit_transaction(db);

	return true;
}

static bool test_account_crud(const tal_t *ctx, struct plugin *p)
{
	bool created;
	struct db *db = db_setup(ctx, p, tmp_dsn(ctx), &created);
	struct node_id *peer_id;
	struct account *acct, *acct2, **acct_list;
	struct chain_event *ev1;
	enum mvt_tag *tags;
	char *name = tal_fmt(ctx, "example");

	peer_id = tal(ctx, struct node_id);
	memset(peer_id, 3, sizeof(struct node_id));

	acct = new_account(ctx, name, NULL);
	CHECK(!acct->is_wallet);

	db_begin_transaction(db);
	account_add(db, acct);
	db_commit_transaction(db);

	db_begin_transaction(db);
	acct_list = list_accounts(ctx, db);
	db_commit_transaction(db);
	CHECK(tal_count(acct_list) == 1);
	accountseq(acct_list[0], acct);

	acct = new_account(ctx, tal_fmt(ctx, "wallet"), NULL);
	CHECK(acct->is_wallet);

	db_begin_transaction(db);
	account_add(db, acct);
	db_commit_transaction(db);

	db_begin_transaction(db);
	acct_list = list_accounts(ctx, db);
	db_commit_transaction(db);
	CHECK(tal_count(acct_list) == 2);

	/* Can we find an account ok? */
	db_begin_transaction(db);
	acct2 = find_account(ctx, db, "wallet");
	db_commit_transaction(db);
	accountseq(acct, acct2);

	/* Will we update an account's properties
	 * correctly, given an event and tag list? */
	ev1 = tal(ctx, struct chain_event);
	ev1->tag = tal_fmt(ctx, "withdrawal");
	ev1->origin_acct = NULL;
	ev1->credit = AMOUNT_MSAT(100);
	ev1->debit = AMOUNT_MSAT(102);
	ev1->output_value = AMOUNT_MSAT(104);
	ev1->currency = "btc";
	ev1->timestamp = 1919191;
	ev1->blockheight = 1919191;
	ev1->ignored = false;
	ev1->stealable = false;
	memset(&ev1->outpoint.txid, 'D', sizeof(struct bitcoin_txid));
	ev1->outpoint.n = 1;
	ev1->spending_txid = tal(ctx, struct bitcoin_txid);
	memset(ev1->spending_txid, 'C', sizeof(struct bitcoin_txid));
	ev1->payment_id = NULL;
	ev1->desc = tal_fmt(ev1, "oh hello");

	db_begin_transaction(db);
	log_chain_event(db, acct, ev1);

	tags = tal_arr(ctx, enum mvt_tag, 2);

	/* should not update the account info */
	tags[0] = PUSHED;
	tags[1] = PENALTY;
	maybe_update_account(db, acct, ev1, tags, 0, peer_id);
	acct2 = find_account(ctx, db, "wallet");
	accountseq(acct, acct2);

	/* channel_open -> open event db updated */
	CHECK(!acct->leased);
	CHECK(acct->open_event_db_id == NULL);
	tags[0] = CHANNEL_OPEN;
	tags[1] = LEASED;
	maybe_update_account(db, acct, ev1, tags, 2, peer_id);
	acct2 = find_account(ctx, db, "wallet");
	accountseq(acct, acct2);
	CHECK(acct->leased);
	CHECK(acct->open_event_db_id != NULL);
	CHECK(acct->closed_count == 2);

	tags[0] = CHANNEL_CLOSE;
	tags[1] = OPENER;
	CHECK(acct->closed_event_db_id == NULL);
	CHECK(!acct->we_opened);
	maybe_update_account(db, acct, ev1, tags, 0, NULL);
	acct2 = find_account(ctx, db, "wallet");
	accountseq(acct, acct2);
	CHECK(acct->closed_event_db_id != NULL);
	CHECK(acct->we_opened);

	db_commit_transaction(db);

	return true;
}

int main(int argc, char *argv[])
{
	bool ok = true;
	/* Dummy for migration hooks */
	struct plugin *plugin = tal(NULL, struct plugin);
	list_head_init(&plugin->js_list);

	common_setup(argv[0]);

	if (HAVE_SQLITE3) {
		ok &= test_account_crud(tmpctx, plugin);
		ok &= test_channel_event_crud(tmpctx, plugin);
		ok &= test_chain_event_crud(tmpctx, plugin);
		ok &= test_account_balances(tmpctx, plugin);
		ok &= test_onchain_fee_chan_close(tmpctx, plugin);
		ok &= test_onchain_fee_chan_open(tmpctx, plugin);
		ok &= test_channel_rebalances(tmpctx, plugin);
		ok &= test_onchain_fee_wallet_spend(tmpctx, plugin);
	}

	tal_free(plugin);
	common_shutdown();
	return !ok;
}
