Unable to push script bytes into a Script builder
Unable to push script bytes into a Script builder
Loading saved threads...
jiamijiang · External communityPost link
External question — Bitcoin Stack Exchange
Author: jiamijiang
Original post: https://bitcoin.stackexchange.com/questions/130649
License: CC BY-SA 4.0 — https://creativecommons.org/licenses/by-sa/4.0/
Adaptation: HTML converted to plain text; contact email addresses removed.
I am using rust-bitcoin to spend a P2SH. I want to construct the scriptSig by pushing a signature and the redeem script. The redeem script is just a 1-of-1 P2MS script.
let redeem_script = Script::builder()
.push_opcode(OP_PUSHNUM_1)
.push_key(&pubkey1)
.push_opcode(OP_PUSHNUM_1)
.push_opcode(OP_CHECKMULTISIG)
.into_script();
...
let mut scriptSig = ScriptBuf::builder();
scriptSig.push_opcode(OP_0);
scriptSig.push_slice(&signature1.serialize());
scriptSig.push_slice(&redeem_script.as_bytes()); // type error here
There is a type error that i get on the
.push_slice(&redeem_script.as_bytes())
segment because the
push_slice
method expects a type that implements
AsRef<PushBytes>
, but the provided type
&[u8]
does not satisfy this trait bound.
How would I convert the
redeem_script
to satisfy the
AsRef<PushBytes>
param type?
Quote
Report
vincenzopalazzo · External communityPost link
External answer — Bitcoin Stack Exchange
Author: vincenzopalazzo
Original post: https://bitcoin.stackexchange.com/a/130650
License: CC BY-SA 4.0 — https://creativecommons.org/licenses/by-sa/4.0/
Adaptation: HTML converted to plain text; contact email addresses removed.
The issue is with the push_slice API in recent versions of rust-bitcoin (≥ 0.30).
ScriptBuf::builder().push_slice
(and
Builder::push_slice
) now requires
T: AsRef<PushBytes>
for safety—it enforces Bitcoin’s push-data limits at compile time where possible and prevents oversized pushes.
&[u8]
(what
redeem_script.as_bytes()
returns) no longer satisfies that bound directly.
Fix
Convert the redeem script bytes to
PushBytesBuf
(the owned version) using
TryFrom
:
use bitcoin::script::{Builder, PushBytesBuf, ScriptBuf}; // or the full path: bitcoin::blockdata::script::*
// ... your redeem_script construction (this part is already correct) ...
let redeem_script = Script::builder()
.push_opcode(OP_PUSHNUM_1)
.push_key(&pubkey1)
.push_opcode(OP_PUSHNUM_1)
.push_opcode(OP_CHECKMULTISIG)
.into_script();
// Build the scriptSig for the P2SH spend (1-of-1 multisig redeem script)
let mut script_sig = Builder::new()
.push_opcode(OP_0) // dummy 0 for CHECKMULTISIG
.push_slice(&signature1.serialize()) // signature (already a valid push)
.push_slice(
PushBytesBuf::try_from(redeem_script.as_bytes())
.expect("redeem script too large to push") // will never fail for normal multisig
)
.into_script();
tx.input[0].script_sig = script_sig; // or however you're attaching it
Why this works
PushBytesBuf::try_from(&[u8])
(or
&PushBytes::try_from(&[u8])
if you prefer a reference) validates the length and gives you a type that implements
AsRef<PushBytes>
.
For a 1-of-1 P2MS redeem script the size is tiny (~36 bytes), so the
expect
/
unwrap
is safe. In production you can handle the
PushBytesError
if you want to be extra defensive.
The resulting
script_sig
will be a valid P2SH unlocking script:
<0> <sig> <redeemScript>
(all pushes).
Alternative one-liners (if you prefer)
.push_slice(PushBytesBuf::from(redeem_script.as_bytes())) // panics on >4 GiB (impossible)
or
.push_slice(redeem_script.as_bytes().try_into().unwrap())
(using the
TryInto
impl that
PushBytesBuf
provides).
This is the idiomatic way in current
rust-bitcoin
. Your redeem script builder and overall P2SH flow look correct—only the final push needed the type adjustment.
Quote
Report
Post Reply
Quoted from Forex.com.bd-Editorial External answer — Bitcoin Stack Exchange Author: vincenzopalazzo Source score (net votes, not local likes): 0 Original post: https://bitcoin.stackexchange.com/a/130650 License: CC BY-SA 4.0 — https://creativecommons.org/licenses/by-sa/4.0/ Adaptation: HTML converted to plain text; contact email addresses removed. The issue is with the push_slice API in recent versions of rust-bitcoin (≥ 0.30). ScriptBuf::builder().push_slice (and Builder::push_slice ) now requires T: AsRef<PushBytes> for safety—it enforces Bitcoin’s push-data limits at compile time where possible and prevents oversized pushes. &[u8] (what redeem_script.as_bytes() returns) no longer satisfies that bound directly. Fix Convert the redeem script bytes to PushBytesBuf (the owned version) using TryFrom : use bitcoin::script::{Builder, PushBytesBuf, ScriptBuf}; // or the full path: bitcoin::blockdata::script::* // ... your redeem_script construction (this part is already correct) ... let redeem_script = Script::builder() .push_opcode(OP_PUSHNUM_1) .push_key(&pubkey1) .push_opcode(OP_PUSHNUM_1) .push_opcode(OP_CHECKMULTISIG) .into_script(); // Build the scriptSig for the P2SH spend (1-of-1 multisig redeem script) let mut script_sig = Builder::new() .push_opcode(OP_0) // dummy 0 for CHECKMULTISIG .push_slice(&signature1.serialize()) // signature (already a valid push) .push_slice( PushBytesBuf::try_from(redeem_script.as_bytes()) .expect("redeem script too large to push") // will never fail for normal multisig ) .into_script(); tx.input[0].script_sig = script_sig; // or however you're attaching it Why this works PushBytesBuf::try_from(&[u8]) (or &PushBytes::try_from(&[u8]) if you prefer a reference) validates the length and gives you a type that implements AsRef<PushBytes> . For a 1-of-1 P2MS redeem script the size is tiny (~36 bytes), so the expect / unwrap is safe. In production you can handle the PushBytesError if you want to be extra defensive. The resulting script_sig will be a valid P2SH unlocking script: <0> <sig> <redeemScript> (all pushes). Alternative one-liners (if you prefer) .push_slice(PushBytesBuf::from(redeem_script.as_bytes())) // panics on >4 GiB (impossible) or .push_slice(redeem_script.as_bytes().try_into().unwrap()) (using the TryInto impl that PushBytesBuf provides). This is the idiomatic way in current rust-bitcoin . Your redeem script builder and overall P2SH flow look correct—only the final push needed the type adjustment.
Checking account access…