diff --git a/lightningd/channel.c b/lightningd/channel.c index 094a66eb38ed..26f108b2d3a2 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -159,9 +159,10 @@ new_inflight(struct channel *channel, struct amount_sat total_funds, struct amount_sat our_funds, struct wally_psbt *psbt STEALS, - struct bitcoin_tx *last_tx STEALS, + struct bitcoin_tx *last_tx, const struct bitcoin_signature last_sig) { + struct wally_psbt *last_tx_psbt_clone; struct channel_inflight *inflight = tal(channel, struct channel_inflight); struct funding_info *funding @@ -177,7 +178,10 @@ new_inflight(struct channel *channel, inflight->channel = channel; inflight->remote_tx_sigs = false; inflight->funding_psbt = tal_steal(inflight, psbt); - inflight->last_tx = tal_steal(inflight, last_tx); + + /* Make a 'clone' of this tx */ + last_tx_psbt_clone = clone_psbt(inflight, last_tx->psbt); + inflight->last_tx = bitcoin_tx_with_psbt(inflight, last_tx_psbt_clone); inflight->last_sig = last_sig; inflight->tx_broadcast = false; @@ -726,15 +730,9 @@ void channel_fail_forget(struct channel *channel, const char *fmt, ...) struct channel_inflight * channel_current_inflight(const struct channel *channel) { - struct channel_inflight *inflight; /* The last inflight should always be the one in progress */ - inflight = list_tail(&channel->inflights, - struct channel_inflight, - list); - if (inflight) - assert(bitcoin_txid_eq(&channel->funding_txid, - &inflight->funding->txid)); - return inflight; + return list_tail(&channel->inflights, + struct channel_inflight, list); } u32 channel_last_funding_feerate(const struct channel *channel) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 53aa43773301..3958e9dfa1b7 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -645,6 +645,8 @@ bool channel_tell_depth(struct lightningd *ld, return true; } + log_debug(channel->log, + "Funding tx %s confirmed, telling peer", txidstr); dualopen_tell_depth(channel->owner, channel, txid, depth); return true; diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index e36d65f43a11..238102360f4d 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -915,6 +915,12 @@ openchannel2_sign_hook_cb(struct openchannel2_psbt_payload *payload STEALS) } inflight = channel_current_inflight(channel); + if (!inflight) { + log_broken(channel->log, + "No current channel inflight"); + msg = towire_dualopend_fail(NULL, "No current channel inflight"); + goto send_msg; + } /* Check that we've got the same / correct PSBT */ psbt_txid(NULL, payload->psbt, &txid, NULL); @@ -1020,9 +1026,9 @@ static struct amount_sat calculate_reserve(struct channel_config *their_config, return reserve; } -static void channel_update_reserve(struct channel *channel, - struct channel_config *their_config, - struct amount_sat funding_total) +void channel_update_reserve(struct channel *channel, + struct channel_config *their_config, + struct amount_sat funding_total) { struct amount_sat reserve; @@ -1068,8 +1074,11 @@ wallet_update_channel(struct lightningd *ld, channel->our_msat = our_msat; channel->msat_to_us_min = our_msat; channel->msat_to_us_max = our_msat; - channel->last_tx = tal_steal(channel, remote_commit); - channel->last_sig = *remote_commit_sig; + + channel_set_last_tx(channel, + tal_steal(channel, remote_commit), + remote_commit_sig, + TX_CHANNEL_UNILATERAL); /* Update in database */ wallet_channel_save(ld->wallet, channel); @@ -1138,8 +1147,11 @@ wallet_commit_channel(struct lightningd *ld, channel->our_msat = our_msat; channel->msat_to_us_min = our_msat; channel->msat_to_us_max = our_msat; + channel->last_tx = tal_steal(channel, remote_commit); channel->last_sig = *remote_commit_sig; + channel->last_tx_type = TX_CHANNEL_UNILATERAL; + channel->channel_info = *channel_info; channel->fee_states = new_fee_states(channel, channel->opener, @@ -1398,6 +1410,13 @@ static void handle_peer_tx_sigs_sent(struct subd *dualopend, } inflight = channel_current_inflight(channel); + if (!inflight) { + channel_internal_error(channel, + "No inflight found for channel %s", + type_to_string(tmpctx, struct channel, + channel)); + return; + } /* Once we've sent our sigs to the peer, we're fine * to broadcast the transaction, even if they haven't @@ -1420,6 +1439,8 @@ static void handle_peer_tx_sigs_sent(struct subd *dualopend, return; } + /* Saves the now finalized version of the psbt */ + wallet_inflight_save(dualopend->ld->wallet, inflight); send_funding_tx(channel, take(wtx)); /* Must be in an "init" state */ @@ -1518,6 +1539,9 @@ static void handle_channel_locked(struct subd *dualopend, "Lockin complete"); channel_record_open(channel); + /* Empty out the inflights */ + wallet_channel_clear_inflights(dualopend->ld->wallet, channel); + /* FIXME: LND sigs/update_fee msgs? */ peer_start_channeld(channel, pps, NULL, false); return; @@ -1539,40 +1563,14 @@ void dualopen_tell_depth(struct subd *dualopend, /* Are we there yet? */ if (to_go == 0) { assert(channel->scid); + assert(bitcoin_txid_eq(&channel->funding_txid, txid)); + + channel_set_billboard(channel, false, + tal_fmt(tmpctx, "Funding depth reached" + " %d confirmations, alerting peer" + " we're locked-in.", + to_go)); - /* Update the channel's info to the correct tx, if we need to */ - if (!bitcoin_txid_eq(&channel->funding_txid, txid)) { - struct channel_inflight *inf; - inf = channel_inflight_find(channel, txid); - if (!inf) { - channel_internal_error(channel, - "Txid %s for channel" - " not found in available inflights." - " (peer %s)", - type_to_string(tmpctx, - struct bitcoin_txid, - txid), - type_to_string(tmpctx, - struct node_id, - &channel->peer->id)); - return; - } - - channel->funding_txid = inf->funding->txid; - channel->funding_outnum = inf->funding->outnum; - channel->funding = inf->funding->total_funds; - channel->our_funds = inf->funding->our_funds; - channel->last_tx = tal_steal(channel, inf->last_tx); - channel->last_sig = inf->last_sig; - - /* Update the reserve */ - channel_update_reserve(channel, - &channel->channel_info.their_config, - inf->funding->total_funds); - - wallet_channel_save(dualopend->ld->wallet, channel); - /* FIXME: delete inflights */ - } msg = towire_dualopend_depth_reached(NULL, depth); subd_send_msg(dualopend, take(msg)); } else @@ -1723,6 +1721,14 @@ static void handle_peer_tx_sigs_msg(struct subd *dualopend, } inflight = channel_current_inflight(channel); + if (!inflight) { + channel_internal_error(channel, + "No inflight found for channel %s", + type_to_string(tmpctx, struct channel, + channel)); + return; + } + /* Save that we've gotten their sigs. Sometimes * the peer doesn't send any sigs (no inputs), otherwise * we could just check the PSBT was finalized */ @@ -2906,11 +2912,14 @@ void peer_restart_dualopend(struct peer *peer, &min_effective_htlc_capacity); inflight = channel_current_inflight(channel); + assert(inflight); + /* Get the first inflight to figure out the original feerate * for this channel. It's fine if it's the same as the current */ first_inflight = list_top(&channel->inflights, struct channel_inflight, list); + assert(first_inflight); msg = towire_dualopend_reinit(NULL, chainparams, peer->ld->our_features, diff --git a/lightningd/dual_open_control.h b/lightningd/dual_open_control.h index 46d27c2f3ed5..4166d3ec6ecd 100644 --- a/lightningd/dual_open_control.h +++ b/lightningd/dual_open_control.h @@ -25,4 +25,8 @@ void channel_unsaved_close_conn(struct channel *channel, const char *why); void json_add_unsaved_channel(struct json_stream *response, const struct channel *channel); + +void channel_update_reserve(struct channel *channel, + struct channel_config *their_config, + struct amount_sat funding_total); #endif /* LIGHTNING_LIGHTNINGD_DUAL_OPEN_CONTROL_H */ diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 24110899f3dd..93b31c17f045 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -180,19 +180,21 @@ u8 *p2wpkh_for_keyidx(const tal_t *ctx, struct lightningd *ld, u64 keyidx) return scriptpubkey_p2wpkh(ctx, &shutdownkey); } -static void sign_last_tx(struct channel *channel) +static void sign_last_tx(struct channel *channel, + struct bitcoin_tx *last_tx, + struct bitcoin_signature *last_sig) { struct lightningd *ld = channel->peer->ld; struct bitcoin_signature sig; u8 *msg, **witness; - assert(!channel->last_tx->wtx->inputs[0].witness); + assert(!last_tx->wtx->inputs[0].witness); msg = towire_hsmd_sign_commitment_tx(tmpctx, - &channel->peer->id, - channel->dbid, - channel->last_tx, - &channel->channel_info - .remote_fundingkey); + &channel->peer->id, + channel->dbid, + last_tx, + &channel->channel_info + .remote_fundingkey); if (!wire_sync_write(ld->hsm_fd, take(msg))) fatal("Could not write to HSM: %s", strerror(errno)); @@ -203,11 +205,11 @@ static void sign_last_tx(struct channel *channel) tal_hex(tmpctx, msg)); witness = - bitcoin_witness_2of2(channel->last_tx, &channel->last_sig, + bitcoin_witness_2of2(last_tx, last_sig, &sig, &channel->channel_info.remote_fundingkey, &channel->local_funding_pubkey); - bitcoin_tx_input_set_witness(channel->last_tx, 0, take(witness)); + bitcoin_tx_input_set_witness(last_tx, 0, take(witness)); } static void remove_sig(struct bitcoin_tx *signed_tx) @@ -337,10 +339,31 @@ static bool invalid_last_tx(const struct bitcoin_tx *tx) #endif } +static void sign_and_send_last(struct lightningd *ld, + struct channel *channel, + struct bitcoin_tx *last_tx, + struct bitcoin_signature *last_sig) +{ + struct bitcoin_txid txid; + + sign_last_tx(channel, last_tx, last_sig); + bitcoin_txid(last_tx, &txid); + wallet_transaction_add(ld->wallet, last_tx->wtx, 0, 0); + wallet_transaction_annotate(ld->wallet, &txid, + channel->last_tx_type, + channel->dbid); + + /* Keep broadcasting until we say stop (can fail due to dup, + * if they beat us to the broadcast). */ + broadcast_tx(ld->topology, channel, last_tx, NULL); + + remove_sig(last_tx); +} + void drop_to_chain(struct lightningd *ld, struct channel *channel, bool cooperative) { - struct bitcoin_txid txid; + struct channel_inflight *inflight; /* BOLT #2: * * - if `next_revocation_number` is greater than expected @@ -357,16 +380,15 @@ void drop_to_chain(struct lightningd *ld, struct channel *channel, "Cannot broadcast our commitment tx:" " it's invalid! (ancient channel?)"); } else { - sign_last_tx(channel); - bitcoin_txid(channel->last_tx, &txid); - wallet_transaction_add(ld->wallet, channel->last_tx->wtx, 0, 0); - wallet_transaction_annotate(ld->wallet, &txid, channel->last_tx_type, channel->dbid); - - /* Keep broadcasting until we say stop (can fail due to dup, - * if they beat us to the broadcast). */ - broadcast_tx(ld->topology, channel, channel->last_tx, NULL); - - remove_sig(channel->last_tx); + /* We need to drop *every* commitment transaction to chain */ + if (!cooperative && !list_empty(&channel->inflights)) { + list_for_each(&channel->inflights, inflight, list) + sign_and_send_last(ld, channel, + inflight->last_tx, + &inflight->last_sig); + } else + sign_and_send_last(ld, channel, channel->last_tx, + &channel->last_sig); } resolve_close_command(ld, channel, cooperative); @@ -744,8 +766,8 @@ static void json_add_channel(struct lightningd *ld, type_to_string(tmpctx, struct channel_id, &channel->cid)); json_add_txid(response, "funding_txid", &channel->funding_txid); - if (channel->state == DUALOPEND_AWAITING_LOCKIN) { - struct channel_inflight *initial; + if (!list_empty(&channel->inflights)) { + struct channel_inflight *initial, *inflight; u32 last_feerate, next_feerate, feerate; u8 feestep; @@ -771,6 +793,34 @@ static void json_add_channel(struct lightningd *ld, for (feestep = 0; feerate < next_feerate; feestep++) feerate += feerate / 4; json_add_num(response, "next_fee_step", feestep); + + /* List the inflights */ + json_array_start(response, "inflight"); + list_for_each(&channel->inflights, inflight, list) { + struct bitcoin_txid txid; + + json_object_start(response, NULL); + json_add_txid(response, "funding_txid", + &inflight->funding->txid); + json_add_num(response, "funding_outnum", + inflight->funding->outnum); + json_add_string(response, "feerate", + tal_fmt(tmpctx, "%d%s", + inflight->funding->feerate, + feerate_style_name( + FEERATE_PER_KSIPA))); + json_add_amount_sat_only(response, + "total_funding_msat", + inflight->funding->total_funds); + json_add_amount_sat_only(response, + "our_funding_msat", + inflight->funding->our_funds); + /* Add the expected commitment tx id also */ + bitcoin_txid(inflight->last_tx, &txid); + json_add_txid(response, "scratch_txid", &txid); + json_object_end(response); + } + json_array_end(response); } if (channel->shutdown_scriptpubkey[LOCAL]) { @@ -1093,7 +1143,7 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa if (feature_negotiated(ld->our_features, peer->their_features, OPT_DUAL_FUND)) { - if (channel) { + if (channel && !list_empty(&channel->inflights)) { assert(!channel->owner); assert(channel->state == DUALOPEND_OPEN_INIT || channel->state == DUALOPEND_AWAITING_LOCKIN @@ -1262,6 +1312,32 @@ static bool check_funding_tx(const struct bitcoin_tx *tx, return false; } +static void update_channel_from_inflight(struct lightningd *ld, + struct channel *channel, + struct channel_inflight *inflight) +{ + struct wally_psbt *psbt_copy; + + channel->funding_txid = inflight->funding->txid; + channel->funding_outnum = inflight->funding->outnum; + channel->funding = inflight->funding->total_funds; + channel->our_funds = inflight->funding->our_funds; + + /* Make a 'clone' of this tx */ + psbt_copy = clone_psbt(channel, inflight->last_tx->psbt); + channel_set_last_tx(channel, + bitcoin_tx_with_psbt(channel, psbt_copy), + &inflight->last_sig, + TX_CHANNEL_UNILATERAL); + + /* Update the reserve */ + channel_update_reserve(channel, + &channel->channel_info.their_config, + inflight->funding->total_funds); + + wallet_channel_save(ld->wallet, channel); +} + static enum watch_result funding_depth_cb(struct lightningd *ld, struct channel *channel, const struct bitcoin_txid *txid, @@ -1292,6 +1368,26 @@ static enum watch_result funding_depth_cb(struct lightningd *ld, * means the stale block with our funding tx was removed) */ if ((min_depth_reached && !channel->scid) || (depth && channel->scid)) { struct txlocator *loc; + struct channel_inflight *inf; + + /* Update the channel's info to the correct tx, if needed to + * It's possible an 'inflight' has reached depth */ + if (!list_empty(&channel->inflights)) { + inf = channel_inflight_find(channel, txid); + if (!inf) { + channel_fail_permanent(channel, REASON_LOCAL, + "Txid %s for channel" + " not found in inflights. (peer %s)", + type_to_string(tmpctx, + struct bitcoin_txid, + txid), + type_to_string(tmpctx, + struct node_id, + &channel->peer->id)); + return DELETE_WATCH; + } + update_channel_from_inflight(ld, channel, inf); + } wallet_annotate_txout(ld->wallet, txid, channel->funding_outnum, TX_CHANNEL_FUNDING, channel->dbid); @@ -1377,6 +1473,19 @@ void channel_watch_funding(struct lightningd *ld, struct channel *channel) channel_watch_wrong_funding(ld, channel); } +static void channel_watch_inflight(struct lightningd *ld, + struct channel *channel, + struct channel_inflight *inflight) +{ + /* FIXME: Remove arg from cb? */ + watch_txid(channel, ld->topology, channel, + &inflight->funding->txid, funding_depth_cb); + watch_txo(channel, ld->topology, channel, + &inflight->funding->txid, + inflight->funding->outnum, + funding_spent); +} + static void json_add_peer(struct lightningd *ld, struct json_stream *response, struct peer *p, @@ -1741,6 +1850,7 @@ static void activate_peer(struct peer *peer, u32 delay) { u8 *msg; struct channel *channel; + struct channel_inflight *inflight; struct lightningd *ld = peer->ld; /* We can only have one active channel: make sure connectd @@ -1774,6 +1884,17 @@ static void activate_peer(struct peer *peer, u32 delay) continue; /* Watching lockin may be unnecessary, but it's harmless. */ channel_watch_funding(ld, channel); + + /* Also watch any inflight txs */ + list_for_each(&channel->inflights, inflight, list) { + /* Don't double watch the txid that's also in + * channel->funding_txid */ + if (bitcoin_txid_eq(&channel->funding_txid, + &inflight->funding->txid)) + continue; + + channel_watch_inflight(ld, channel, inflight); + } } } @@ -2263,10 +2384,28 @@ static struct command_result *json_sign_last_tx(struct command *cmd, log_debug(channel->log, "dev-sign-last-tx: signing tx with %zu outputs", channel->last_tx->wtx->num_outputs); - sign_last_tx(channel); + sign_last_tx(channel, channel->last_tx, &channel->last_sig); json_add_tx(response, "tx", channel->last_tx); remove_sig(channel->last_tx); + /* If we've got inflights, return them */ + if (!list_empty(&channel->inflights)) { + struct channel_inflight *inflight; + + json_array_start(response, "inflights"); + list_for_each(&channel->inflights, inflight, list) { + sign_last_tx(channel, inflight->last_tx, + &inflight->last_sig); + json_object_start(response, NULL); + json_add_txid(response, "funding_txid", + &inflight->funding->txid); + remove_sig(inflight->last_tx); + json_add_tx(response, "tx", channel->last_tx); + json_object_end(response); + } + json_array_end(response); + } + return command_success(cmd, response); } diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index b81b083ac27a..5634b25b9549 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -82,6 +82,10 @@ struct htlc_in *channel_has_htlc_in(struct channel *channel UNNEEDED) /* Generated stub for channel_has_htlc_out */ struct htlc_out *channel_has_htlc_out(struct channel *channel UNNEEDED) { fprintf(stderr, "channel_has_htlc_out called!\n"); abort(); } +/* Generated stub for channel_inflight_find */ +struct channel_inflight *channel_inflight_find(struct channel *channel UNNEEDED, + const struct bitcoin_txid *txid UNNEEDED) +{ fprintf(stderr, "channel_inflight_find called!\n"); abort(); } /* Generated stub for channel_internal_error */ void channel_internal_error(struct channel *channel UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "channel_internal_error called!\n"); abort(); } @@ -92,6 +96,12 @@ u32 channel_last_funding_feerate(const struct channel *channel UNNEEDED) void channel_set_billboard(struct channel *channel UNNEEDED, bool perm UNNEEDED, const char *str TAKES UNNEEDED) { fprintf(stderr, "channel_set_billboard called!\n"); abort(); } +/* Generated stub for channel_set_last_tx */ +void channel_set_last_tx(struct channel *channel UNNEEDED, + struct bitcoin_tx *tx UNNEEDED, + const struct bitcoin_signature *sig UNNEEDED, + enum wallet_tx_type type UNNEEDED) +{ fprintf(stderr, "channel_set_last_tx called!\n"); abort(); } /* Generated stub for channel_set_state */ void channel_set_state(struct channel *channel UNNEEDED, enum channel_state old_state UNNEEDED, @@ -114,6 +124,11 @@ bool channel_tell_depth(struct lightningd *ld UNNEEDED, /* Generated stub for channel_unsaved_close_conn */ void channel_unsaved_close_conn(struct channel *channel UNNEEDED, const char *why UNNEEDED) { fprintf(stderr, "channel_unsaved_close_conn called!\n"); abort(); } +/* Generated stub for channel_update_reserve */ +void channel_update_reserve(struct channel *channel UNNEEDED, + struct channel_config *their_config UNNEEDED, + struct amount_sat funding_total UNNEEDED) +{ fprintf(stderr, "channel_update_reserve called!\n"); abort(); } /* Generated stub for command_fail */ struct command_result *command_fail(struct command *cmd UNNEEDED, errcode_t code UNNEEDED, const char *fmt UNNEEDED, ...) diff --git a/tests/data/upgrade_inflight.sqlite3.xz b/tests/data/upgrade_inflight.sqlite3.xz new file mode 100644 index 000000000000..108fc59c4a2e Binary files /dev/null and b/tests/data/upgrade_inflight.sqlite3.xz differ diff --git a/tests/test_db.py b/tests/test_db.py index 9cd625a46e4a..3d018b55f85e 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -143,6 +143,28 @@ def test_scid_upgrade(node_factory, bitcoind): assert l1.db_query('SELECT failchannel from payments;') == [{'failchannel': '103x1x1'}] +@unittest.skipIf(not COMPAT, "needs COMPAT to convert obsolete db") +@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "This test is based on a sqlite3 snapshot") +@unittest.skipIf(TEST_NETWORK != 'regtest', "The network must match the DB snapshot") +def test_last_tx_inflight_psbt_upgrade(node_factory, bitcoind): + bitcoind.generate_block(12) + + prior_txs = ['02000000019CCCA2E59D863B00B5BD835BF7BA93CC257932D2C7CDBE51EFE2EE4A9D29DFCB01000000009DB0E280024A01000000000000220020BE7935A77CA9AB70A4B8B1906825637767FED3C00824AA90C988983587D68488F0820100000000002200209F4684DDB28ACDC73959BC194D1A25DF906F61ED030F52D163E6F1E247D32CBB9A3ED620', '020000000122F9EBE38F54208545B681AD7F73A7AE3504A09C8201F502673D34E28424687C01000000009DB0E280024A01000000000000220020BE7935A77CA9AB70A4B8B1906825637767FED3C00824AA90C988983587D68488F0820100000000002200209F4684DDB28ACDC73959BC194D1A25DF906F61ED030F52D163E6F1E247D32CBB9A3ED620'] + + l1 = node_factory.get_node(dbfile='upgrade_inflight.sqlite3.xz') + + b64_last_txs = [base64.b64encode(x['last_tx']).decode('utf-8') for x in l1.db_query('SELECT last_tx FROM channel_funding_inflights ORDER BY channel_id, funding_feerate;')] + for i in range(len(b64_last_txs)): + bpsbt = b64_last_txs[i] + psbt = bitcoind.rpc.decodepsbt(bpsbt) + tx = prior_txs[i] + assert psbt['tx']['txid'] == bitcoind.rpc.decoderawtransaction(tx)['txid'] + funding_input = only_one(psbt['inputs']) + assert funding_input['witness_utxo']['amount'] == Decimal('0.001') + assert funding_input['witness_utxo']['scriptPubKey']['type'] == 'witness_v0_scripthash' + assert funding_input['witness_script']['type'] == 'multisig' + + @unittest.skipIf(not COMPAT, "needs COMPAT to convert obsolete db") @unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "This test is based on a sqlite3 snapshot") @unittest.skipIf(TEST_NETWORK != 'regtest', "The network must match the DB snapshot") diff --git a/tests/test_opening.py b/tests/test_opening.py index 236370685047..d3723e9e037c 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -680,7 +680,8 @@ def test_rbf_no_overlap(node_factory, bitcoind, chainparams): next_feerate = find_next_feerate(l1, l2) - # Initiate an RBF + # Initiate an RBF (this grabs the non-reserved utxo, which isnt the + # one we started with) startweight = 42 + 172 # base weight, funding output initpsbt = l1.rpc.fundpsbt(chan_amount, next_feerate, startweight, min_witness_weight=110, @@ -693,6 +694,275 @@ def test_rbf_no_overlap(node_factory, bitcoind, chainparams): l1.rpc.openchannel_update(chan_id, bump['psbt']) +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@pytest.mark.openchannel('v2') +@pytest.mark.developer("uses dev-sign-last-tx") +def test_rbf_fails_to_broadcast(node_factory, bitcoind, chainparams): + l1, l2 = node_factory.get_nodes(2, + opts={'allow_warning': True, + 'may_reconnect': True}) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + amount = 2**24 + chan_amount = 100000 + bitcoind.rpc.sendtoaddress(l1.rpc.newaddr()['bech32'], amount / 10**8 + 0.01) + bitcoind.generate_block(1) + # Wait for it to arrive. + wait_for(lambda: len(l1.rpc.listfunds()['outputs']) > 0) + + # Really low feerate means that the bump wont work the first time + res = l1.rpc.fundchannel(l2.info['id'], chan_amount, feerate='253perkw') + chan_id = res['channel_id'] + vins = bitcoind.rpc.decoderawtransaction(res['tx'])['vin'] + assert(only_one(vins)) + prev_utxos = ["{}:{}".format(vins[0]['txid'], vins[0]['vout'])] + + # Check that we're waiting for lockin + l1.daemon.wait_for_log(' to DUALOPEND_AWAITING_LOCKIN') + inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight'] + assert inflights[-1]['funding_txid'] in bitcoind.rpc.getrawmempool() + + def run_retry(): + startweight = 42 + 173 + next_feerate = find_next_feerate(l1, l2) + initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight, + prev_utxos, reservedok=True, + min_witness_weight=110, + excess_as_change=True) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt']) + # We should be able to call this with while an open is progress + # but not yet committed + l1.rpc.dev_sign_last_tx(l2.info['id']) + update = l1.rpc.openchannel_update(chan_id, bump['psbt']) + assert update['commitments_secured'] + + return l1.rpc.signpsbt(update['psbt'])['signed_psbt'] + + signed_psbt = run_retry() + with pytest.raises(RpcError, match=r'insufficient fee, rejecting replacement'): + l1.rpc.openchannel_signed(chan_id, signed_psbt) + inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight'] + assert inflights[-1]['funding_txid'] not in bitcoind.rpc.getrawmempool() + + # If we restart and listpeers, it will crash + l1.restart() + + l1.rpc.listpeers() + + # We've restarted. Let's RBF until we successfully get a + # new funding transaction for this channel + # do it again + signed_psbt = run_retry() + with pytest.raises(RpcError, match=r'insufficient fee, rejecting replacement'): + l1.rpc.openchannel_signed(chan_id, signed_psbt) + inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight'] + assert inflights[-1]['funding_txid'] not in bitcoind.rpc.getrawmempool() + + # and again + signed_psbt = run_retry() + with pytest.raises(RpcError, match=r'insufficient fee, rejecting replacement'): + l1.rpc.openchannel_signed(chan_id, signed_psbt) + inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight'] + assert inflights[-1]['funding_txid'] not in bitcoind.rpc.getrawmempool() + + # now we should be ok + signed_psbt = run_retry() + l1.rpc.openchannel_signed(chan_id, signed_psbt) + inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight'] + assert len(inflights) == 5 + assert inflights[-1]['funding_txid'] in bitcoind.rpc.getrawmempool() + + l1.restart() + + # Are inflights the same post restart + prev_inflights = inflights + inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight'] + assert prev_inflights == inflights + assert inflights[-1]['funding_txid'] in bitcoind.rpc.getrawmempool() + + # Produce a signature for every inflight + last_txs = l1.rpc.dev_sign_last_tx(l2.info['id']) + assert len(last_txs['inflights']) == len(inflights) + for last_tx, inflight in zip(last_txs['inflights'], inflights): + assert last_tx['funding_txid'] == inflight['funding_txid'] + assert last_txs['tx'] + + +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@pytest.mark.openchannel('v2') +def test_rbf_broadcast_close_inflights(node_factory, bitcoind, chainparams): + """ + Close a channel before it's mined, and the most recent transaction + hasn't made it to the mempool. Should publish all the commitment + transactions that we have. + """ + l1, l2 = node_factory.get_nodes(2, + opts={'allow_warning': True}) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + amount = 2**24 + chan_amount = 100000 + bitcoind.rpc.sendtoaddress(l1.rpc.newaddr()['bech32'], amount / 10**8 + 0.01) + bitcoind.generate_block(1) + # Wait for it to arrive. + wait_for(lambda: len(l1.rpc.listfunds()['outputs']) > 0) + + res = l1.rpc.fundchannel(l2.info['id'], chan_amount, feerate='7500perkw') + chan_id = res['channel_id'] + vins = bitcoind.rpc.decoderawtransaction(res['tx'])['vin'] + assert(only_one(vins)) + prev_utxos = ["{}:{}".format(vins[0]['txid'], vins[0]['vout'])] + + # Check that we're waiting for lockin + l1.daemon.wait_for_log(' to DUALOPEND_AWAITING_LOCKIN') + inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight'] + assert inflights[-1]['funding_txid'] in bitcoind.rpc.getrawmempool() + + # Make it such that l1 and l2 cannot broadcast transactions + # (mimics failing to reach the miner with replacement) + def censoring_sendrawtx(r): + return {'id': r['id'], 'result': {}} + + l1.daemon.rpcproxy.mock_rpc('sendrawtransaction', censoring_sendrawtx) + l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', censoring_sendrawtx) + + def run_retry(): + startweight = 42 + 173 + next_feerate = find_next_feerate(l1, l2) + initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight, + prev_utxos, reservedok=True, + min_witness_weight=110, + excess_as_change=True) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt']) + update = l1.rpc.openchannel_update(chan_id, bump['psbt']) + assert update['commitments_secured'] + + return l1.rpc.signpsbt(update['psbt'])['signed_psbt'] + + signed_psbt = run_retry() + l1.rpc.openchannel_signed(chan_id, signed_psbt) + inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight'] + assert inflights[-1]['funding_txid'] not in bitcoind.rpc.getrawmempool() + + cmtmt_txid = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['scratch_txid'] + assert cmtmt_txid == inflights[-1]['scratch_txid'] + + # l2 goes offline + l2.stop() + + # l1 drops to chain. + l1.daemon.rpcproxy.mock_rpc('sendrawtransaction', None) + l1.rpc.close(chan_id, 1) + l1.daemon.wait_for_logs(['Broadcasting txid {}'.format(inflights[0]['scratch_txid']), + 'Broadcasting txid {}'.format(inflights[1]['scratch_txid']), + 'sendrawtx exit 0', + 'sendrawtx exit 25']) + assert inflights[0]['scratch_txid'] in bitcoind.rpc.getrawmempool() + assert inflights[1]['scratch_txid'] not in bitcoind.rpc.getrawmempool() + + +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +@pytest.mark.openchannel('v2') +def test_rbf_non_last_mined(node_factory, bitcoind, chainparams): + """ + What happens if a 'non-tip' RBF transaction is mined? + """ + l1, l2 = node_factory.get_nodes(2, + opts={'allow_warning': True, + 'may_reconnect': True}) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + amount = 2**24 + chan_amount = 100000 + bitcoind.rpc.sendtoaddress(l1.rpc.newaddr()['bech32'], amount / 10**8 + 0.01) + bitcoind.generate_block(1) + # Wait for it to arrive. + wait_for(lambda: len(l1.rpc.listfunds()['outputs']) > 0) + + res = l1.rpc.fundchannel(l2.info['id'], chan_amount, feerate='7500perkw') + chan_id = res['channel_id'] + vins = bitcoind.rpc.decoderawtransaction(res['tx'])['vin'] + assert(only_one(vins)) + prev_utxos = ["{}:{}".format(vins[0]['txid'], vins[0]['vout'])] + + # Check that we're waiting for lockin + l1.daemon.wait_for_log(' to DUALOPEND_AWAITING_LOCKIN') + inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight'] + assert inflights[-1]['funding_txid'] in bitcoind.rpc.getrawmempool() + + def run_retry(): + startweight = 42 + 173 + next_feerate = find_next_feerate(l1, l2) + initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight, + prev_utxos, reservedok=True, + min_witness_weight=110, + excess_as_change=True) + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt']) + update = l1.rpc.openchannel_update(chan_id, bump['psbt']) + assert update['commitments_secured'] + + return l1.rpc.signpsbt(update['psbt'])['signed_psbt'] + + # Make a second inflight + signed_psbt = run_retry() + l1.rpc.openchannel_signed(chan_id, signed_psbt) + + # Make it such that l1 and l2 cannot broadcast transactions + # (mimics failing to reach the miner with replacement) + def censoring_sendrawtx(r): + return {'id': r['id'], 'result': {}} + + l1.daemon.rpcproxy.mock_rpc('sendrawtransaction', censoring_sendrawtx) + l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', censoring_sendrawtx) + + # Make a 3rd inflight that won't make it into the mempool + signed_psbt = run_retry() + l1.rpc.openchannel_signed(chan_id, signed_psbt) + + l1.daemon.rpcproxy.mock_rpc('sendrawtransaction', None) + l2.daemon.rpcproxy.mock_rpc('sendrawtransaction', None) + + # We fetch out our inflights list + inflights = only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['inflight'] + + # l2 goes offline + l2.stop() + + # The funding transaction gets mined (should be the 2nd inflight) + bitcoind.generate_block(6, wait_for_mempool=1) + + # l2 comes back up + l2.start() + + # everybody's got the right things now + l1.daemon.wait_for_log(r'to CHANNELD_NORMAL') + l2.daemon.wait_for_log(r'to CHANNELD_NORMAL') + + channel = only_one(only_one(l1.rpc.listpeers()['peers'])['channels']) + assert channel['funding_txid'] == inflights[1]['funding_txid'] + assert channel['scratch_txid'] == inflights[1]['scratch_txid'] + + # We delete inflights when the channel is in normal ops + assert 'inflights' not in channel + + # l2 stops, again + l2.stop() + + # l1 drops to chain. + l1.rpc.close(chan_id, 1) + l1.daemon.wait_for_log('Broadcasting txid {}'.format(channel['scratch_txid'])) + + # The funding transaction gets mined (should be the 2nd inflight) + bitcoind.generate_block(1, wait_for_mempool=1) + l1.daemon.wait_for_log(r'to ONCHAIN') + + @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') def test_funder_options(node_factory, bitcoind): diff --git a/wallet/db.c b/wallet/db.c index 95c033225357..60e5b73396f6 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -48,6 +48,10 @@ static void migrate_our_funding(struct lightningd *ld, struct db *db, static void migrate_last_tx_to_psbt(struct lightningd *ld, struct db *db, const struct migration_context *mc); +static void +migrate_inflight_last_tx_to_psbt(struct lightningd *ld, struct db *db, + const struct migration_context *mc); + static void fillin_missing_scriptpubkeys(struct lightningd *ld, struct db *db, const struct migration_context *mc); @@ -712,6 +716,7 @@ static struct migration dbmigrations[] = { /* Oops, can I haz money back plz? */ {SQL("ALTER TABLE channels ADD shutdown_wrong_txid BLOB DEFAULT NULL"), NULL}, {SQL("ALTER TABLE channels ADD shutdown_wrong_outnum INTEGER DEFAULT NULL"), NULL}, + {NULL, migrate_inflight_last_tx_to_psbt}, }; /* Leak tracking. */ @@ -1404,6 +1409,92 @@ static void fillin_missing_local_basepoints(struct lightningd *ld, tal_free(stmt); } +void +migrate_inflight_last_tx_to_psbt(struct lightningd *ld, struct db *db, + const struct migration_context *mc) +{ + struct db_stmt *stmt, *update_stmt; + stmt = db_prepare_v2(db, SQL("SELECT " + " c.id" + ", p.node_id" + ", c.fundingkey_remote" + ", inflight.last_tx" + ", inflight.last_sig" + ", inflight.funding_satoshi" + ", inflight.funding_tx_id" + " FROM channels c" + " LEFT OUTER JOIN peers p" + " ON p.id = c.peer_id" + " LEFT OUTER JOIN" + " channel_funding_inflights inflight" + " ON c.id = inflight.channel_id" + " WHERE inflight.last_tx IS NOT NULL;")); + + db_query_prepared(stmt); + while (db_step(stmt)) { + struct bitcoin_tx *last_tx; + struct bitcoin_txid funding_txid; + struct amount_sat funding_sat; + struct node_id peer_id; + struct pubkey local_funding_pubkey, remote_funding_pubkey; + struct basepoints local_basepoints UNUSED; + struct bitcoin_signature last_sig; + u64 cdb_id; + u8 *funding_wscript; + + cdb_id = db_column_u64(stmt, 0); + last_tx = db_column_tx(stmt, stmt, 3); + assert(last_tx != NULL); + + /* If we've forgotten about the peer_id + * because we closed / forgot the channel, + * we can skip this. */ + if (db_column_is_null(stmt, 1)) + continue; + db_column_node_id(stmt, 1, &peer_id); + db_column_amount_sat(stmt, 5, &funding_sat); + db_column_pubkey(stmt, 2, &remote_funding_pubkey); + db_column_txid(stmt, 6, &funding_txid); + + get_channel_basepoints(ld, &peer_id, cdb_id, + &local_basepoints, &local_funding_pubkey); + + funding_wscript = bitcoin_redeem_2of2(stmt, &local_funding_pubkey, + &remote_funding_pubkey); + + + psbt_input_set_wit_utxo(last_tx->psbt, 0, + scriptpubkey_p2wsh(last_tx->psbt, funding_wscript), + funding_sat); + psbt_input_set_witscript(last_tx->psbt, 0, funding_wscript); + + if (!db_column_signature(stmt, 4, &last_sig.s)) + abort(); + + last_sig.sighash_type = SIGHASH_ALL; + if (!psbt_input_set_signature(last_tx->psbt, 0, + &remote_funding_pubkey, &last_sig)) + abort(); + psbt_input_add_pubkey(last_tx->psbt, 0, + &local_funding_pubkey); + psbt_input_add_pubkey(last_tx->psbt, 0, + &remote_funding_pubkey); + + update_stmt = db_prepare_v2(db, + SQL("UPDATE channel_funding_inflights" + " SET last_tx = ?" + " WHERE channel_id = ?" + " AND funding_tx_id = ?;")); + db_bind_psbt(update_stmt, 0, last_tx->psbt); + db_bind_int(update_stmt, 1, cdb_id); + db_bind_txid(update_stmt, 2, &funding_txid); + db_exec_prepared_v2(update_stmt); + tal_free(update_stmt); + } + + tal_free(stmt); +} + /* We're moving everything over to PSBTs from tx's, particularly our last_tx's * which are commitment transactions for channels. * This migration loads all of the last_tx's and 're-formats' them into psbts, diff --git a/wallet/db_postgres_sqlgen.c b/wallet/db_postgres_sqlgen.c index a65d479ffc6f..efeaae5bba67 100644 --- a/wallet/db_postgres_sqlgen.c +++ b/wallet/db_postgres_sqlgen.c @@ -1034,6 +1034,18 @@ struct db_query db_postgres_queries[] = { .placeholders = 6, .readonly = false, }, + { + .name = "SELECT c.id, p.node_id, c.fundingkey_remote, inflight.last_tx, inflight.last_sig, inflight.funding_satoshi, inflight.funding_tx_id FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id LEFT OUTER JOIN channel_funding_inflights inflight ON c.id = inflight.channel_id WHERE inflight.last_tx IS NOT NULL;", + .query = "SELECT c.id, p.node_id, c.fundingkey_remote, inflight.last_tx, inflight.last_sig, inflight.funding_satoshi, inflight.funding_tx_id FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id LEFT OUTER JOIN channel_funding_inflights inflight ON c.id = inflight.channel_id WHERE inflight.last_tx IS NOT NULL;", + .placeholders = 0, + .readonly = true, + }, + { + .name = "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;", + .query = "UPDATE channel_funding_inflights SET last_tx = $1 WHERE channel_id = $2 AND funding_tx_id = $3;", + .placeholders = 3, + .readonly = false, + }, { .name = "SELECT c.id, p.node_id, c.last_tx, c.funding_satoshi, c.fundingkey_remote, c.last_sig FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id;", .query = "SELECT c.id, p.node_id, c.last_tx, c.funding_satoshi, c.fundingkey_remote, c.last_sig FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id;", @@ -1275,8 +1287,14 @@ struct db_query db_postgres_queries[] = { .readonly = false, }, { - .name = "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = ?", - .query = "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = $1", + .name = "DELETE FROM channel_funding_inflights WHERE channel_id = ?", + .query = "DELETE FROM channel_funding_inflights WHERE channel_id = $1", + .placeholders = 1, + .readonly = false, + }, + { + .name = "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", + .query = "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = $1 ORDER BY funding_feerate", .placeholders = 1, .readonly = true, }, @@ -1882,10 +1900,10 @@ struct db_query db_postgres_queries[] = { }, }; -#define DB_POSTGRES_QUERY_COUNT 312 +#define DB_POSTGRES_QUERY_COUNT 315 #endif /* HAVE_POSTGRES */ #endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */ -// SHA256STAMP:74b99da984e5e1872a7b3de32d3fc00efd7538e95e0509c6a839097522ea8a94 +// SHA256STAMP:3e9e616dd7902bee25e0b17b878a60e57a7a8c9bfec2376b4efe7c4094ffe617 diff --git a/wallet/db_sqlite3_sqlgen.c b/wallet/db_sqlite3_sqlgen.c index e07ca3ac3c3b..1e6be805effa 100644 --- a/wallet/db_sqlite3_sqlgen.c +++ b/wallet/db_sqlite3_sqlgen.c @@ -1034,6 +1034,18 @@ struct db_query db_sqlite3_queries[] = { .placeholders = 6, .readonly = false, }, + { + .name = "SELECT c.id, p.node_id, c.fundingkey_remote, inflight.last_tx, inflight.last_sig, inflight.funding_satoshi, inflight.funding_tx_id FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id LEFT OUTER JOIN channel_funding_inflights inflight ON c.id = inflight.channel_id WHERE inflight.last_tx IS NOT NULL;", + .query = "SELECT c.id, p.node_id, c.fundingkey_remote, inflight.last_tx, inflight.last_sig, inflight.funding_satoshi, inflight.funding_tx_id FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id LEFT OUTER JOIN channel_funding_inflights inflight ON c.id = inflight.channel_id WHERE inflight.last_tx IS NOT NULL;", + .placeholders = 0, + .readonly = true, + }, + { + .name = "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;", + .query = "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;", + .placeholders = 3, + .readonly = false, + }, { .name = "SELECT c.id, p.node_id, c.last_tx, c.funding_satoshi, c.fundingkey_remote, c.last_sig FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id;", .query = "SELECT c.id, p.node_id, c.last_tx, c.funding_satoshi, c.fundingkey_remote, c.last_sig FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id;", @@ -1275,8 +1287,14 @@ struct db_query db_sqlite3_queries[] = { .readonly = false, }, { - .name = "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = ?", - .query = "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = ?", + .name = "DELETE FROM channel_funding_inflights WHERE channel_id = ?", + .query = "DELETE FROM channel_funding_inflights WHERE channel_id = ?", + .placeholders = 1, + .readonly = false, + }, + { + .name = "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", + .query = "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate", .placeholders = 1, .readonly = true, }, @@ -1882,10 +1900,10 @@ struct db_query db_sqlite3_queries[] = { }, }; -#define DB_SQLITE3_QUERY_COUNT 312 +#define DB_SQLITE3_QUERY_COUNT 315 #endif /* HAVE_SQLITE3 */ #endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */ -// SHA256STAMP:74b99da984e5e1872a7b3de32d3fc00efd7538e95e0509c6a839097522ea8a94 +// SHA256STAMP:3e9e616dd7902bee25e0b17b878a60e57a7a8c9bfec2376b4efe7c4094ffe617 diff --git a/wallet/statements_gettextgen.po b/wallet/statements_gettextgen.po index 1c249dd51ffd..7dc0f81857ce 100644 --- a/wallet/statements_gettextgen.po +++ b/wallet/statements_gettextgen.po @@ -1,692 +1,700 @@ -#: wallet/db.c:65 +#: wallet/db.c:69 msgid "CREATE TABLE version (version INTEGER)" msgstr "" -#: wallet/db.c:66 +#: wallet/db.c:70 msgid "INSERT INTO version VALUES (1)" msgstr "" -#: wallet/db.c:67 +#: wallet/db.c:71 msgid "CREATE TABLE outputs ( prev_out_tx BLOB, prev_out_index INTEGER, value BIGINT, type INTEGER, status INTEGER, keyindex INTEGER, PRIMARY KEY (prev_out_tx, prev_out_index));" msgstr "" -#: wallet/db.c:76 +#: wallet/db.c:80 msgid "CREATE TABLE vars ( name VARCHAR(32), val VARCHAR(255), PRIMARY KEY (name));" msgstr "" -#: wallet/db.c:82 +#: wallet/db.c:86 msgid "CREATE TABLE shachains ( id BIGSERIAL, min_index BIGINT, num_valid BIGINT, PRIMARY KEY (id));" msgstr "" -#: wallet/db.c:89 +#: wallet/db.c:93 msgid "CREATE TABLE shachain_known ( shachain_id BIGINT REFERENCES shachains(id) ON DELETE CASCADE, pos INTEGER, idx BIGINT, hash BLOB, PRIMARY KEY (shachain_id, pos));" msgstr "" -#: wallet/db.c:97 +#: wallet/db.c:101 msgid "CREATE TABLE peers ( id BIGSERIAL, node_id BLOB UNIQUE, address TEXT, PRIMARY KEY (id));" msgstr "" -#: wallet/db.c:104 +#: wallet/db.c:108 msgid "CREATE TABLE channels ( id BIGSERIAL, peer_id BIGINT REFERENCES peers(id) ON DELETE CASCADE, short_channel_id TEXT, channel_config_local BIGINT, channel_config_remote BIGINT, state INTEGER, funder INTEGER, channel_flags INTEGER, minimum_depth INTEGER, next_index_local BIGINT, next_index_remote BIGINT, next_htlc_id BIGINT, funding_tx_id BLOB, funding_tx_outnum INTEGER, funding_satoshi BIGINT, funding_locked_remote INTEGER, push_msatoshi BIGINT, msatoshi_local BIGINT, fundingkey_remote BLOB, revocation_basepoint_remote BLOB, payment_basepoint_remote BLOB, htlc_basepoint_remote BLOB, delayed_payment_basepoint_remote BLOB, per_commit_remote BLOB, old_per_commit_remote BLOB, local_feerate_per_kw INTEGER, remote_feerate_per_kw INTEGER, shachain_remote_id BIGINT, shutdown_scriptpubkey_remote BLOB, shutdown_keyidx_local BIGINT, last_sent_commit_state BIGINT, last_sent_commit_id INTEGER, last_tx BLOB, last_sig BLOB, closing_fee_received INTEGER, closing_sig_received BLOB, PRIMARY KEY (id));" msgstr "" -#: wallet/db.c:146 +#: wallet/db.c:150 msgid "CREATE TABLE channel_configs ( id BIGSERIAL, dust_limit_satoshis BIGINT, max_htlc_value_in_flight_msat BIGINT, channel_reserve_satoshis BIGINT, htlc_minimum_msat BIGINT, to_self_delay INTEGER, max_accepted_htlcs INTEGER, PRIMARY KEY (id));" msgstr "" -#: wallet/db.c:157 +#: wallet/db.c:161 msgid "CREATE TABLE channel_htlcs ( id BIGSERIAL, channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, channel_htlc_id BIGINT, direction INTEGER, origin_htlc BIGINT, msatoshi BIGINT, cltv_expiry INTEGER, payment_hash BLOB, payment_key BLOB, routing_onion BLOB, failuremsg BLOB, malformed_onion INTEGER, hstate INTEGER, shared_secret BLOB, PRIMARY KEY (id), UNIQUE (channel_id, channel_htlc_id, direction));" msgstr "" -#: wallet/db.c:177 +#: wallet/db.c:181 msgid "CREATE TABLE invoices ( id BIGSERIAL, state INTEGER, msatoshi BIGINT, payment_hash BLOB, payment_key BLOB, label TEXT, PRIMARY KEY (id), UNIQUE (label), UNIQUE (payment_hash));" msgstr "" -#: wallet/db.c:189 +#: wallet/db.c:193 msgid "CREATE TABLE payments ( id BIGSERIAL, timestamp INTEGER, status INTEGER, payment_hash BLOB, direction INTEGER, destination BLOB, msatoshi BIGINT, PRIMARY KEY (id), UNIQUE (payment_hash));" msgstr "" -#: wallet/db.c:202 +#: wallet/db.c:206 msgid "ALTER TABLE invoices ADD expiry_time BIGINT;" msgstr "" -#: wallet/db.c:203 +#: wallet/db.c:207 msgid "UPDATE invoices SET expiry_time=9223372036854775807;" msgstr "" -#: wallet/db.c:205 +#: wallet/db.c:209 msgid "ALTER TABLE invoices ADD pay_index BIGINT;" msgstr "" -#: wallet/db.c:206 +#: wallet/db.c:210 msgid "CREATE UNIQUE INDEX invoices_pay_index ON invoices(pay_index);" msgstr "" -#: wallet/db.c:208 +#: wallet/db.c:212 msgid "UPDATE invoices SET pay_index=id WHERE state=1;" msgstr "" -#: wallet/db.c:211 +#: wallet/db.c:215 msgid "INSERT INTO vars(name, val) VALUES('next_pay_index', COALESCE((SELECT MAX(pay_index) FROM invoices WHERE state=1), 0) + 1 );" msgstr "" -#: wallet/db.c:220 +#: wallet/db.c:224 msgid "ALTER TABLE channels ADD first_blocknum BIGINT;" msgstr "" -#: wallet/db.c:221 +#: wallet/db.c:225 msgid "UPDATE channels SET first_blocknum=1 WHERE short_channel_id IS NOT NULL;" msgstr "" -#: wallet/db.c:223 +#: wallet/db.c:227 msgid "ALTER TABLE outputs ADD COLUMN channel_id BIGINT;" msgstr "" -#: wallet/db.c:224 +#: wallet/db.c:228 msgid "ALTER TABLE outputs ADD COLUMN peer_id BLOB;" msgstr "" -#: wallet/db.c:225 +#: wallet/db.c:229 msgid "ALTER TABLE outputs ADD COLUMN commitment_point BLOB;" msgstr "" -#: wallet/db.c:226 +#: wallet/db.c:230 msgid "ALTER TABLE invoices ADD COLUMN msatoshi_received BIGINT;" msgstr "" -#: wallet/db.c:228 +#: wallet/db.c:232 msgid "UPDATE invoices SET msatoshi_received=0 WHERE state=1;" msgstr "" -#: wallet/db.c:229 +#: wallet/db.c:233 msgid "ALTER TABLE channels ADD COLUMN last_was_revoke INTEGER;" msgstr "" -#: wallet/db.c:233 wallet/db.c:526 +#: wallet/db.c:237 wallet/db.c:530 msgid "ALTER TABLE payments RENAME TO temp_payments;" msgstr "" -#: wallet/db.c:234 +#: wallet/db.c:238 msgid "CREATE TABLE payments ( id BIGSERIAL, timestamp INTEGER, status INTEGER, payment_hash BLOB, destination BLOB, msatoshi BIGINT, PRIMARY KEY (id), UNIQUE (payment_hash));" msgstr "" -#: wallet/db.c:245 +#: wallet/db.c:249 msgid "INSERT INTO payments SELECT id, timestamp, status, payment_hash, destination, msatoshi FROM temp_payments WHERE direction=1;" msgstr "" -#: wallet/db.c:248 wallet/db.c:601 +#: wallet/db.c:252 wallet/db.c:605 msgid "DROP TABLE temp_payments;" msgstr "" -#: wallet/db.c:250 +#: wallet/db.c:254 msgid "ALTER TABLE payments ADD COLUMN payment_preimage BLOB;" msgstr "" -#: wallet/db.c:252 +#: wallet/db.c:256 msgid "ALTER TABLE payments ADD COLUMN path_secrets BLOB;" msgstr "" -#: wallet/db.c:255 +#: wallet/db.c:259 msgid "ALTER TABLE invoices ADD paid_timestamp BIGINT;" msgstr "" -#: wallet/db.c:256 +#: wallet/db.c:260 msgid "UPDATE invoices SET paid_timestamp = CURRENT_TIMESTAMP() WHERE state = 1;" msgstr "" -#: wallet/db.c:264 +#: wallet/db.c:268 msgid "ALTER TABLE payments ADD COLUMN route_nodes BLOB;" msgstr "" -#: wallet/db.c:265 +#: wallet/db.c:269 msgid "ALTER TABLE payments ADD COLUMN route_channels BLOB;" msgstr "" -#: wallet/db.c:266 +#: wallet/db.c:270 msgid "CREATE TABLE htlc_sigs (channelid INTEGER REFERENCES channels(id) ON DELETE CASCADE, signature BLOB);" msgstr "" -#: wallet/db.c:269 +#: wallet/db.c:273 msgid "CREATE INDEX channel_idx ON htlc_sigs (channelid)" msgstr "" -#: wallet/db.c:271 +#: wallet/db.c:275 msgid "DELETE FROM channels WHERE state=1" msgstr "" -#: wallet/db.c:273 +#: wallet/db.c:277 msgid "CREATE TABLE db_upgrades (upgrade_from INTEGER, lightning_version TEXT);" msgstr "" -#: wallet/db.c:277 wallet/db.c:467 +#: wallet/db.c:281 wallet/db.c:471 msgid "DELETE FROM peers WHERE id NOT IN (SELECT peer_id FROM channels);" msgstr "" -#: wallet/db.c:281 +#: wallet/db.c:285 msgid "UPDATE channels SET STATE = 8 WHERE state > 8;" msgstr "" -#: wallet/db.c:283 +#: wallet/db.c:287 msgid "ALTER TABLE invoices ADD bolt11 TEXT;" msgstr "" -#: wallet/db.c:287 +#: wallet/db.c:291 msgid "CREATE TABLE blocks (height INT, hash BLOB, prev_hash BLOB, UNIQUE(height));" msgstr "" -#: wallet/db.c:297 +#: wallet/db.c:301 msgid "ALTER TABLE outputs ADD COLUMN confirmation_height INTEGER REFERENCES blocks(height) ON DELETE SET NULL;" msgstr "" -#: wallet/db.c:300 +#: wallet/db.c:304 msgid "ALTER TABLE outputs ADD COLUMN spend_height INTEGER REFERENCES blocks(height) ON DELETE SET NULL;" msgstr "" -#: wallet/db.c:304 +#: wallet/db.c:308 msgid "CREATE INDEX output_height_idx ON outputs (confirmation_height, spend_height);" msgstr "" -#: wallet/db.c:307 +#: wallet/db.c:311 msgid "CREATE TABLE utxoset ( txid BLOB, outnum INT, blockheight INT REFERENCES blocks(height) ON DELETE CASCADE, spendheight INT REFERENCES blocks(height) ON DELETE SET NULL, txindex INT, scriptpubkey BLOB, satoshis BIGINT, PRIMARY KEY(txid, outnum));" msgstr "" -#: wallet/db.c:317 +#: wallet/db.c:321 msgid "CREATE INDEX short_channel_id ON utxoset (blockheight, txindex, outnum)" msgstr "" -#: wallet/db.c:322 +#: wallet/db.c:326 msgid "CREATE INDEX utxoset_spend ON utxoset (spendheight)" msgstr "" -#: wallet/db.c:324 +#: wallet/db.c:328 msgid "UPDATE channels SET shutdown_keyidx_local=0 WHERE shutdown_keyidx_local = -1;" msgstr "" -#: wallet/db.c:330 +#: wallet/db.c:334 msgid "ALTER TABLE payments ADD failonionreply BLOB;" msgstr "" -#: wallet/db.c:332 +#: wallet/db.c:336 msgid "ALTER TABLE payments ADD faildestperm INTEGER;" msgstr "" -#: wallet/db.c:334 +#: wallet/db.c:338 msgid "ALTER TABLE payments ADD failindex INTEGER;" msgstr "" -#: wallet/db.c:336 +#: wallet/db.c:340 msgid "ALTER TABLE payments ADD failcode INTEGER;" msgstr "" -#: wallet/db.c:337 +#: wallet/db.c:341 msgid "ALTER TABLE payments ADD failnode BLOB;" msgstr "" -#: wallet/db.c:338 +#: wallet/db.c:342 msgid "ALTER TABLE payments ADD failchannel TEXT;" msgstr "" -#: wallet/db.c:340 +#: wallet/db.c:344 msgid "ALTER TABLE payments ADD failupdate BLOB;" msgstr "" -#: wallet/db.c:344 +#: wallet/db.c:348 msgid "UPDATE payments SET path_secrets = NULL , route_nodes = NULL , route_channels = NULL WHERE status <> 0;" msgstr "" -#: wallet/db.c:351 +#: wallet/db.c:355 msgid "ALTER TABLE channels ADD in_payments_offered INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:352 +#: wallet/db.c:356 msgid "ALTER TABLE channels ADD in_payments_fulfilled INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:353 +#: wallet/db.c:357 msgid "ALTER TABLE channels ADD in_msatoshi_offered BIGINT DEFAULT 0;" msgstr "" -#: wallet/db.c:354 +#: wallet/db.c:358 msgid "ALTER TABLE channels ADD in_msatoshi_fulfilled BIGINT DEFAULT 0;" msgstr "" -#: wallet/db.c:355 +#: wallet/db.c:359 msgid "ALTER TABLE channels ADD out_payments_offered INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:356 +#: wallet/db.c:360 msgid "ALTER TABLE channels ADD out_payments_fulfilled INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:357 +#: wallet/db.c:361 msgid "ALTER TABLE channels ADD out_msatoshi_offered BIGINT DEFAULT 0;" msgstr "" -#: wallet/db.c:358 +#: wallet/db.c:362 msgid "ALTER TABLE channels ADD out_msatoshi_fulfilled BIGINT DEFAULT 0;" msgstr "" -#: wallet/db.c:359 +#: wallet/db.c:363 msgid "UPDATE channels SET in_payments_offered = 0, in_payments_fulfilled = 0 , in_msatoshi_offered = 0, in_msatoshi_fulfilled = 0 , out_payments_offered = 0, out_payments_fulfilled = 0 , out_msatoshi_offered = 0, out_msatoshi_fulfilled = 0 ;" msgstr "" -#: wallet/db.c:368 +#: wallet/db.c:372 msgid "ALTER TABLE payments ADD msatoshi_sent BIGINT;" msgstr "" -#: wallet/db.c:369 +#: wallet/db.c:373 msgid "UPDATE payments SET msatoshi_sent = msatoshi;" msgstr "" -#: wallet/db.c:371 +#: wallet/db.c:375 msgid "DELETE FROM utxoset WHERE blockheight IN ( SELECT DISTINCT(blockheight) FROM utxoset LEFT OUTER JOIN blocks on (blockheight = blocks.height) WHERE blocks.hash IS NULL);" msgstr "" -#: wallet/db.c:379 +#: wallet/db.c:383 msgid "ALTER TABLE channels ADD min_possible_feerate INTEGER;" msgstr "" -#: wallet/db.c:380 +#: wallet/db.c:384 msgid "ALTER TABLE channels ADD max_possible_feerate INTEGER;" msgstr "" -#: wallet/db.c:383 +#: wallet/db.c:387 msgid "UPDATE channels SET min_possible_feerate=0, max_possible_feerate=250000;" msgstr "" -#: wallet/db.c:387 +#: wallet/db.c:391 msgid "ALTER TABLE channels ADD msatoshi_to_us_min BIGINT;" msgstr "" -#: wallet/db.c:388 +#: wallet/db.c:392 msgid "ALTER TABLE channels ADD msatoshi_to_us_max BIGINT;" msgstr "" -#: wallet/db.c:389 +#: wallet/db.c:393 msgid "UPDATE channels SET msatoshi_to_us_min = msatoshi_local , msatoshi_to_us_max = msatoshi_local ;" msgstr "" -#: wallet/db.c:398 +#: wallet/db.c:402 msgid "CREATE TABLE transactions ( id BLOB, blockheight INTEGER REFERENCES blocks(height) ON DELETE SET NULL, txindex INTEGER, rawtx BLOB, PRIMARY KEY (id));" msgstr "" -#: wallet/db.c:407 +#: wallet/db.c:411 msgid "ALTER TABLE payments ADD faildetail TEXT;" msgstr "" -#: wallet/db.c:408 +#: wallet/db.c:412 msgid "UPDATE payments SET faildetail = 'unspecified payment failure reason' WHERE status = 2;" msgstr "" -#: wallet/db.c:413 +#: wallet/db.c:417 msgid "CREATE TABLE channeltxs ( id BIGSERIAL, channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, type INTEGER, transaction_id BLOB REFERENCES transactions(id) ON DELETE CASCADE, input_num INTEGER, blockheight INTEGER REFERENCES blocks(height) ON DELETE CASCADE, PRIMARY KEY(id));" msgstr "" -#: wallet/db.c:429 +#: wallet/db.c:433 msgid "DELETE FROM blocks WHERE height > (SELECT MIN(first_blocknum) FROM channels);" msgstr "" -#: wallet/db.c:435 +#: wallet/db.c:439 msgid "INSERT INTO blocks (height) VALUES ((SELECT MIN(first_blocknum) FROM channels)) ON CONFLICT(height) DO NOTHING;" msgstr "" -#: wallet/db.c:439 +#: wallet/db.c:443 msgid "DELETE FROM blocks WHERE height IS NULL;" msgstr "" -#: wallet/db.c:441 +#: wallet/db.c:445 msgid "ALTER TABLE invoices ADD description TEXT;" msgstr "" -#: wallet/db.c:443 +#: wallet/db.c:447 msgid "ALTER TABLE payments ADD description TEXT;" msgstr "" -#: wallet/db.c:445 +#: wallet/db.c:449 msgid "ALTER TABLE channels ADD future_per_commitment_point BLOB;" msgstr "" -#: wallet/db.c:447 +#: wallet/db.c:451 msgid "ALTER TABLE channels ADD last_sent_commit BLOB;" msgstr "" -#: wallet/db.c:452 +#: wallet/db.c:456 msgid "CREATE TABLE forwarded_payments ( in_htlc_id BIGINT REFERENCES channel_htlcs(id) ON DELETE SET NULL, out_htlc_id BIGINT REFERENCES channel_htlcs(id) ON DELETE SET NULL, in_channel_scid BIGINT, out_channel_scid BIGINT, in_msatoshi BIGINT, out_msatoshi BIGINT, state INTEGER, UNIQUE(in_htlc_id, out_htlc_id));" msgstr "" -#: wallet/db.c:464 +#: wallet/db.c:468 msgid "ALTER TABLE payments ADD faildirection INTEGER;" msgstr "" -#: wallet/db.c:469 +#: wallet/db.c:473 msgid "ALTER TABLE outputs ADD scriptpubkey BLOB;" msgstr "" -#: wallet/db.c:471 +#: wallet/db.c:475 msgid "ALTER TABLE payments ADD bolt11 TEXT;" msgstr "" -#: wallet/db.c:473 +#: wallet/db.c:477 msgid "ALTER TABLE channels ADD feerate_base INTEGER;" msgstr "" -#: wallet/db.c:474 +#: wallet/db.c:478 msgid "ALTER TABLE channels ADD feerate_ppm INTEGER;" msgstr "" -#: wallet/db.c:476 +#: wallet/db.c:480 msgid "ALTER TABLE channel_htlcs ADD received_time BIGINT" msgstr "" -#: wallet/db.c:477 +#: wallet/db.c:481 msgid "ALTER TABLE forwarded_payments ADD received_time BIGINT" msgstr "" -#: wallet/db.c:478 +#: wallet/db.c:482 msgid "ALTER TABLE forwarded_payments ADD resolved_time BIGINT" msgstr "" -#: wallet/db.c:479 +#: wallet/db.c:483 msgid "ALTER TABLE channels ADD remote_upfront_shutdown_script BLOB;" msgstr "" -#: wallet/db.c:482 +#: wallet/db.c:486 msgid "ALTER TABLE forwarded_payments ADD failcode INTEGER;" msgstr "" -#: wallet/db.c:484 +#: wallet/db.c:488 msgid "ALTER TABLE channels ADD remote_ann_node_sig BLOB;" msgstr "" -#: wallet/db.c:485 +#: wallet/db.c:489 msgid "ALTER TABLE channels ADD remote_ann_bitcoin_sig BLOB;" msgstr "" -#: wallet/db.c:487 +#: wallet/db.c:491 msgid "ALTER TABLE transactions ADD type BIGINT;" msgstr "" -#: wallet/db.c:492 +#: wallet/db.c:496 msgid "ALTER TABLE transactions ADD channel_id BIGINT;" msgstr "" -#: wallet/db.c:494 +#: wallet/db.c:498 msgid "UPDATE channels SET short_channel_id = REPLACE(short_channel_id, ':', 'x') WHERE short_channel_id IS NOT NULL;" msgstr "" -#: wallet/db.c:497 +#: wallet/db.c:501 msgid "UPDATE payments SET failchannel = REPLACE(failchannel, ':', 'x') WHERE failchannel IS NOT NULL;" msgstr "" -#: wallet/db.c:500 +#: wallet/db.c:504 msgid "ALTER TABLE channels ADD COLUMN option_static_remotekey INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:502 +#: wallet/db.c:506 msgid "ALTER TABLE vars ADD COLUMN intval INTEGER" msgstr "" -#: wallet/db.c:503 +#: wallet/db.c:507 msgid "ALTER TABLE vars ADD COLUMN blobval BLOB" msgstr "" -#: wallet/db.c:504 +#: wallet/db.c:508 msgid "UPDATE vars SET intval = CAST(val AS INTEGER) WHERE name IN ('bip32_max_index', 'last_processed_block', 'next_pay_index')" msgstr "" -#: wallet/db.c:505 +#: wallet/db.c:509 msgid "UPDATE vars SET blobval = CAST(val AS BLOB) WHERE name = 'genesis_hash'" msgstr "" -#: wallet/db.c:506 +#: wallet/db.c:510 msgid "CREATE TABLE transaction_annotations ( txid BLOB, idx INTEGER, location INTEGER, type INTEGER, channel BIGINT REFERENCES channels(id), UNIQUE(txid, idx));" msgstr "" -#: wallet/db.c:518 +#: wallet/db.c:522 msgid "ALTER TABLE channels ADD shutdown_scriptpubkey_local BLOB;" msgstr "" -#: wallet/db.c:521 +#: wallet/db.c:525 msgid "UPDATE forwarded_payments SET received_time=0 WHERE received_time IS NULL;" msgstr "" -#: wallet/db.c:523 +#: wallet/db.c:527 msgid "ALTER TABLE invoices ADD COLUMN features BLOB DEFAULT '';" msgstr "" -#: wallet/db.c:527 +#: wallet/db.c:531 msgid "CREATE TABLE payments ( id BIGSERIAL, timestamp INTEGER, status INTEGER, payment_hash BLOB, destination BLOB, msatoshi BIGINT, payment_preimage BLOB, path_secrets BLOB, route_nodes BLOB, route_channels BLOB, failonionreply BLOB, faildestperm INTEGER, failindex INTEGER, failcode INTEGER, failnode BLOB, failchannel TEXT, failupdate BLOB, msatoshi_sent BIGINT, faildetail TEXT, description TEXT, faildirection INTEGER, bolt11 TEXT, total_msat BIGINT, partid BIGINT, PRIMARY KEY (id), UNIQUE (payment_hash, partid))" msgstr "" -#: wallet/db.c:554 +#: wallet/db.c:558 msgid "INSERT INTO payments (id, timestamp, status, payment_hash, destination, msatoshi, payment_preimage, path_secrets, route_nodes, route_channels, failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, msatoshi_sent, faildetail, description, faildirection, bolt11)SELECT id, timestamp, status, payment_hash, destination, msatoshi, payment_preimage, path_secrets, route_nodes, route_channels, failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, msatoshi_sent, faildetail, description, faildirection, bolt11 FROM temp_payments;" msgstr "" -#: wallet/db.c:599 +#: wallet/db.c:603 msgid "UPDATE payments SET total_msat = msatoshi;" msgstr "" -#: wallet/db.c:600 +#: wallet/db.c:604 msgid "UPDATE payments SET partid = 0;" msgstr "" -#: wallet/db.c:602 +#: wallet/db.c:606 msgid "ALTER TABLE channel_htlcs ADD partid BIGINT;" msgstr "" -#: wallet/db.c:603 +#: wallet/db.c:607 msgid "UPDATE channel_htlcs SET partid = 0;" msgstr "" -#: wallet/db.c:604 +#: wallet/db.c:608 msgid "CREATE TABLE channel_feerates ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, hstate INTEGER, feerate_per_kw INTEGER, UNIQUE (channel_id, hstate));" msgstr "" -#: wallet/db.c:615 +#: wallet/db.c:619 msgid "INSERT INTO channel_feerates(channel_id, hstate, feerate_per_kw) SELECT id, 4, local_feerate_per_kw FROM channels WHERE funder = 0;" msgstr "" -#: wallet/db.c:619 +#: wallet/db.c:623 msgid "INSERT INTO channel_feerates(channel_id, hstate, feerate_per_kw) SELECT id, 1, remote_feerate_per_kw FROM channels WHERE funder = 0 and local_feerate_per_kw != remote_feerate_per_kw;" msgstr "" -#: wallet/db.c:624 +#: wallet/db.c:628 msgid "INSERT INTO channel_feerates(channel_id, hstate, feerate_per_kw) SELECT id, 14, remote_feerate_per_kw FROM channels WHERE funder = 1;" msgstr "" -#: wallet/db.c:628 +#: wallet/db.c:632 msgid "INSERT INTO channel_feerates(channel_id, hstate, feerate_per_kw) SELECT id, 11, local_feerate_per_kw FROM channels WHERE funder = 1 and local_feerate_per_kw != remote_feerate_per_kw;" msgstr "" -#: wallet/db.c:632 +#: wallet/db.c:636 msgid "INSERT INTO vars (name, intval) VALUES ('data_version', 0);" msgstr "" -#: wallet/db.c:635 +#: wallet/db.c:639 msgid "ALTER TABLE channel_htlcs ADD localfailmsg BLOB;" msgstr "" -#: wallet/db.c:636 +#: wallet/db.c:640 msgid "UPDATE channel_htlcs SET localfailmsg=decode('2002', 'hex') WHERE malformed_onion != 0 AND direction = 1;" msgstr "" -#: wallet/db.c:637 +#: wallet/db.c:641 msgid "ALTER TABLE channels ADD our_funding_satoshi BIGINT DEFAULT 0;" msgstr "" -#: wallet/db.c:638 +#: wallet/db.c:642 msgid "CREATE TABLE penalty_bases ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, commitnum BIGINT, txid BLOB, outnum INTEGER, amount BIGINT, PRIMARY KEY (channel_id, commitnum));" msgstr "" -#: wallet/db.c:648 +#: wallet/db.c:652 msgid "ALTER TABLE channel_htlcs ADD we_filled INTEGER;" msgstr "" -#: wallet/db.c:650 +#: wallet/db.c:654 msgid "INSERT INTO vars (name, intval) VALUES ('coin_moves_count', 0);" msgstr "" -#: wallet/db.c:652 +#: wallet/db.c:656 msgid "ALTER TABLE outputs ADD reserved_til INTEGER DEFAULT NULL;" msgstr "" -#: wallet/db.c:655 +#: wallet/db.c:659 msgid "ALTER TABLE channels ADD COLUMN option_anchor_outputs INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:658 +#: wallet/db.c:662 msgid "ALTER TABLE outputs ADD option_anchor_outputs INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:660 +#: wallet/db.c:664 msgid "ALTER TABLE channels ADD full_channel_id BLOB DEFAULT NULL;" msgstr "" -#: wallet/db.c:661 +#: wallet/db.c:665 msgid "ALTER TABLE channels ADD funding_psbt BLOB DEFAULT NULL;" msgstr "" -#: wallet/db.c:663 +#: wallet/db.c:667 msgid "ALTER TABLE channels ADD closer INTEGER DEFAULT 2;" msgstr "" -#: wallet/db.c:664 +#: wallet/db.c:668 msgid "ALTER TABLE channels ADD state_change_reason INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:665 +#: wallet/db.c:669 msgid "CREATE TABLE channel_state_changes ( channel_id BIGINT REFERENCES channels(id) ON DELETE CASCADE, timestamp BIGINT, old_state INTEGER, new_state INTEGER, cause INTEGER, message TEXT);" msgstr "" -#: wallet/db.c:673 +#: wallet/db.c:677 msgid "CREATE TABLE offers ( offer_id BLOB, bolt12 TEXT, label TEXT, status INTEGER, PRIMARY KEY (offer_id));" msgstr "" -#: wallet/db.c:681 +#: wallet/db.c:685 msgid "ALTER TABLE invoices ADD COLUMN local_offer_id BLOB DEFAULT NULL REFERENCES offers(offer_id);" msgstr "" -#: wallet/db.c:683 +#: wallet/db.c:687 msgid "ALTER TABLE payments ADD COLUMN local_offer_id BLOB DEFAULT NULL REFERENCES offers(offer_id);" msgstr "" -#: wallet/db.c:684 +#: wallet/db.c:688 msgid "ALTER TABLE channels ADD funding_tx_remote_sigs_received INTEGER DEFAULT 0;" msgstr "" -#: wallet/db.c:687 +#: wallet/db.c:691 msgid "CREATE INDEX forwarded_payments_out_htlc_id ON forwarded_payments (out_htlc_id);" msgstr "" -#: wallet/db.c:689 +#: wallet/db.c:693 msgid "UPDATE channel_htlcs SET malformed_onion = 0 WHERE malformed_onion IS NULL" msgstr "" -#: wallet/db.c:691 +#: wallet/db.c:695 msgid "CREATE INDEX forwarded_payments_state ON forwarded_payments (state)" msgstr "" -#: wallet/db.c:692 +#: wallet/db.c:696 msgid "CREATE TABLE channel_funding_inflights ( channel_id BIGSERIAL REFERENCES channels(id) ON DELETE CASCADE, funding_tx_id BLOB, funding_tx_outnum INTEGER, funding_feerate INTEGER, funding_satoshi BIGINT, our_funding_satoshi BIGINT, funding_psbt BLOB, last_tx BLOB, last_sig BLOB, funding_tx_remote_sigs_received INTEGER, PRIMARY KEY (channel_id, funding_tx_id));" msgstr "" -#: wallet/db.c:706 +#: wallet/db.c:710 msgid "ALTER TABLE channels ADD revocation_basepoint_local BLOB" msgstr "" -#: wallet/db.c:707 +#: wallet/db.c:711 msgid "ALTER TABLE channels ADD payment_basepoint_local BLOB" msgstr "" -#: wallet/db.c:708 +#: wallet/db.c:712 msgid "ALTER TABLE channels ADD htlc_basepoint_local BLOB" msgstr "" -#: wallet/db.c:709 +#: wallet/db.c:713 msgid "ALTER TABLE channels ADD delayed_payment_basepoint_local BLOB" msgstr "" -#: wallet/db.c:710 +#: wallet/db.c:714 msgid "ALTER TABLE channels ADD funding_pubkey_local BLOB" msgstr "" -#: wallet/db.c:713 +#: wallet/db.c:717 msgid "ALTER TABLE channels ADD shutdown_wrong_txid BLOB DEFAULT NULL" msgstr "" -#: wallet/db.c:714 +#: wallet/db.c:718 msgid "ALTER TABLE channels ADD shutdown_wrong_outnum INTEGER DEFAULT NULL" msgstr "" -#: wallet/db.c:941 +#: wallet/db.c:946 msgid "UPDATE vars SET intval = intval + 1 WHERE name = 'data_version' AND intval = ?" msgstr "" -#: wallet/db.c:1041 +#: wallet/db.c:1046 msgid "SELECT version FROM version LIMIT 1" msgstr "" -#: wallet/db.c:1103 +#: wallet/db.c:1108 msgid "UPDATE version SET version=?;" msgstr "" -#: wallet/db.c:1111 +#: wallet/db.c:1116 msgid "INSERT INTO db_upgrades VALUES (?, ?);" msgstr "" -#: wallet/db.c:1123 +#: wallet/db.c:1128 msgid "SELECT intval FROM vars WHERE name = 'data_version'" msgstr "" -#: wallet/db.c:1150 +#: wallet/db.c:1155 msgid "SELECT intval FROM vars WHERE name= ? LIMIT 1" msgstr "" -#: wallet/db.c:1166 +#: wallet/db.c:1171 msgid "UPDATE vars SET intval=? WHERE name=?;" msgstr "" -#: wallet/db.c:1175 +#: wallet/db.c:1180 msgid "INSERT INTO vars (name, intval) VALUES (?, ?);" msgstr "" -#: wallet/db.c:1189 +#: wallet/db.c:1194 msgid "UPDATE channels SET feerate_base = ?, feerate_ppm = ?;" msgstr "" -#: wallet/db.c:1210 +#: wallet/db.c:1215 msgid "UPDATE channels SET our_funding_satoshi = funding_satoshi WHERE funder = 0;" msgstr "" -#: wallet/db.c:1226 +#: wallet/db.c:1231 msgid "SELECT type, keyindex, prev_out_tx, prev_out_index, channel_id, peer_id, commitment_point FROM outputs WHERE scriptpubkey IS NULL;" msgstr "" -#: wallet/db.c:1288 +#: wallet/db.c:1293 msgid "UPDATE outputs SET scriptpubkey = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/db.c:1313 +#: wallet/db.c:1318 msgid "SELECT id, funding_tx_id, funding_tx_outnum FROM channels;" msgstr "" -#: wallet/db.c:1332 +#: wallet/db.c:1337 msgid "UPDATE channels SET full_channel_id = ? WHERE id = ?;" msgstr "" -#: wallet/db.c:1353 +#: wallet/db.c:1358 msgid "SELECT channels.id, peers.node_id FROM channels JOIN peers ON (peers.id = channels.peer_id)" msgstr "" -#: wallet/db.c:1386 +#: wallet/db.c:1391 msgid "UPDATE channels SET revocation_basepoint_local = ?, payment_basepoint_local = ?, htlc_basepoint_local = ?, delayed_payment_basepoint_local = ?, funding_pubkey_local = ? WHERE id = ?;" msgstr "" #: wallet/db.c:1417 -msgid "SELECT c.id, p.node_id, c.last_tx, c.funding_satoshi, c.fundingkey_remote, c.last_sig FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id;" +msgid "SELECT c.id, p.node_id, c.fundingkey_remote, inflight.last_tx, inflight.last_sig, inflight.funding_satoshi, inflight.funding_tx_id FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id LEFT OUTER JOIN channel_funding_inflights inflight ON c.id = inflight.channel_id WHERE inflight.last_tx IS NOT NULL;" msgstr "" #: wallet/db.c:1484 +msgid "UPDATE channel_funding_inflights SET last_tx = ? WHERE channel_id = ? AND funding_tx_id = ?;" +msgstr "" + +#: wallet/db.c:1508 +msgid "SELECT c.id, p.node_id, c.last_tx, c.funding_satoshi, c.fundingkey_remote, c.last_sig FROM channels c LEFT OUTER JOIN peers p ON p.id = c.peer_id;" +msgstr "" + +#: wallet/db.c:1575 msgid "UPDATE channels SET last_tx = ? WHERE id = ?;" msgstr "" @@ -842,391 +850,395 @@ msgstr "" msgid "UPDATE channel_funding_inflights SET funding_psbt=?, funding_tx_remote_sigs_received=? WHERE channel_id=? AND funding_tx_id=? AND funding_tx_outnum=?" msgstr "" -#: wallet/wallet.c:1041 -msgid "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = ?" +#: wallet/wallet.c:1011 +msgid "DELETE FROM channel_funding_inflights WHERE channel_id = ?" +msgstr "" + +#: wallet/wallet.c:1059 +msgid "SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate" msgstr "" -#: wallet/wallet.c:1269 +#: wallet/wallet.c:1288 msgid "SELECT id FROM channels ORDER BY id DESC LIMIT 1;" msgstr "" -#: wallet/wallet.c:1286 +#: wallet/wallet.c:1305 msgid "SELECT id, peer_id, short_channel_id, full_channel_id, channel_config_local, channel_config_remote, state, funder, channel_flags, minimum_depth, next_index_local, next_index_remote, next_htlc_id, funding_tx_id, funding_tx_outnum, funding_satoshi, our_funding_satoshi, funding_locked_remote, push_msatoshi, msatoshi_local, fundingkey_remote, revocation_basepoint_remote, payment_basepoint_remote, htlc_basepoint_remote, delayed_payment_basepoint_remote, per_commit_remote, old_per_commit_remote, local_feerate_per_kw, remote_feerate_per_kw, shachain_remote_id, shutdown_scriptpubkey_remote, shutdown_keyidx_local, last_sent_commit_state, last_sent_commit_id, last_tx, last_sig, last_was_revoke, first_blocknum, min_possible_feerate, max_possible_feerate, msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point, last_sent_commit, feerate_base, feerate_ppm, remote_upfront_shutdown_script, option_static_remotekey, option_anchor_outputs, shutdown_scriptpubkey_local, closer, state_change_reason, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local, shutdown_wrong_txid, shutdown_wrong_outnum FROM channels WHERE state != ?;" msgstr "" -#: wallet/wallet.c:1384 +#: wallet/wallet.c:1403 msgid "UPDATE channels SET in_payments_offered = COALESCE(in_payments_offered, 0) + 1 , in_msatoshi_offered = COALESCE(in_msatoshi_offered, 0) + ? WHERE id = ?;" msgstr "" -#: wallet/wallet.c:1389 +#: wallet/wallet.c:1408 msgid "UPDATE channels SET in_payments_fulfilled = COALESCE(in_payments_fulfilled, 0) + 1 , in_msatoshi_fulfilled = COALESCE(in_msatoshi_fulfilled, 0) + ? WHERE id = ?;" msgstr "" -#: wallet/wallet.c:1394 +#: wallet/wallet.c:1413 msgid "UPDATE channels SET out_payments_offered = COALESCE(out_payments_offered, 0) + 1 , out_msatoshi_offered = COALESCE(out_msatoshi_offered, 0) + ? WHERE id = ?;" msgstr "" -#: wallet/wallet.c:1399 +#: wallet/wallet.c:1418 msgid "UPDATE channels SET out_payments_fulfilled = COALESCE(out_payments_fulfilled, 0) + 1 , out_msatoshi_fulfilled = COALESCE(out_msatoshi_fulfilled, 0) + ? WHERE id = ?;" msgstr "" -#: wallet/wallet.c:1441 +#: wallet/wallet.c:1460 msgid "SELECT in_payments_offered, in_payments_fulfilled, in_msatoshi_offered, in_msatoshi_fulfilled, out_payments_offered, out_payments_fulfilled, out_msatoshi_offered, out_msatoshi_fulfilled FROM channels WHERE id = ?" msgstr "" -#: wallet/wallet.c:1470 +#: wallet/wallet.c:1489 msgid "SELECT MIN(height), MAX(height) FROM blocks;" msgstr "" -#: wallet/wallet.c:1492 +#: wallet/wallet.c:1511 msgid "INSERT INTO channel_configs DEFAULT VALUES;" msgstr "" -#: wallet/wallet.c:1504 +#: wallet/wallet.c:1523 msgid "UPDATE channel_configs SET dust_limit_satoshis=?, max_htlc_value_in_flight_msat=?, channel_reserve_satoshis=?, htlc_minimum_msat=?, to_self_delay=?, max_accepted_htlcs=? WHERE id=?;" msgstr "" -#: wallet/wallet.c:1528 +#: wallet/wallet.c:1547 msgid "SELECT id, dust_limit_satoshis, max_htlc_value_in_flight_msat, channel_reserve_satoshis, htlc_minimum_msat, to_self_delay, max_accepted_htlcs FROM channel_configs WHERE id= ? ;" msgstr "" -#: wallet/wallet.c:1562 +#: wallet/wallet.c:1581 msgid "UPDATE channels SET remote_ann_node_sig=?, remote_ann_bitcoin_sig=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1581 +#: wallet/wallet.c:1600 msgid "UPDATE channels SET shachain_remote_id=?, short_channel_id=?, full_channel_id=?, state=?, funder=?, channel_flags=?, minimum_depth=?, next_index_local=?, next_index_remote=?, next_htlc_id=?, funding_tx_id=?, funding_tx_outnum=?, funding_satoshi=?, our_funding_satoshi=?, funding_locked_remote=?, push_msatoshi=?, msatoshi_local=?, shutdown_scriptpubkey_remote=?, shutdown_keyidx_local=?, channel_config_local=?, last_tx=?, last_sig=?, last_was_revoke=?, min_possible_feerate=?, max_possible_feerate=?, msatoshi_to_us_min=?, msatoshi_to_us_max=?, feerate_base=?, feerate_ppm=?, remote_upfront_shutdown_script=?, option_static_remotekey=?, option_anchor_outputs=?, shutdown_scriptpubkey_local=?, closer=?, state_change_reason=?, shutdown_wrong_txid=?, shutdown_wrong_outnum=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1673 +#: wallet/wallet.c:1692 msgid "UPDATE channels SET fundingkey_remote=?, revocation_basepoint_remote=?, payment_basepoint_remote=?, htlc_basepoint_remote=?, delayed_payment_basepoint_remote=?, per_commit_remote=?, old_per_commit_remote=?, channel_config_remote=?, future_per_commitment_point=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1700 +#: wallet/wallet.c:1719 msgid "DELETE FROM channel_feerates WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1710 +#: wallet/wallet.c:1729 msgid "INSERT INTO channel_feerates VALUES(?, ?, ?)" msgstr "" -#: wallet/wallet.c:1727 +#: wallet/wallet.c:1746 msgid "UPDATE channels SET last_sent_commit=? WHERE id=?" msgstr "" -#: wallet/wallet.c:1750 +#: wallet/wallet.c:1769 msgid "INSERT INTO channel_state_changes ( channel_id, timestamp, old_state, new_state, cause, message) VALUES (?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:1778 +#: wallet/wallet.c:1797 msgid "SELECT timestamp, old_state, new_state, cause, message FROM channel_state_changes WHERE channel_id = ? ORDER BY timestamp ASC;" msgstr "" -#: wallet/wallet.c:1807 +#: wallet/wallet.c:1826 msgid "SELECT id FROM peers WHERE node_id = ?" msgstr "" -#: wallet/wallet.c:1819 +#: wallet/wallet.c:1838 msgid "UPDATE peers SET address = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:1828 +#: wallet/wallet.c:1847 msgid "INSERT INTO peers (node_id, address) VALUES (?, ?);" msgstr "" -#: wallet/wallet.c:1849 +#: wallet/wallet.c:1868 msgid "INSERT INTO channels ( peer_id, first_blocknum, id, revocation_basepoint_local, payment_basepoint_local, htlc_basepoint_local, delayed_payment_basepoint_local, funding_pubkey_local) VALUES (?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:1890 +#: wallet/wallet.c:1909 msgid "DELETE FROM channel_htlcs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1896 +#: wallet/wallet.c:1915 msgid "DELETE FROM htlc_sigs WHERE channelid=?" msgstr "" -#: wallet/wallet.c:1902 +#: wallet/wallet.c:1921 msgid "DELETE FROM channeltxs WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1909 +#: wallet/wallet.c:1928 msgid "DELETE FROM channel_funding_inflights WHERE channel_id=?" msgstr "" -#: wallet/wallet.c:1915 +#: wallet/wallet.c:1934 msgid "DELETE FROM shachains WHERE id IN ( SELECT shachain_remote_id FROM channels WHERE channels.id=?)" msgstr "" -#: wallet/wallet.c:1925 +#: wallet/wallet.c:1944 msgid "UPDATE channels SET state=?, peer_id=? WHERE channels.id=?" msgstr "" -#: wallet/wallet.c:1939 +#: wallet/wallet.c:1958 msgid "SELECT * FROM channels WHERE peer_id = ?;" msgstr "" -#: wallet/wallet.c:1947 +#: wallet/wallet.c:1966 msgid "DELETE FROM peers WHERE id=?" msgstr "" -#: wallet/wallet.c:1958 +#: wallet/wallet.c:1977 msgid "UPDATE outputs SET confirmation_height = ? WHERE prev_out_tx = ?" msgstr "" -#: wallet/wallet.c:2061 +#: wallet/wallet.c:2080 msgid "INSERT INTO channel_htlcs ( channel_id, channel_htlc_id, direction, msatoshi, cltv_expiry, payment_hash, payment_key, hstate, shared_secret, routing_onion, received_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:2114 +#: wallet/wallet.c:2133 msgid "INSERT INTO channel_htlcs ( channel_id, channel_htlc_id, direction, origin_htlc, msatoshi, cltv_expiry, payment_hash, payment_key, hstate, routing_onion, malformed_onion, partid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?);" msgstr "" -#: wallet/wallet.c:2175 +#: wallet/wallet.c:2194 msgid "UPDATE channel_htlcs SET hstate=?, payment_key=?, malformed_onion=?, failuremsg=?, localfailmsg=?, we_filled=? WHERE id=?" msgstr "" -#: wallet/wallet.c:2391 +#: wallet/wallet.c:2410 msgid "SELECT id, channel_htlc_id, msatoshi, cltv_expiry, hstate, payment_hash, payment_key, routing_onion, failuremsg, malformed_onion, origin_htlc, shared_secret, received_time, we_filled FROM channel_htlcs WHERE direction= ? AND channel_id= ? AND hstate != ?" msgstr "" -#: wallet/wallet.c:2438 +#: wallet/wallet.c:2457 msgid "SELECT id, channel_htlc_id, msatoshi, cltv_expiry, hstate, payment_hash, payment_key, routing_onion, failuremsg, malformed_onion, origin_htlc, shared_secret, received_time, partid, localfailmsg FROM channel_htlcs WHERE direction = ? AND channel_id = ? AND hstate != ?" msgstr "" -#: wallet/wallet.c:2569 +#: wallet/wallet.c:2588 msgid "SELECT channel_id, direction, cltv_expiry, channel_htlc_id, payment_hash FROM channel_htlcs WHERE channel_id = ?;" msgstr "" -#: wallet/wallet.c:2603 +#: wallet/wallet.c:2622 msgid "DELETE FROM channel_htlcs WHERE direction = ? AND origin_htlc = ? AND payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2656 +#: wallet/wallet.c:2675 msgid "SELECT status FROM payments WHERE payment_hash=? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2674 +#: wallet/wallet.c:2693 msgid "INSERT INTO payments ( status, payment_hash, destination, msatoshi, timestamp, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, total_msat, partid, local_offer_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:2763 +#: wallet/wallet.c:2782 msgid "DELETE FROM payments WHERE payment_hash = ? AND partid = ?" msgstr "" -#: wallet/wallet.c:2777 +#: wallet/wallet.c:2796 msgid "DELETE FROM payments WHERE payment_hash = ?" msgstr "" -#: wallet/wallet.c:2878 +#: wallet/wallet.c:2897 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid, local_offer_id FROM payments WHERE payment_hash = ? AND partid = ?" msgstr "" -#: wallet/wallet.c:2928 +#: wallet/wallet.c:2947 msgid "UPDATE payments SET status=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:2938 +#: wallet/wallet.c:2957 msgid "UPDATE payments SET payment_preimage=? WHERE payment_hash=? AND partid=?" msgstr "" -#: wallet/wallet.c:2948 +#: wallet/wallet.c:2967 msgid "UPDATE payments SET path_secrets = NULL , route_nodes = NULL , route_channels = NULL WHERE payment_hash = ? AND partid = ?;" msgstr "" -#: wallet/wallet.c:2980 +#: wallet/wallet.c:2999 msgid "SELECT failonionreply, faildestperm, failindex, failcode, failnode, failchannel, failupdate, faildetail, faildirection FROM payments WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3047 +#: wallet/wallet.c:3066 msgid "UPDATE payments SET failonionreply=? , faildestperm=? , failindex=? , failcode=? , failnode=? , failchannel=? , failupdate=? , faildetail=? , faildirection=? WHERE payment_hash=? AND partid=?;" msgstr "" -#: wallet/wallet.c:3106 +#: wallet/wallet.c:3125 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid, local_offer_id FROM payments WHERE payment_hash = ?;" msgstr "" -#: wallet/wallet.c:3128 +#: wallet/wallet.c:3147 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid, local_offer_id FROM payments ORDER BY id;" msgstr "" -#: wallet/wallet.c:3179 +#: wallet/wallet.c:3198 msgid "SELECT id, status, destination, msatoshi, payment_hash, timestamp, payment_preimage, path_secrets, route_nodes, route_channels, msatoshi_sent, description, bolt11, failonionreply, total_msat, partid, local_offer_id FROM payments WHERE local_offer_id = ?;" msgstr "" -#: wallet/wallet.c:3224 +#: wallet/wallet.c:3243 msgid "DELETE FROM htlc_sigs WHERE channelid = ?" msgstr "" -#: wallet/wallet.c:3231 +#: wallet/wallet.c:3250 msgid "INSERT INTO htlc_sigs (channelid, signature) VALUES (?, ?)" msgstr "" -#: wallet/wallet.c:3243 +#: wallet/wallet.c:3262 msgid "SELECT blobval FROM vars WHERE name='genesis_hash'" msgstr "" -#: wallet/wallet.c:3267 +#: wallet/wallet.c:3286 msgid "INSERT INTO vars (name, blobval) VALUES ('genesis_hash', ?);" msgstr "" -#: wallet/wallet.c:3285 +#: wallet/wallet.c:3304 msgid "SELECT txid, outnum FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3297 +#: wallet/wallet.c:3316 msgid "DELETE FROM utxoset WHERE spendheight < ?" msgstr "" -#: wallet/wallet.c:3305 wallet/wallet.c:3419 +#: wallet/wallet.c:3324 wallet/wallet.c:3438 msgid "INSERT INTO blocks (height, hash, prev_hash) VALUES (?, ?, ?);" msgstr "" -#: wallet/wallet.c:3324 +#: wallet/wallet.c:3343 msgid "DELETE FROM blocks WHERE hash = ?" msgstr "" -#: wallet/wallet.c:3330 +#: wallet/wallet.c:3349 msgid "SELECT * FROM blocks WHERE height >= ?;" msgstr "" -#: wallet/wallet.c:3339 +#: wallet/wallet.c:3358 msgid "DELETE FROM blocks WHERE height > ?" msgstr "" -#: wallet/wallet.c:3351 +#: wallet/wallet.c:3370 msgid "UPDATE outputs SET spend_height = ?, status = ? WHERE prev_out_tx = ? AND prev_out_index = ?" msgstr "" -#: wallet/wallet.c:3369 +#: wallet/wallet.c:3388 msgid "UPDATE utxoset SET spendheight = ? WHERE txid = ? AND outnum = ?" msgstr "" -#: wallet/wallet.c:3392 wallet/wallet.c:3430 +#: wallet/wallet.c:3411 wallet/wallet.c:3449 msgid "INSERT INTO utxoset ( txid, outnum, blockheight, spendheight, txindex, scriptpubkey, satoshis) VALUES(?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3456 +#: wallet/wallet.c:3475 msgid "SELECT height FROM blocks WHERE height = ?" msgstr "" -#: wallet/wallet.c:3469 +#: wallet/wallet.c:3488 msgid "SELECT txid, spendheight, scriptpubkey, satoshis FROM utxoset WHERE blockheight = ? AND txindex = ? AND outnum = ? AND spendheight IS NULL" msgstr "" -#: wallet/wallet.c:3511 +#: wallet/wallet.c:3530 msgid "SELECT blockheight, txindex, outnum FROM utxoset WHERE spendheight = ?" msgstr "" -#: wallet/wallet.c:3542 wallet/wallet.c:3702 +#: wallet/wallet.c:3561 wallet/wallet.c:3721 msgid "SELECT blockheight FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3552 +#: wallet/wallet.c:3571 msgid "INSERT INTO transactions ( id, blockheight, txindex, rawtx) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3573 +#: wallet/wallet.c:3592 msgid "UPDATE transactions SET blockheight = ?, txindex = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3590 +#: wallet/wallet.c:3609 msgid "INSERT INTO transaction_annotations (txid, idx, location, type, channel) VALUES (?, ?, ?, ?, ?) ON CONFLICT(txid,idx) DO NOTHING;" msgstr "" -#: wallet/wallet.c:3622 +#: wallet/wallet.c:3641 msgid "SELECT type, channel_id FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3638 +#: wallet/wallet.c:3657 msgid "UPDATE transactions SET type = ?, channel_id = ? WHERE id = ?" msgstr "" -#: wallet/wallet.c:3657 +#: wallet/wallet.c:3676 msgid "SELECT type FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3680 +#: wallet/wallet.c:3699 msgid "SELECT rawtx FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3726 +#: wallet/wallet.c:3745 msgid "SELECT blockheight, txindex FROM transactions WHERE id=?" msgstr "" -#: wallet/wallet.c:3754 +#: wallet/wallet.c:3773 msgid "SELECT id FROM transactions WHERE blockheight=?" msgstr "" -#: wallet/wallet.c:3773 +#: wallet/wallet.c:3792 msgid "INSERT INTO channeltxs ( channel_id, type, transaction_id, input_num, blockheight) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3797 +#: wallet/wallet.c:3816 msgid "SELECT DISTINCT(channel_id) FROM channeltxs WHERE type = ?;" msgstr "" -#: wallet/wallet.c:3818 +#: wallet/wallet.c:3837 msgid "SELECT c.type, c.blockheight, t.rawtx, c.input_num, c.blockheight - t.blockheight + 1 AS depth, t.id as txid FROM channeltxs c JOIN transactions t ON t.id = c.transaction_id WHERE c.channel_id = ? ORDER BY c.id ASC;" msgstr "" -#: wallet/wallet.c:3863 +#: wallet/wallet.c:3882 msgid "UPDATE forwarded_payments SET in_msatoshi=?, out_msatoshi=?, state=?, resolved_time=?, failcode=? WHERE in_htlc_id=?" msgstr "" -#: wallet/wallet.c:3921 +#: wallet/wallet.c:3940 msgid "INSERT INTO forwarded_payments ( in_htlc_id, out_htlc_id, in_channel_scid, out_channel_scid, in_msatoshi, out_msatoshi, state, received_time, resolved_time, failcode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:3980 +#: wallet/wallet.c:3999 msgid "SELECT CAST(COALESCE(SUM(in_msatoshi - out_msatoshi), 0) AS BIGINT)FROM forwarded_payments WHERE state = ?;" msgstr "" -#: wallet/wallet.c:4029 +#: wallet/wallet.c:4048 msgid "SELECT f.state, in_msatoshi, out_msatoshi, hin.payment_hash as payment_hash, in_channel_scid, out_channel_scid, f.received_time, f.resolved_time, f.failcode FROM forwarded_payments f LEFT JOIN channel_htlcs hin ON (f.in_htlc_id = hin.id) WHERE (1 = ? OR f.state = ?) AND (1 = ? OR f.in_channel_scid = ?) AND (1 = ? OR f.out_channel_scid = ?)" msgstr "" -#: wallet/wallet.c:4151 +#: wallet/wallet.c:4170 msgid "SELECT t.id, t.rawtx, t.blockheight, t.txindex, t.type as txtype, c2.short_channel_id as txchan, a.location, a.idx as ann_idx, a.type as annotation_type, c.short_channel_id FROM transactions t LEFT JOIN transaction_annotations a ON (a.txid = t.id) LEFT JOIN channels c ON (a.channel = c.id) LEFT JOIN channels c2 ON (t.channel_id = c2.id) ORDER BY t.blockheight, t.txindex ASC" msgstr "" -#: wallet/wallet.c:4245 +#: wallet/wallet.c:4264 msgid "INSERT INTO penalty_bases ( channel_id, commitnum, txid, outnum, amount) VALUES (?, ?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4270 +#: wallet/wallet.c:4289 msgid "SELECT commitnum, txid, outnum, amount FROM penalty_bases WHERE channel_id = ?" msgstr "" -#: wallet/wallet.c:4294 +#: wallet/wallet.c:4313 msgid "DELETE FROM penalty_bases WHERE channel_id = ? AND commitnum = ?" msgstr "" -#: wallet/wallet.c:4312 +#: wallet/wallet.c:4331 msgid "SELECT 1 FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4325 +#: wallet/wallet.c:4344 msgid "INSERT INTO offers ( offer_id, bolt12, label, status) VALUES (?, ?, ?, ?);" msgstr "" -#: wallet/wallet.c:4352 +#: wallet/wallet.c:4371 msgid "SELECT bolt12, label, status FROM offers WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4380 +#: wallet/wallet.c:4399 msgid "SELECT offer_id FROM offers;" msgstr "" -#: wallet/wallet.c:4406 +#: wallet/wallet.c:4425 msgid "UPDATE offers SET status=? WHERE offer_id = ?;" msgstr "" -#: wallet/wallet.c:4417 +#: wallet/wallet.c:4436 msgid "UPDATE invoices SET state=? WHERE state=? AND local_offer_id = ?;" msgstr "" -#: wallet/wallet.c:4445 +#: wallet/wallet.c:4464 msgid "SELECT status FROM offers WHERE offer_id = ?;" msgstr "" @@ -1238,11 +1250,11 @@ msgstr "" msgid "not a valid SQL statement" msgstr "" -#: wallet/test/run-wallet.c:1444 +#: wallet/test/run-wallet.c:1449 msgid "SELECT COUNT(1) FROM channel_funding_inflights WHERE channel_id = ?;" msgstr "" -#: wallet/test/run-wallet.c:1642 +#: wallet/test/run-wallet.c:1647 msgid "INSERT INTO channels (id) VALUES (1);" msgstr "" -# SHA256STAMP:6f39707798a473b25ddf2706f514421533231682d47b0141df500193e9c27fd2 +# SHA256STAMP:78ef666d4e867ffdef1d84235050b0a6dc2c6f0c16a3b2703cd70c80e266f543 diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 955d84175067..56254e02aca9 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -69,6 +69,11 @@ bool channel_tell_depth(struct lightningd *ld UNNEEDED, /* Generated stub for channel_unsaved_close_conn */ void channel_unsaved_close_conn(struct channel *channel UNNEEDED, const char *why UNNEEDED) { fprintf(stderr, "channel_unsaved_close_conn called!\n"); abort(); } +/* Generated stub for channel_update_reserve */ +void channel_update_reserve(struct channel *channel UNNEEDED, + struct channel_config *their_config UNNEEDED, + struct amount_sat funding_total UNNEEDED) +{ fprintf(stderr, "channel_update_reserve called!\n"); abort(); } /* Generated stub for command_fail */ struct command_result *command_fail(struct command *cmd UNNEEDED, errcode_t code UNNEEDED, const char *fmt UNNEEDED, ...) diff --git a/wallet/wallet.c b/wallet/wallet.c index 3818dfa11b5f..eca255c79fe9 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -969,7 +969,7 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight) db_bind_amount_sat(stmt, 4, &inflight->funding->total_funds); db_bind_amount_sat(stmt, 5, &inflight->funding->our_funds); db_bind_psbt(stmt, 6, inflight->funding_psbt); - db_bind_tx(stmt, 7, inflight->last_tx->wtx); + db_bind_psbt(stmt, 7, inflight->last_tx->psbt); db_bind_signature(stmt, 8, &inflight->last_sig.s); db_exec_prepared_v2(stmt); assert(!stmt->error); @@ -1001,6 +1001,24 @@ void wallet_inflight_save(struct wallet *w, db_exec_prepared_v2(take(stmt)); } +void wallet_channel_clear_inflights(struct wallet *w, + struct channel *chan) +{ + struct db_stmt *stmt; + struct channel_inflight *inflight; + + /* Remove all the inflights for the channel */ + stmt = db_prepare_v2(w->db, SQL("DELETE FROM channel_funding_inflights" + " WHERE channel_id = ?")); + db_bind_u64(stmt, 0, chan->dbid); + db_exec_prepared_v2(take(stmt)); + + /* Empty out the list too */ + while ((inflight = list_tail(&chan->inflights, + struct channel_inflight, list))) + tal_free(inflight); +} + static struct channel_inflight * wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, struct channel *chan) @@ -1024,7 +1042,7 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, funding_sat, our_funding_sat, db_column_psbt(tmpctx, stmt, 5), - db_column_tx(tmpctx, stmt, 6), + db_column_psbt_to_tx(tmpctx, stmt, 6), last_sig); /* Pull out the serialized tx-sigs-received-ness */ @@ -1049,7 +1067,8 @@ static bool wallet_channel_load_inflights(struct wallet *w, ", last_sig" // 7 ", funding_tx_remote_sigs_received" //8 " FROM channel_funding_inflights" - " WHERE channel_id = ?")); // ?0 + " WHERE channel_id = ?" // ?0 + " ORDER BY funding_feerate")); db_bind_u64(stmt, 0, chan->dbid); db_query_prepared(stmt); diff --git a/wallet/wallet.h b/wallet/wallet.h index 8a7e28ff47fc..b6b67f521bb2 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -520,6 +520,12 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight); void wallet_inflight_save(struct wallet *w, struct channel_inflight *inflight); +/** + * Remove all the inflights from a channel. Also cleans up + * the channel's inflight list + */ +void wallet_channel_clear_inflights(struct wallet *w, + struct channel *chan); /** * After fully resolving a channel, only keep a lightweight stub */