diff --git a/bitcoin/src/blockdata/script/builder.rs b/bitcoin/src/blockdata/script/builder.rs index 7efacd10e..aa857e0ec 100644 --- a/bitcoin/src/blockdata/script/builder.rs +++ b/bitcoin/src/blockdata/script/builder.rs @@ -74,12 +74,36 @@ impl Builder { pub(in crate::blockdata) fn push_int_non_minimal(self, data: i64) -> Builder { let mut buf = [0u8; 8]; let len = write_scriptint(&mut buf, data); - self.push_slice(&<&PushBytes>::from(&buf)[..len]) + self.push_slice_non_minimal(&<&PushBytes>::from(&buf)[..len]) } /// Adds instructions to push some arbitrary data onto the stack. - pub fn push_slice>(mut self, data: T) -> Builder { - self.0.push_slice(data); + pub fn push_slice>(self, data: T) -> Builder { + let bytes = data.as_ref().as_bytes(); + if bytes.len() == 1 && (bytes[0] == 0x81 || bytes[0] <= 16) { + match bytes[0] { + 0x81 => self.push_opcode(OP_PUSHNUM_NEG1), + 0 => self.push_opcode(OP_PUSHBYTES_0), + 1..=16 => { + self.push_opcode(Opcode::from(bytes[0] + (OP_PUSHNUM_1.to_u8() - 1))) + } + _ => self, // unreachable arm + } + } else { + self.push_slice_non_minimal(data.as_ref()) + } + } + + /// Adds instructions to push some arbitrary data onto the stack without minimality. + /// + /// Standardness rules require push minimality according to [CheckMinimalPush] of core. + /// + /// [CheckMinimalPush]: + pub fn push_slice_non_minimal>( + mut self, + data: T, + ) -> Builder { + self.0.push_slice_non_minimal(data); self.1 = None; self } diff --git a/bitcoin/src/blockdata/script/owned.rs b/bitcoin/src/blockdata/script/owned.rs index 8b8b73e38..7d4c9b978 100644 --- a/bitcoin/src/blockdata/script/owned.rs +++ b/bitcoin/src/blockdata/script/owned.rs @@ -37,6 +37,25 @@ crate::internal_macros::define_extension_trait! { /// Adds instructions to push some arbitrary data onto the stack. fn push_slice>(&mut self, data: T) { + let bytes = data.as_ref().as_bytes(); + if bytes.len() == 1 && (bytes[0] == 0x81 || bytes[0] <= 16) { + match bytes[0] { + 0x81 => { self.push_opcode(OP_PUSHNUM_NEG1); }, + 0 => { self.push_opcode(OP_PUSHBYTES_0); }, + 1..=16 => { self.push_opcode(Opcode::from(bytes[0] + (OP_PUSHNUM_1.to_u8() - 1))); }, + _ => {}, // unreachable arm + } + } else { + self.push_slice_non_minimal(data); + } + } + + /// Adds instructions to push some arbitrary data onto the stack without minimality. + /// + /// Standardness rules require push minimality according to [CheckMinimalPush] of core. + /// + /// [CheckMinimalPush]: + fn push_slice_non_minimal>(&mut self, data: T) { let data = data.as_ref(); self.reserve(ScriptBuf::reserved_len_for_slice(data.len())); self.push_slice_no_opt(data);