diff --git a/common/utxo.h b/common/utxo.h index 634143630..7ed145cb9 100644 --- a/common/utxo.h +++ b/common/utxo.h @@ -1,11 +1,20 @@ #ifndef LIGHTNING_COMMON_UTXO_H #define LIGHTNING_COMMON_UTXO_H #include "config.h" +#include +#include #include #include #include #include +/* Information needed for their_unilateral/to-us outputs */ +struct unilateral_close_info { + u64 channel_id; + struct pubkey peer_id; + struct pubkey commitment_point; +}; + struct utxo { struct bitcoin_txid txid; u32 outnum; @@ -13,6 +22,10 @@ struct utxo { u32 keyindex; bool is_p2sh; u8 status; + + /* Optional unilateral close information, NULL if this is just + * a HD key */ + struct unilateral_close_info *close_info; }; void towire_utxo(u8 **pptr, const struct utxo *utxo); diff --git a/lightningd/test/run-funding_tx.c b/lightningd/test/run-funding_tx.c index e6f3f5aac..2de351269 100644 --- a/lightningd/test/run-funding_tx.c +++ b/lightningd/test/run-funding_tx.c @@ -99,6 +99,7 @@ int main(void) utxo.outnum = 0; utxo.amount = 5000000000; utxo.is_p2sh = false; + utxo.close_info = NULL; funding_satoshis = 10000000; fee = 13920; diff --git a/wallet/db.c b/wallet/db.c index a9a2b380d..887dc4954 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -150,6 +150,9 @@ char *dbmigrations[] = { * pre-release software, so it's forgivable. */ "ALTER TABLE channels ADD first_blocknum INTEGER;", "UPDATE channels SET first_blocknum=CAST(short_channel_id AS INTEGER) WHERE short_channel_id IS NOT NULL;", + "ALTER TABLE outputs ADD COLUMN channel_id INTEGER;", + "ALTER TABLE outputs ADD COLUMN peer_id BLOB;", + "ALTER TABLE outputs ADD COLUMN commitment_point BLOB;", NULL, }; @@ -493,3 +496,15 @@ bool sqlite3_bind_sha256(sqlite3_stmt *stmt, int col, const struct sha256 *p) sqlite3_bind_blob(stmt, col, p, sizeof(struct sha256), SQLITE_TRANSIENT); return true; } + +bool sqlite3_column_sha256_double(sqlite3_stmt *stmt, int col, struct sha256_double *dest) +{ + assert(sqlite3_column_bytes(stmt, col) == sizeof(struct sha256_double)); + return memcpy(dest, sqlite3_column_blob(stmt, col), sizeof(struct sha256_double)); +} + +bool sqlite3_bind_sha256_double(sqlite3_stmt *stmt, int col, const struct sha256_double *p) +{ + sqlite3_bind_blob(stmt, col, p, sizeof(struct sha256_double), SQLITE_TRANSIENT); + return true; +} diff --git a/wallet/db.h b/wallet/db.h index eb731acbf..706dd2afa 100644 --- a/wallet/db.h +++ b/wallet/db.h @@ -132,4 +132,7 @@ bool sqlite3_bind_preimage(sqlite3_stmt *stmt, int col, const struct preimage *p bool sqlite3_column_sha256(sqlite3_stmt *stmt, int col, struct sha256 *dest); bool sqlite3_bind_sha256(sqlite3_stmt *stmt, int col, const struct sha256 *p); +bool sqlite3_column_sha256_double(sqlite3_stmt *stmt, int col, struct sha256_double *dest); +bool sqlite3_bind_sha256_double(sqlite3_stmt *stmt, int col, const struct sha256_double *p); + #endif /* WALLET_DB_H */ diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 09d4d1998..5c815b7e5 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -17,6 +17,7 @@ static void db_log_(struct log *log, enum log_level level, const char *fmt, ...) #include #include #include +#include #include #include @@ -87,16 +88,22 @@ static bool test_wallet_outputs(void) char filename[] = "/tmp/ldb-XXXXXX"; struct utxo u; int fd = mkstemp(filename); - struct wallet *w = tal(NULL, struct wallet); CHECK_MSG(fd != -1, "Unable to generate temp filename"); close(fd); + struct wallet *w = tal(NULL, struct wallet); + struct pubkey pk; + u64 fee_estimate, change_satoshis; + const struct utxo **utxos; + w->db = db_open(w, filename); CHECK_MSG(w->db, "Failed opening the db"); db_migrate(w->db, NULL); CHECK_MSG(!wallet_err, "DB migration failed"); memset(&u, 0, sizeof(u)); + u.amount = 1; + pubkey_from_der(tal_hexdata(w, "02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc", 66), 33, &pk); db_begin_transaction(w->db); @@ -108,6 +115,27 @@ static bool test_wallet_outputs(void) CHECK_MSG(!wallet_add_utxo(w, &u, p2sh_wpkh), "wallet_add_utxo succeeded on second add"); + /* Attempt to save a utxo with close_info set */ + memset(&u.txid, 1, sizeof(u.txid)); + u.close_info = tal(w, struct unilateral_close_info); + u.close_info->channel_id = 42; + u.close_info->peer_id = pk; + u.close_info->commitment_point = pk; + CHECK_MSG(wallet_add_utxo(w, &u, p2sh_wpkh), + "wallet_add_utxo with close_info"); + + /* Now select them */ + utxos = wallet_select_coins(w, w, 2, 0, 21, &fee_estimate, &change_satoshis); + CHECK(utxos && tal_count(utxos) == 2); + + u = *utxos[1]; + CHECK(u.close_info->channel_id == 42 && + pubkey_eq(&u.close_info->commitment_point, &pk) && + pubkey_eq(&u.close_info->peer_id, &pk)); + /* Now un-reserve them for the tests below */ + tal_free(utxos); + + /* Attempt to reserve the utxo */ CHECK_MSG(wallet_update_output_status(w, &u.txid, u.outnum, output_state_available, @@ -133,6 +161,7 @@ static bool test_wallet_outputs(void) "could not change output state ignoring oldstate"); db_commit_transaction(w->db); + tal_free(w); return true; } diff --git a/wallet/wallet.c b/wallet/wallet.c index d98cb239c..cd1e4bc57 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -29,13 +29,22 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, { sqlite3_stmt *stmt; - stmt = db_prepare(w->db, "INSERT INTO outputs (prev_out_tx, prev_out_index, value, type, status, keyindex) VALUES (?, ?, ?, ?, ?, ?);"); + stmt = db_prepare(w->db, "INSERT INTO outputs (prev_out_tx, prev_out_index, value, type, status, keyindex, channel_id, peer_id, commitment_point) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);"); sqlite3_bind_blob(stmt, 1, &utxo->txid, sizeof(utxo->txid), SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 2, utxo->outnum); sqlite3_bind_int64(stmt, 3, utxo->amount); sqlite3_bind_int(stmt, 4, type); sqlite3_bind_int(stmt, 5, output_state_available); sqlite3_bind_int(stmt, 6, utxo->keyindex); + if (utxo->close_info) { + sqlite3_bind_int64(stmt, 7, utxo->close_info->channel_id); + sqlite3_bind_pubkey(stmt, 8, &utxo->close_info->peer_id); + sqlite3_bind_pubkey(stmt, 9, &utxo->close_info->commitment_point); + } else { + sqlite3_bind_null(stmt, 7); + sqlite3_bind_null(stmt, 8); + sqlite3_bind_null(stmt, 9); + } return db_exec_prepared_mayfail(w->db, stmt); } @@ -46,12 +55,21 @@ bool wallet_add_utxo(struct wallet *w, struct utxo *utxo, */ static bool wallet_stmt2output(sqlite3_stmt *stmt, struct utxo *utxo) { - memcpy(&utxo->txid, sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0)); + sqlite3_column_sha256_double(stmt, 0, &utxo->txid.shad); utxo->outnum = sqlite3_column_int(stmt, 1); utxo->amount = sqlite3_column_int(stmt, 2); utxo->is_p2sh = sqlite3_column_int(stmt, 3) == p2sh_wpkh; utxo->status = sqlite3_column_int(stmt, 4); utxo->keyindex = sqlite3_column_int(stmt, 5); + if (sqlite3_column_type(stmt, 6) != SQLITE_NULL) { + utxo->close_info = tal(utxo, struct unilateral_close_info); + utxo->close_info->channel_id = sqlite3_column_int64(stmt, 6); + sqlite3_column_pubkey(stmt, 7, &utxo->close_info->peer_id); + sqlite3_column_pubkey(stmt, 8, &utxo->close_info->commitment_point); + } else { + utxo->close_info = NULL; + } + return true; } @@ -85,7 +103,8 @@ struct utxo **wallet_get_utxos(const tal_t *ctx, struct wallet *w, const enum ou int i; sqlite3_stmt *stmt = db_prepare( - w->db, "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex " + w->db, "SELECT prev_out_tx, prev_out_index, value, type, status, keyindex, " + "channel_id, peer_id, commitment_point " "FROM outputs WHERE status=?1 OR ?1=255"); sqlite3_bind_int(stmt, 1, state); @@ -829,6 +848,7 @@ int wallet_extract_owned_outputs(struct wallet *w, const struct bitcoin_tx *tx, utxo->status = output_state_available; bitcoin_txid(tx, &utxo->txid); utxo->outnum = output; + utxo->close_info = NULL; log_debug(w->log, "Owning output %zu %"PRIu64" (%s) txid %s", output, tx->output[output].amount, is_p2sh ? "P2SH" : "SEGWIT",