onchaind, pytest: disable RBF logic.

We'll reimplement it once lightningd makes all the onchain txs.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2023-04-06 09:03:24 +09:30
parent 80cd6f0afe
commit 36dd70e677
2 changed files with 3 additions and 342 deletions

View File

@@ -721,236 +721,6 @@ static struct bitcoin_tx *tx_to_us(const tal_t *ctx,
return tx; 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, static void hsm_sign_local_htlc_tx(struct bitcoin_tx *tx,
const u8 *wscript, const u8 *wscript,
struct bitcoin_signature *sig) struct bitcoin_signature *sig)
@@ -1037,106 +807,6 @@ static void ignore_output(struct tracked_output *out)
out->resolved->tx_type = SELF; 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) static void handle_spend_created(struct tracked_output *out, const u8 *msg)
{ {
struct onchain_witness_element **witness; 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) static void proposal_meets_depth(struct tracked_output *out)
{ {
assert(out->proposal); 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 we simply wanted to ignore it after some depth */
if (!out->proposal->tx) { if (!out->proposal->tx) {
ignore_output(out); ignore_output(out);
@@ -1182,7 +848,7 @@ static void proposal_meets_depth(struct tracked_output *out)
wire_sync_write( wire_sync_write(
REQ_FD, REQ_FD,
take(towire_onchaind_broadcast_tx( 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. */ /* Don't wait for this if we're ignoring the tiny payment. */
if (out->proposal->tx_type == IGNORING_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) { && depth >= outs[i]->proposal->depth_required) {
proposal_meets_depth(outs[i]); 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]);
} }
} }

View File

@@ -1589,6 +1589,7 @@ def test_penalty_htlc_tx_timeout(node_factory, bitcoind, chainparams):
assert acc['resolved_at_block'] > 0 assert acc['resolved_at_block'] > 0
@pytest.mark.xfail(strict=True)
@pytest.mark.developer("uses dev_sign_last_tx") @pytest.mark.developer("uses dev_sign_last_tx")
def test_penalty_rbf_normal(node_factory, bitcoind, executor, chainparams): 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) check_utxos_channel(l2, [channel_id], expected_2)
@pytest.mark.xfail(strict=True)
@pytest.mark.developer("uses dev_sign_last_tx") @pytest.mark.developer("uses dev_sign_last_tx")
def test_penalty_rbf_burn(node_factory, bitcoind, executor, chainparams): def test_penalty_rbf_burn(node_factory, bitcoind, executor, chainparams):
''' '''