diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 8e9b6687b..f767f5720 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -721,236 +721,6 @@ static struct bitcoin_tx *tx_to_us(const tal_t *ctx, return tx; } -/** replace_penalty_tx_to_us - * - * @brief creates a replacement TX for - * a given penalty tx. - * - * @param ctx - the context to allocate - * off of. - * @param hsm_sign_msg - function to construct - * the signing message to HSM. - * @param penalty_tx - the original - * penalty transaction. - * @param output_amount - the output - * amount to use instead of the - * original penalty transaction. - * If this amount is below the dust - * limit, the output is replaced with - * an `OP_RETURN` instead. - * - * @return the signed transaction. - */ -static struct bitcoin_tx * -replace_penalty_tx_to_us(const tal_t *ctx, - u8 *(*hsm_sign_msg)(const tal_t *ctx, - struct bitcoin_tx *tx, - const u8 *wscript), - const struct bitcoin_tx *penalty_tx, - struct amount_sat *output_amount) -{ - struct bitcoin_tx *tx; - - /* The penalty tx input. */ - const struct wally_tx_input *input; - /* Specs of the penalty tx input. */ - struct bitcoin_outpoint input_outpoint; - u8 *input_wscript; - u8 *input_element; - struct amount_sat input_amount; - - /* Signature from the HSM. */ - u8 *msg; - struct bitcoin_signature sig; - /* Witness we generate from the signature and other data. */ - u8 **witness; - - - /* Get the single input of the penalty tx. */ - input = &penalty_tx->wtx->inputs[0]; - /* Extract the input-side data. */ - bitcoin_tx_input_get_txid(penalty_tx, 0, &input_outpoint.txid); - input_outpoint.n = input->index; - input_wscript = tal_dup_arr(tmpctx, u8, - input->witness->items[2].witness, - input->witness->items[2].witness_len, - 0); - input_element = tal_dup_arr(tmpctx, u8, - input->witness->items[1].witness, - input->witness->items[1].witness_len, - 0); - input_amount = psbt_input_get_amount(penalty_tx->psbt, 0); - - /* Create the replacement. */ - tx = bitcoin_tx(ctx, chainparams, 1, 1, /*locktime*/ 0); - /* Reconstruct the input. */ - bitcoin_tx_add_input(tx, &input_outpoint, - BITCOIN_TX_RBF_SEQUENCE, - NULL, input_amount, NULL, input_wscript); - /* Reconstruct the output with a smaller amount. */ - if (amount_sat_greater(*output_amount, dust_limit)) { - bitcoin_tx_add_output(tx, - scriptpubkey_p2wpkh(tx, - &our_wallet_pubkey), - NULL, - *output_amount); - psbt_add_keypath_to_last_output(tx, our_wallet_index, &our_wallet_ext_key); - } else { - bitcoin_tx_add_output(tx, - scriptpubkey_opreturn_padded(tx), - NULL, - AMOUNT_SAT(0)); - *output_amount = AMOUNT_SAT(0); - } - - /* Finalize the transaction. */ - bitcoin_tx_finalize(tx); - - /* Ask HSM to sign it. */ - if (!wire_sync_write(HSM_FD, take(hsm_sign_msg(NULL, tx, - input_wscript)))) - status_failed(STATUS_FAIL_HSM_IO, "While feebumping penalty: writing sign request to hsm"); - msg = wire_sync_read(tmpctx, HSM_FD); - if (!msg || !fromwire_hsmd_sign_tx_reply(msg, &sig)) - status_failed(STATUS_FAIL_HSM_IO, "While feebumping penalty: reading sign_tx_reply: %s", tal_hex(tmpctx, msg)); - - /* Install the witness with the signature. */ - witness = bitcoin_witness_sig_and_element(tx, &sig, - input_element, - tal_bytelen(input_element), - input_wscript); - bitcoin_tx_input_set_witness(tx, 0, take(witness)); - - return tx; -} - -/** min_rbf_bump - * - * @brief computes the minimum RBF bump required by - * BIP125, given an index. - * - * @desc BIP125 requires that an replacement transaction - * pay, not just the fee of the evicted transactions, - * but also the minimum relay fee for itself. - * This function assumes that previous RBF attempts - * paid exactly the return value for that attempt, on - * top of the initial transaction fee. - * It can serve as a baseline for other functions that - * compute a suggested fee: get whichever is higher, - * the fee this function suggests, or your own unique - * function. - * - * This function is provided as a common function that - * all RBF-bump computations can use. - * - * @param weight - the weight of the transaction you - * are RBFing. - * @param index - 0 makes no sense, 1 means this is - * the first RBF attempt, 2 means this is the 2nd - * RBF attempt, etc. - * - * @return the suggested total fee. - */ -static struct amount_sat min_rbf_bump(size_t weight, - size_t index) -{ - struct amount_sat min_relay_fee; - struct amount_sat min_rbf_bump; - - /* Compute the minimum relay fee for a transaction of the given - * weight. */ - min_relay_fee = amount_tx_fee(min_relay_feerate, weight); - - /* For every RBF attempt, we add the min-relay-fee. - * Or in other words, we multiply the min-relay-fee by the - * index number of the attempt. - */ - if (mul_overflows_u64(index, min_relay_fee.satoshis)) /* Raw: multiplication. */ - min_rbf_bump = AMOUNT_SAT(UINT64_MAX); - else - min_rbf_bump.satoshis = index * min_relay_fee.satoshis; /* Raw: multiplication. */ - - return min_rbf_bump; -} - -/** compute_penalty_output_amount - * - * @brief computes the appropriate output amount for a - * penalty transaction that spends a theft transaction - * that is already of a specific depth. - * - * @param initial_amount - the outout amount of the first - * penalty transaction. - * @param depth - the current depth of the theft - * transaction. - * @param max_depth - the maximum depth of the theft - * transaction, after which the theft transaction will - * succeed. - * @param weight - the weight of the first penalty - * transaction, in Sipa. - */ -static struct amount_sat -compute_penalty_output_amount(struct amount_sat initial_amount, - u32 depth, u32 max_depth, - size_t weight) -{ - struct amount_sat max_output_amount; - struct amount_sat output_amount; - struct amount_sat deducted_amount; - struct amount_sat min_output_amount, max_fee; - - assert(depth <= max_depth); - assert(depth > 0); - - /* We never pay more than max_penalty_feerate; at some point, - * it's clearly not working. */ - max_fee = amount_tx_fee(max_penalty_feerate, weight); - if (!amount_sat_sub(&min_output_amount, initial_amount, max_fee)) - /* We may just donate the whole output as fee, meaning - * we get zero amount. */ - min_output_amount = AMOUNT_SAT(0); - - /* The difference between initial_amount, and the fee suggested - * by min_rbf_bump, is the largest allowed output amount. - * - * depth = 1 is the first attempt, thus maps to the 0th RBF - * (i.e. the initial attempt that is not RBFed itself). - * We actually start to replace at depth = 2, so we use - * depth - 1 as the index for min_rbf_bump. - */ - if (!amount_sat_sub(&max_output_amount, - initial_amount, min_rbf_bump(weight, depth - 1))) - return min_output_amount; - - /* Map the depth / max_depth into a number between 0->1. */ - double x = (double) depth / (double) max_depth; - /* Get the cube of the above position, resulting in a graph - * where the y is close to 0 up to less than halfway through, - * then quickly rises up to 1 as depth nears the max depth. - */ - double y = x * x * x; - /* Scale according to the initial_amount. */ - deducted_amount.satoshis = (u64) (y * initial_amount.satoshis); /* Raw: multiplication. */ - - /* output_amount = initial_amount - deducted_amount. */ - if (!amount_sat_sub(&output_amount, - initial_amount, deducted_amount)) { - /* If underflow, force to min. */ - output_amount = min_output_amount; - } - - /* If output below min, return min. */ - if (amount_sat_less(output_amount, min_output_amount)) - return min_output_amount; - - /* If output exceeds max, return max. */ - if (amount_sat_less(max_output_amount, output_amount)) - return max_output_amount; - - return output_amount; -} - - static void hsm_sign_local_htlc_tx(struct bitcoin_tx *tx, const u8 *wscript, struct bitcoin_signature *sig) @@ -1037,106 +807,6 @@ static void ignore_output(struct tracked_output *out) out->resolved->tx_type = SELF; } -/** proposal_is_rbfable - * - * @brief returns true if the given proposal - * would be RBFed if the output it is tracking - * increases in depth without being spent. - */ -static bool proposal_is_rbfable(const struct proposed_resolution *proposal) -{ - /* Future onchain resolutions, such as anchored commitments, might - * want to RBF as well. - */ - return proposal->tx_type == OUR_PENALTY_TX; -} - -/** proposal_should_rbf - * - * @brief the given output just increased its depth, - * so the proposal for it should be RBFed and - * rebroadcast. - * - * @desc precondition: the given output must have an - * rbfable proposal as per `proposal_is_rbfable`. - */ -static void proposal_should_rbf(struct tracked_output *out) -{ - struct bitcoin_tx *tx = NULL; - u32 depth; - - assert(out->proposal); - assert(proposal_is_rbfable(out->proposal)); - - depth = out->depth; - - /* Do not RBF at depth 1. - * - * Since we react to *onchain* events, whatever proposal we made, - * the output for that proposal is already at depth 1. - * - * Since our initial proposal was broadcasted with the output at - * depth 1, we should not RBF until a new block arrives, which is - * at depth 2. - */ - if (depth <= 1) - return; - - if (out->proposal->tx_type == OUR_PENALTY_TX) { - u32 max_depth = to_self_delay[REMOTE]; - u32 my_depth = depth; - size_t weight = bitcoin_tx_weight(out->proposal->tx); - struct amount_sat initial_amount; - struct amount_sat new_amount; - - if (max_depth >= 1) - max_depth -= 1; - if (my_depth >= max_depth) - my_depth = max_depth; - - bitcoin_tx_output_get_amount_sat(out->proposal->tx, 0, - &initial_amount); - - /* Compute the new output amount for the RBF. */ - new_amount = compute_penalty_output_amount(initial_amount, - my_depth, max_depth, - weight); - assert(amount_sat_less_eq(new_amount, initial_amount)); - /* Recreate the penalty tx. */ - tx = replace_penalty_tx_to_us(tmpctx, - &penalty_to_us, - out->proposal->tx, &new_amount); - - /* We also update the output's value, so our accounting - * is correct. */ - out->sat = new_amount; - - status_debug("Created RBF OUR_PENALTY_TX with output %s " - "(originally %s) for depth %"PRIu32"/%"PRIu32".", - type_to_string(tmpctx, struct amount_sat, - &new_amount), - type_to_string(tmpctx, struct amount_sat, - &initial_amount), - depth, to_self_delay[LOCAL]); - } - /* Add other RBF-able proposals here. */ - - /* Broadcast the transaction. */ - if (tx) { - status_debug("Broadcasting RBF %s (%s) to resolve %s/%s " - "depth=%"PRIu32"", - tx_type_name(out->proposal->tx_type), - type_to_string(tmpctx, struct bitcoin_tx, tx), - tx_type_name(out->tx_type), - output_type_name(out->output_type), - depth); - - wire_sync_write(REQ_FD, - take(towire_onchaind_broadcast_tx(NULL, tx, - true))); - } -} - static void handle_spend_created(struct tracked_output *out, const u8 *msg) { struct onchain_witness_element **witness; @@ -1158,10 +828,6 @@ static void handle_spend_created(struct tracked_output *out, const u8 *msg) static void proposal_meets_depth(struct tracked_output *out) { assert(out->proposal); - - /* Our own penalty transactions are going to be RBFed. */ - bool is_rbf = proposal_is_rbfable(out->proposal); - /* If we simply wanted to ignore it after some depth */ if (!out->proposal->tx) { ignore_output(out); @@ -1182,7 +848,7 @@ static void proposal_meets_depth(struct tracked_output *out) wire_sync_write( REQ_FD, take(towire_onchaind_broadcast_tx( - NULL, out->proposal->tx, is_rbf))); + NULL, out->proposal->tx, false))); /* Don't wait for this if we're ignoring the tiny payment. */ if (out->proposal->tx_type == IGNORING_TINY_PAYMENT) { @@ -2040,13 +1706,6 @@ static void tx_new_depth(struct tracked_output **outs, && depth >= outs[i]->proposal->depth_required) { proposal_meets_depth(outs[i]); } - - /* Otherwise, is this an output whose proposed resolution - * we should RBF? */ - if (outs[i]->proposal - && bitcoin_txid_eq(&outs[i]->outpoint.txid, txid) - && proposal_is_rbfable(outs[i]->proposal)) - proposal_should_rbf(outs[i]); } } diff --git a/tests/test_closing.py b/tests/test_closing.py index 4a34f5b80..259ff7987 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -1589,6 +1589,7 @@ def test_penalty_htlc_tx_timeout(node_factory, bitcoind, chainparams): assert acc['resolved_at_block'] > 0 +@pytest.mark.xfail(strict=True) @pytest.mark.developer("uses dev_sign_last_tx") def test_penalty_rbf_normal(node_factory, bitcoind, executor, chainparams): ''' @@ -1713,6 +1714,7 @@ def test_penalty_rbf_normal(node_factory, bitcoind, executor, chainparams): check_utxos_channel(l2, [channel_id], expected_2) +@pytest.mark.xfail(strict=True) @pytest.mark.developer("uses dev_sign_last_tx") def test_penalty_rbf_burn(node_factory, bitcoind, executor, chainparams): '''