diff --git a/bitcoin/psbt.c b/bitcoin/psbt.c index 13692c50b..f73c0aef4 100644 --- a/bitcoin/psbt.c +++ b/bitcoin/psbt.c @@ -24,36 +24,26 @@ static struct wally_psbt *init_psbt(const tal_t *ctx, size_t num_inputs, size_t tal_wally_start(); if (is_elements(chainparams)) - wally_err = wally_psbt_elements_init_alloc(0, num_inputs, num_outputs, 0, &psbt); + wally_err = wally_psbt_init_alloc(2, num_inputs, num_outputs, 0, WALLY_PSBT_INIT_PSET, &psbt); else - wally_err = wally_psbt_init_alloc(0, num_inputs, num_outputs, 0, &psbt); + wally_err = wally_psbt_init_alloc(2, num_inputs, num_outputs, 0, 0, &psbt); assert(wally_err == WALLY_OK); + /* By default we are modifying them internally; allow it */ + wally_psbt_set_tx_modifiable_flags(psbt, WALLY_PSBT_TXMOD_INPUTS | WALLY_PSBT_TXMOD_OUTPUTS); tal_add_destructor(psbt, psbt_destroy); tal_wally_end_onto(ctx, psbt, struct wally_psbt); return psbt; } +/* FIXME extremely thin wrapper; remove? */ struct wally_psbt *create_psbt(const tal_t *ctx, size_t num_inputs, size_t num_outputs, u32 locktime) { - int wally_err; - struct wally_tx *wtx; struct wally_psbt *psbt; - tal_wally_start(); - if (wally_tx_init_alloc(WALLY_TX_VERSION_2, locktime, num_inputs, num_outputs, &wtx) != WALLY_OK) - abort(); - /* wtx is freed below */ - tal_wally_end(NULL); - psbt = init_psbt(ctx, num_inputs, num_outputs); + wally_psbt_set_fallback_locktime(psbt, locktime); - tal_wally_start(); - wally_err = wally_psbt_set_global_tx(psbt, wtx); - assert(wally_err == WALLY_OK); - tal_wally_end(psbt); - - wally_tx_free(wtx); return psbt; } @@ -72,17 +62,18 @@ struct wally_psbt *new_psbt(const tal_t *ctx, const struct wally_tx *wtx) struct wally_psbt *psbt; int wally_err; - psbt = init_psbt(ctx, wtx->num_inputs, wtx->num_outputs); + psbt = create_psbt(ctx, wtx->num_inputs, wtx->num_outputs, wtx->locktime); tal_wally_start(); - /* Set directly: avoids psbt checks for non-NULL scripts/witnesses */ - wally_err = wally_tx_clone_alloc(wtx, 0, &psbt->tx); - assert(wally_err == WALLY_OK); - /* Inputs/outs are pre-allocated above, 'add' them as empty dummies */ - psbt->num_inputs = wtx->num_inputs; - psbt->num_outputs = wtx->num_outputs; + + /* locktime set in create_psbt for now */ + wally_psbt_set_tx_version(psbt, wtx->version); + wally_psbt_set_tx_modifiable_flags(psbt, WALLY_PSBT_TXMOD_INPUTS | WALLY_PSBT_TXMOD_OUTPUTS); for (size_t i = 0; i < wtx->num_inputs; i++) { + wally_err = wally_psbt_add_tx_input_at(psbt, i, 0, &wtx->inputs[i]); + assert(wally_err == WALLY_OK); + /* add these scripts + witnesses to the psbt */ if (wtx->inputs[i].script) { wally_err = @@ -90,24 +81,19 @@ struct wally_psbt *new_psbt(const tal_t *ctx, const struct wally_tx *wtx) wtx->inputs[i].script, wtx->inputs[i].script_len); assert(wally_err == WALLY_OK); - - /* Clear out script sig data */ - psbt->tx->inputs[i].script_len = 0; - tal_free(psbt->tx->inputs[i].script); - psbt->tx->inputs[i].script = NULL; } if (wtx->inputs[i].witness) { wally_err = wally_psbt_input_set_final_witness(&psbt->inputs[i], wtx->inputs[i].witness); assert(wally_err == WALLY_OK); - - /* Delete the witness data */ - wally_tx_witness_stack_free(psbt->tx->inputs[i].witness); - psbt->tx->inputs[i].witness = NULL; } } + for (size_t i = 0; i < wtx->num_outputs; i++) { + wally_psbt_add_tx_output_at(psbt, i, 0, &wtx->outputs[i]); + } + tal_wally_end(psbt); return psbt; } @@ -128,7 +114,7 @@ struct wally_psbt_input *psbt_add_input(struct wally_psbt *psbt, int wally_err; tal_wally_start(); - wally_err = wally_psbt_add_input_at(psbt, insert_at, flags, input); + wally_err = wally_psbt_add_tx_input_at(psbt, insert_at, flags, input); assert(wally_err == WALLY_OK); tal_wally_end(psbt); return &psbt->inputs[insert_at]; @@ -168,7 +154,7 @@ struct wally_psbt_input *psbt_append_input(struct wally_psbt *psbt, abort(); } - wally_err = wally_psbt_add_input_at(psbt, input_num, flags, tx_in); + wally_err = wally_psbt_add_tx_input_at(psbt, input_num, flags, tx_in); assert(wally_err == WALLY_OK); wally_tx_input_free(tx_in); tal_wally_end(psbt); @@ -204,7 +190,7 @@ struct wally_psbt_output *psbt_add_output(struct wally_psbt *psbt, int wally_err; tal_wally_start(); - wally_err = wally_psbt_add_output_at(psbt, insert_at, 0, output); + wally_err = wally_psbt_add_tx_output_at(psbt, insert_at, 0, output); assert(wally_err == WALLY_OK); tal_wally_end(psbt); return &psbt->outputs[insert_at]; @@ -217,7 +203,7 @@ struct wally_psbt_output *psbt_append_output(struct wally_psbt *psbt, struct wally_psbt_output *out; struct wally_tx_output *tx_out = wally_tx_output(NULL, script, amount); - out = psbt_add_output(psbt, tx_out, psbt->tx->num_outputs); + out = psbt_add_output(psbt, tx_out, psbt->num_outputs); wally_tx_output_free(tx_out); return out; } @@ -264,7 +250,7 @@ void psbt_input_add_pubkey(struct wally_psbt *psbt, size_t in, pubkey_to_der(pk_der, pubkey); tal_wally_start(); - wally_err = wally_psbt_input_add_keypath_item(&psbt->inputs[in], + wally_err = wally_psbt_input_keypath_add(&psbt->inputs[in], pk_der, sizeof(pk_der), fingerprint, sizeof(fingerprint), empty_path, ARRAY_SIZE(empty_path)); @@ -361,7 +347,7 @@ void psbt_elements_input_set_asset(struct wally_psbt *psbt, size_t in, tal_wally_start(); if (asset->value > 0) - if (wally_psbt_input_set_value(&psbt->inputs[in], + if (wally_psbt_input_set_amount(&psbt->inputs[in], asset->value) != WALLY_OK) abort(); @@ -375,7 +361,6 @@ void psbt_elements_input_set_asset(struct wally_psbt *psbt, size_t in, void psbt_elements_normalize_fees(struct wally_psbt *psbt) { - struct amount_asset asset; size_t fee_output_idx = psbt->num_outputs; if (!is_elements(chainparams)) @@ -383,15 +368,15 @@ void psbt_elements_normalize_fees(struct wally_psbt *psbt) /* Elements requires that every input value is accounted for, * including the fees */ - struct amount_sat total_in = AMOUNT_SAT(0), val; + struct amount_sat total_fee = AMOUNT_SAT(0), val; for (size_t i = 0; i < psbt->num_inputs; i++) { val = psbt_input_get_amount(psbt, i); - if (!amount_sat_add(&total_in, total_in, val)) + if (!amount_sat_add(&total_fee, total_fee, val)) return; } for (size_t i = 0; i < psbt->num_outputs; i++) { - asset = wally_tx_output_get_amount(&psbt->tx->outputs[i]); - if (elements_wtx_output_is_fee(psbt->tx, i)) { + struct amount_asset output_amount = wally_psbt_output_get_amount(&psbt->outputs[i]); + if (elements_psbt_output_is_fee(psbt, i)) { if (fee_output_idx == psbt->num_outputs) { fee_output_idx = i; continue; @@ -401,40 +386,47 @@ void psbt_elements_normalize_fees(struct wally_psbt *psbt) psbt_rm_output(psbt, i--); continue; } - if (!amount_asset_is_main(&asset)) + if (!amount_asset_is_main(&output_amount)) continue; - if (!amount_sat_sub(&total_in, total_in, - amount_asset_to_sat(&asset))) + if (!amount_sat_sub(&total_fee, total_fee, + amount_asset_to_sat(&output_amount))) return; } - if (amount_sat_eq(total_in, AMOUNT_SAT(0))) + if (amount_sat_eq(total_fee, AMOUNT_SAT(0))) return; /* We need to add a fee output */ if (fee_output_idx == psbt->num_outputs) { - psbt_append_output(psbt, NULL, total_in); + psbt_append_output(psbt, NULL, total_fee); } else { - u64 sats = total_in.satoshis; /* Raw: wally API */ - struct wally_tx_output *out = &psbt->tx->outputs[fee_output_idx]; - if (wally_tx_confidential_value_from_satoshi( - sats, out->value, out->value_len) != WALLY_OK) - return; + int ret; + u64 sats = total_fee.satoshis; /* Raw: wally API */ + struct wally_psbt_output *out = &psbt->outputs[fee_output_idx]; + ret = wally_psbt_output_set_amount(out, sats); + assert(ret == WALLY_OK); } } +void wally_psbt_input_get_txid(const struct wally_psbt_input *in, + struct bitcoin_txid *txid) +{ + BUILD_ASSERT(sizeof(struct bitcoin_txid) == sizeof(in->txhash)); + memcpy(txid, in->txhash, sizeof(struct bitcoin_txid)); +} + bool psbt_has_input(const struct wally_psbt *psbt, const struct bitcoin_outpoint *outpoint) { for (size_t i = 0; i < psbt->num_inputs; i++) { struct bitcoin_txid in_txid; - struct wally_tx_input *in = &psbt->tx->inputs[i]; + const struct wally_psbt_input *in = &psbt->inputs[i]; if (outpoint->n != in->index) continue; - wally_tx_input_get_txid(in, &in_txid); + wally_psbt_input_get_txid(in, &in_txid); if (bitcoin_txid_eq(&outpoint->txid, &in_txid)) return true; } @@ -452,7 +444,7 @@ struct amount_sat psbt_input_get_amount(const struct wally_psbt *psbt, assert(amount_asset_is_main(&amt_asset)); val = amount_asset_to_sat(&amt_asset); } else if (psbt->inputs[in].utxo) { - int idx = psbt->tx->inputs[in].index; + int idx = psbt->inputs[in].index; struct wally_tx *prev_tx = psbt->inputs[in].utxo; val = amount_sat(prev_tx->outputs[idx].satoshi); } else @@ -466,7 +458,7 @@ struct amount_sat psbt_output_get_amount(const struct wally_psbt *psbt, { struct amount_asset asset; assert(out < psbt->num_outputs); - asset = wally_tx_output_get_amount(&psbt->tx->outputs[out]); + asset = wally_psbt_output_get_amount(&psbt->outputs[out]); assert(amount_asset_is_main(&asset)); return amount_asset_to_sat(&asset); } @@ -505,7 +497,7 @@ u8 *psbt_make_key(const tal_t *ctx, u8 key_subtype, const u8 *key_data) *** */ u8 *key = tal_arr(ctx, u8, 0); - add_type(&key, PSBT_PROPRIETARY_TYPE); + add_type(&key, WALLY_PSBT_PROPRIETARY_TYPE); add_varint(&key, strlen(LIGHTNING_PROPRIETARY_PREFIX)); add(&key, LIGHTNING_PROPRIETARY_PREFIX, strlen(LIGHTNING_PROPRIETARY_PREFIX)); @@ -616,9 +608,11 @@ bool psbt_finalize(struct wally_psbt *psbt) for (size_t i = 0; i < psbt->num_inputs; i++) { struct wally_psbt_input *input = &psbt->inputs[i]; struct wally_tx_witness_stack *stack; + const struct wally_map_item *iws; - if (!is_anchor_witness_script(input->witness_script, - input->witness_script_len)) + iws = wally_map_get_integer(&input->psbt_fields, /* PSBT_IN_WITNESS_SCRIPT */ 0x05); + if (!iws || !is_anchor_witness_script(iws->value, + iws->value_len)) continue; if (input->signatures.num_items != 1) @@ -643,8 +637,8 @@ bool psbt_finalize(struct wally_psbt *psbt) input->signatures.items[0].value, input->signatures.items[0].value_len); wally_tx_witness_stack_add(stack, - input->witness_script, - input->witness_script_len); + iws->value, + iws->value_len); wally_psbt_input_set_final_witness(input, stack); } @@ -662,7 +656,7 @@ struct wally_tx *psbt_final_tx(const tal_t *ctx, const struct wally_psbt *psbt) return NULL; tal_wally_start(); - if (wally_psbt_extract(psbt, &wtx) == WALLY_OK) + if (wally_psbt_extract(psbt, /* flags */ 0, &wtx) == WALLY_OK) tal_add_destructor(wtx, wally_tx_destroy); else wtx = NULL; @@ -679,7 +673,7 @@ struct wally_psbt *psbt_from_b64(const tal_t *ctx, char *str = tal_strndup(tmpctx, b64, b64len); tal_wally_start(); - if (wally_psbt_from_base64(str, &psbt) == WALLY_OK) + if (wally_psbt_from_base64(str, /* flags */ 0, &psbt) == WALLY_OK) tal_add_destructor(psbt, psbt_destroy); else psbt = NULL; @@ -713,7 +707,9 @@ const u8 *psbt_get_bytes(const tal_t *ctx, const struct wally_psbt *psbt, return NULL; } - wally_psbt_get_length(psbt, 0, &len); + if (wally_psbt_get_length(psbt, 0, &len) != WALLY_OK) { + abort(); + } bytes = tal_arr(ctx, u8, len); if (wally_psbt_to_bytes(psbt, 0, bytes, len, bytes_written) != WALLY_OK || @@ -730,7 +726,7 @@ struct wally_psbt *psbt_from_bytes(const tal_t *ctx, const u8 *bytes, struct wally_psbt *psbt; tal_wally_start(); - if (wally_psbt_from_bytes(bytes, byte_len, &psbt) == WALLY_OK) + if (wally_psbt_from_bytes(bytes, byte_len, /* flags */ 0, &psbt) == WALLY_OK) tal_add_destructor(psbt, psbt_destroy); else psbt = NULL; @@ -780,38 +776,23 @@ struct wally_psbt *fromwire_wally_psbt(const tal_t *ctx, return psbt; } -/* This only works on a non-final psbt because we're ALL SEGWIT! */ void psbt_txid(const tal_t *ctx, - const struct wally_psbt *psbt, struct bitcoin_txid *txid, + const struct wally_psbt *psbt, + struct bitcoin_txid *txid, struct wally_tx **wtx) { struct wally_tx *tx; + int wally_err; + assert(psbt->version == 2); - /* You can *almost* take txid of global tx. But @niftynei thought - * about this far more than me and pointed out that P2SH - * inputs would not be represented, so here we go. */ + /* We rely on wally extractor to fill out all txid-related fields including scriptSigs */ tal_wally_start(); - wally_tx_clone_alloc(psbt->tx, 0, &tx); + wally_err = wally_psbt_extract(psbt, WALLY_PSBT_EXTRACT_NON_FINAL, &tx); + assert(wally_err == WALLY_OK); + wally_err = wally_tx_get_txid(tx, txid->shad.sha.u.u8, sizeof(txid->shad.sha.u.u8)); + assert(wally_err == WALLY_OK); + tal_wally_end(ctx); - for (size_t i = 0; i < tx->num_inputs; i++) { - if (psbt->inputs[i].final_scriptsig) { - wally_tx_set_input_script(tx, i, - psbt->inputs[i].final_scriptsig, - psbt->inputs[i].final_scriptsig_len); - } else if (psbt->inputs[i].redeem_script) { - u8 *script; - - /* P2SH requires push of the redeemscript, from libwally src */ - script = tal_arr(tmpctx, u8, 0); - script_push_bytes(&script, - psbt->inputs[i].redeem_script, - psbt->inputs[i].redeem_script_len); - wally_tx_set_input_script(tx, i, script, tal_bytelen(script)); - } - } - tal_wally_end_onto(ctx, tx, struct wally_tx); - - wally_txid(tx, txid); if (wtx) *wtx = tx; else @@ -832,9 +813,9 @@ struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt) } for (size_t i = 0; i < psbt->num_outputs; i++) { - asset = wally_tx_output_get_amount(&psbt->tx->outputs[i]); + asset = wally_psbt_output_get_amount(&psbt->outputs[i]); if (!amount_asset_is_main(&asset) - || elements_wtx_output_is_fee(psbt->tx, i)) + || elements_psbt_output_is_fee(psbt, i)) continue; ok = amount_sat_sub(&fee, fee, amount_asset_to_sat(&asset)); @@ -844,3 +825,93 @@ struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt) return fee; } + +bool wally_psbt_input_spends(const struct wally_psbt_input *input, + const struct bitcoin_outpoint *outpoint) +{ + /* Useful, as tx_part can have some NULL inputs */ + if (!input) + return false; + BUILD_ASSERT(sizeof(outpoint->txid) == sizeof(input->txhash)); + if (input->index != outpoint->n) + return false; + if (memcmp(&outpoint->txid, input->txhash, sizeof(outpoint->txid)) != 0) + return false; + return true; +} + +void wally_psbt_input_get_outpoint(const struct wally_psbt_input *in, + struct bitcoin_outpoint *outpoint) +{ + BUILD_ASSERT(sizeof(struct bitcoin_txid) == sizeof(in->txhash)); + memcpy(&outpoint->txid, in->txhash, sizeof(struct bitcoin_txid)); + outpoint->n = in->index; +} + +const u8 *wally_psbt_output_get_script(const tal_t *ctx, + const struct wally_psbt_output *output) +{ + if (output->script == NULL) { + /* This can happen for coinbase transactions, pegin + * transactions, and elements fee outputs */ + return NULL; + } + + return tal_dup_arr(ctx, u8, output->script, output->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 +wally_psbt_output_get_amount(const struct wally_psbt_output *output) +{ + struct amount_asset amount; + size_t asset_out; + + if (chainparams->is_elements) { + if (wally_psbt_output_get_asset(output, amount.asset + 1, sizeof(amount.asset) - 1, &asset_out) != WALLY_OK) { + amount.value = 0; + return amount; + } + assert(asset_out == 32); + amount.asset[0] = 0x01; /* explicit */ + /* We currently only support explicit value + * asset tags, others are confidential, so + * don't even try to assign a value to it. */ + if (output->has_amount == true) { + amount.value = output->amount; + } else { + amount.value = 0; + } + } else { + /* Do not assign amount.asset, we should never touch it in + * non-elements scenarios. */ + if (output->has_amount) { + amount.value = output->amount; + } else { + abort(); + } + } + + return amount; +} + +bool elements_psbt_output_is_fee(const struct wally_psbt *psbt, size_t outnum) +{ + assert(outnum < psbt->num_outputs); + return chainparams->is_elements && + psbt->outputs[outnum].script_len == 0; +} + +bool psbt_set_version(struct wally_psbt *psbt, u32 version) +{ + bool ok; + + tal_wally_start(); + ok = wally_psbt_set_version(psbt, 0, version) == WALLY_OK; + if (ok && version == 2) { + ok &= wally_psbt_set_tx_modifiable_flags(psbt, WALLY_PSBT_TXMOD_INPUTS | WALLY_PSBT_TXMOD_OUTPUTS) == WALLY_OK; + } + tal_wally_end(psbt); + return ok; +} diff --git a/bitcoin/psbt.h b/bitcoin/psbt.h index 53ff1c4ce..18b0351da 100644 --- a/bitcoin/psbt.h +++ b/bitcoin/psbt.h @@ -29,7 +29,7 @@ struct wally_psbt *create_psbt(const tal_t *ctx, size_t num_inputs, size_t num_o /* * new_psbt - Create a PSBT, using the passed in tx - * as the global_tx + * as the locktime/inputs/output psbt fields * * @ctx - allocation context * @wtx - global_tx starter kit @@ -228,6 +228,33 @@ struct amount_sat psbt_compute_fee(const struct wally_psbt *psbt); bool psbt_has_input(const struct wally_psbt *psbt, const struct bitcoin_outpoint *outpoint); +/* wally_psbt_input_spends - Returns true if PSBT input spends given outpoint + * + * @input - psbt input + * @outpoint - outpoint + */ +bool wally_psbt_input_spends(const struct wally_psbt_input *input, + const struct bitcoin_outpoint *outpoint); + +void wally_psbt_input_get_outpoint(const struct wally_psbt_input *in, + struct bitcoin_outpoint *outpoint); + +const u8 *wally_psbt_output_get_script(const tal_t *ctx, + const struct wally_psbt_output *output); + +void wally_psbt_input_get_txid(const struct wally_psbt_input *in, + struct bitcoin_txid *txid); + +struct amount_asset +wally_psbt_output_get_amount(const struct wally_psbt_output *output); + +/* psbt_set_version - Returns false if there was any issue with the PSBT. + * Returns true if it was a well-formed PSET and treats it as a no-op + */ +bool psbt_set_version(struct wally_psbt *psbt, u32 version); + +bool elements_psbt_output_is_fee(const struct wally_psbt *psbt, size_t outnum); + struct wally_psbt *psbt_from_b64(const tal_t *ctx, const char *b64, size_t b64len); diff --git a/bitcoin/test/run-bitcoin_block_from_hex.c b/bitcoin/test/run-bitcoin_block_from_hex.c index 4c910f8b8..0e2eefa95 100644 --- a/bitcoin/test/run-bitcoin_block_from_hex.c +++ b/bitcoin/test/run-bitcoin_block_from_hex.c @@ -72,9 +72,6 @@ void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UN /* Generated stub for pubkey_to_hash160 */ void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) { fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } -/* Generated stub for script_push_bytes */ -void script_push_bytes(u8 **scriptp UNNEEDED, const void *mem UNNEEDED, size_t len UNNEEDED) -{ fprintf(stderr, "script_push_bytes called!\n"); abort(); } /* Generated stub for scriptpubkey_p2wsh */ u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); } diff --git a/bitcoin/test/run-psbt-from-tx.c b/bitcoin/test/run-psbt-from-tx.c index 5aefcb9ed..f05809728 100644 --- a/bitcoin/test/run-psbt-from-tx.c +++ b/bitcoin/test/run-psbt-from-tx.c @@ -53,9 +53,6 @@ void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UN /* Generated stub for pubkey_to_hash160 */ void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) { fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } -/* Generated stub for script_push_bytes */ -void script_push_bytes(u8 **scriptp UNNEEDED, const void *mem UNNEEDED, size_t len UNNEEDED) -{ fprintf(stderr, "script_push_bytes called!\n"); abort(); } /* Generated stub for scriptpubkey_p2wsh */ u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); } @@ -105,7 +102,8 @@ int main(int argc, char *argv[]) /* Witness/scriptsig data is saved down into psbt */ assert(tx2->psbt->num_inputs == 1); - assert(tx2->psbt->inputs[0].final_scriptsig_len > 0); + const struct wally_map_item *final_scriptsig = wally_map_get_integer(&tx2->psbt->inputs[0].psbt_fields, /* PSBT_IN_FINAL_SCRIPTSIG */ 0x07); + assert(final_scriptsig->value_len > 0); assert(tx2->psbt->inputs[0].final_witness != NULL); common_shutdown(); diff --git a/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c b/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c index b387279c2..05892c964 100644 --- a/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c +++ b/bitcoin/test/run-tx-bitcoin_tx_2of2_input_witness_weight.c @@ -81,10 +81,6 @@ struct wally_psbt_input *psbt_append_input(struct wally_psbt *psbt UNNEEDED, const u8 *input_wscript UNNEEDED, const u8 *redeemscript UNNEEDED) { fprintf(stderr, "psbt_append_input called!\n"); abort(); } -/* Generated stub for psbt_elements_input_set_asset */ -void psbt_elements_input_set_asset(struct wally_psbt *psbt UNNEEDED, size_t in UNNEEDED, - struct amount_asset *asset UNNEEDED) -{ fprintf(stderr, "psbt_elements_input_set_asset called!\n"); abort(); } /* Generated stub for psbt_final_tx */ struct wally_tx *psbt_final_tx(const tal_t *ctx UNNEEDED, const struct wally_psbt *psbt UNNEEDED) { fprintf(stderr, "psbt_final_tx called!\n"); abort(); } diff --git a/bitcoin/test/run-tx-encode.c b/bitcoin/test/run-tx-encode.c index e84b4e5a0..aecd28ab2 100644 --- a/bitcoin/test/run-tx-encode.c +++ b/bitcoin/test/run-tx-encode.c @@ -73,9 +73,6 @@ void pubkey_to_der(u8 der[PUBKEY_CMPR_LEN] UNNEEDED, const struct pubkey *key UN /* Generated stub for pubkey_to_hash160 */ void pubkey_to_hash160(const struct pubkey *pk UNNEEDED, struct ripemd160 *hash UNNEEDED) { fprintf(stderr, "pubkey_to_hash160 called!\n"); abort(); } -/* Generated stub for script_push_bytes */ -void script_push_bytes(u8 **scriptp UNNEEDED, const void *mem UNNEEDED, size_t len UNNEEDED) -{ fprintf(stderr, "script_push_bytes called!\n"); abort(); } /* Generated stub for scriptpubkey_p2wsh */ u8 *scriptpubkey_p2wsh(const tal_t *ctx UNNEEDED, const u8 *witnessscript UNNEEDED) { fprintf(stderr, "scriptpubkey_p2wsh called!\n"); abort(); } diff --git a/bitcoin/tx.c b/bitcoin/tx.c index 7d575196c..951798234 100644 --- a/bitcoin/tx.c +++ b/bitcoin/tx.c @@ -180,7 +180,36 @@ static int elements_tx_add_fee_output(struct bitcoin_tx *tx) void bitcoin_tx_set_locktime(struct bitcoin_tx *tx, u32 locktime) { tx->wtx->locktime = locktime; - tx->psbt->tx->locktime = locktime; + tx->psbt->fallback_locktime = locktime; + tx->psbt->has_fallback_locktime = true; +} + +/* FIXME Stolen from psbt_append_input; export? */ +static struct wally_tx_input *wally_tx_input_from_outpoint_sequence(const struct bitcoin_outpoint *outpoint, + u32 sequence) +{ + struct wally_tx_input *tx_in; + if (chainparams->is_elements) { + if (wally_tx_elements_input_init_alloc(outpoint->txid.shad.sha.u.u8, + sizeof(outpoint->txid.shad.sha.u.u8), + outpoint->n, + sequence, NULL, 0, + NULL, + NULL, 0, + NULL, 0, NULL, 0, + NULL, 0, NULL, 0, + NULL, 0, NULL, + &tx_in) != WALLY_OK) + abort(); + } else { + if (wally_tx_input_init_alloc(outpoint->txid.shad.sha.u.u8, + sizeof(outpoint->txid.shad.sha.u.u8), + outpoint->n, + sequence, NULL, 0, NULL, + &tx_in) != WALLY_OK) + abort(); + } + return tx_in; } int bitcoin_tx_add_input(struct bitcoin_tx *tx, @@ -191,6 +220,7 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, { int wally_err; int input_num = tx->wtx->num_inputs; + struct wally_tx_input *tx_input; psbt_append_input(tx->psbt, outpoint, sequence, scriptSig, @@ -205,9 +235,11 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, scriptPubkey, amount); tal_wally_start(); + tx_input = wally_tx_input_from_outpoint_sequence(outpoint, sequence); wally_err = wally_tx_add_input(tx->wtx, - &tx->psbt->tx->inputs[input_num]); + tx_input); assert(wally_err == WALLY_OK); + wally_tx_input_free(tx_input); /* scriptsig isn't actually stored in psbt input, so add that now */ wally_tx_set_input_script(tx->wtx, input_num, @@ -215,12 +247,10 @@ int bitcoin_tx_add_input(struct bitcoin_tx *tx, tal_wally_end(tx->wtx); if (is_elements(chainparams)) { - struct amount_asset asset; /* FIXME: persist asset tags */ - asset = amount_sat_to_asset(&amount, + amount_sat_to_asset(&amount, chainparams->fee_asset_tag); /* FIXME: persist nonces */ - psbt_elements_input_set_asset(tx->psbt, input_num, &asset); } return input_num; } @@ -258,10 +288,6 @@ void bitcoin_tx_output_set_amount(struct bitcoin_tx *tx, int outnum, assert(ret == WALLY_OK); } else { output->satoshi = satoshis; - - /* update the global tx for the psbt also */ - output = &tx->psbt->tx->outputs[outnum]; - output->satoshi = satoshis; } } @@ -291,14 +317,16 @@ u8 *bitcoin_tx_output_get_witscript(const tal_t *ctx, const struct bitcoin_tx *t int outnum) { struct wally_psbt_output *out; + const struct wally_map_item *output_witness_script; assert(outnum < tx->psbt->num_outputs); out = &tx->psbt->outputs[outnum]; - if (out->witness_script_len == 0) + output_witness_script = wally_map_get_integer(&out->psbt_fields, /* PSBT_OUT_WITNESS_SCRIPT */ 0x01); + if (output_witness_script->value_len == 0) return NULL; - return tal_dup_arr(ctx, u8, out->witness_script, out->witness_script_len, 0); + return tal_dup_arr(ctx, u8, output_witness_script->value, output_witness_script->value_len, 0); } struct amount_asset bitcoin_tx_output_get_amount(const struct bitcoin_tx *tx, @@ -536,18 +564,21 @@ void bitcoin_tx_finalize(struct bitcoin_tx *tx) struct bitcoin_tx *bitcoin_tx_with_psbt(const tal_t *ctx, struct wally_psbt *psbt STEALS) { + size_t locktime; + wally_psbt_get_locktime(psbt, &locktime); struct bitcoin_tx *tx = bitcoin_tx(ctx, chainparams, - psbt->tx->num_inputs, - psbt->tx->num_outputs, - psbt->tx->locktime); + psbt->num_inputs, + psbt->num_outputs, + locktime); wally_tx_free(tx->wtx); psbt_finalize(psbt); tx->wtx = psbt_final_tx(tx, psbt); if (!tx->wtx) { tal_wally_start(); - if (wally_tx_clone_alloc(psbt->tx, 0, &tx->wtx) != WALLY_OK) + if (wally_psbt_extract(psbt, WALLY_PSBT_EXTRACT_NON_FINAL, &tx->wtx) != WALLY_OK) { tx->wtx = NULL; + } tal_wally_end_onto(tx, tx->wtx, struct wally_tx); if (!tx->wtx) return tal_free(tx); diff --git a/common/permute_tx.c b/common/permute_tx.c index 75fdf6140..ab76e3106 100644 --- a/common/permute_tx.c +++ b/common/permute_tx.c @@ -3,7 +3,6 @@ #include static void swap_wally_outputs(struct wally_tx_output *outputs, - struct wally_tx_output *psbt_global_outs, struct wally_psbt_output *psbt_outs, const void **map, u32 *cltvs, size_t i1, size_t i2) @@ -18,12 +17,6 @@ static void swap_wally_outputs(struct wally_tx_output *outputs, outputs[i1] = outputs[i2]; outputs[i2] = tmpoutput; - /* For the PSBT, we swap the psbt outputs and - * the global tx's outputs */ - tmpoutput = psbt_global_outs[i1]; - psbt_global_outs[i1] = psbt_global_outs[i2]; - psbt_global_outs[i2] = tmpoutput; - tmppsbtout = psbt_outs[i1]; psbt_outs[i1] = psbt_outs[i2]; psbt_outs[i2] = tmppsbtout; @@ -106,7 +99,6 @@ void permute_outputs(struct bitcoin_tx *tx, u32 *cltvs, const void **map) /* Swap best into first place. */ swap_wally_outputs(tx->wtx->outputs, - tx->psbt->tx->outputs, tx->psbt->outputs, map, cltvs, i, best_pos); } diff --git a/common/psbt_internal.c b/common/psbt_internal.c index bc7ca0a9c..475b4cabc 100644 --- a/common/psbt_internal.c +++ b/common/psbt_internal.c @@ -26,6 +26,7 @@ void psbt_finalize_input(const tal_t *ctx, struct wally_psbt_input *in, const struct witness_element **elements) { + const struct wally_map_item *redeem_script; psbt_input_set_final_witness_stack(ctx, in, elements); /* There's this horrible edgecase where we set the final_witnesses @@ -35,18 +36,16 @@ void psbt_finalize_input(const tal_t *ctx, * on these just .. ignores it!? Murder. Anyway, here we do a final * scriptsig check -- if there's a redeemscript field still around we * just go ahead and mush it into the final_scriptsig field. */ - if (in->redeem_script) { + redeem_script = wally_map_get_integer(&in->psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04); + if (redeem_script) { u8 *redeemscript = tal_dup_arr(NULL, u8, - in->redeem_script, - in->redeem_script_len, 0); - in->final_scriptsig = + redeem_script->value, + redeem_script->value_len, 0); + u8 *final_scriptsig = bitcoin_scriptsig_redeem(NULL, take(redeemscript)); - in->final_scriptsig_len = - tal_bytelen(in->final_scriptsig); - - in->redeem_script = tal_free(in->redeem_script); - in->redeem_script_len = 0; + wally_psbt_input_set_final_scriptsig(in, final_scriptsig, tal_bytelen(final_scriptsig)); + wally_psbt_input_set_redeem_script(in, tal_arr(NULL, u8, 0), 0); } } diff --git a/common/psbt_keypath.c b/common/psbt_keypath.c index 5037a0a40..f163614e4 100644 --- a/common/psbt_keypath.c +++ b/common/psbt_keypath.c @@ -14,7 +14,7 @@ void psbt_set_keypath(u32 index, const struct ext_key *ext, struct wally_map *ma u32 path[1]; path[0] = index; - if (wally_map_add_keypath_item(map_in, + if (wally_map_keypath_add(map_in, ext->pub_key, sizeof(ext->pub_key), fingerprint, sizeof(fingerprint), path, 1) != WALLY_OK) diff --git a/common/psbt_open.c b/common/psbt_open.c index 646b4ea02..80cbe7fb4 100644 --- a/common/psbt_open.c +++ b/common/psbt_open.c @@ -58,17 +58,11 @@ static int compare_outputs_at(const struct output_set *a, } static const u8 *linearize_input(const tal_t *ctx, - const struct wally_psbt_input *in, - const struct wally_tx_input *tx_in) + const struct wally_psbt_input *in) { struct wally_psbt *psbt = create_psbt(NULL, 1, 0, 0); size_t byte_len; - tal_wally_start(); - if (wally_tx_add_input(psbt->tx, tx_in) != WALLY_OK) - abort(); - tal_wally_end(psbt->tx); - psbt->inputs[0] = *in; psbt->num_inputs++; @@ -77,11 +71,10 @@ static const u8 *linearize_input(const tal_t *ctx, wally_map_sort(&psbt->inputs[0].unknowns, 0); /* signatures, keypaths, etc - we dont care if they change */ - psbt->inputs[0].final_witness = NULL; - psbt->inputs[0].final_scriptsig_len = 0; - psbt->inputs[0].witness_script = NULL; - psbt->inputs[0].witness_script_len = 0; - psbt->inputs[0].redeem_script_len = 0; + wally_psbt_input_set_final_witness(&psbt->inputs[0], NULL); + wally_psbt_input_set_final_scriptsig(&psbt->inputs[0], NULL, 0); + wally_psbt_input_set_witness_script(&psbt->inputs[0], NULL, 0); + wally_psbt_input_set_redeem_script(&psbt->inputs[0], NULL, 0); psbt->inputs[0].keypaths.num_items = 0; psbt->inputs[0].signatures.num_items = 0; @@ -94,22 +87,16 @@ static const u8 *linearize_input(const tal_t *ctx, } static const u8 *linearize_output(const tal_t *ctx, - const struct wally_psbt_output *out, - const struct wally_tx_output *tx_out) + const struct wally_psbt_output *out) { struct wally_psbt *psbt = create_psbt(NULL, 1, 1, 0); size_t byte_len; struct bitcoin_outpoint outpoint; - /* Add a 'fake' input so this will linearize the tx */ - memset(&outpoint, 0, sizeof(outpoint)); + /* Add a 'fake' non-zero input so libwally will agree to linearize the tx */ + memset(&outpoint, 1, sizeof(outpoint)); psbt_append_input(psbt, &outpoint, 0, NULL, NULL, NULL); - tal_wally_start(); - if (wally_tx_add_output(psbt->tx, tx_out) != WALLY_OK) - abort(); - tal_wally_end(psbt->tx); - psbt->outputs[0] = *out; psbt->num_outputs++; /* Sort the outputs, so serializing them is ok */ @@ -118,8 +105,8 @@ static const u8 *linearize_output(const tal_t *ctx, /* We don't care if the keypaths change */ psbt->outputs[0].keypaths.num_items = 0; /* And you can add scripts, no problem */ - psbt->outputs[0].witness_script_len = 0; - psbt->outputs[0].redeem_script_len = 0; + wally_psbt_output_set_witness_script(&psbt->outputs[0], NULL, 0); + wally_psbt_output_set_redeem_script(&psbt->outputs[0], NULL, 0); const u8 *bytes = psbt_get_bytes(ctx, psbt, &byte_len); @@ -135,11 +122,9 @@ static bool input_identical(const struct wally_psbt *a, size_t b_index) { const u8 *a_in = linearize_input(tmpctx, - &a->inputs[a_index], - &a->tx->inputs[a_index]); + &a->inputs[a_index]); const u8 *b_in = linearize_input(tmpctx, - &b->inputs[b_index], - &b->tx->inputs[b_index]); + &b->inputs[b_index]); return memeq(a_in, tal_bytelen(a_in), b_in, tal_bytelen(b_in)); @@ -151,11 +136,9 @@ static bool output_identical(const struct wally_psbt *a, size_t b_index) { const u8 *a_out = linearize_output(tmpctx, - &a->outputs[a_index], - &a->tx->outputs[a_index]); + &a->outputs[a_index]); const u8 *b_out = linearize_output(tmpctx, - &b->outputs[b_index], - &b->tx->outputs[b_index]); + &b->outputs[b_index]); return memeq(a_out, tal_bytelen(a_out), b_out, tal_bytelen(b_out)); } @@ -168,7 +151,6 @@ static void sort_inputs(struct wally_psbt *psbt) psbt->num_inputs); for (size_t i = 0; i < tal_count(set); i++) { - set[i].tx_input = psbt->tx->inputs[i]; set[i].input = psbt->inputs[i]; } @@ -178,7 +160,6 @@ static void sort_inputs(struct wally_psbt *psbt) /* Put PSBT parts into place */ for (size_t i = 0; i < tal_count(set); i++) { psbt->inputs[i] = set[i].input; - psbt->tx->inputs[i] = set[i].tx_input; } tal_free(set); @@ -191,7 +172,6 @@ static void sort_outputs(struct wally_psbt *psbt) struct output_set, psbt->num_outputs); for (size_t i = 0; i < tal_count(set); i++) { - set[i].tx_output = psbt->tx->outputs[i]; set[i].output = psbt->outputs[i]; } @@ -201,7 +181,6 @@ static void sort_outputs(struct wally_psbt *psbt) /* Put PSBT parts into place */ for (size_t i = 0; i < tal_count(set); i++) { psbt->outputs[i] = set[i].output; - psbt->tx->outputs[i] = set[i].tx_output; } tal_free(set); @@ -217,7 +196,6 @@ void psbt_sort_by_serial_id(struct wally_psbt *psbt) do { \ struct type##_set a; \ a.type = from->type##s[index]; \ - a.tx_##type = from->tx->type##s[index]; \ a.idx = index; \ tal_arr_expand(&add_to, a); \ } while (0) @@ -398,6 +376,7 @@ bool psbt_has_required_fields(struct wally_psbt *psbt) { u64 serial_id; for (size_t i = 0; i < psbt->num_inputs; i++) { + const struct wally_map_item *redeem_script; struct wally_psbt_input *input = &psbt->inputs[i]; if (!psbt_get_serial_id(&input->unknowns, &serial_id)) @@ -408,13 +387,13 @@ bool psbt_has_required_fields(struct wally_psbt *psbt) return false; /* If is P2SH, redeemscript must be present */ - assert(psbt->tx->inputs[i].index < input->utxo->num_outputs); + assert(psbt->inputs[i].index < input->utxo->num_outputs); const u8 *outscript = wally_tx_output_get_script(tmpctx, - &input->utxo->outputs[psbt->tx->inputs[i].index]); - if (is_p2sh(outscript, NULL) && input->redeem_script_len == 0) + &input->utxo->outputs[psbt->inputs[i].index]); + redeem_script = wally_map_get_integer(&psbt->inputs[i].psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04); + if (is_p2sh(outscript, NULL) && (!redeem_script || redeem_script->value_len == 0)) return false; - } for (size_t i = 0; i < psbt->num_outputs; i++) { @@ -511,6 +490,8 @@ bool psbt_output_to_external(const struct wally_psbt_output *output) bool psbt_contribs_changed(struct wally_psbt *orig, struct wally_psbt *new) { + assert(orig->version == 2 && new->version == 2); + struct psbt_changeset *cs; bool ok; cs = psbt_get_changeset(NULL, orig, new); diff --git a/common/psbt_open.h b/common/psbt_open.h index 134a5da65..be3c4995b 100644 --- a/common/psbt_open.h +++ b/common/psbt_open.h @@ -15,14 +15,12 @@ struct wally_psbt_output; struct wally_map; struct input_set { - struct wally_tx_input tx_input; struct wally_psbt_input input; /* index on PSBT of this input */ size_t idx; }; struct output_set { - struct wally_tx_output tx_output; struct wally_psbt_output output; /* index on PSBT of this output */ size_t idx; diff --git a/common/test/run-psbt_diff.c b/common/test/run-psbt_diff.c index 4c8ff0587..37f4fdf49 100644 --- a/common/test/run-psbt_diff.c +++ b/common/test/run-psbt_diff.c @@ -132,6 +132,19 @@ static void check_psbt_comparison(void) struct wally_psbt *newpsbt = psbt_from_b64(tmpctx, "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", strlen("cHNidP8BAO4CAAAAAzN5VhNaE8Vcck3HxVgzwzZ222MTllIAnbHt0n14wqK3AwAAAAABAAAAA6eMOG9Offcfn4WU8H2d0Z6kxU7rcAqvyvtranQVGTwAAAAAAP3///90da/+7PPocKC7hy/NS8LJl91lxs8w0QDITv4yiUOK2wAAAAAA/f///wOMnh4AAAAAACIAIHbV3spzDYJViRvskhH+rV1dx9dvac3CR5/iDdsa1rOBSP4OAAAAAAAWABRrnRZ3l/w3gUj80T2t5objcD9W0O7mfAAAAAAAFgAUtmotjMoZeRMsAbICfElGqwiW3UocpwoAAAEA/bsBAgAAAAABAXPfLv55YUFV5bYj2nW0Qg21s+wun9ml6OSboVUZk2wLAAAAAABatvuABEoBAAAAAAAAIgAgcvZQbEPQgaQZheQRE2h0qKIYGEvEnR8AMgqGtqkMQ0JKAQAAAAAAACIAIPKe3p1VfFQC7ANr0L8T5jqBNZiRsy1otltPruOm62IUYcYCAAAAAAAiACCvU6YsJg1wnAODdsViE6KHEB7x8larBFmohA/vXE5ynYAsAwAAAAAAIgAgH/GZYEVN/fM86vqoSYtZ1PxX4cQVPG9HVTOA6qA/UkkEAEcwRAIgI5QU3lRHdW78aZwx4QptrEtqcx7bOcVBU+6j636qYG0CIHJnhPaHlHVjUI88gFWlFM957z/5JCSYWxJacc4w5C4rAUcwRAIgGc5N3cKTLBY4gZrZDZQa+mxGGDlKWRNkcwu70AOrO2oCIH1KSDAF8EhRXCVPAXJ15naYm34QdL3cP/ZGvFO0HYqYAUdSIQIxs+uJrVTubrGY2Jfk4utUK+VWAvMEyP78BtPi4yRXFyECa/fDQc/qrr4ySj2F8lKL/QTmVYx8pmYpd8Sz1NSqbMtSroDGayABASuALAMAAAAAACIAIB/xmWBFTf3zPOr6qEmLWdT8V+HEFTxvR1UzgOqgP1JJIgIDpG3E4i4cEZ7J8ZlaNfLkz1WD15BDXHpHcPkE3lrLi/lHMEQCIC4j5ihiNgV2oU9YlBLykbhO46/j8Z8eAsmp2HtP7YlpAiAKzgD7NY/OT6JP4dit5sjOnuYtzh0nm5DXO05SFloTmAEBBSUhA6RtxOIuHBGeyfGZWjXy5M9Vg9eQQ1x6R3D5BN5ay4v5rVGyIgYDpG3E4i4cEZ7J8ZlaNfLkz1WD15BDXHpHcPkE3lrLi/kI7QmAqwAAAAAM/AlsaWdodG5pbmcBCAU2hruIvIHrDPwJbGlnaHRuaW5nAgIAAQABAP0qAQEAAAAAAQH/0h9RflGgWKtkgrf56Lvb0rUobrhIOhTwcM+NmIkNKQAAAAAA/////wEuWx4AAAAAABYAFKHoOpmce16DZrQEZH7V+JP+/y6sA0gwRQIhAI+LLQh/G/oNRqePyb0R6yhfSEc/yP0V6Cti/1kkK/PwAiBdvSa2uLgDW2XbwXvAVzBxFVZrLNxybntS2lyz+euiywEgWV6uBVDCzxkOUZ98rnVFC79uPiakDUAnOQrSkX5JPUxqggEgh2OpFG0bRi0KpOvy3VBKHBhCgHtCD9daiCECMy6tBttEFqwwYKNj2B8rTGlArAak70ptIeVDA2r6LydndQNhogqxdSEC7jd/4xMMFEl0hPMVqO8Q45Ji78odoDYvqCttkPvZt6dorAAAAAAM/AlsaWdodG5pbmcBCH87vQhiysC4AAEA/Z0BAgAAAAABAvB6IVCYPv0ng28Boi5DWjT8Iu+7VnivjfxNpPrG73OrAQAAAAD9////fA9s+2Srlzm17DlKwhRh+6gPKnM8629vAxtVZCnVIrIAAAAAAP3///8DWP2IAAAAAAAWABTLOlJDpOxjeEEODHpxxWqyUCXBOpq2LQAAAAAAFgAU99rC3PzJ7JF47Zkz6pjOAFPSWtX4jB4AAAAAACIAIMhDUyNE62r0XElEok1XhBe39KGewKnw2wdQKSoUfYjKAkcwRAIgd9pEPhXZypnSOkAyKtXC/CdNamQ/qkXXxDYUnK7VjyACIGJORtWT1YVHfVJ3mMkOAPub/mb+ZWZjyWRP/cdJSOgoASEDp6bb50UoFqPN0UrAPzGb+B2kN/WjZ6h8gYpgCvWP/rMCRzBEAiAizM/eUhu2VLPbj490jkVL8zQoHkhD8ifUGdJ6pncoMQIgPI7IRfhxNrO3OfD5IEDkf1YpZTS/PrJzXsWiuzZ79T4BIQLuiWdS530flKFu+ZEnDssecpFTobBG2q0Er08sG9CGK1ieCgABAR9Y/YgAAAAAABYAFMs6UkOk7GN4QQ4MenHFarJQJcE6IgIDgqd2l8O+iYomobEnbUm/SkF77ModebdszzhKrQdoO81HMEQCIGMYEyX9E2lKN9ZGErPLT7rLUT6jiMavmf9KvVGyQhKzAiBl3tkmpLT3aBA/bHiWBp30kIH/MZEUVlJ2FjK8Qxf03AEiBgOCp3aXw76JiiahsSdtSb9KQXvsyh15t2zPOEqtB2g7zQjLOlJDAAAAAAz8CWxpZ2h0bmluZwEIyr1nYR+yWpMM/AlsaWdodG5pbmcCAgABAAz8CWxpZ2h0bmluZwEIPmp7W2cbgzQADPwJbGlnaHRuaW5nAQhfGBujAwg9RgAM/AlsaWdodG5pbmcBCLlmPrAtodZRAA==")); + /* Round-trip versioning of both PSBTs as belt and suspender check */ + tal_wally_start(); + wally_psbt_set_version(oldpsbt, 0 /* flags */, 2); + wally_psbt_set_version(oldpsbt, 0 /* flags */, 0); + wally_psbt_set_version(oldpsbt, 0 /* flags */, 2); + tal_wally_end(oldpsbt); + + tal_wally_start(); + wally_psbt_set_version(newpsbt, 0 /* flags */, 2); + wally_psbt_set_version(newpsbt, 0 /* flags */, 0); + wally_psbt_set_version(newpsbt, 0 /* flags */, 2); + tal_wally_end(newpsbt); + assert(!psbt_contribs_changed(oldpsbt, newpsbt)); } diff --git a/external/libwally-core b/external/libwally-core index d839dbab4..23e6b626c 160000 --- a/external/libwally-core +++ b/external/libwally-core @@ -1 +1 @@ -Subproject commit d839dbab4279e1d3d1ece4e52d4766f523b3f7ee +Subproject commit 23e6b626c8906bce2e3179409b938c9ef9bca463 diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index 0ba4c87ec..557fb414f 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -466,7 +466,7 @@ static void sign_our_inputs(struct utxo **utxos, struct wally_psbt *psbt) struct privkey privkey; struct pubkey pubkey; - if (!wally_tx_input_spends(&psbt->tx->inputs[j], + if (!wally_psbt_input_spends(&psbt->inputs[j], &utxo->outpoint)) continue; diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index d38a3f9c9..faebf7b33 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -2180,11 +2180,11 @@ static void handle_validate_rbf(struct subd *dualopend, list_for_each(&channel->inflights, inflight, list) { /* Remove every non-matching input from set */ for (size_t i = 0; i < candidate_psbt->num_inputs; i++) { - struct wally_tx_input *input = - &candidate_psbt->tx->inputs[i]; + const struct wally_psbt_input *input = + &candidate_psbt->inputs[i]; struct bitcoin_outpoint outpoint; - wally_tx_input_get_outpoint(input, &outpoint); + wally_psbt_input_get_outpoint(input, &outpoint); if (!psbt_has_input(inflight->funding_psbt, &outpoint)) @@ -2793,6 +2793,11 @@ static struct command_result *json_openchannel_init(struct command *cmd, NULL)) return command_param_failed(); + /* We only deal in v2 */ + if (!psbt_set_version(psbt, 2)) { + return command_fail(cmd, LIGHTNINGD, "Could not set PSBT version."); + } + /* Gotta expect some rates ! */ if (!amount_sat_zero(*request_amt) && !rates) return command_fail(cmd, JSONRPC2_INVALID_PARAMS, diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 68a3b3037..7156d5f62 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1009,10 +1009,15 @@ static struct command_result *json_fundchannel_complete(struct command *cmd, fc = peer->uncommitted_channel->fc; + /* We only deal with V2 internally */ + if (!psbt_set_version(funding_psbt, 2)) { + return command_fail(cmd, LIGHTNINGD, "Could not set PSBT version."); + } + /* Figure out the correct output, and perform sanity checks. */ - for (size_t i = 0; i < funding_psbt->tx->num_outputs; i++) { - if (memeq(funding_psbt->tx->outputs[i].script, - funding_psbt->tx->outputs[i].script_len, + for (size_t i = 0; i < funding_psbt->num_outputs; i++) { + if (memeq(funding_psbt->outputs[i].script, + funding_psbt->outputs[i].script_len, fc->funding_scriptpubkey, tal_bytelen(fc->funding_scriptpubkey))) { if (funding_txout_num) @@ -1028,14 +1033,14 @@ static struct command_result *json_fundchannel_complete(struct command *cmd, /* Can't really check amounts for elements. */ if (!chainparams->is_elements - && !amount_sat_eq(amount_sat(funding_psbt->tx->outputs - [*funding_txout_num].satoshi), + && !amount_sat_eq(amount_sat(funding_psbt->outputs + [*funding_txout_num].amount), fc->funding_sats)) return command_fail(cmd, FUNDING_PSBT_INVALID, "Output to open channel is %"PRIu64"sat," " should be %s", - funding_psbt->tx->outputs - [*funding_txout_num].satoshi, + funding_psbt->outputs + [*funding_txout_num].amount, type_to_string(tmpctx, struct amount_sat, &fc->funding_sats)); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 7ab13ba3f..71c15a8f2 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1891,6 +1891,8 @@ void channel_watch_wrong_funding(struct lightningd *ld, struct channel *channel) void channel_watch_funding(struct lightningd *ld, struct channel *channel) { /* FIXME: Remove arg from cb? */ + log_debug(channel->log, "Watching for funding txid: %s", + type_to_string(tmpctx, struct bitcoin_txid, &channel->funding.txid)); watch_txid(channel, ld->topology, channel, &channel->funding.txid, funding_depth_cb); watch_txo(channel, ld->topology, channel, diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 4f46b6d02..5375331aa 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -250,8 +250,8 @@ static u8 *psbt_changeset_get_next(const tal_t *ctx, in->input.utxo); msg = towire_tx_add_input(ctx, cid, serial_id, - prevtx, in->tx_input.index, - in->tx_input.sequence); + prevtx, in->input.index, + in->input.sequence); tal_arr_remove(&set->added_ins, 0); return msg; @@ -274,10 +274,11 @@ static u8 *psbt_changeset_get_next(const tal_t *ctx, if (!psbt_get_serial_id(&out->output.unknowns, &serial_id)) abort(); - asset_amt = wally_tx_output_get_amount(&out->tx_output); + asset_amt = wally_psbt_output_get_amount(&out->output); sats = amount_asset_to_sat(&asset_amt); - const u8 *script = wally_tx_output_get_script(ctx, - &out->tx_output); + const u8 *script = wally_psbt_output_get_script(ctx, + &out->output); + msg = towire_tx_add_output(ctx, cid, serial_id, sats.satoshis, /* Raw: wire interface */ @@ -596,12 +597,20 @@ static size_t psbt_input_weight(struct wally_psbt *psbt, size_t in) { size_t weight; + const struct wally_map_item *redeem_script; + + redeem_script = wally_map_get_integer(&psbt->inputs[in].psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04); /* txid + txout + sequence */ weight = (32 + 4 + 4) * 4; - weight += - (psbt->inputs[in].redeem_script_len + - (varint_t) varint_size(psbt->inputs[in].redeem_script_len)) * 4; + if (redeem_script) { + weight += + (redeem_script->value_len + + (varint_t) varint_size(redeem_script->value_len)) * 4; + } else { + /* zero scriptSig length */ + weight += (varint_t) varint_size(0) * 4; + } return weight; } @@ -609,15 +618,15 @@ static size_t psbt_input_weight(struct wally_psbt *psbt, static size_t psbt_output_weight(struct wally_psbt *psbt, size_t outnum) { - return (8 + psbt->tx->outputs[outnum].script_len + - varint_size(psbt->tx->outputs[outnum].script_len)) * 4; + return (8 + psbt->outputs[outnum].script_len + + varint_size(psbt->outputs[outnum].script_len)) * 4; } static bool find_txout(struct wally_psbt *psbt, const u8 *wscript, u32 *funding_txout) { for (size_t i = 0; i < psbt->num_outputs; i++) { - if (memeq(wscript, tal_bytelen(wscript), psbt->tx->outputs[i].script, - psbt->tx->outputs[i].script_len)) { + if (memeq(wscript, tal_bytelen(wscript), psbt->outputs[i].script, + psbt->outputs[i].script_len)) { *funding_txout = i; return true; } @@ -2382,9 +2391,17 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) if (!tx_state->psbt) tx_state->psbt = create_psbt(tx_state, 0, 0, tx_state->tx_locktime); - else + else { /* Locktimes must match! */ - tx_state->psbt->tx->locktime = tx_state->tx_locktime; + tx_state->psbt->fallback_locktime = tx_state->tx_locktime; + if (!psbt_set_version(tx_state->psbt, 2)) { + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Could not set PSBT version: %s", + type_to_string(tmpctx, + struct wally_psbt, + tx_state->psbt)); + } + } /* BOLT- #2: * @@ -2914,6 +2931,7 @@ static void opener_start(struct state *state, u8 *msg) struct lease_rates *expected_rates; struct tx_state *tx_state = state->tx_state; struct amount_sat *requested_lease; + size_t locktime; if (!fromwire_dualopend_opener_init(state, msg, &tx_state->psbt, @@ -2930,8 +2948,8 @@ static void opener_start(struct state *state, u8 *msg) master_badmsg(WIRE_DUALOPEND_OPENER_INIT, msg); state->our_role = TX_INITIATOR; - tx_state->tx_locktime = tx_state->psbt->tx->locktime; - + wally_psbt_get_locktime(tx_state->psbt, &locktime); + tx_state->tx_locktime = locktime; open_tlv = tlv_opening_tlvs_new(tmpctx); /* BOLT #2: @@ -3456,6 +3474,7 @@ static void rbf_local_start(struct state *state, u8 *msg) /* tmpctx gets cleaned midway, so we have a context for this fn */ char *rbf_ctx = notleak_with_children(tal(state, char)); + size_t locktime; /* We need a new tx_state! */ tx_state = new_tx_state(rbf_ctx); @@ -3490,8 +3509,8 @@ static void rbf_local_start(struct state *state, u8 *msg) return; } - tx_state->tx_locktime = tx_state->psbt->tx->locktime; - + wally_psbt_get_locktime(tx_state->psbt, &locktime); + tx_state->tx_locktime = locktime; /* For now, we always just echo/send the funding amount */ init_rbf_tlvs->funding_output_contribution = tal(init_rbf_tlvs, u64); diff --git a/plugins/funder.c b/plugins/funder.c index 877c5a08e..dc09e310f 100644 --- a/plugins/funder.c +++ b/plugins/funder.c @@ -5,6 +5,7 @@ */ #include "config.h" #include +#include #include #include #include @@ -212,14 +213,14 @@ remember_channel_utxos(struct command *cmd, signed_psbt); utxos_bin = tal_arr(cmd, u8, 0); - for (size_t i = 0; i < signed_psbt->tx->num_inputs; i++) { + for (size_t i = 0; i < signed_psbt->num_inputs; i++) { struct bitcoin_outpoint outpoint; /* Don't save peer's UTXOS */ if (!psbt_input_is_ours(&signed_psbt->inputs[i])) continue; - wally_tx_input_get_outpoint(&signed_psbt->tx->inputs[i], + wally_psbt_input_get_outpoint(&signed_psbt->inputs[i], &outpoint); towire_bitcoin_outpoint(&utxos_bin, &outpoint); } diff --git a/plugins/spender/multifundchannel.c b/plugins/spender/multifundchannel.c index 28a578c07..38c836f53 100644 --- a/plugins/spender/multifundchannel.c +++ b/plugins/spender/multifundchannel.c @@ -572,6 +572,14 @@ after_signpsbt(struct command *cmd, json_tok_full_len(field), json_tok_full(buf, field)); + if (!psbt_set_version(psbt, 2)) { + /* It should be well-formed? */ + plugin_err(mfc->cmd->plugin, + "mfc: could not set PSBT version: %s", + type_to_string(tmpctx, struct wally_psbt, + mfc->psbt)); + } + if (!psbt_finalize(psbt)) plugin_err(mfc->cmd->plugin, "mfc %"PRIu64": Signed PSBT won't finalize" @@ -831,11 +839,21 @@ perform_funding_tx_finalize(struct multifundchannel_command *mfc) size_t v1_dest_count = dest_count(mfc, FUND_CHANNEL); size_t v2_dest_count = dest_count(mfc, OPEN_CHANNEL); size_t i, deck_i; + u32 psbt_version = mfc->psbt->version; plugin_log(mfc->cmd->plugin, LOG_DBG, "mfc %"PRIu64": Creating funding tx.", mfc->id); + /* We operate over PSBTv2 only */ + if (!psbt_set_version(mfc->psbt, 2)) { + /* It should be well-formed? */ + plugin_err(mfc->cmd->plugin, + "mfc: could not set PSBT version: %s", + type_to_string(tmpctx, struct wally_psbt, + mfc->psbt)); + } + /* Construct a deck of destinations. */ deck = tal_arr(tmpctx, struct multifundchannel_destination *, v1_dest_count + mfc->change_needed); @@ -929,6 +947,14 @@ perform_funding_tx_finalize(struct multifundchannel_command *mfc) mfc->txid), content); + if (!psbt_set_version(mfc->psbt, psbt_version)) { + /* It should be well-formed? */ + plugin_err(mfc->cmd->plugin, + "mfc: could not set PSBT version: %s", + type_to_string(tmpctx, struct wally_psbt, + mfc->psbt)); + } + /* Now we can feed the TXID and outnums to the peer. */ return perform_fundchannel_complete(mfc); } @@ -1343,6 +1369,9 @@ after_fundpsbt(struct command *cmd, if (!mfc->psbt) goto fail; + if (!psbt_set_version(mfc->psbt, 2)) + goto fail; + field = json_get_member(buf, result, "feerate_per_kw"); if (!field || !json_to_u32(buf, field, &mfc->feerate_per_kw)) goto fail; diff --git a/plugins/spender/multiwithdraw.c b/plugins/spender/multiwithdraw.c index 9eb93c30e..d0f864077 100644 --- a/plugins/spender/multiwithdraw.c +++ b/plugins/spender/multiwithdraw.c @@ -421,6 +421,8 @@ mw_after_fundpsbt(struct command *cmd, field->end - field->start) : NULL; ok = ok && mw->psbt; + ok = ok && psbt_set_version(mw->psbt, 2); + field = ok ? json_get_member(buf, result, "feerate_per_kw") : NULL; ok = ok && field; ok = ok && json_to_number(buf, field, &feerate_per_kw); diff --git a/plugins/spender/openchannel.c b/plugins/spender/openchannel.c index 41a5bc804..74cd90839 100644 --- a/plugins/spender/openchannel.c +++ b/plugins/spender/openchannel.c @@ -112,9 +112,16 @@ static bool update_parent_psbt(const tal_t *ctx, if (s_idx != -1) goto fail; - psbt_add_input(clone, - &changes->added_ins[i].tx_input, - idx); + const struct wally_psbt_input *input = &changes->added_ins[i].input; + struct bitcoin_outpoint outpoint; + wally_psbt_input_get_outpoint(input, &outpoint); + psbt_append_input(clone, + &outpoint, + input->sequence, + NULL /* scriptSig */, + NULL /* input_wscript */, + NULL /* redeemscript */); + /* Move the input over */ clone->inputs[idx] = *in; @@ -172,9 +179,9 @@ static bool update_parent_psbt(const tal_t *ctx, if (s_idx != -1) goto fail; - psbt_add_output(clone, - &changes->added_outs[i].tx_output, - idx); + const struct wally_psbt_output *output = &changes->added_outs[i].output; + psbt_append_output(clone, output->script, amount_sat(output->amount)); + /* Move output over */ clone->outputs[idx] = *out; @@ -638,8 +645,8 @@ funding_transaction_established(struct multifundchannel_command *mfc) for (size_t j = 0; j < mfc->psbt->num_outputs; j++) { if (memeq(dest->funding_script, tal_bytelen(dest->funding_script), - mfc->psbt->tx->outputs[j].script, - mfc->psbt->tx->outputs[j].script_len)) + mfc->psbt->outputs[j].script, + mfc->psbt->outputs[j].script_len)) dest->outnum = j; } if (dest->outnum == mfc->psbt->num_outputs) diff --git a/plugins/txprepare.c b/plugins/txprepare.c index 5b668043f..a80376813 100644 --- a/plugins/txprepare.c +++ b/plugins/txprepare.c @@ -216,7 +216,7 @@ static struct command_result *finish_txprepare(struct command *cmd, utx = tal(NULL, struct unreleased_tx); utx->is_upgrade = txp->is_upgrade; utx->psbt = tal_steal(utx, txp->psbt); - psbt_txid(utx, txp->psbt, &utx->txid, &utx->tx); + psbt_txid(utx, utx->psbt, &utx->txid, &utx->tx); /* If this is a withdraw, we sign and send immediately. */ if (txp->is_withdraw) { @@ -301,6 +301,11 @@ static struct command_result *psbt_created(struct command *cmd, psbttok->end - psbttok->start, buf + psbttok->start); + if (!psbt_set_version(txp->psbt, 2)) { + return command_fail(cmd, LIGHTNINGD, + "Unable to convert PSBT to version 2."); + } + if (!json_to_number(buf, json_get_member(buf, result, "feerate_per_kw"), &txp->feerate)) return command_fail(cmd, LIGHTNINGD, diff --git a/tests/test_db.py b/tests/test_db.py index 8c8b7dea8..5229b6611 100644 --- a/tests/test_db.py +++ b/tests/test_db.py @@ -1,8 +1,7 @@ -from decimal import Decimal from fixtures import * # noqa: F401,F403 from fixtures import TEST_NETWORK from pyln.client import RpcError -from utils import wait_for, sync_blockheight, COMPAT, VALGRIND, DEVELOPER, TIMEOUT, only_one, scid_to_int +from utils import wait_for, sync_blockheight, COMPAT, VALGRIND, DEVELOPER, TIMEOUT, scid_to_int import base64 import os @@ -171,21 +170,16 @@ def test_scid_upgrade(node_factory, bitcoind): def test_last_tx_inflight_psbt_upgrade(node_factory, bitcoind): bitcoind.generate_block(12) - prior_txs = ['02000000019CCCA2E59D863B00B5BD835BF7BA93CC257932D2C7CDBE51EFE2EE4A9D29DFCB01000000009DB0E280024A01000000000000220020BE7935A77CA9AB70A4B8B1906825637767FED3C00824AA90C988983587D68488F0820100000000002200209F4684DDB28ACDC73959BC194D1A25DF906F61ED030F52D163E6F1E247D32CBB9A3ED620', '020000000122F9EBE38F54208545B681AD7F73A7AE3504A09C8201F502673D34E28424687C01000000009DB0E280024A01000000000000220020BE7935A77CA9AB70A4B8B1906825637767FED3C00824AA90C988983587D68488F0820100000000002200209F4684DDB28ACDC73959BC194D1A25DF906F61ED030F52D163E6F1E247D32CBB9A3ED620'] + # FIXME: Re-add dynamic checks once PSBTv2 support is in both Core/Elements, or get python support + # These PSBTs were manually checked for 0.001 BTC multisig witness utxos in a single input + upgraded_psbts = ['cHNidP8BAgQCAAAAAQMEmj7WIAEEAQEBBQECAQYBAwH7BAIAAAAAAQEroIYBAAAAAAAiACBbjNO5FM9nzdj6YnPJMDU902R2c0+9liECwt9TuQiAzSICAuO9OACYZsnajsSqmcxOqcbA3UbfFcYe8M4fJxKRcU5XRjBDAiBgFZ+8xOkvxfBoC9QdAhBuX6zhpvKsqWw8QeN2gK1b4wIfQdSIq+vNMfnFZqLyv3Un4s7i2MzHUiTs2morB/t/SwEBAwQBAAAAAQVHUiECMkJm3oQDs6sVegnx94TVh69hgxyZjBUbzCG7dMKyMUshAuO9OACYZsnajsSqmcxOqcbA3UbfFcYe8M4fJxKRcU5XUq4iBgIyQmbehAOzqxV6CfH3hNWHr2GDHJmMFRvMIbt0wrIxSwhK0xNpAAAAACIGAuO9OACYZsnajsSqmcxOqcbA3UbfFcYe8M4fJxKRcU5XCBq8wdAAAAAAAQ4gnMyi5Z2GOwC1vYNb97qTzCV5MtLHzb5R7+LuSp0p38sBDwQBAAAAARAEnbDigAABAwhKAQAAAAAAAAEEIgAgvnk1p3ypq3CkuLGQaCVjd2f+08AIJKqQyYiYNYfWhIgAAQMI8IIBAAAAAAABBCIAIJ9GhN2yis3HOVm8GU0aJd+Qb2HtAw9S0WPm8eJH0yy7AA==', 'cHNidP8BAgQCAAAAAQMEmj7WIAEEAQEBBQECAQYBAwH7BAIAAAAAAQEroIYBAAAAAAAiACBbjNO5FM9nzdj6YnPJMDU902R2c0+9liECwt9TuQiAzSICAuO9OACYZsnajsSqmcxOqcbA3UbfFcYe8M4fJxKRcU5XRzBEAiBWXvsSYMpD69abqr7X9XurE6B6GkhyI5JeGuKYByBukAIgUmk9q/g3PIS9HjTVJ4OmRoSZAMKLFdsowq15Sl9OAD8BAQMEAQAAAAEFR1IhAjJCZt6EA7OrFXoJ8feE1YevYYMcmYwVG8whu3TCsjFLIQLjvTgAmGbJ2o7EqpnMTqnGwN1G3xXGHvDOHycSkXFOV1KuIgYCMkJm3oQDs6sVegnx94TVh69hgxyZjBUbzCG7dMKyMUsIStMTaQAAAAAiBgLjvTgAmGbJ2o7EqpnMTqnGwN1G3xXGHvDOHycSkXFOVwgavMHQAAAAAAEOICL56+OPVCCFRbaBrX9zp641BKCcggH1Amc9NOKEJGh8AQ8EAQAAAAEQBJ2w4oAAAQMISgEAAAAAAAABBCIAIL55Nad8qatwpLixkGglY3dn/tPACCSqkMmImDWH1oSIAAEDCPCCAQAAAAAAAQQiACCfRoTdsorNxzlZvBlNGiXfkG9h7QMPUtFj5vHiR9MsuwA='] l1 = node_factory.get_node(dbfile='upgrade_inflight.sqlite3.xz', options={'database-upgrade': True}) b64_last_txs = [base64.b64encode(x['last_tx']).decode('utf-8') for x in l1.db_query('SELECT last_tx FROM channel_funding_inflights ORDER BY channel_id, funding_feerate;')] for i in range(len(b64_last_txs)): - bpsbt = b64_last_txs[i] - psbt = bitcoind.rpc.decodepsbt(bpsbt) - tx = prior_txs[i] - assert psbt['tx']['txid'] == bitcoind.rpc.decoderawtransaction(tx)['txid'] - funding_input = only_one(psbt['inputs']) - assert funding_input['witness_utxo']['amount'] == Decimal('0.001') - assert funding_input['witness_utxo']['scriptPubKey']['type'] == 'witness_v0_scripthash' - assert funding_input['witness_script']['type'] == 'multisig' + assert b64_last_txs[i] == upgraded_psbts[i] @unittest.skipIf(not COMPAT, "needs COMPAT to convert obsolete db") @@ -194,22 +188,16 @@ def test_last_tx_inflight_psbt_upgrade(node_factory, bitcoind): def test_last_tx_psbt_upgrade(node_factory, bitcoind): bitcoind.generate_block(12) - prior_txs = ['02000000018DD699861B00061E50937A233DB584BF8ED4C0BF50B44C0411F71B031A06455000000000000EF7A9800350C300000000000022002073356CFF7E1588F14935EF138E142ABEFB5F7E3D51DE942758DCD5A179449B6250A90600000000002200202DF545EA882889846C52FC5E111AC07CE07E0C09418AC15743A6F6284C2A4FA720A1070000000000160014E89954FAC8F7A2DCE51E095D7BEB5271C3F7DA56EF81DC20', '02000000018A0AE4C63BCDF9D78B07EB4501BB23404FDDBC73973C592793F047BE1495074B010000000074D99980010A2D0F00000000002200203B8CB644781CBECA96BE8B2BF1827AFD908B3CFB5569AC74DAB9395E8DDA39E4C9555420', '020000000135DAB2996E57762E3EC158C0D57D39F43CA657E882D93FC24F5FEBAA8F36ED9A0100000000566D1D800350C30000000000002200205679A7D06E1BD276AA25F56E9E4DF7E07D9837EFB0C5F63604F10CD9F766A03ED4DD0600000000001600147E5B5C8F4FC1A9484E259F92CA4CBB7FA2814EA49A6C070000000000220020AB6226DEBFFEFF4A741C01367FA3C875172483CFB3E327D0F8C7AA4C51EDECAA27AA4720'] + # FIXME: Re-add dynamic checks once PSBTv2 support is in both Core/Elements, or get python support + # These PSBTs were manually checked for 0.01 BTC multisig witness utxos in a single input + upgraded_psbts = ['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'] l1 = node_factory.get_node(dbfile='last_tx_upgrade.sqlite3.xz', options={'database-upgrade': True}) b64_last_txs = [base64.b64encode(x['last_tx']).decode('utf-8') for x in l1.db_query('SELECT last_tx FROM channels ORDER BY id;')] for i in range(len(b64_last_txs)): - bpsbt = b64_last_txs[i] - psbt = bitcoind.rpc.decodepsbt(bpsbt) - tx = prior_txs[i] - assert psbt['tx']['txid'] == bitcoind.rpc.decoderawtransaction(tx)['txid'] - funding_input = only_one(psbt['inputs']) - # Every opened channel was funded with the same amount: 1M sats - assert funding_input['witness_utxo']['amount'] == Decimal('0.01') - assert funding_input['witness_utxo']['scriptPubKey']['type'] == 'witness_v0_scripthash' - assert funding_input['witness_script']['type'] == 'multisig' + assert b64_last_txs[i] == upgraded_psbts[i] l1.stop() # Test again, but this time with a database with a closed channel + forgotten peer @@ -222,8 +210,9 @@ def test_last_tx_psbt_upgrade(node_factory, bitcoind): options={'database-upgrade': True}) last_txs = [x['last_tx'] for x in l2.db_query('SELECT last_tx FROM channels ORDER BY id;')] - # The first tx should be psbt, the second should still be hex - bitcoind.rpc.decodepsbt(base64.b64encode(last_txs[0]).decode('utf-8')) + # The first tx should be psbt, the second should still be hex (Newer Core version required for better error message) + assert last_txs[0][:4] == b'psbt' + bitcoind.rpc.decoderawtransaction(last_txs[1].hex()) diff --git a/tests/test_misc.py b/tests/test_misc.py index 02c7e17ee..c040c76c4 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -461,6 +461,7 @@ def test_bech32_funding(node_factory, chainparams): assert only_one(fundingtx['vin'])['txid'] == res['wallettxid'] +@unittest.skipIf(not TEST_NETWORK == 'regtest', 'no support for PSETv0') def test_withdraw_misc(node_factory, bitcoind, chainparams): def dont_spend_outputs(n, txid): """Reserve both outputs (we assume there are two!) in case any our ours, so we don't spend change: wrecks accounting checks""" diff --git a/tests/test_wallet.py b/tests/test_wallet.py index 6d4ccac3c..20090b0c4 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -441,6 +441,7 @@ def test_txprepare(node_factory, bitcoind, chainparams): assert decode['vout'][changenum]['scriptPubKey']['type'] == 'witness_v0_keyhash' +@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '') def test_reserveinputs(node_factory, bitcoind, chainparams): amount = 1000000 total_outs = 12 @@ -494,6 +495,7 @@ def test_reserveinputs(node_factory, bitcoind, chainparams): assert not any('reserved_to_block' in o for o in l1.rpc.listfunds()['outputs']) +@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '') def test_fundpsbt(node_factory, bitcoind, chainparams): amount = 1000000 total_outs = 4 @@ -577,6 +579,7 @@ def test_fundpsbt(node_factory, bitcoind, chainparams): l1.rpc.fundpsbt(amount // 2, feerate, 0) +@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '') def test_utxopsbt(node_factory, bitcoind, chainparams): amount = 1000000 l1 = node_factory.get_node() @@ -691,6 +694,7 @@ def test_utxopsbt(node_factory, bitcoind, chainparams): reservedok=True) +@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '') def test_sign_external_psbt(node_factory, bitcoind, chainparams): """ A PSBT w/ one of our inputs should be signable (we can fill @@ -719,6 +723,7 @@ def test_sign_external_psbt(node_factory, bitcoind, chainparams): l1.rpc.signpsbt(psbt) +@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', '') def test_sign_and_send_psbt(node_factory, bitcoind, chainparams): """ Tests for the sign + send psbt RPCs diff --git a/wallet/reservation.c b/wallet/reservation.c index da1e27454..d131aa375 100644 --- a/wallet/reservation.c +++ b/wallet/reservation.c @@ -97,12 +97,21 @@ static struct command_result *json_reserveinputs(struct command *cmd, NULL)) return command_param_failed(); + /* We only deal with V2 internally */ + if (!psbt_set_version(psbt, 2)) { + return command_fail(cmd, LIGHTNINGD, + "Failed to set version for PSBT: %s", + type_to_string(tmpctx, + struct wally_psbt, + psbt)); + } + current_height = get_block_height(cmd->ld->topology); - for (size_t i = 0; i < psbt->tx->num_inputs; i++) { + for (size_t i = 0; i < psbt->num_inputs; i++) { struct bitcoin_outpoint outpoint; struct utxo *utxo; - wally_tx_input_get_outpoint(&psbt->tx->inputs[i], &outpoint); + wally_psbt_input_get_outpoint(&psbt->inputs[i], &outpoint); utxo = wallet_utxo_get(cmd, cmd->ld->wallet, &outpoint); if (!utxo) continue; @@ -152,6 +161,14 @@ static struct command_result *json_unreserveinputs(struct command *cmd, NULL)) return command_param_failed(); + /* We only deal with V2 internally */ + if (!psbt_set_version(psbt, 2)) { + log_broken(cmd->ld->log, + "Unable to set version for PSBT: %s", + type_to_string(tmpctx, struct wally_psbt, + psbt)); + } + /* We should also add the utxo info for these inputs! * (absolutely required for using this psbt in a dual-funded * round) */ @@ -159,7 +176,7 @@ static struct command_result *json_unreserveinputs(struct command *cmd, struct bitcoin_tx *utxo_tx; struct bitcoin_txid txid; - wally_tx_input_get_txid(&psbt->tx->inputs[i], &txid); + wally_psbt_input_get_txid(&psbt->inputs[i], &txid); utxo_tx = wallet_transaction_get(psbt, cmd->ld->wallet, &txid); if (utxo_tx) { @@ -176,13 +193,13 @@ static struct command_result *json_unreserveinputs(struct command *cmd, response = json_stream_success(cmd); json_array_start(response, "reservations"); - for (size_t i = 0; i < psbt->tx->num_inputs; i++) { + for (size_t i = 0; i < psbt->num_inputs; i++) { struct bitcoin_outpoint outpoint; struct utxo *utxo; enum output_status oldstatus; u32 old_res; - wally_tx_input_get_outpoint(&psbt->tx->inputs[i], &outpoint); + wally_psbt_input_get_outpoint(&psbt->inputs[i], &outpoint); utxo = wallet_utxo_get(cmd, cmd->ld->wallet, &outpoint); if (!utxo || utxo->status != OUTPUT_STATE_RESERVED) continue; @@ -295,14 +312,10 @@ static struct wally_psbt *psbt_using_utxos(const tal_t *ctx, psbt_input_set_wit_utxo(psbt, i, scriptPubkey, utxos[i]->amount); if (is_elements(chainparams)) { - struct amount_asset asset; /* FIXME: persist asset tags */ - asset = amount_sat_to_asset(&utxos[i]->amount, + amount_sat_to_asset(&utxos[i]->amount, chainparams->fee_asset_tag); /* FIXME: persist nonces */ - psbt_elements_input_set_asset(psbt, - psbt->num_inputs - 1, - &asset); } /* FIXME: as of 17 sept 2020, elementsd is *at most* at par @@ -358,7 +371,7 @@ static struct command_result *finish_psbt(struct command *cmd, psbt = psbt_using_utxos(cmd, cmd->ld->wallet, utxos, *locktime, BITCOIN_TX_RBF_SEQUENCE); - + assert(psbt->version == 2); /* Should we add a change output for the excess? */ if (excess_as_change) { struct amount_sat change; @@ -401,7 +414,14 @@ fee_calc: psbt_append_output(psbt, NULL, est_fee); /* Add additional weight of fee output */ weight += bitcoin_tx_output_weight(0); + } else { + /* PSETv0 doesn't exist */ + if (!psbt_set_version(psbt, 0)) { + return command_fail(cmd, LIGHTNINGD, + "Failed to set PSBT version number back to 0."); + } } + response = json_stream_success(cmd); json_add_psbt(response, "psbt", psbt); json_add_num(response, "feerate_per_kw", feerate_per_kw); diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index aa3e2ea7e..0f6ccab73 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -614,14 +614,14 @@ static struct command_result *match_psbt_inputs_to_utxos(struct command *cmd, struct utxo ***utxos) { *utxos = tal_arr(cmd, struct utxo *, 0); - for (size_t i = 0; i < psbt->tx->num_inputs; i++) { + for (size_t i = 0; i < psbt->num_inputs; i++) { struct utxo *utxo; struct bitcoin_outpoint outpoint; if (only_inputs && !in_only_inputs(only_inputs, i)) continue; - wally_tx_input_get_outpoint(&psbt->tx->inputs[i], &outpoint); + wally_psbt_input_get_outpoint(&psbt->inputs[i], &outpoint); utxo = wallet_utxo_get(*utxos, cmd->ld->wallet, &outpoint); if (!utxo) { if (only_inputs) @@ -673,7 +673,6 @@ static struct command_result *match_psbt_inputs_to_utxos(struct command *cmd, static void match_psbt_outputs_to_wallet(struct wally_psbt *psbt, struct wallet *w) { - assert(psbt->tx->num_outputs == psbt->num_outputs); tal_wally_start(); for (size_t outndx = 0; outndx < psbt->num_outputs; ++outndx) { u32 index; @@ -681,8 +680,8 @@ static void match_psbt_outputs_to_wallet(struct wally_psbt *psbt, const u8 *script; struct ext_key ext; - script = wally_tx_output_get_script(tmpctx, - &psbt->tx->outputs[outndx]); + script = wally_psbt_output_get_script(tmpctx, + &psbt->outputs[outndx]); if (!script) continue; @@ -735,6 +734,7 @@ static struct command_result *json_signpsbt(struct command *cmd, struct wally_psbt *psbt, *signed_psbt; struct utxo **utxos; u32 *input_nums; + u32 psbt_version; if (!param(cmd, buffer, params, p_req("psbt", param_psbt, &psbt), @@ -742,6 +742,15 @@ static struct command_result *json_signpsbt(struct command *cmd, NULL)) return command_param_failed(); + /* We internally deal with v2 only but we want to return V2 if given */ + psbt_version = psbt->version; + if (!psbt_set_version(psbt, 2)) { + return command_fail(cmd, LIGHTNINGD, + "Could not set PSBT version: %s", + type_to_string(tmpctx, struct wally_psbt, + psbt)); + } + /* Sanity check! */ for (size_t i = 0; i < tal_count(input_nums); i++) { if (input_nums[i] >= psbt->num_inputs) @@ -782,6 +791,13 @@ static struct command_result *json_signpsbt(struct command *cmd, "HSM gave bad sign_withdrawal_reply %s", tal_hex(tmpctx, msg)); + if (!psbt_set_version(signed_psbt, psbt_version)) { + return command_fail(cmd, LIGHTNINGD, + "Signed PSBT unable to have version set: %s", + type_to_string(tmpctx, struct wally_psbt, + psbt)); + } + response = json_stream_success(cmd); json_add_psbt(response, "signed_psbt", signed_psbt); return command_success(cmd, response); @@ -824,8 +840,8 @@ static void maybe_notify_new_external_send(struct lightningd *ld, return; /* If it's going to our wallet, ignore */ - script = wally_tx_output_get_script(tmpctx, - &psbt->tx->outputs[outnum]); + script = wally_psbt_output_get_script(tmpctx, + &psbt->outputs[outnum]); if (wallet_can_spend(ld->wallet, script, &index, &is_p2sh)) return; @@ -870,6 +886,11 @@ static void sendpsbt_done(struct bitcoind *bitcoind UNUSED, return; } + /* Internal-only after, set to v2 */ + if (!psbt_set_version(sending->psbt, 2)) { + abort(); // Send succeeded but later calls may fail + } + wallet_transaction_add(ld->wallet, sending->wtx, 0, 0); /* Extract the change output and add it to the DB */