rgb-cln/wallet/test/run-db.c

472 lines
19 KiB
C

#include "config.h"
#include <lightningd/log.h>
static void db_log_(struct logger *log UNUSED, enum log_level level UNUSED, const struct node_id *node_id UNUSED, bool call_notifier UNUSED, const char *fmt UNUSED, ...)
{
}
#define log_ db_log_
#include "db/bindings.c"
#include "db/db_sqlite3.c"
#include "db/exec.c"
#include "db/utils.c"
#include "wallet/db.c"
#include "wallet/wallet.c"
#include "test_utils.h"
#include <common/setup.h>
#include <common/utils.h>
#include <lightningd/channel.h>
#include <stdio.h>
#include <unistd.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for bip32_pubkey */
void bip32_pubkey(struct lightningd *ld UNNEEDED, struct pubkey *pubkey UNNEEDED, u32 index UNNEEDED)
{ fprintf(stderr, "bip32_pubkey called!\n"); abort(); }
/* Generated stub for channel_scid_or_local_alias */
const struct short_channel_id *channel_scid_or_local_alias(const struct channel *chan UNNEEDED)
{ fprintf(stderr, "channel_scid_or_local_alias called!\n"); abort(); }
/* Generated stub for connect_htlc_in */
void connect_htlc_in(struct htlc_in_map *map UNNEEDED, struct htlc_in *hin UNNEEDED)
{ fprintf(stderr, "connect_htlc_in called!\n"); abort(); }
/* Generated stub for connect_htlc_out */
void connect_htlc_out(struct htlc_out_map *map UNNEEDED, struct htlc_out *hout UNNEEDED)
{ fprintf(stderr, "connect_htlc_out called!\n"); abort(); }
/* Generated stub for create_onionreply */
struct onionreply *create_onionreply(const tal_t *ctx UNNEEDED,
const struct secret *shared_secret UNNEEDED,
const u8 *failure_msg UNNEEDED)
{ fprintf(stderr, "create_onionreply called!\n"); abort(); }
/* Generated stub for derive_channel_id */
void derive_channel_id(struct channel_id *channel_id UNNEEDED,
const struct bitcoin_outpoint *outpoint UNNEEDED)
{ fprintf(stderr, "derive_channel_id called!\n"); abort(); }
/* Generated stub for fatal */
void fatal(const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "fatal called!\n"); abort(); }
/* Generated stub for fatal_vfmt */
void fatal_vfmt(const char *fmt UNNEEDED, va_list ap UNNEEDED)
{ fprintf(stderr, "fatal_vfmt called!\n"); abort(); }
/* Generated stub for find_peer_by_dbid */
struct peer *find_peer_by_dbid(struct lightningd *ld UNNEEDED, u64 dbid UNNEEDED)
{ fprintf(stderr, "find_peer_by_dbid called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_get_channel_basepoints_reply */
bool fromwire_hsmd_get_channel_basepoints_reply(const void *p UNNEEDED, struct basepoints *basepoints UNNEEDED, struct pubkey *funding_pubkey UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_get_channel_basepoints_reply called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_get_output_scriptpubkey_reply */
bool fromwire_hsmd_get_output_scriptpubkey_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **script UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_get_output_scriptpubkey_reply called!\n"); abort(); }
/* Generated stub for get_channel_basepoints */
void get_channel_basepoints(struct lightningd *ld UNNEEDED,
const struct node_id *peer_id UNNEEDED,
const u64 dbid UNNEEDED,
struct basepoints *local_basepoints UNNEEDED,
struct pubkey *local_funding_pubkey UNNEEDED)
{ fprintf(stderr, "get_channel_basepoints called!\n"); abort(); }
/* Generated stub for htlc_in_check */
struct htlc_in *htlc_in_check(const struct htlc_in *hin UNNEEDED, const char *abortstr UNNEEDED)
{ fprintf(stderr, "htlc_in_check called!\n"); abort(); }
/* Generated stub for htlc_out_connect_htlc_in */
void htlc_out_connect_htlc_in(struct htlc_out *hout UNNEEDED, struct htlc_in *hin UNNEEDED)
{ fprintf(stderr, "htlc_out_connect_htlc_in called!\n"); abort(); }
/* Generated stub for invoices_new */
struct invoices *invoices_new(const tal_t *ctx UNNEEDED,
struct wallet *wallet UNNEEDED,
struct timers *timers UNNEEDED)
{ fprintf(stderr, "invoices_new called!\n"); abort(); }
/* Generated stub for logv */
void logv(struct logger *logger UNNEEDED, enum log_level level UNNEEDED, const struct node_id *node_id UNNEEDED,
bool call_notifier UNNEEDED, const char *fmt UNNEEDED, va_list ap UNNEEDED)
{ fprintf(stderr, "logv called!\n"); abort(); }
/* Generated stub for new_channel */
struct channel *new_channel(struct peer *peer UNNEEDED, u64 dbid UNNEEDED,
/* NULL or stolen */
struct wallet_shachain *their_shachain STEALS UNNEEDED,
enum channel_state state UNNEEDED,
enum side opener UNNEEDED,
/* NULL or stolen */
struct logger *log STEALS UNNEEDED,
const char *transient_billboard TAKES UNNEEDED,
u8 channel_flags UNNEEDED,
bool req_confirmed_ins_local UNNEEDED,
bool req_confirmed_ins_remote UNNEEDED,
const struct channel_config *our_config UNNEEDED,
u32 minimum_depth UNNEEDED,
u64 next_index_local UNNEEDED,
u64 next_index_remote UNNEEDED,
u64 next_htlc_id UNNEEDED,
const struct bitcoin_outpoint *funding UNNEEDED,
struct amount_sat funding_sats UNNEEDED,
struct amount_msat push UNNEEDED,
struct amount_sat our_funds UNNEEDED,
bool remote_channel_ready UNNEEDED,
/* NULL or stolen */
struct short_channel_id *scid STEALS UNNEEDED,
struct short_channel_id *alias_local STEALS UNNEEDED,
struct short_channel_id *alias_remote STEALS UNNEEDED,
struct channel_id *cid UNNEEDED,
struct amount_msat our_msatoshi UNNEEDED,
struct amount_msat msatoshi_to_us_min UNNEEDED,
struct amount_msat msatoshi_to_us_max UNNEEDED,
struct bitcoin_tx *last_tx STEALS UNNEEDED,
const struct bitcoin_signature *last_sig UNNEEDED,
/* NULL or stolen */
const struct bitcoin_signature *last_htlc_sigs STEALS UNNEEDED,
const struct channel_info *channel_info UNNEEDED,
const struct fee_states *fee_states TAKES UNNEEDED,
/* NULL or stolen */
u8 *remote_shutdown_scriptpubkey STEALS UNNEEDED,
const u8 *local_shutdown_scriptpubkey UNNEEDED,
u64 final_key_idx UNNEEDED,
bool last_was_revoke UNNEEDED,
/* NULL or stolen */
struct changed_htlc *last_sent_commit STEALS UNNEEDED,
u32 first_blocknum UNNEEDED,
u32 min_possible_feerate UNNEEDED,
u32 max_possible_feerate UNNEEDED,
const struct basepoints *local_basepoints UNNEEDED,
const struct pubkey *local_funding_pubkey UNNEEDED,
const struct pubkey *future_per_commitment_point UNNEEDED,
u32 feerate_base UNNEEDED,
u32 feerate_ppm UNNEEDED,
/* NULL or stolen */
const u8 *remote_upfront_shutdown_script STEALS UNNEEDED,
u64 local_static_remotekey_start UNNEEDED,
u64 remote_static_remotekey_start UNNEEDED,
const struct channel_type *type STEALS UNNEEDED,
enum side closer UNNEEDED,
enum state_change reason UNNEEDED,
/* NULL or stolen */
const struct bitcoin_outpoint *shutdown_wrong_funding STEALS UNNEEDED,
const struct height_states *height_states TAKES UNNEEDED,
u32 lease_expiry UNNEEDED,
secp256k1_ecdsa_signature *lease_commit_sig STEALS UNNEEDED,
u32 lease_chan_max_msat UNNEEDED,
u16 lease_chan_max_ppt UNNEEDED,
struct amount_msat htlc_minimum_msat UNNEEDED,
struct amount_msat htlc_maximum_msat UNNEEDED,
bool ignore_fee_limits UNNEEDED)
{ fprintf(stderr, "new_channel called!\n"); abort(); }
/* Generated stub for new_coin_wallet_deposit */
struct chain_coin_mvt *new_coin_wallet_deposit(const tal_t *ctx UNNEEDED,
const struct bitcoin_outpoint *outpoint UNNEEDED,
u32 blockheight UNNEEDED,
struct amount_sat amount UNNEEDED,
enum mvt_tag tag)
{ fprintf(stderr, "new_coin_wallet_deposit called!\n"); abort(); }
/* Generated stub for new_inflight */
struct channel_inflight *new_inflight(struct channel *channel UNNEEDED,
const struct bitcoin_outpoint *funding_outpoint UNNEEDED,
u32 funding_feerate UNNEEDED,
struct amount_sat funding_sat UNNEEDED,
struct amount_sat our_funds UNNEEDED,
struct wally_psbt *funding_psbt STEALS UNNEEDED,
struct bitcoin_tx *last_tx STEALS UNNEEDED,
const struct bitcoin_signature last_sig UNNEEDED,
const u32 lease_expiry UNNEEDED,
const secp256k1_ecdsa_signature *lease_commit_sig UNNEEDED,
const u32 lease_chan_max_msat UNNEEDED,
const u16 lease_chan_max_ppt UNNEEDED,
const u32 lease_blockheight_start UNNEEDED,
const struct amount_msat lease_fee UNNEEDED,
const struct amount_sat lease_amt UNNEEDED,
s64 splice_amnt UNNEEDED,
bool i_am_initiator UNNEEDED)
{ fprintf(stderr, "new_inflight called!\n"); abort(); }
/* Generated stub for new_logger */
struct logger *new_logger(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED,
const struct node_id *default_node_id UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "new_logger called!\n"); abort(); }
/* Generated stub for new_peer */
struct peer *new_peer(struct lightningd *ld UNNEEDED, u64 dbid UNNEEDED,
const struct node_id *id UNNEEDED,
const struct wireaddr_internal *addr UNNEEDED,
const u8 *their_features TAKES UNNEEDED,
bool connected_incoming UNNEEDED)
{ fprintf(stderr, "new_peer called!\n"); abort(); }
/* Generated stub for notify_chain_mvt */
void notify_chain_mvt(struct lightningd *ld UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED)
{ fprintf(stderr, "notify_chain_mvt called!\n"); abort(); }
/* Generated stub for notify_forward_event */
void notify_forward_event(struct lightningd *ld UNNEEDED,
const struct htlc_in *in UNNEEDED,
/* May be NULL if we don't know. */
const struct short_channel_id *scid_out UNNEEDED,
/* May be NULL. */
const struct amount_msat *amount_out UNNEEDED,
enum forward_status state UNNEEDED,
enum onion_wire failcode UNNEEDED,
struct timeabs *resolved_time UNNEEDED,
enum forward_style forward_style UNNEEDED)
{ fprintf(stderr, "notify_forward_event called!\n"); abort(); }
/* Generated stub for onion_wire_name */
const char *onion_wire_name(int e UNNEEDED)
{ fprintf(stderr, "onion_wire_name called!\n"); abort(); }
/* Generated stub for outpointfilter_add */
void outpointfilter_add(struct outpointfilter *of UNNEEDED,
const struct bitcoin_outpoint *outpoint UNNEEDED)
{ fprintf(stderr, "outpointfilter_add called!\n"); abort(); }
/* Generated stub for outpointfilter_matches */
bool outpointfilter_matches(struct outpointfilter *of UNNEEDED,
const struct bitcoin_outpoint *outpoint UNNEEDED)
{ fprintf(stderr, "outpointfilter_matches called!\n"); abort(); }
/* Generated stub for outpointfilter_new */
struct outpointfilter *outpointfilter_new(tal_t *ctx UNNEEDED)
{ fprintf(stderr, "outpointfilter_new called!\n"); abort(); }
/* Generated stub for outpointfilter_remove */
void outpointfilter_remove(struct outpointfilter *of UNNEEDED,
const struct bitcoin_outpoint *outpoint UNNEEDED)
{ fprintf(stderr, "outpointfilter_remove called!\n"); abort(); }
/* Generated stub for peer_set_dbid */
void peer_set_dbid(struct peer *peer UNNEEDED, u64 dbid UNNEEDED)
{ fprintf(stderr, "peer_set_dbid called!\n"); abort(); }
/* Generated stub for psbt_fixup */
const u8 *psbt_fixup(const tal_t *ctx UNNEEDED, const u8 *psbtblob UNNEEDED)
{ fprintf(stderr, "psbt_fixup called!\n"); abort(); }
/* Generated stub for remove_htlc_in_by_dbid */
struct htlc_in *remove_htlc_in_by_dbid(struct htlc_in_map *remaining_htlcs_in UNNEEDED,
u64 dbid UNNEEDED)
{ fprintf(stderr, "remove_htlc_in_by_dbid called!\n"); abort(); }
/* Generated stub for rune_is_ours */
const char *rune_is_ours(struct lightningd *ld UNNEEDED, const struct rune *rune UNNEEDED)
{ fprintf(stderr, "rune_is_ours called!\n"); abort(); }
/* Generated stub for rune_unique_id */
u64 rune_unique_id(const struct rune *rune UNNEEDED)
{ fprintf(stderr, "rune_unique_id called!\n"); abort(); }
/* Generated stub for to_canonical_invstr */
const char *to_canonical_invstr(const tal_t *ctx UNNEEDED, const char *invstring UNNEEDED)
{ fprintf(stderr, "to_canonical_invstr called!\n"); abort(); }
/* Generated stub for towire_hsmd_get_channel_basepoints */
u8 *towire_hsmd_get_channel_basepoints(const tal_t *ctx UNNEEDED, const struct node_id *peerid UNNEEDED, u64 dbid UNNEEDED)
{ fprintf(stderr, "towire_hsmd_get_channel_basepoints called!\n"); abort(); }
/* Generated stub for towire_hsmd_get_output_scriptpubkey */
u8 *towire_hsmd_get_output_scriptpubkey(const tal_t *ctx UNNEEDED, u64 channel_id UNNEEDED, const struct node_id *peer_id UNNEEDED, const struct pubkey *commitment_point UNNEEDED)
{ fprintf(stderr, "towire_hsmd_get_output_scriptpubkey called!\n"); abort(); }
/* Generated stub for towire_temporary_node_failure */
u8 *towire_temporary_node_failure(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "towire_temporary_node_failure called!\n"); abort(); }
/* Generated stub for trace_span_end */
void trace_span_end(const void *key UNNEEDED)
{ fprintf(stderr, "trace_span_end called!\n"); abort(); }
/* Generated stub for trace_span_start */
void trace_span_start(const char *name UNNEEDED, const void *key UNNEEDED)
{ fprintf(stderr, "trace_span_start called!\n"); abort(); }
/* Generated stub for txfilter_add_scriptpubkey */
void txfilter_add_scriptpubkey(struct txfilter *filter UNNEEDED, const u8 *script TAKES UNNEEDED)
{ fprintf(stderr, "txfilter_add_scriptpubkey called!\n"); abort(); }
/* Generated stub for wait_index_name */
const char *wait_index_name(enum wait_index index UNNEEDED)
{ fprintf(stderr, "wait_index_name called!\n"); abort(); }
/* Generated stub for wait_subsystem_name */
const char *wait_subsystem_name(enum wait_subsystem subsystem UNNEEDED)
{ fprintf(stderr, "wait_subsystem_name called!\n"); abort(); }
/* Generated stub for wire_sync_read */
u8 *wire_sync_read(const tal_t *ctx UNNEEDED, int fd UNNEEDED)
{ fprintf(stderr, "wire_sync_read called!\n"); abort(); }
/* Generated stub for wire_sync_write */
bool wire_sync_write(int fd UNNEEDED, const void *msg TAKES UNNEEDED)
{ fprintf(stderr, "wire_sync_write called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
void plugin_hook_db_sync(struct db *db UNNEEDED)
{
}
static struct db *create_test_db(void)
{
struct db *db;
char *dsn, *filename;
int fd = tmpdir_mkstemp(tmpctx, "ldb-XXXXXX", &filename);
if (fd == -1)
return NULL;
close(fd);
dsn = tal_fmt(NULL, "sqlite3://%s", filename);
tal_free(filename);
db = db_open(NULL, dsn, true, db_error, (struct lightningd *)NULL);
db->data_version = 0;
db->report_changes_fn = NULL;
tal_free(dsn);
return db;
}
static bool test_empty_db_migrate(struct lightningd *ld)
{
struct db *db = create_test_db();
const struct ext_key *bip32_base = NULL;
CHECK(db);
db_begin_transaction(db);
CHECK(db_get_version(db) == -1);
db_migrate(ld, db, bip32_base);
db_commit_transaction(db);
db_begin_transaction(db);
CHECK(db_get_version(db) == ARRAY_SIZE(dbmigrations) - 1);
db_commit_transaction(db);
tal_free(db);
return true;
}
static bool test_primitives(void)
{
struct db_stmt *stmt;
struct db *db = create_test_db();
db_begin_transaction(db);
CHECK(db->in_transaction);
db_commit_transaction(db);
CHECK(!db->in_transaction);
db_begin_transaction(db);
db_commit_transaction(db);
db_begin_transaction(db);
stmt = db_prepare_v2(db, SQL("SELECT name FROM sqlite_master WHERE type='table';"));
db_exec_prepared_v2(stmt);
tal_free(stmt);
/* We didn't migrate the DB, so don't have the vars table. Pretend we
* didn't change anything so we don't bump the data_version. */
db->dirty = false;
db_commit_transaction(db);
CHECK(!db->in_transaction);
tal_free(db);
return true;
}
static bool test_vars(struct lightningd *ld)
{
struct db *db = create_test_db();
char *varname = "testvar";
const struct ext_key *bip32_base = NULL;
CHECK(db);
db_begin_transaction(db);
db_migrate(ld, db, bip32_base);
/* Check default behavior */
CHECK(db_get_intvar(db, varname, 42) == 42);
/* Check setting and getting */
db_set_intvar(db, varname, 1);
CHECK(db_get_intvar(db, varname, 42) == 1);
/* Check updating */
db_set_intvar(db, varname, 2);
CHECK(db_get_intvar(db, varname, 42) == 2);
db_commit_transaction(db);
tal_free(db);
return true;
}
static bool test_manip_columns(void)
{
struct db_stmt *stmt;
struct db *db = create_test_db();
const char *field1 = "field1";
db_begin_transaction(db);
/* tablea refers to tableb */
stmt = db_prepare_v2(db, SQL("CREATE TABLE tablea ("
" id BIGSERIAL"
", field1 INTEGER"
", PRIMARY KEY (id))"));
db_exec_prepared_v2(stmt);
tal_free(stmt);
stmt = db_prepare_v2(db, SQL("INSERT INTO tablea (id, field1) VALUES (0, 1);"));
db_exec_prepared_v2(stmt);
tal_free(stmt);
stmt = db_prepare_v2(db, SQL("CREATE TABLE tableb ("
" id REFERENCES tablea(id) ON DELETE CASCADE"
", field1 INTEGER"
", field2 INTEGER);"));
db_exec_prepared_v2(stmt);
tal_free(stmt);
stmt = db_prepare_v2(db, SQL("INSERT INTO tableb (id, field1, field2) VALUES (0, 1, 2);"));
db_exec_prepared_v2(stmt);
tal_free(stmt);
/* Needs vars table, since this changes db. */
stmt = db_prepare_v2(db, SQL("CREATE TABLE vars (name VARCHAR(32), intval);"));
db_exec_prepared_v2(stmt);
tal_free(stmt);
stmt = db_prepare_v2(db, SQL("INSERT INTO vars VALUES ('data_version', 0);"));
db_exec_prepared_v2(stmt);
tal_free(stmt);
/* Rename tablea.field1 -> table1.field1a. */
CHECK(db->config->rename_column(db, "tablea", "field1", "field1a"));
/* Remove tableb.field1. */
CHECK(db->config->delete_columns(db, "tableb", &field1, 1));
stmt = db_prepare_v2(db, SQL("SELECT id, field1a FROM tablea;"));
CHECK_MSG(db_query_prepared_canfail(stmt), "db_query_prepared must succeed");
CHECK(db_step(stmt));
CHECK(db_col_u64(stmt, "id") == 0);
CHECK(db_col_u64(stmt, "field1a") == 1);
CHECK(!db_step(stmt));
tal_free(stmt);
stmt = db_prepare_v2(db, SQL("SELECT id, field2 FROM tableb;"));
CHECK_MSG(db_query_prepared_canfail(stmt), "db_query_prepared must succeed");
CHECK(db_step(stmt));
CHECK(db_col_u64(stmt, "id") == 0);
CHECK(db_col_u64(stmt, "field2") == 2);
CHECK(!db_step(stmt));
tal_free(stmt);
db->dirty = false;
db->changes = tal_arr(db, const char *, 0);
db_commit_transaction(db);
db_begin_transaction(db);
/* This will actually fail */
stmt = db_prepare_v2(db, SQL("SELECT field1 FROM tablea;"));
CHECK_MSG(!db_query_prepared_canfail(stmt), "db_query_prepared must fail");
db->dirty = false;
db->changes = tal_arr(db, const char *, 0);
db_commit_transaction(db);
db_begin_transaction(db);
/* This will actually fail */
stmt = db_prepare_v2(db, SQL("SELECT field1 FROM tableb;"));
CHECK_MSG(!db_query_prepared_canfail(stmt), "db_query_prepared must fail");
db->dirty = false;
db->changes = tal_arr(db, const char *, 0);
db_commit_transaction(db);
tal_free(db);
return true;
}
int main(int argc, char *argv[])
{
bool ok = true;
/* Dummy for migration hooks */
struct lightningd *ld = tal(NULL, struct lightningd);
common_setup(argv[0]);
ld->config = test_config;
/* We do a runtime test here, so we still check compile! */
if (HAVE_SQLITE3) {
ok &= test_empty_db_migrate(ld);
ok &= test_vars(ld);
ok &= test_primitives();
ok &= test_manip_columns();
}
tal_free(ld);
common_shutdown();
return !ok;
}