diff --git a/bitcoin/tx.c b/bitcoin/tx.c index e1c04f329..f9ee88ab2 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -256,39 +256,12 @@ u8 *bitcoin_tx_output_get_witscript(const tal_t *ctx, const struct bitcoin_tx *t return tal_dup_arr(ctx, u8, out->witness_script, out->witness_script_len, 0); } -/* FIXME(cdecker) Make the caller pass in a reference to amount_asset, and - * return false if unintelligible/encrypted. (WARN UNUSED). */ struct amount_asset bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx, int outnum) { - struct amount_asset amount; - struct wally_tx_output *output; - be64 raw; - assert(tx->chainparams); assert(outnum < tx->wtx->num_outputs); - output = &tx->wtx->outputs[outnum]; - - if (chainparams->is_elements) { - assert(output->asset_len == sizeof(amount.asset)); - memcpy(&amount.asset, output->asset, sizeof(amount.asset)); - - /* We currently only support explicit value asset tags, others - * are confidential, so don't even try to assign a value to - * it. */ - if (output->asset[0] == 0x01) { - memcpy(&raw, output->value + 1, sizeof(raw)); - amount.value = be64_to_cpu(raw); - } else { - amount.value = 0; - } - } else { - /* Do not assign amount.asset, we should never touch it in - * non-elements scenarios. */ - amount.value = tx->wtx->outputs[outnum].satoshi; - } - - return amount; + return wally_tx_output_get_amount(&tx->wtx->outputs[outnum]); } void bitcoin_tx_output_get_amount_sat(struct bitcoin_tx *tx, int outnum, @@ -359,76 +332,50 @@ void bitcoin_tx_input_get_txid(const struct bitcoin_tx *tx, int innum, struct bitcoin_txid *out) { assert(innum < tx->wtx->num_inputs); - assert(sizeof(struct bitcoin_txid) == - sizeof(tx->wtx->inputs[innum].txhash)); - memcpy(out, tx->wtx->inputs[innum].txhash, sizeof(struct bitcoin_txid)); + wally_tx_input_get_txid(&tx->wtx->inputs[innum], out); +} + +void wally_tx_input_get_txid(const struct wally_tx_input *in, + struct bitcoin_txid *txid) +{ + BUILD_ASSERT(sizeof(struct bitcoin_txid) == sizeof(in->txhash)); + memcpy(txid, in->txhash, sizeof(struct bitcoin_txid)); } /* BIP144: * If the witness is empty, the old serialization format should be used. */ -static bool uses_witness(const struct bitcoin_tx *tx) +static bool uses_witness(const struct wally_tx *wtx) { size_t i; - for (i = 0; i < tx->wtx->num_inputs; i++) { - if (tx->wtx->inputs[i].witness) + for (i = 0; i < wtx->num_inputs; i++) { + if (wtx->inputs[i].witness) return true; } return false; } -/* For signing, we ignore input scripts on other inputs, and pretend - * the current input has a certain script: this is indicated by a - * non-NULL override_script. - * - * For this (and other signing weirdness like SIGHASH_SINGLE), we - * also need the current input being signed; that's in input_num. - * We also need sighash_type. - */ -static void push_tx(const struct bitcoin_tx *tx, - const u8 *override_script, - size_t input_num, - void (*push)(const void *, size_t, void *), void *pushp, - bool bip144) +u8 *linearize_tx(const tal_t *ctx, const struct bitcoin_tx *tx) { - int res; + return linearize_wtx(ctx, tx->wtx); +} + +u8 *linearize_wtx(const tal_t *ctx, const struct wally_tx *wtx) +{ + u8 *arr; + u32 flag = 0; size_t len, written; - u8 *serialized;; - u8 flag = 0; + int res; - if (bip144 && uses_witness(tx)) + if (uses_witness(wtx)) flag |= WALLY_TX_FLAG_USE_WITNESS; - res = wally_tx_get_length(tx->wtx, flag, &len); - assert(res == WALLY_OK); - serialized = tal_arr(tmpctx, u8, len); - - res = wally_tx_to_bytes(tx->wtx, flag, serialized, len, &written); + res = wally_tx_get_length(wtx, flag, &len); assert(res == WALLY_OK); + arr = tal_arr(ctx, u8, len); + res = wally_tx_to_bytes(wtx, flag, arr, len, &written); assert(len == written); - push(serialized, len, pushp); - tal_free(serialized); -} - -static void push_sha(const void *data, size_t len, void *shactx_) -{ - struct sha256_ctx *ctx = shactx_; - sha256_update(ctx, memcheck(data, len), len); -} - -static void push_linearize(const void *data, size_t len, void *pptr_) -{ - u8 **pptr = pptr_; - size_t oldsize = tal_count(*pptr); - tal_resize(pptr, oldsize + len); - memcpy(*pptr + oldsize, memcheck(data, len), len); -} - -u8 *linearize_tx(const tal_t *ctx, const struct bitcoin_tx *tx) -{ - u8 *arr = tal_arr(ctx, u8, 0); - push_tx(tx, NULL, 0, push_linearize, &arr, true); return arr; } @@ -440,13 +387,29 @@ size_t bitcoin_tx_weight(const struct bitcoin_tx *tx) return weight; } -void bitcoin_txid(const struct bitcoin_tx *tx, struct bitcoin_txid *txid) +void wally_txid(const struct wally_tx *wtx, struct bitcoin_txid *txid) { - struct sha256_ctx ctx = SHA256_INIT; + u8 *arr; + size_t len, written; + int res; + + /* Never use BIP141 form for txid */ + res = wally_tx_get_length(wtx, 0, &len); + assert(res == WALLY_OK); + arr = tal_arr(NULL, u8, len); + res = wally_tx_to_bytes(wtx, 0, arr, len, &written); + assert(len == written); - /* For TXID, we never use extended form. */ - push_tx(tx, NULL, 0, push_sha, &ctx, false); - sha256_double_done(&ctx, &txid->shad); + sha256_double(&txid->shad, arr, len); + tal_free(arr); +} + +/* We used to have beautiful, optimal code which fed the tx parts directly + * into sha256_update(). But that was before libwally; but now we don't have + * to maintain our own transaction code, so there's that. */ +void bitcoin_txid(const struct bitcoin_tx *tx, struct bitcoin_txid *txid) +{ + wally_txid(tx->wtx, txid); } /* Use the bitcoin_tx destructor to also free the wally_tx */ @@ -717,3 +680,46 @@ void towire_bitcoin_tx_output(u8 **pptr, const struct bitcoin_tx_output *output) towire_u16(pptr, tal_count(output->script)); towire_u8_array(pptr, output->script, tal_count(output->script)); } + +bool wally_tx_input_spends(const struct wally_tx_input *input, + const struct bitcoin_txid *txid, + int outnum) +{ + /* Useful, as tx_part can have some NULL inputs */ + if (!input) + return false; + BUILD_ASSERT(sizeof(*txid) == sizeof(input->txhash)); + if (memcmp(txid, input->txhash, sizeof(*txid)) != 0) + return false; + return input->index == outnum; +} + +/* FIXME(cdecker) Make the caller pass in a reference to amount_asset, and + * return false if unintelligible/encrypted. (WARN UNUSED). */ +struct amount_asset +wally_tx_output_get_amount(const struct wally_tx_output *output) +{ + struct amount_asset amount; + be64 raw; + + if (chainparams->is_elements) { + assert(output->asset_len == sizeof(amount.asset)); + memcpy(&amount.asset, output->asset, sizeof(amount.asset)); + + /* We currently only support explicit value asset tags, others + * are confidential, so don't even try to assign a value to + * it. */ + if (output->asset[0] == 0x01) { + memcpy(&raw, output->value + 1, sizeof(raw)); + amount.value = be64_to_cpu(raw); + } else { + amount.value = 0; + } + } else { + /* Do not assign amount.asset, we should never touch it in + * non-elements scenarios. */ + amount.value = output->satoshi; + } + + return amount; +} diff --git a/bitcoin/tx.h b/bitcoin/tx.h index a46513887..baade4858 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -38,11 +38,13 @@ struct bitcoin_tx_output { u8 *script; }; -/* SHA256^2 the tx: simpler than sha256_tx */ +/* SHA256^2 the tx in legacy format. */ void bitcoin_txid(const struct bitcoin_tx *tx, struct bitcoin_txid *txid); +void wally_txid(const struct wally_tx *wtx, struct bitcoin_txid *txid); /* Linear bytes of tx. */ u8 *linearize_tx(const tal_t *ctx, const struct bitcoin_tx *tx); +u8 *linearize_wtx(const tal_t *ctx, const struct wally_tx *wtx); /* Get weight of tx in Sipa. */ size_t bitcoin_tx_weight(const struct bitcoin_tx *tx); @@ -82,6 +84,13 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, const struct bitcoin_txid *txid, u32 outnum, u32 sequence, struct amount_sat amount, u8 *script); +/* This helps is useful because wally uses a raw byte array for txids */ +bool wally_tx_input_spends(const struct wally_tx_input *input, + const struct bitcoin_txid *txid, + int outnum); + +struct amount_asset +wally_tx_output_get_amount(const struct wally_tx_output *output); /** * Set the output amount on the transaction. @@ -147,6 +156,8 @@ const u8 *bitcoin_tx_input_get_witness(const tal_t *ctx, */ void bitcoin_tx_input_get_txid(const struct bitcoin_tx *tx, int innum, struct bitcoin_txid *out); +void wally_tx_input_get_txid(const struct wally_tx_input *in, + struct bitcoin_txid *txid); /** * Check a transaction for consistency.