Browse Source

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 <decker.christian@gmail.com>
pr-2587
Christian Decker 6 years ago
committed by Rusty Russell
parent
commit
509bb2c7ae
  1. 171
      bitcoin/tx.c
  2. 2
      bitcoin/tx.h
  3. 1
      channeld/commit_tx.c
  4. 1
      common/close_tx.c
  5. 1
      common/initial_commit_tx.c
  6. 50
      common/permute_tx.c

171
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;
}

2
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

1
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:

1
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));

1
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:
*

50
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);
}
}

Loading…
Cancel
Save