mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +01:00
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>
This commit is contained in:
committed by
Rusty Russell
parent
cf9f484168
commit
509bb2c7ae
171
bitcoin/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;
|
size_t i = tx->used_outputs;
|
||||||
struct wally_tx_output *output;
|
struct wally_tx_output *output;
|
||||||
assert(i < tal_count(tx->output));
|
assert(i < tx->wtx->outputs_allocation_len);
|
||||||
assert(memeqzero(&tx->output[i], sizeof(struct bitcoin_tx_output)));
|
|
||||||
|
|
||||||
tx->output[i].amount = *amount;
|
|
||||||
tx->output[i].script = script;
|
|
||||||
|
|
||||||
assert(tx->wtx != NULL);
|
assert(tx->wtx != NULL);
|
||||||
wally_tx_output_init_alloc(amount->satoshis /* Raw: low-level helper */,
|
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;
|
size_t i = tx->used_inputs;
|
||||||
struct wally_tx_input *input;
|
struct wally_tx_input *input;
|
||||||
assert(i < tal_count(tx->input));
|
assert(i < tx->wtx->inputs_allocation_len);
|
||||||
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(tx->wtx != NULL);
|
assert(tx->wtx != NULL);
|
||||||
wally_tx_input_init_alloc(txid->shad.sha.u.u8,
|
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)
|
bool bitcoin_tx_check(const struct bitcoin_tx *tx)
|
||||||
{
|
{
|
||||||
u8 *oldtx = linearize_tx(tmpctx, tx);
|
|
||||||
u8 *newtx;
|
u8 *newtx;
|
||||||
size_t written;
|
size_t written;
|
||||||
|
|
||||||
@@ -75,21 +64,24 @@ bool bitcoin_tx_check(const struct bitcoin_tx *tx)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
newtx = tal_arr(tmpctx, u8, written);
|
newtx = tal_arr(tmpctx, u8, written);
|
||||||
if (wally_tx_to_bytes(tx->wtx, WALLY_TX_FLAG_USE_WITNESS, newtx, written,
|
if (wally_tx_to_bytes(tx->wtx, WALLY_TX_FLAG_USE_WITNESS, newtx,
|
||||||
&written) != WALLY_OK)
|
written, &written) != WALLY_OK)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (written != tal_bytelen(newtx))
|
if (written != tal_bytelen(newtx))
|
||||||
return false;
|
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,
|
void bitcoin_tx_output_set_amount(struct bitcoin_tx *tx, int outnum,
|
||||||
struct amount_sat *amount)
|
struct amount_sat *amount)
|
||||||
{
|
{
|
||||||
assert(outnum < tx->used_outputs);
|
assert(outnum < tx->used_outputs);
|
||||||
tx->output[outnum].amount = *amount;
|
|
||||||
tx->wtx->outputs[outnum].satoshi = amount->satoshis; /* Raw: low-level helper */
|
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);
|
size_t stack_size = tal_count(witness);
|
||||||
|
|
||||||
/* Free any lingering witness */
|
/* Free any lingering witness */
|
||||||
tal_free(tx->input[innum].witness);
|
|
||||||
tx->input[innum].witness = witness;
|
|
||||||
|
|
||||||
if (witness) {
|
if (witness) {
|
||||||
wally_tx_witness_stack_init_alloc(stack_size, &stack);
|
wally_tx_witness_stack_init_alloc(stack_size, &stack);
|
||||||
for (size_t i = 0; i < stack_size; i++)
|
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);
|
wally_tx_set_input_witness(tx->wtx, innum, stack);
|
||||||
if (stack)
|
if (stack)
|
||||||
wally_tx_witness_stack_free(stack);
|
wally_tx_witness_stack_free(stack);
|
||||||
|
tal_free(witness);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitcoin_tx_input_set_script(struct bitcoin_tx *tx, int innum, u8 *script)
|
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));
|
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)
|
varint_t output_count)
|
||||||
{
|
{
|
||||||
struct bitcoin_tx *tx = tal(ctx, struct bitcoin_tx);
|
struct bitcoin_tx *tx = tal(ctx, struct bitcoin_tx);
|
||||||
size_t i;
|
|
||||||
tx->used_inputs = 0;
|
tx->used_inputs = 0;
|
||||||
tx->used_outputs = 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);
|
tal_add_destructor(tx, bitcoin_tx_destroy);
|
||||||
|
|
||||||
tx->input_amounts = tal_arrz(tx, struct amount_sat*, input_count);
|
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->locktime = 0;
|
||||||
tx->wtx->version = 2;
|
tx->wtx->version = 2;
|
||||||
return tx;
|
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,
|
struct bitcoin_tx *pull_bitcoin_tx(const tal_t *ctx, const u8 **cursor,
|
||||||
size_t *max)
|
size_t *max)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
u64 count;
|
|
||||||
u8 flag = 0;
|
|
||||||
const u8 *oldcursor = *cursor;
|
|
||||||
size_t wsize;
|
size_t wsize;
|
||||||
struct bitcoin_tx *tx = tal(ctx, struct bitcoin_tx);
|
struct bitcoin_tx *tx = tal(ctx, struct bitcoin_tx);
|
||||||
if (wally_tx_from_bytes(*cursor, *max, 0, &tx->wtx) != WALLY_OK) {
|
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);
|
tal_add_destructor(tx, bitcoin_tx_destroy);
|
||||||
wally_tx_get_length(tx->wtx, WALLY_TX_FLAG_USE_WITNESS, &wsize);
|
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 =
|
tx->input_amounts =
|
||||||
tal_arrz(tx, struct amount_sat *, tx->wtx->inputs_allocation_len);
|
tal_arrz(tx, struct amount_sat *, tx->wtx->inputs_allocation_len);
|
||||||
|
|
||||||
assert(pull_le32(cursor, max) == tx->wtx->version);
|
tx->used_outputs = tx->wtx->num_outputs;
|
||||||
count = pull_length(cursor, max, 32 + 4 + 4 + 1);
|
tx->used_inputs = tx->wtx->num_inputs;
|
||||||
/* 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);
|
*cursor += wsize;
|
||||||
tx->used_inputs = count;
|
*max -= wsize;
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
assert(!*cursor || oldcursor + wsize == *cursor);
|
|
||||||
/* If we ran short, fail. */
|
|
||||||
if (!*cursor)
|
|
||||||
tx = tal_free(tx);
|
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ struct bitcoin_tx {
|
|||||||
/* Keep track of input amounts, this is needed for signatures (NULL if
|
/* Keep track of input amounts, this is needed for signatures (NULL if
|
||||||
* unknown) */
|
* unknown) */
|
||||||
struct amount_sat **input_amounts;
|
struct amount_sat **input_amounts;
|
||||||
struct bitcoin_tx_input *input;
|
|
||||||
struct bitcoin_tx_output *output;
|
|
||||||
struct wally_tx *wtx;
|
struct wally_tx *wtx;
|
||||||
|
|
||||||
/* Keep track of how many inputs and outputs were filled so far. This
|
/* Keep track of how many inputs and outputs were filled so far. This
|
||||||
|
|||||||
@@ -270,7 +270,6 @@ struct bitcoin_tx *commit_tx(const tal_t *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(n <= tx->wtx->outputs_allocation_len);
|
assert(n <= tx->wtx->outputs_allocation_len);
|
||||||
tal_resize(&tx->output, n);
|
|
||||||
tal_resize(htlcmap, n);
|
tal_resize(htlcmap, n);
|
||||||
|
|
||||||
/* BOLT #3:
|
/* BOLT #3:
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ struct bitcoin_tx *create_close_tx(const tal_t *ctx,
|
|||||||
/* Can't have no outputs at all! */
|
/* Can't have no outputs at all! */
|
||||||
if (num_outputs == 0)
|
if (num_outputs == 0)
|
||||||
return tal_free(tx);
|
return tal_free(tx);
|
||||||
tal_resize(&tx->output, num_outputs);
|
|
||||||
|
|
||||||
permute_outputs(tx, NULL, NULL);
|
permute_outputs(tx, NULL, NULL);
|
||||||
assert(bitcoin_tx_check(tx));
|
assert(bitcoin_tx_check(tx));
|
||||||
|
|||||||
@@ -198,7 +198,6 @@ struct bitcoin_tx *initial_commit_tx(const tal_t *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(n <= tx->wtx->num_outputs);
|
assert(n <= tx->wtx->num_outputs);
|
||||||
tal_resize(&tx->output, n);
|
|
||||||
|
|
||||||
/* BOLT #3:
|
/* BOLT #3:
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -34,27 +34,6 @@ static size_t find_best_in(struct wally_tx_input *inputs, size_t num)
|
|||||||
return best;
|
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,
|
static void swap_wally_inputs(struct wally_tx_input *inputs,
|
||||||
const void **map,
|
const void **map,
|
||||||
size_t i1, size_t i2)
|
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);
|
best_pos = i + find_best_in(inputs + i, num_inputs - i);
|
||||||
/* Swap best into first place. */
|
/* Swap best into first place. */
|
||||||
swap_wally_inputs(tx->wtx->inputs, map, i, best_pos);
|
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);
|
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,
|
static void swap_wally_outputs(struct wally_tx_output *outputs,
|
||||||
const void **map,
|
const void **map,
|
||||||
u32 *cltvs,
|
u32 *cltvs,
|
||||||
@@ -223,6 +174,5 @@ void permute_outputs(struct bitcoin_tx *tx, u32 *cltvs, const void **map)
|
|||||||
|
|
||||||
/* Swap best into first place. */
|
/* Swap best into first place. */
|
||||||
swap_wally_outputs(tx->wtx->outputs, map, cltvs, i, best_pos);
|
swap_wally_outputs(tx->wtx->outputs, map, cltvs, i, best_pos);
|
||||||
swap_outputs(tx->output, NULL, NULL, i, best_pos);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user