From 509bb2c7aee5887a96e8966869c39bb4d5aba766 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Mon, 25 Mar 2019 13:52:31 +0100 Subject: [PATCH] wally: Remove tx->input and tx->output, wally all the way! This is what all of this has been working towards: ripping out the handwoven transaction handling. By removing the custom parsing we can finally switch over to using `wally_tx` as sole representation of transactions in memory. The commit is a bit larger but it's mostly removing setters and old references to the input and output fields. Signed-off-by: Christian Decker --- bitcoin/tx.c | 171 ++++--------------------------------- bitcoin/tx.h | 2 - channeld/commit_tx.c | 1 - common/close_tx.c | 1 - common/initial_commit_tx.c | 1 - common/permute_tx.c | 50 ----------- 6 files changed, 16 insertions(+), 210 deletions(-) diff --git a/bitcoin/tx.c b/bitcoin/tx.c index 4030ccc71..857c1bd7b 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -18,11 +18,7 @@ int bitcoin_tx_add_output(struct bitcoin_tx *tx, u8 *script, { size_t i = tx->used_outputs; struct wally_tx_output *output; - assert(i < tal_count(tx->output)); - assert(memeqzero(&tx->output[i], sizeof(struct bitcoin_tx_output))); - - tx->output[i].amount = *amount; - tx->output[i].script = script; + assert(i < tx->wtx->outputs_allocation_len); assert(tx->wtx != NULL); wally_tx_output_init_alloc(amount->satoshis /* Raw: low-level helper */, @@ -40,13 +36,7 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, const struct bitcoin_txid *txid, { size_t i = tx->used_inputs; struct wally_tx_input *input; - assert(i < tal_count(tx->input)); - assert(memeqzero(&tx->input[i].txid, sizeof(struct bitcoin_txid))); - - tx->input[i].txid = *txid; - tx->input[i].index = outnum; - tx->input[i].sequence_number = sequence; - tx->input[i].script = script; + assert(i < tx->wtx->inputs_allocation_len); assert(tx->wtx != NULL); wally_tx_input_init_alloc(txid->shad.sha.u.u8, @@ -66,7 +56,6 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, const struct bitcoin_txid *txid, bool bitcoin_tx_check(const struct bitcoin_tx *tx) { - u8 *oldtx = linearize_tx(tmpctx, tx); u8 *newtx; size_t written; @@ -75,21 +64,24 @@ bool bitcoin_tx_check(const struct bitcoin_tx *tx) return false; newtx = tal_arr(tmpctx, u8, written); - if (wally_tx_to_bytes(tx->wtx, WALLY_TX_FLAG_USE_WITNESS, newtx, written, - &written) != WALLY_OK) + if (wally_tx_to_bytes(tx->wtx, WALLY_TX_FLAG_USE_WITNESS, newtx, + written, &written) != WALLY_OK) return false; if (written != tal_bytelen(newtx)) return false; - return memeq(oldtx, tal_bytelen(oldtx), newtx, tal_bytelen(newtx)); + if (tx->used_inputs != tx->wtx->num_inputs || + tx->used_outputs != tx->wtx->num_outputs) + return false; + + return true; } void bitcoin_tx_output_set_amount(struct bitcoin_tx *tx, int outnum, struct amount_sat *amount) { assert(outnum < tx->used_outputs); - tx->output[outnum].amount = *amount; tx->wtx->outputs[outnum].satoshi = amount->satoshis; /* Raw: low-level helper */ } @@ -121,9 +113,6 @@ void bitcoin_tx_input_set_witness(struct bitcoin_tx *tx, int innum, size_t stack_size = tal_count(witness); /* Free any lingering witness */ - tal_free(tx->input[innum].witness); - tx->input[innum].witness = witness; - if (witness) { wally_tx_witness_stack_init_alloc(stack_size, &stack); for (size_t i = 0; i < stack_size; i++) @@ -133,11 +122,11 @@ void bitcoin_tx_input_set_witness(struct bitcoin_tx *tx, int innum, wally_tx_set_input_witness(tx->wtx, innum, stack); if (stack) wally_tx_witness_stack_free(stack); + tal_free(witness); } void bitcoin_tx_input_set_script(struct bitcoin_tx *tx, int innum, u8 *script) { - tx->input[innum].script = script; wally_tx_set_input_script(tx->wtx, innum, script, tal_bytelen(script)); } @@ -294,7 +283,6 @@ struct bitcoin_tx *bitcoin_tx(const tal_t *ctx, varint_t input_count, varint_t output_count) { struct bitcoin_tx *tx = tal(ctx, struct bitcoin_tx); - size_t i; tx->used_inputs = 0; tx->used_outputs = 0; @@ -303,112 +291,14 @@ struct bitcoin_tx *bitcoin_tx(const tal_t *ctx, varint_t input_count, tal_add_destructor(tx, bitcoin_tx_destroy); tx->input_amounts = tal_arrz(tx, struct amount_sat*, input_count); - tx->output = tal_arrz(tx, struct bitcoin_tx_output, output_count); - tx->input = tal_arrz(tx, struct bitcoin_tx_input, input_count); - for (i = 0; i < tal_count(tx->input); i++) { - /* We assume NULL is a zero bitmap */ - assert(tx->input[i].script == NULL); - tx->input[i].sequence_number = BITCOIN_TX_DEFAULT_SEQUENCE; - tx->input[i].witness = NULL; - } tx->wtx->locktime = 0; tx->wtx->version = 2; return tx; } -static bool pull_sha256_double(const u8 **cursor, size_t *max, - struct sha256_double *h) -{ - return pull(cursor, max, h, sizeof(*h)); -} - -static u64 pull_value(const u8 **cursor, size_t *max) -{ - u64 amount; - - amount = pull_le64(cursor, max); - return amount; -} - -static struct amount_sat pull_amount_sat(const u8 **cursor, size_t *max) -{ - struct amount_sat sat; - - sat.satoshis = pull_value(cursor, max); /* Raw: low-level helper */ - return sat; -} - -/* Pulls a varint which specifies n items of mult size: ensures basic - * sanity to avoid trivial OOM */ -static u64 pull_length(const u8 **cursor, size_t *max, size_t mult) -{ - u64 v = pull_varint(cursor, max); - if (v * mult > *max) { - *cursor = NULL; - *max = 0; - return 0; - } - return v; -} - -static void pull_input(const tal_t *ctx, const u8 **cursor, size_t *max, - struct bitcoin_tx_input *input) -{ - u64 script_len; - pull_sha256_double(cursor, max, &input->txid.shad); - input->index = pull_le32(cursor, max); - script_len = pull_length(cursor, max, 1); - if (script_len) - input->script = tal_arr(ctx, u8, script_len); - else - input->script = NULL; - pull(cursor, max, input->script, tal_count(input->script)); - input->sequence_number = pull_le32(cursor, max); -} - -static void pull_output(const tal_t *ctx, const u8 **cursor, size_t *max, - struct bitcoin_tx_output *output) -{ - output->amount = pull_amount_sat(cursor, max); - output->script = tal_arr(ctx, u8, pull_length(cursor, max, 1)); - pull(cursor, max, output->script, tal_count(output->script)); -} - -static u8 *pull_witness_item(const tal_t *ctx, const u8 **cursor, size_t *max) -{ - uint64_t len = pull_length(cursor, max, 1); - u8 *item; - - item = tal_arr(ctx, u8, len); - pull(cursor, max, item, len); - return item; -} - -static void pull_witness(struct bitcoin_tx_input *inputs, size_t i, - const u8 **cursor, size_t *max) -{ - uint64_t j, num = pull_length(cursor, max, 1); - - /* 0 means not using witness. */ - if (num == 0) { - inputs[i].witness = NULL; - return; - } - - inputs[i].witness = tal_arr(inputs, u8 *, num); - for (j = 0; j < num; j++) { - inputs[i].witness[j] = pull_witness_item(inputs[i].witness, - cursor, max); - } -} - struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx, const u8 **cursor, size_t *max) { - size_t i; - u64 count; - u8 flag = 0; - const u8 *oldcursor = *cursor; size_t wsize; struct bitcoin_tx *tx = tal(ctx, struct bitcoin_tx); if (wally_tx_from_bytes(*cursor, *max, 0, &tx->wtx) != WALLY_OK) { @@ -417,45 +307,16 @@ struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx, const u8 **cursor, } tal_add_destructor(tx, bitcoin_tx_destroy); wally_tx_get_length(tx->wtx, WALLY_TX_FLAG_USE_WITNESS, &wsize); + + /* We don't know the input amounts yet, so set them all to NULL */ tx->input_amounts = tal_arrz(tx, struct amount_sat *, tx->wtx->inputs_allocation_len); - assert(pull_le32(cursor, max) == tx->wtx->version); - count = pull_length(cursor, max, 32 + 4 + 4 + 1); - /* BIP 144 marker is 0 (impossible to have tx with 0 inputs) */ - if (count == 0) { - pull(cursor, max, &flag, 1); - if (flag != SEGREGATED_WITNESS_FLAG) - return tal_free(tx); - count = pull_length(cursor, max, 32 + 4 + 4 + 1); - } - - tx->input = tal_arr(tx, struct bitcoin_tx_input, count); - tx->used_inputs = count; - - for (i = 0; i < tal_count(tx->input); i++) - pull_input(tx, cursor, max, tx->input + i); - - count = pull_length(cursor, max, 8 + 1); - tx->output = tal_arr(tx, struct bitcoin_tx_output, count); - tx->used_outputs = count; - - for (i = 0; i < tal_count(tx->output); i++) - pull_output(tx, cursor, max, tx->output + i); - - if (flag & SEGREGATED_WITNESS_FLAG) { - for (i = 0; i < tal_count(tx->input); i++) - pull_witness(tx->input, i, cursor, max); - } else { - for (i = 0; i < tal_count(tx->input); i++) - tx->input[i].witness = NULL; - } - assert(pull_le32(cursor, max) == tx->wtx->locktime); + tx->used_outputs = tx->wtx->num_outputs; + tx->used_inputs = tx->wtx->num_inputs; - assert(!*cursor || oldcursor + wsize == *cursor); - /* If we ran short, fail. */ - if (!*cursor) - tx = tal_free(tx); + *cursor += wsize; + *max -= wsize; return tx; } diff --git a/bitcoin/tx.h b/bitcoin/tx.h index 01fb5fecb..cedc9a454 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -22,8 +22,6 @@ struct bitcoin_tx { /* Keep track of input amounts, this is needed for signatures (NULL if * unknown) */ struct amount_sat **input_amounts; - struct bitcoin_tx_input *input; - struct bitcoin_tx_output *output; struct wally_tx *wtx; /* Keep track of how many inputs and outputs were filled so far. This diff --git a/channeld/commit_tx.c b/channeld/commit_tx.c index c679c63be..c0b917074 100644 --- a/channeld/commit_tx.c +++ b/channeld/commit_tx.c @@ -270,7 +270,6 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx, } assert(n <= tx->wtx->outputs_allocation_len); - tal_resize(&tx->output, n); tal_resize(htlcmap, n); /* BOLT #3: diff --git a/common/close_tx.c b/common/close_tx.c index 3a00801cf..a11072c5f 100644 --- a/common/close_tx.c +++ b/common/close_tx.c @@ -58,7 +58,6 @@ struct bitcoin_tx *create_close_tx(const tal_t *ctx, /* Can't have no outputs at all! */ if (num_outputs == 0) return tal_free(tx); - tal_resize(&tx->output, num_outputs); permute_outputs(tx, NULL, NULL); assert(bitcoin_tx_check(tx)); diff --git a/common/initial_commit_tx.c b/common/initial_commit_tx.c index 7a24f0a63..479472df7 100644 --- a/common/initial_commit_tx.c +++ b/common/initial_commit_tx.c @@ -198,7 +198,6 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx, } assert(n <= tx->wtx->num_outputs); - tal_resize(&tx->output, n); /* BOLT #3: * diff --git a/common/permute_tx.c b/common/permute_tx.c index e9064d04f..c1f70570f 100644 --- a/common/permute_tx.c +++ b/common/permute_tx.c @@ -34,27 +34,6 @@ static size_t find_best_in(struct wally_tx_input *inputs, size_t num) return best; } -static void swap_inputs(struct bitcoin_tx_input *inputs, - const void **map, - size_t i1, size_t i2) -{ - struct bitcoin_tx_input tmpinput; - const void *tmp; - - if (i1 == i2) - return; - - tmpinput = inputs[i1]; - inputs[i1] = inputs[i2]; - inputs[i2] = tmpinput; - - if (map) { - tmp = map[i1]; - map[i1] = map[i2]; - map[i2] = tmp; - } -} - static void swap_wally_inputs(struct wally_tx_input *inputs, const void **map, size_t i1, size_t i2) @@ -99,38 +78,10 @@ void permute_inputs(struct bitcoin_tx *tx, const void **map) best_pos = i + find_best_in(inputs + i, num_inputs - i); /* Swap best into first place. */ swap_wally_inputs(tx->wtx->inputs, map, i, best_pos); - swap_inputs(tx->input, NULL, i, best_pos); swap_input_amounts(tx->input_amounts, i, best_pos); } } -static void swap_outputs(struct bitcoin_tx_output *outputs, - const void **map, - u32 *cltvs, - size_t i1, size_t i2) -{ - struct bitcoin_tx_output tmpoutput; - - if (i1 == i2) - return; - - tmpoutput = outputs[i1]; - outputs[i1] = outputs[i2]; - outputs[i2] = tmpoutput; - - if (map) { - const void *tmp = map[i1]; - map[i1] = map[i2]; - map[i2] = tmp; - } - - if (cltvs) { - u32 tmp = cltvs[i1]; - cltvs[i1] = cltvs[i2]; - cltvs[i2] = tmp; - } -} - static void swap_wally_outputs(struct wally_tx_output *outputs, const void **map, u32 *cltvs, @@ -223,6 +174,5 @@ void permute_outputs(struct bitcoin_tx *tx, u32 *cltvs, const void **map) /* Swap best into first place. */ swap_wally_outputs(tx->wtx->outputs, map, cltvs, i, best_pos); - swap_outputs(tx->output, NULL, NULL, i, best_pos); } }