Skip to content

Commit f465b79

Browse files
committed
Merge rust-bitcoin/rust-bitcoin#1033: Avoid allocation in build_scriptint
c80dbc2 Avoid allocation in build_scriptint (Steven Roose) Pull request description: Hehe, reason for party, let's invite apoelstra ! ACKs for top commit: apoelstra: ACK c80dbc2 tcharding: ACK c80dbc2 Tree-SHA512: 8446e765d8b9fa562f636817327db6fad4bb9c906d3f69fda76e61cd258fc4c296e6ffaa440a357125c2ab45603eb05c58cb8d6822deea2fe5746e5c7c3f1e4d
2 parents a580a11 + 280fc81 commit f465b79

File tree

1 file changed

+31
-13
lines changed

1 file changed

+31
-13
lines changed

src/blockdata/script.rs

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -241,30 +241,36 @@ impl From<bitcoinconsensus::Error> for Error {
241241
Error::BitcoinConsensus(err)
242242
}
243243
}
244-
/// Helper to encode an integer in script format
245-
fn build_scriptint(n: i64) -> Vec<u8> {
246-
if n == 0 { return vec![] }
244+
245+
/// Helper to encode an integer in script format.
246+
/// Writes bytes into the buffer and returns the number of bytes written.
247+
fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize {
248+
let mut len = 0;
249+
if n == 0 { return len; }
247250

248251
let neg = n < 0;
249252

250253
let mut abs = if neg { -n } else { n } as usize;
251-
let mut v = vec![];
252254
while abs > 0xFF {
253-
v.push((abs & 0xFF) as u8);
255+
out[len] = (abs & 0xFF) as u8;
256+
len += 1;
254257
abs >>= 8;
255258
}
256259
// If the number's value causes the sign bit to be set, we need an extra
257260
// byte to get the correct value and correct sign bit
258261
if abs & 0x80 != 0 {
259-
v.push(abs as u8);
260-
v.push(if neg { 0x80u8 } else { 0u8 });
262+
out[len] = abs as u8;
263+
len += 1;
264+
out[len] = if neg { 0x80u8 } else { 0u8 };
265+
len += 1;
261266
}
262267
// Otherwise we just set the sign bit ourselves
263268
else {
264269
abs |= if neg { 0x80 } else { 0 };
265-
v.push(abs as u8);
270+
out[len] = abs as u8;
271+
len += 1;
266272
}
267-
v
273+
len
268274
}
269275

270276
/// Helper to decode an integer in script format
@@ -908,7 +914,9 @@ impl Builder {
908914
/// Adds instructions to push an integer onto the stack, using the explicit
909915
/// encoding regardless of the availability of dedicated opcodes.
910916
pub fn push_scriptint(self, data: i64) -> Builder {
911-
self.push_slice(&build_scriptint(data))
917+
let mut buf = [0u8; 8];
918+
let len = write_scriptint(&mut buf, data);
919+
self.push_slice(&buf[..len])
912920
}
913921

914922
/// Adds instructions to push some arbitrary data onto the stack.
@@ -1106,7 +1114,7 @@ mod test {
11061114
use core::str::FromStr;
11071115

11081116
use super::*;
1109-
use super::build_scriptint;
1117+
use super::write_scriptint;
11101118

11111119
use crate::hashes::hex::{FromHex, ToHex};
11121120
use crate::consensus::encode::{deserialize, serialize};
@@ -1287,13 +1295,23 @@ mod test {
12871295

12881296
#[test]
12891297
fn scriptint_round_trip() {
1298+
fn build_scriptint(n: i64) -> Vec<u8> {
1299+
let mut buf = [0u8; 8];
1300+
let len = write_scriptint(&mut buf, n);
1301+
assert!(len <= 8);
1302+
buf[..len].to_vec()
1303+
}
1304+
12901305
assert_eq!(build_scriptint(-1), vec![0x81]);
12911306
assert_eq!(build_scriptint(255), vec![255, 0]);
12921307
assert_eq!(build_scriptint(256), vec![0, 1]);
12931308
assert_eq!(build_scriptint(257), vec![1, 1]);
12941309
assert_eq!(build_scriptint(511), vec![255, 1]);
1295-
for &i in [10, 100, 255, 256, 1000, 10000, 25000, 200000, 5000000, 1000000000,
1296-
(1 << 31) - 1, -((1 << 31) - 1)].iter() {
1310+
let test_vectors = [
1311+
10, 100, 255, 256, 1000, 10000, 25000, 200000, 5000000, 1000000000,
1312+
(1 << 31) - 1, -((1 << 31) - 1),
1313+
];
1314+
for &i in test_vectors.iter() {
12971315
assert_eq!(Ok(i), read_scriptint(&build_scriptint(i)));
12981316
assert_eq!(Ok(-i), read_scriptint(&build_scriptint(-i)));
12991317
}

0 commit comments

Comments
 (0)