diff --git a/bitcoin/psbt.c b/bitcoin/psbt.c index 5c8a7b4eb..1b4740f03 100644 --- a/bitcoin/psbt.c +++ b/bitcoin/psbt.c @@ -343,6 +343,44 @@ struct wally_tx *psbt_finalize(struct wally_psbt *psbt, bool finalize_in_place) } else tmppsbt = cast_const(struct wally_psbt *, psbt); + /* Wally doesn't know how to finalize P2WSH; this happens with + * option_anchor_outputs, and finalizing is trivial. */ + /* FIXME: miniscript! miniscript! miniscript! */ + for (size_t i = 0; i < tmppsbt->num_inputs; i++) { + struct wally_psbt_input *input = &tmppsbt->inputs[i]; + struct wally_tx_witness_stack *stack; + + if (!is_anchor_witness_script(input->witness_script, + input->witness_script_len)) + continue; + + if (input->signatures.num_items != 1) + continue; + + /* BOLT-a12da24dd0102c170365124782b46d9710950ac1 #3: + * #### `to_remote` Output + *... + * + * If `option_anchor_outputs` applies to the commitment + * transaction, the `to_remote` output is encumbered by a one + * block csv lock. + * + * OP_CHECKSIGVERIFY 1 OP_CHECKSEQUENCEVERIFY + * + * The output is spent by a transaction with `nSequence` field set to `1` and witness: + * + * + */ + wally_tx_witness_stack_init_alloc(2, &stack); + wally_tx_witness_stack_add(stack, + input->signatures.items[0].value, + input->signatures.items[0].value_len); + wally_tx_witness_stack_add(stack, + input->witness_script, + input->witness_script_len); + input->final_witness = stack; + } + if (wally_psbt_finalize(tmppsbt) != WALLY_OK) { if (!finalize_in_place) wally_psbt_free(tmppsbt); diff --git a/bitcoin/script.c b/bitcoin/script.c index d24436f5d..1f4f03b30 100644 --- a/bitcoin/script.c +++ b/bitcoin/script.c @@ -340,9 +340,25 @@ u8 *anchor_to_remote_redeem(const tal_t *ctx, add_number(&script, 1); add_op(&script, OP_CHECKSEQUENCEVERIFY); + assert(is_anchor_witness_script(script, tal_bytelen(script))); return script; } +bool is_anchor_witness_script(const u8 *script, size_t script_len) +{ + if (script_len != 34 + 1 + 1 + 1) + return false; + if (script[0] != OP_PUSHBYTES(33)) + return false; + if (script[34] != OP_CHECKSIGVERIFY) + return false; + if (script[35] != 0x51) + return false; + if (script[36] != OP_CHECKSEQUENCEVERIFY) + return false; + return true; +} + /* Create a witness which spends the 2of2. */ u8 **bitcoin_witness_2of2(const tal_t *ctx, const struct bitcoin_signature *sig1, diff --git a/bitcoin/script.h b/bitcoin/script.h index 43a437f2e..6a7e14fe1 100644 --- a/bitcoin/script.h +++ b/bitcoin/script.h @@ -149,6 +149,9 @@ bool is_p2wpkh(const u8 *script, struct bitcoin_address *addr); /* Is this one of the four above script types? */ bool is_known_scripttype(const u8 *script); +/* Is this an anchor witness script? */ +bool is_anchor_witness_script(const u8 *script, size_t script_len); + /* Are these two scripts equal? */ bool scripteq(const u8 *s1, const u8 *s2); diff --git a/bitcoin/test/run-bitcoin_block_from_hex.c b/bitcoin/test/run-bitcoin_block_from_hex.c index 97a80d798..9f4e6f5fc 100644 --- a/bitcoin/test/run-bitcoin_block_from_hex.c +++ b/bitcoin/test/run-bitcoin_block_from_hex.c @@ -63,6 +63,9 @@ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u32 */ u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u32 called!\n"); abort(); } +/* Generated stub for is_anchor_witness_script */ +bool is_anchor_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED) +{ fprintf(stderr, "is_anchor_witness_script called!\n"); abort(); } /* Generated stub for is_p2sh */ bool is_p2sh(const u8 *script UNNEEDED, struct ripemd160 *addr UNNEEDED) { fprintf(stderr, "is_p2sh called!\n"); abort(); } diff --git a/bitcoin/test/run-tx-encode.c b/bitcoin/test/run-tx-encode.c index e46718449..84e89078a 100644 --- a/bitcoin/test/run-tx-encode.c +++ b/bitcoin/test/run-tx-encode.c @@ -64,6 +64,9 @@ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_u32 */ u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u32 called!\n"); abort(); } +/* Generated stub for is_anchor_witness_script */ +bool is_anchor_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED) +{ fprintf(stderr, "is_anchor_witness_script called!\n"); abort(); } /* Generated stub for is_p2sh */ bool is_p2sh(const u8 *script UNNEEDED, struct ripemd160 *addr UNNEEDED) { fprintf(stderr, "is_p2sh called!\n"); abort(); }