text: #include <assert.h>
  #include <bitcoin/tx_parts.h>
  #include <common/utils.h>
  #include <wire/wire.h>
  
  /* This destructor makes it behave like a native tal tree (a little!) */
  static void destroy_wally_tx_input(struct wally_tx_input *in)
  {
  	wally_tx_input_free(in);
  }
  
  static struct wally_tx_input *clone_input(const tal_t *ctx,
  					  const struct wally_tx_input *src)
  {
  	struct wally_tx_input *in;
  	int ret;
  
  	if (is_elements(chainparams)) {
  		ret = wally_tx_elements_input_init_alloc
  			(src->txhash, sizeof(src->txhash),
  			 src->index, src->sequence,
  			 src->script, src->script_len,
  			 src->witness,
  			 src->blinding_nonce, sizeof(src->blinding_nonce),
  			 src->entropy, sizeof(src->entropy),
  			 src->issuance_amount, src->issuance_amount_len,
  			 src->inflation_keys, src->inflation_keys_len,
  			 src->issuance_amount_rangeproof,
  			 src->issuance_amount_rangeproof_len,
  			 src->inflation_keys_rangeproof,
  			 src->inflation_keys_rangeproof_len,
  			 src->pegin_witness,
  			 &in);
  	} else {
  		ret = wally_tx_input_init_alloc(src->txhash, sizeof(src->txhash),
  						src->index, src->sequence,
  						src->script, src->script_len,
  						src->witness, &in);
  	}
  	assert(ret == WALLY_OK);
  
  	tal_add_destructor(in, destroy_wally_tx_input);
  	return tal_steal(ctx, in);
  }
  
  static void destroy_wally_tx_output(struct wally_tx_output *out)
  {
  	wally_tx_output_free(out);
  }
  
  static struct wally_tx_output *clone_output(const tal_t *ctx,
  					  const struct wally_tx_output *src)
  {
  	struct wally_tx_output *out;
  	int ret;
  
  	if (is_elements(chainparams)) {
  		ret = wally_tx_elements_output_init_alloc
  			(src->script, src->script_len,
  			 src->asset, src->asset_len,
  			 src->value, src->value_len,
  			 src->nonce, src->nonce_len,
  			 src->surjectionproof, src->surjectionproof_len,
  			 src->rangeproof, src->rangeproof_len,
  			 &out);
  	} else {
  		ret = wally_tx_output_init_alloc(src->satoshi,
  						 src->script, src->script_len,
  						 &out);
  	}
  	assert(ret == WALLY_OK);
  
  	tal_add_destructor(out, destroy_wally_tx_output);
  	return tal_steal(ctx, out);
  }
  
  struct tx_parts *tx_parts_from_wally_tx(const tal_t *ctx,
  					const struct wally_tx *wtx,
  					int input, int output)
  {
  	struct tx_parts *txp = tal(ctx, struct tx_parts);
  
  	wally_txid(wtx, &txp->txid);
  	txp->inputs = tal_arrz(txp, struct wally_tx_input *, wtx->num_inputs);
  	txp->outputs = tal_arrz(txp, struct wally_tx_output *, wtx->num_outputs);
  
  	for (size_t i = 0; i < wtx->num_inputs; i++) {
  		if (input != -1 && input != i)
  			continue;
  		txp->inputs[i] = clone_input(txp->inputs, &wtx->inputs[i]);
  	}
  
  	for (size_t i = 0; i < wtx->num_outputs; i++) {
  		if (output != -1 && output != i)
  			continue;
  		txp->outputs[i] = clone_output(txp->outputs, &wtx->outputs[i]);
  	}
  
  	return txp;
  }
  
  /* FIXME: If libwally exposed their linearization code, we could use it */
  static struct wally_tx_witness_stack *
  fromwire_wally_tx_witness_stack(const tal_t *ctx,
  				const u8 **cursor,
  				size_t *max)
  {
  	struct wally_tx_witness_stack *ws;
  	size_t num;
  	int ret;
  
  	num = fromwire_u32(cursor, max);
  	if (num == 0)
  		return NULL;
  
  	ret = wally_tx_witness_stack_init_alloc(num, &ws);
  	if (ret != WALLY_OK) {
  		fromwire_fail(cursor, max);
  		return NULL;
  	}
  
  	for (size_t i = 0; i < num; i++) {
  		u8 *w = fromwire_tal_arrn(tmpctx,
  					  cursor, max,
  					  fromwire_u32(cursor, max));
  		ret = wally_tx_witness_stack_add(ws, w, tal_bytelen(w));
  		if (ret != WALLY_OK) {
  			wally_tx_witness_stack_free(ws);
  			fromwire_fail(cursor, max);
  			return NULL;
  		}
  	}
  
  	return ws;
  }
  
  static void towire_wally_tx_witness_stack(u8 **pptr,
  					  const struct wally_tx_witness_stack *ws)
  {
  	if (!ws) {
  		towire_u32(pptr, 0);
  		return;
  	}
  
  	towire_u32(pptr, ws->num_items);
  	for (size_t i = 0; i < ws->num_items; i++) {
  		towire_u32(pptr, ws->items[i].witness_len);
  		towire_u8_array(pptr,
  				ws->items[i].witness,
  				ws->items[i].witness_len);
  	}
  }
  
  static struct wally_tx_input *fromwire_wally_tx_input(const tal_t *ctx,
  						      const u8 **cursor,
  						      size_t *max)
  {
  	struct wally_tx_input *in;
  	struct bitcoin_txid txid;
  	u32 index, sequence;
  	u8 *script;
  	struct wally_tx_witness_stack *ws;
  	int ret;
  
  	fromwire_bitcoin_txid(cursor, max, &txid);
  	index = fromwire_u32(cursor, max);
  	sequence = fromwire_u32(cursor, max);
  	script = fromwire_tal_arrn(tmpctx,
  				   cursor, max, fromwire_u32(cursor, max));
  	/* libwally doesn't like non-NULL ptrs with zero lengths. */
  	if (tal_bytelen(script) == 0)
  		script = tal_free(script);
  	ws = fromwire_wally_tx_witness_stack(tmpctx, cursor, max);
  
  	if (is_elements(chainparams)) {
  		u8 *blinding_nonce, *entropy, *issuance_amount,
  			*inflation_keys, *issuance_amount_rangeproof,
  			*inflation_keys_rangeproof;
  		struct wally_tx_witness_stack *pegin_witness;
  
  		blinding_nonce = fromwire_tal_arrn(tmpctx,
  						   cursor, max,
  						   fromwire_u32(cursor, max));
  		entropy = fromwire_tal_arrn(tmpctx,
  					    cursor, max,
  					    fromwire_u32(cursor, max));
  		issuance_amount = fromwire_tal_arrn(tmpctx,
  						    cursor, max,
  						    fromwire_u32(cursor, max));
  		inflation_keys = fromwire_tal_arrn(tmpctx,
  						   cursor, max,
  						   fromwire_u32(cursor, max));
  		issuance_amount_rangeproof = fromwire_tal_arrn(tmpctx,
  						   cursor, max,
  						   fromwire_u32(cursor, max));
  		inflation_keys_rangeproof = fromwire_tal_arrn(tmpctx,
  						   cursor, max,
  						   fromwire_u32(cursor, max));
  		pegin_witness = fromwire_wally_tx_witness_stack(tmpctx,
  								cursor, max);
  		ret = wally_tx_elements_input_init_alloc
  			(txid.shad.sha.u.u8, sizeof(txid.shad.sha.u.u8),
  			 index, sequence,
  			 script, tal_bytelen(script),
  			 ws,
  			 blinding_nonce, tal_bytelen(blinding_nonce),
  			 entropy, tal_bytelen(entropy),
  			 issuance_amount, tal_bytelen(issuance_amount),
  			 inflation_keys, tal_bytelen(inflation_keys),
  			 issuance_amount_rangeproof,
  			 tal_bytelen(issuance_amount_rangeproof),
  			 inflation_keys_rangeproof,
  			 tal_bytelen(inflation_keys_rangeproof),
  			 pegin_witness,
  			 &in);
  	} else {
  		ret = wally_tx_input_init_alloc(txid.shad.sha.u.u8,
  						sizeof(txid.shad.sha.u.u8),
  						index, sequence,
  						script, tal_bytelen(script),
  						ws, &in);
  	}
  	if (ret != WALLY_OK) {
  		fromwire_fail(cursor, max);
  		return NULL;
  	}
  
  	tal_add_destructor(in, destroy_wally_tx_input);
  	return tal_steal(ctx, in);
  }
  
  static struct wally_tx_output *fromwire_wally_tx_output(const tal_t *ctx,
  							const u8 **cursor,
  							size_t *max)
  {
  	struct wally_tx_output *out;
  	unsigned char *script;
  	int ret;
  
  	script = fromwire_tal_arrn(tmpctx,
  				   cursor, max, fromwire_u32(cursor, max));
  
  	if (is_elements(chainparams)) {
  		u8 *asset, *value, *nonce, *surjectionproof, *rangeproof;
  
  		asset = fromwire_tal_arrn(tmpctx,
  					  cursor, max,
  					  fromwire_u32(cursor, max));
  		value = fromwire_tal_arrn(tmpctx,
  					  cursor, max,
  					  fromwire_u32(cursor, max));
  		nonce = fromwire_tal_arrn(tmpctx,
  					  cursor, max,
  					  fromwire_u32(cursor, max));
  		surjectionproof = fromwire_tal_arrn(tmpctx,
  						    cursor, max,
  						    fromwire_u32(cursor, max));
  		rangeproof = fromwire_tal_arrn(tmpctx,
  					       cursor, max,
  					       fromwire_u32(cursor, max));
  		ret = wally_tx_elements_output_init_alloc
  			(script, tal_bytelen(script),
  			 asset, tal_bytelen(asset),
  			 value, tal_bytelen(value),
  			 nonce, tal_bytelen(nonce),
  			 surjectionproof, tal_bytelen(surjectionproof),
  			 rangeproof, tal_bytelen(rangeproof),
  			 &out);
  	} else {
  		u64 satoshi;
  		satoshi = fromwire_u64(cursor, max);
  		ret = wally_tx_output_init_alloc(satoshi,
  						 script, tal_bytelen(script),
  						 &out);
  	}
  	if (ret != WALLY_OK) {
  		fromwire_fail(cursor, max);
  		return NULL;
  	}
  
  	tal_add_destructor(out, destroy_wally_tx_output);
  	return tal_steal(ctx, out);
  }
  
  static void towire_wally_tx_input(u8 **pptr, const struct wally_tx_input *in)
  {
  	/* Just like a bitcoin_txid */
  	towire_u8_array(pptr, in->txhash, sizeof(in->txhash));
  	towire_u32(pptr, in->index);
  	towire_u32(pptr, in->sequence);
  	towire_u32(pptr, in->script_len);
  	towire_u8_array(pptr, in->script, in->script_len);
  	towire_wally_tx_witness_stack(pptr, in->witness);
  
  	if (is_elements(chainparams)) {
  		towire_u32(pptr, sizeof(in->blinding_nonce));
  		towire_u8_array(pptr, in->blinding_nonce,
  				sizeof(in->blinding_nonce));
  		towire_u32(pptr, sizeof(in->entropy));
  		towire_u8_array(pptr, in->entropy, sizeof(in->entropy));
  		towire_u32(pptr, in->issuance_amount_len);
  		towire_u8_array(pptr, in->issuance_amount,
  				in->issuance_amount_len);
  		towire_u32(pptr, in->inflation_keys_len);
  		towire_u8_array(pptr, in->inflation_keys,
  				in->inflation_keys_len);
  		towire_u32(pptr, in->issuance_amount_rangeproof_len);
  		towire_u8_array(pptr, in->issuance_amount_rangeproof,
  				in->issuance_amount_rangeproof_len);
  		towire_u32(pptr, in->inflation_keys_rangeproof_len);
  		towire_u8_array(pptr, in->inflation_keys_rangeproof,
  				in->inflation_keys_rangeproof_len);
  		towire_wally_tx_witness_stack(pptr, in->pegin_witness);
  	}
  }
  
  static void towire_wally_tx_output(u8 **pptr, const struct wally_tx_output *out)
  {
  	towire_u32(pptr, out->script_len);
  	towire_u8_array(pptr, out->script, out->script_len);
  
  	if (is_elements(chainparams)) {
  		towire_u32(pptr, out->asset_len);
  		towire_u8_array(pptr, out->asset, out->asset_len);
  		towire_u32(pptr, out->value_len);
  		towire_u8_array(pptr, out->value, out->value_len);
  		towire_u32(pptr, out->nonce_len);
  		towire_u8_array(pptr, out->nonce, out->nonce_len);
  		towire_u32(pptr, out->surjectionproof_len);
  		towire_u8_array(pptr, out->surjectionproof,
  				out->surjectionproof_len);
  		towire_u32(pptr, out->rangeproof_len);
  		towire_u8_array(pptr, out->rangeproof, out->rangeproof_len);
  	} else {
  		towire_u64(pptr, out->satoshi);
  	}
  }
  
  /* Wire marshalling and unmarshalling */
  struct tx_parts *fromwire_tx_parts(const tal_t *ctx,
  				   const u8 **cursor, size_t *max)
  {
  	struct tx_parts *txp = tal(ctx, struct tx_parts);
  	u32 num_inputs, num_outputs;
  
  	fromwire_bitcoin_txid(cursor, max, &txp->txid);
  	num_inputs = fromwire_u32(cursor, max);
  	txp->inputs = tal_arr(txp, struct wally_tx_input *, num_inputs);
  	for (size_t i = 0; i < num_inputs; i++) {
  		if (fromwire_bool(cursor, max)) {
  			txp->inputs[i] = fromwire_wally_tx_input(txp->inputs,
  								 cursor, max);
  		} else {
  			txp->inputs[i] = NULL;
  		}
  	}
  
  	num_outputs = fromwire_u32(cursor, max);
  	txp->outputs = tal_arr(txp, struct wally_tx_output *, num_outputs);
  	for (size_t i = 0; i < num_outputs; i++) {
  		if (fromwire_bool(cursor, max)) {
  			txp->outputs[i] = fromwire_wally_tx_output(txp->outputs,
  								 cursor, max);
  		} else {
  			txp->outputs[i] = NULL;
  		}
  	}
  
  	if (*cursor == NULL)
  		return tal_free(txp);
  
  	return txp;
  }
  
  void towire_tx_parts(u8 **pptr, const struct tx_parts *txp)
  {
  	towire_bitcoin_txid(pptr, &txp->txid);
  
  	towire_u32(pptr, tal_count(txp->inputs));
  	for (size_t i = 0; i < tal_count(txp->inputs); i++) {
  		if (txp->inputs[i]) {
  			towire_bool(pptr, true);
  			towire_wally_tx_input(pptr, txp->inputs[i]);
  		} else {
  			towire_bool(pptr, false);
  		}
  	}
  
  	towire_u32(pptr, tal_count(txp->outputs));
  	for (size_t i = 0; i < tal_count(txp->outputs); i++) {
  		if (txp->outputs[i]) {
  			towire_bool(pptr, true);
  			towire_wally_tx_output(pptr, txp->outputs[i]);
  		} else {
  			towire_bool(pptr, false);
  		}
  	}
  }
  