fix: enforce minimal push for push_slice

This commit is contained in:
ChrisCho-H 2025-04-17 06:03:57 +09:00
parent 7307c115e8
commit 354e1e42ad
2 changed files with 46 additions and 3 deletions

View File

@ -74,12 +74,36 @@ impl Builder {
pub(in crate::blockdata) fn push_int_non_minimal(self, data: i64) -> Builder { pub(in crate::blockdata) fn push_int_non_minimal(self, data: i64) -> Builder {
let mut buf = [0u8; 8]; let mut buf = [0u8; 8];
let len = write_scriptint(&mut buf, data); 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. /// Adds instructions to push some arbitrary data onto the stack.
pub fn push_slice<T: AsRef<PushBytes>>(mut self, data: T) -> Builder { pub fn push_slice<T: AsRef<PushBytes>>(self, data: T) -> Builder {
self.0.push_slice(data); 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]: <https://github.com/bitcoin/bitcoin/blob/99a4ddf5ab1b3e514d08b90ad8565827fda7b63b/src/script/script.cpp#L366>
pub fn push_slice_non_minimal<T: AsRef<PushBytes>>(
mut self,
data: T,
) -> Builder {
self.0.push_slice_non_minimal(data);
self.1 = None; self.1 = None;
self self
} }

View File

@ -37,6 +37,25 @@ crate::internal_macros::define_extension_trait! {
/// Adds instructions to push some arbitrary data onto the stack. /// Adds instructions to push some arbitrary data onto the stack.
fn push_slice<T: AsRef<PushBytes>>(&mut self, data: T) { fn push_slice<T: AsRef<PushBytes>>(&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]: <https://github.com/bitcoin/bitcoin/blob/99a4ddf5ab1b3e514d08b90ad8565827fda7b63b/src/script/script.cpp#L366>
fn push_slice_non_minimal<T: AsRef<PushBytes>>(&mut self, data: T) {
let data = data.as_ref(); let data = data.as_ref();
self.reserve(ScriptBuf::reserved_len_for_slice(data.len())); self.reserve(ScriptBuf::reserved_len_for_slice(data.len()));
self.push_slice_no_opt(data); self.push_slice_no_opt(data);