Browse Source

tx: Strengthen transaction construction checks

We roll the `elements_add_fee_output` function and the cropping of
overallocated arrays into the `bitcoin_tx_finalize` function. This is supposed
to be the final cleanup and compaction step before a tx can be sent to bitcoin
or passed off to other daemons.

This is the cleanup promised in #3491
travis-debug
Christian Decker 5 years ago
committed by Rusty Russell
parent
commit
42a63e4416
  1. 45
      bitcoin/tx.c
  2. 9
      bitcoin/tx.h
  3. 4
      channeld/commit_tx.c
  4. 2
      common/close_tx.c
  5. 2
      common/funding_tx.c
  6. 4
      common/htlc_tx.c
  7. 4
      common/initial_commit_tx.c
  8. 3
      common/withdraw_tx.c

45
bitcoin/tx.c

@ -101,7 +101,7 @@ static struct amount_sat bitcoin_tx_compute_fee(const struct bitcoin_tx *tx)
int elements_tx_add_fee_output(struct bitcoin_tx *tx) int elements_tx_add_fee_output(struct bitcoin_tx *tx)
{ {
struct amount_sat fee = bitcoin_tx_compute_fee(tx); struct amount_sat fee = bitcoin_tx_compute_fee(tx);
int pos = -1; int pos;
struct witscript *w; struct witscript *w;
/* If we aren't using elements, we don't add explicit fee outputs */ /* If we aren't using elements, we don't add explicit fee outputs */
@ -109,17 +109,21 @@ int elements_tx_add_fee_output(struct bitcoin_tx *tx)
return -1; return -1;
/* Try to find any existing fee output */ /* Try to find any existing fee output */
for (int i=0; i<tx->wtx->num_outputs; i++) { for (pos = 0; pos < tx->wtx->num_outputs; pos++) {
if (elements_tx_output_is_fee(tx, i)) { if (elements_tx_output_is_fee(tx, pos))
assert(pos == -1); break;
pos = i;
}
} }
if (pos == -1) { if (pos == tx->wtx->num_outputs) {
w = tal(tx->output_witscripts, struct witscript); w = tal(tx->output_witscripts, struct witscript);
w->ptr = tal_arr(w, u8, 0); w->ptr = tal_arr(w, u8, 0);
tx->output_witscripts[tx->wtx->num_outputs] = w;
/* Make sure we have a place to stash the witness script in. */
if (tal_count(tx->output_witscripts) < pos + 1) {
tal_resize(&tx->output_witscripts, pos + 1);
}
tx->output_witscripts[pos] = w;
return bitcoin_tx_add_output(tx, NULL, fee); return bitcoin_tx_add_output(tx, NULL, fee);
} else { } else {
bitcoin_tx_output_set_amount(tx, pos, fee); bitcoin_tx_output_set_amount(tx, pos, fee);
@ -160,6 +164,12 @@ bool bitcoin_tx_check(const struct bitcoin_tx *tx)
size_t written; size_t written;
int flags = WALLY_TX_FLAG_USE_WITNESS; int flags = WALLY_TX_FLAG_USE_WITNESS;
if (tal_count(tx->input_amounts) != tx->wtx->num_inputs)
return false;
if (tal_count(tx->output_witscripts) != tx->wtx->num_outputs)
return false;
if (wally_tx_get_length(tx->wtx, flags, &written) != WALLY_OK) if (wally_tx_get_length(tx->wtx, flags, &written) != WALLY_OK)
return false; return false;
@ -408,6 +418,19 @@ struct bitcoin_tx *bitcoin_tx(const tal_t *ctx,
return tx; return tx;
} }
void bitcoin_tx_finalize(struct bitcoin_tx *tx)
{
size_t num_outputs, num_inputs;
elements_tx_add_fee_output(tx);
num_outputs = tx->wtx->num_outputs;
tal_resize(&(tx->output_witscripts), num_outputs);
num_inputs = tx->wtx->num_inputs;
tal_resize(&tx->input_amounts, num_inputs);
assert(bitcoin_tx_check(tx));
}
struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx, const u8 **cursor, struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx, const u8 **cursor,
size_t *max) size_t *max)
{ {
@ -470,6 +493,12 @@ struct bitcoin_tx *bitcoin_tx_from_hex(const tal_t *ctx, const char *hex,
goto fail_free_tx; goto fail_free_tx;
tal_free(linear_tx); tal_free(linear_tx);
tx->output_witscripts =
tal_arrz(tx, struct witscript *, tx->wtx->num_outputs);
tx->input_amounts =
tal_arrz(tx, struct amount_sat *, tx->wtx->num_inputs);
return tx; return tx;
fail_free_tx: fail_free_tx:

9
bitcoin/tx.h

@ -156,6 +156,15 @@ void bitcoin_tx_input_get_txid(const struct bitcoin_tx *tx, int innum,
*/ */
bool bitcoin_tx_check(const struct bitcoin_tx *tx); bool bitcoin_tx_check(const struct bitcoin_tx *tx);
/**
* Finalize a transaction by truncating overallocated and temporary
* fields. This includes adding a fee output for elements transactions or
* adjusting an existing fee output, and resizing metadata arrays for inputs
* and outputs.
*/
void bitcoin_tx_finalize(struct bitcoin_tx *tx);
/** /**
* Add an explicit fee output if necessary. * Add an explicit fee output if necessary.
* *

4
channeld/commit_tx.c

@ -305,8 +305,8 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx,
u32 sequence = (0x80000000 | ((obscured_commitment_number>>24) & 0xFFFFFF)); u32 sequence = (0x80000000 | ((obscured_commitment_number>>24) & 0xFFFFFF));
bitcoin_tx_add_input(tx, funding_txid, funding_txout, sequence, funding, NULL); bitcoin_tx_add_input(tx, funding_txid, funding_txout, sequence, funding, NULL);
elements_tx_add_fee_output(tx); bitcoin_tx_finalize(tx);
tal_resize(&(tx->output_witscripts), tx->wtx->num_outputs); assert(bitcoin_tx_check(tx));
return tx; return tx;
} }

2
common/close_tx.c

@ -60,8 +60,8 @@ struct bitcoin_tx *create_close_tx(const tal_t *ctx,
return tal_free(tx); return tal_free(tx);
permute_outputs(tx, NULL, NULL); permute_outputs(tx, NULL, NULL);
elements_tx_add_fee_output(tx);
bitcoin_tx_finalize(tx);
assert(bitcoin_tx_check(tx)); assert(bitcoin_tx_check(tx));
return tx; return tx;
} }

2
common/funding_tx.c

@ -50,7 +50,7 @@ struct bitcoin_tx *funding_tx(const tal_t *ctx,
permute_inputs(tx, (const void **)utxomap); permute_inputs(tx, (const void **)utxomap);
elements_tx_add_fee_output(tx); bitcoin_tx_finalize(tx);
assert(bitcoin_tx_check(tx)); assert(bitcoin_tx_check(tx));
return tx; return tx;
} }

4
common/htlc_tx.c

@ -61,7 +61,9 @@ static struct bitcoin_tx *htlc_tx(const tal_t *ctx,
wscript = bitcoin_wscript_htlc_tx(tx, to_self_delay, revocation_pubkey, wscript = bitcoin_wscript_htlc_tx(tx, to_self_delay, revocation_pubkey,
local_delayedkey); local_delayedkey);
bitcoin_tx_add_output(tx, scriptpubkey_p2wsh(tx, wscript), amount); bitcoin_tx_add_output(tx, scriptpubkey_p2wsh(tx, wscript), amount);
elements_tx_add_fee_output(tx);
bitcoin_tx_finalize(tx);
assert(bitcoin_tx_check(tx));
tal_free(wscript); tal_free(wscript);

4
common/initial_commit_tx.c

@ -241,9 +241,7 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx,
sequence = (0x80000000 | ((obscured_commitment_number>>24) & 0xFFFFFF)); sequence = (0x80000000 | ((obscured_commitment_number>>24) & 0xFFFFFF));
bitcoin_tx_add_input(tx, funding_txid, funding_txout, sequence, funding, NULL); bitcoin_tx_add_input(tx, funding_txid, funding_txout, sequence, funding, NULL);
elements_tx_add_fee_output(tx); bitcoin_tx_finalize(tx);
tal_resize(&(tx->output_witscripts), tx->wtx->num_outputs);
assert(bitcoin_tx_check(tx)); assert(bitcoin_tx_check(tx));
return tx; return tx;

3
common/withdraw_tx.c

@ -52,7 +52,8 @@ struct bitcoin_tx *withdraw_tx(const tal_t *ctx,
*change_outnum = -1; *change_outnum = -1;
permute_inputs(tx, (const void **)utxos); permute_inputs(tx, (const void **)utxos);
elements_tx_add_fee_output(tx);
bitcoin_tx_finalize(tx);
assert(bitcoin_tx_check(tx)); assert(bitcoin_tx_check(tx));
return tx; return tx;
} }

Loading…
Cancel
Save