1use crate::error::{Error, Result};
7use alloy::primitives::keccak256;
8
9#[derive(Debug, Clone)]
11pub struct Bytecode {
12 bytes: Vec<u8>,
13}
14
15impl Bytecode {
16 pub fn from_hex(hex: &str) -> Result<Self> {
18 let clean = hex.trim_start_matches("0x");
19 if clean.is_empty() {
20 return Ok(Self { bytes: Vec::new() });
21 }
22 let bytes = hex::decode(clean)?;
23 Ok(Self { bytes })
24 }
25
26 pub fn from_bytes(bytes: Vec<u8>) -> Self {
28 Self { bytes }
29 }
30
31 pub fn hash(&self) -> String {
33 if self.bytes.is_empty() {
34 return String::new();
35 }
36 format!("{:x}", keccak256(&self.bytes))
37 }
38
39 pub fn is_empty(&self) -> bool {
41 self.bytes.is_empty()
42 }
43
44 pub fn len(&self) -> usize {
46 self.bytes.len()
47 }
48
49 pub fn as_bytes(&self) -> &[u8] {
51 &self.bytes
52 }
53
54 pub fn to_hex(&self) -> String {
56 if self.bytes.is_empty() {
57 return "0x".to_string();
58 }
59 format!("0x{}", hex::encode(&self.bytes))
60 }
61}
62
63pub fn is_valid_bytecode(hex: &str) -> bool {
65 let clean = hex.trim_start_matches("0x");
66 !clean.is_empty() && hex::decode(clean).is_ok()
67}
68
69pub fn compute_bytecode_hash(hex: &str) -> Result<String> {
71 let bytecode = Bytecode::from_hex(hex)?;
72 Ok(bytecode.hash())
73}
74
75pub fn parse_hex_block_number(hex: &str) -> Result<i64> {
77 let clean = hex.trim_start_matches("0x");
78 i64::from_str_radix(clean, 16)
79 .map_err(|_| Error::Validation(format!("Invalid hex block number: {}", hex)))
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn test_bytecode_from_hex() {
88 let bytecode = Bytecode::from_hex("0x6080604052").unwrap();
89 assert!(!bytecode.is_empty());
90 assert_eq!(bytecode.len(), 5);
91 }
92
93 #[test]
94 fn test_bytecode_from_hex_no_prefix() {
95 let bytecode = Bytecode::from_hex("6080604052").unwrap();
96 assert!(!bytecode.is_empty());
97 assert_eq!(bytecode.len(), 5);
98 }
99
100 #[test]
101 fn test_bytecode_empty() {
102 let bytecode = Bytecode::from_hex("").unwrap();
103 assert!(bytecode.is_empty());
104 assert_eq!(bytecode.hash(), "");
105 }
106
107 #[test]
108 fn test_bytecode_hash() {
109 let bytecode = Bytecode::from_hex("0x6080604052").unwrap();
110 let hash = bytecode.hash();
111 assert!(!hash.is_empty());
112 assert_eq!(hash.len(), 64); }
114
115 #[test]
116 fn test_bytecode_to_hex() {
117 let bytecode = Bytecode::from_hex("6080604052").unwrap();
118 assert_eq!(bytecode.to_hex(), "0x6080604052");
119 }
120
121 #[test]
122 fn test_is_valid_bytecode() {
123 assert!(is_valid_bytecode("0x6080604052"));
124 assert!(is_valid_bytecode("6080604052"));
125 assert!(!is_valid_bytecode(""));
126 assert!(!is_valid_bytecode("0x"));
127 assert!(!is_valid_bytecode("not_hex"));
128 }
129
130 #[test]
131 fn test_compute_bytecode_hash() {
132 let hash = compute_bytecode_hash("0x6080604052").unwrap();
133 assert_eq!(hash.len(), 64);
134 }
135
136 #[test]
137 fn test_parse_hex_block_number() {
138 assert_eq!(parse_hex_block_number("0x1a4").unwrap(), 420);
139 assert_eq!(parse_hex_block_number("1a4").unwrap(), 420);
140 assert_eq!(parse_hex_block_number("0x0").unwrap(), 0);
141 assert_eq!(parse_hex_block_number("0xff").unwrap(), 255);
142 }
143
144 #[test]
145 fn test_parse_hex_block_number_invalid() {
146 assert!(parse_hex_block_number("not_hex").is_err());
147 }
148}