huff_neo_utils/
bytes_util.rs1use crate::{evm_version::EVMVersion, opcodes::Opcode};
2use std::num::ParseIntError;
3
4pub fn str_to_bytes32(s: &str) -> [u8; 32] {
9 let s = format_even_bytes(String::from(s));
10
11 let bytes: Vec<u8> = (0..s.len()).step_by(2).map(|c| u8::from_str_radix(&s[c..c + 2], 16).unwrap()).collect();
12
13 let mut padded = [0u8; 32];
14
15 for i in 32 - bytes.len()..32 {
16 padded[i] = bytes[bytes.len() - (32 - i)];
17 }
18
19 padded
20}
21
22pub fn bytes32_to_hex_string(bytes: &[u8; 32], prefixed: bool) -> String {
24 let mut s = String::default();
25 let start = bytes.iter().position(|b| *b != 0).unwrap_or(bytes.len() - 1);
26 for b in &bytes[start..bytes.len()] {
27 s = format!("{s}{:02x}", *b);
28 }
29 format!("{}{s}", if prefixed { "0x" } else { "" })
30}
31
32pub fn hex_to_usize(s: &str) -> Result<usize, ParseIntError> {
34 usize::from_str_radix(s, 16)
35}
36
37pub fn pad_n_bytes(hex: &str, num_bytes: usize) -> String {
40 let mut hex = hex.to_owned();
41 while hex.len() < num_bytes * 2 {
42 hex = format!("0{hex}");
43 }
44 hex
45}
46
47fn push_min_width(value: usize) -> String {
49 let width = ((usize::BITS - value.leading_zeros()) as usize).div_ceil(8).max(1);
50 format!("{:02x}{:0digits$x}", 0x5f + width, value, digits = width * 2)
51}
52
53pub fn deploy_bootstrap(runtime_len: usize, ctor_body_len: usize) -> (String, usize) {
59 let size_push = push_min_width(runtime_len);
60 let mut offset_width = 1;
62 loop {
63 let bootstrap_len = size_push.len() / 2 + 1 + (1 + offset_width) + 4;
65 let offset_push = push_min_width(ctor_body_len + bootstrap_len);
66 if offset_push.len() / 2 == 1 + offset_width {
67 return (format!("{size_push}80{offset_push}3d393df3"), bootstrap_len);
69 }
70 offset_width += 1;
71 }
72}
73
74pub fn format_even_bytes(hex: String) -> String {
76 if hex.len() % 2 == 1 { format!("0{hex}") } else { hex }
77}
78
79pub fn str_to_vec(s: &str) -> Result<Vec<u8>, std::num::ParseIntError> {
81 let bytes: Result<Vec<u8>, _> = (0..s.len()).step_by(2).map(|c| u8::from_str_radix(&s[c..c + 2], 16)).collect();
82 bytes
83}
84
85pub fn literal_gen(evm_version: &EVMVersion, l: &[u8; 32]) -> String {
87 let hex_literal: String = bytes32_to_hex_string(l, false);
88 match hex_literal.as_str() {
89 "00" => format_push0(evm_version, hex_literal),
90 _ => format_literal(hex_literal),
91 }
92}
93
94fn format_push0(evm_version: &EVMVersion, hex_literal: String) -> String {
96 if evm_version.has_push0() { Opcode::Push0.to_string() } else { format_literal(hex_literal) }
97}
98
99pub fn format_literal(hex_literal: String) -> String {
101 format!("{:02x}{hex_literal}", 95 + hex_literal.len() / 2)
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn test_deploy_bootstrap_push_widths() {
110 assert_eq!(deploy_bootstrap(0, 0), ("60008060093d393df3".to_string(), 9));
112 assert_eq!(deploy_bootstrap(300, 0), ("61012c80600a3d393df3".to_string(), 10));
114 assert_eq!(deploy_bootstrap(1, 250), ("6001806101043d393df3".to_string(), 10));
116 assert_eq!(deploy_bootstrap(0x10000, 0), ("6201000080600b3d393df3".to_string(), 11));
118 assert_eq!(deploy_bootstrap(1, 0xfff5), ("60018061ffff3d393df3".to_string(), 10));
120 assert_eq!(deploy_bootstrap(1, 0xfff6), ("600180620100013d393df3".to_string(), 11));
121 }
122}