mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-23 15:00:34 +01:00
1440 lines
45 KiB
C
1440 lines
45 KiB
C
#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>
|
|
|
|
static char *db_err;
|
|
#ifndef DB_FATAL
|
|
#define DB_FATAL
|
|
void db_fatal(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
/* Fail hard if we're complaining about not being in transaction */
|
|
assert(!strstarts(fmt, "No longer in transaction"));
|
|
|
|
va_start(ap, fmt);
|
|
db_err = tal_vfmt(NULL, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
#endif /* DB_FATAL */
|
|
|
|
#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_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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
db_begin_transaction(db);
|
|
ofs = list_chain_fees(ctx, db);
|
|
db_commit_transaction(db);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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_MSG(!db_err, db_err);
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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_MSG(!db_err, db_err);
|
|
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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_MSG(!db_err, db_err);
|
|
|
|
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_MSG(!db_err, db_err);
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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_MSG(!db_err, db_err);
|
|
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
db_begin_transaction(db);
|
|
chan_evs = account_get_channel_events(ctx, db, acct);
|
|
db_commit_transaction(db);
|
|
CHECK_MSG(!db_err, db_err);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* Try to add an already exiting event */
|
|
db_begin_transaction(db);
|
|
log_chain_event(db, acct, ev2);
|
|
db_commit_transaction(db);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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_MSG(!db_err, db_err);
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
/* 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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
db_begin_transaction(db);
|
|
acct_list = list_accounts(ctx, db);
|
|
db_commit_transaction(db);
|
|
CHECK_MSG(!db_err, db_err);
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
db_begin_transaction(db);
|
|
acct_list = list_accounts(ctx, db);
|
|
db_commit_transaction(db);
|
|
CHECK_MSG(!db_err, db_err);
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
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);
|
|
CHECK_MSG(!db_err, db_err);
|
|
|
|
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;
|
|
}
|