Skip to content

Commit

Permalink
bitcoin/psbt: handle anchor spends.
Browse files Browse the repository at this point in the history
Turns out it's a single sig, identical to the already-handled
case where we spend a to_remote output.

We also close a temporary memleak: stack was unused, but
tallocated off the psbt, so it lives as long as the PSBT.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Jun 29, 2023
1 parent c2dffca commit 3133543
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 3 deletions.
26 changes: 23 additions & 3 deletions bitcoin/psbt.c
Original file line number Diff line number Diff line change
Expand Up @@ -586,18 +586,24 @@ bool psbt_finalize(struct wally_psbt *psbt)
tal_wally_start();

/* Wally doesn't know how to finalize P2WSH; this happens with
* option_anchor_outputs, and finalizing is trivial. */
* option_anchor_outputs, and finalizing those two cases is trivial. */
/* FIXME: miniscript! miniscript! miniscript! */
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;

iws = wally_map_get_integer(&input->psbt_fields, /* PSBT_IN_WITNESS_SCRIPT */ 0x05);
if (!iws || !is_to_remote_anchored_witness_script(iws->value,
iws->value_len))
if (!iws)
continue;

if (!is_to_remote_anchored_witness_script(iws->value,
iws->value_len)
&& !is_anchor_witness_script(iws->value,
iws->value_len)) {
continue;
}

if (input->signatures.num_items != 1)
continue;

Expand All @@ -615,6 +621,19 @@ bool psbt_finalize(struct wally_psbt *psbt)
*
* <remote_sig>
*/
/* BOLT #3:
* #### `to_local_anchor` and `to_remote_anchor` Output (option_anchors)
*...
* <local_funding_pubkey/remote_funding_pubkey> OP_CHECKSIG OP_IFDUP
* OP_NOTIF
* OP_16 OP_CHECKSEQUENCEVERIFY
* OP_ENDIF
*...
* Spending of the output requires the following witness:
* <local_sig/remote_sig>
*/

/* i.e. in both cases, this is the same thing */
wally_tx_witness_stack_init_alloc(2, &stack);
wally_tx_witness_stack_add(stack,
input->signatures.items[0].value,
Expand All @@ -623,6 +642,7 @@ bool psbt_finalize(struct wally_psbt *psbt)
iws->value,
iws->value_len);
wally_psbt_input_set_final_witness(input, stack);
wally_tx_witness_stack_free(stack);
}

ok = (wally_psbt_finalize(psbt, 0 /* flags */) == WALLY_OK);
Expand Down
22 changes: 22 additions & 0 deletions bitcoin/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -874,9 +874,31 @@ u8 *bitcoin_wscript_anchor(const tal_t *ctx,
add_op(&script, OP_CHECKSEQUENCEVERIFY);
add_op(&script, OP_ENDIF);

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 + 1 + 1 + 1)
return false;
if (script[0] != OP_PUSHBYTES(33))
return false;
if (script[34] != OP_CHECKSIG)
return false;
if (script[35] != OP_IFDUP)
return false;
if (script[36] != OP_NOTIF)
return false;
if (script[37] != 0x50 + 16)
return false;
if (script[38] != OP_CHECKSEQUENCEVERIFY)
return false;
if (script[39] != OP_ENDIF)
return false;
return true;
}

bool scripteq(const u8 *s1, const u8 *s2)
{
memcheck(s1, tal_count(s1));
Expand Down
3 changes: 3 additions & 0 deletions bitcoin/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ bool is_known_scripttype(const u8 *script);
/* Is this a to-remote witness script (used for option_anchor_outputs)? */
bool is_to_remote_anchored_witness_script(const u8 *script, size_t script_len);

/* 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);

Expand Down
3 changes: 3 additions & 0 deletions bitcoin/test/run-bitcoin_block_from_hex.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_u8_array */
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_u8_array 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_to_remote_anchored_witness_script */
bool is_to_remote_anchored_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED)
{ fprintf(stderr, "is_to_remote_anchored_witness_script called!\n"); abort(); }
Expand Down
3 changes: 3 additions & 0 deletions bitcoin/test/run-psbt-from-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED)
void fromwire_sha256_double(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
struct sha256_double *sha256d UNNEEDED)
{ fprintf(stderr, "fromwire_sha256_double 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_to_remote_anchored_witness_script */
bool is_to_remote_anchored_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED)
{ fprintf(stderr, "is_to_remote_anchored_witness_script called!\n"); abort(); }
Expand Down
3 changes: 3 additions & 0 deletions bitcoin/test/run-tx-encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_u8_array */
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_u8_array 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_to_remote_anchored_witness_script */
bool is_to_remote_anchored_witness_script(const u8 *script UNNEEDED, size_t script_len UNNEEDED)
{ fprintf(stderr, "is_to_remote_anchored_witness_script called!\n"); abort(); }
Expand Down

0 comments on commit 3133543

Please sign in to comment.