ethcontract_common/
bytecode.rs1use crate::errors::{BytecodeError, LinkError};
6use serde::de::{Error as DeError, Visitor};
7use serde::{Deserialize, Deserializer, Serialize};
8use std::collections::HashSet;
9use std::fmt::{Formatter, Result as FmtResult};
10use std::mem;
11use web3::types::{Address, Bytes};
12
13#[derive(Clone, Debug, Default, Serialize)]
17pub struct Bytecode(String);
18
19impl Bytecode {
20 pub fn from_hex_str(s: &str) -> Result<Self, BytecodeError> {
22 if s.is_empty() {
23 return Ok(Bytecode::default());
25 }
26
27 if s.len() % 2 != 0 {
29 return Err(BytecodeError::InvalidLength);
30 }
31
32 let s = s.strip_prefix("0x").unwrap_or(s);
34
35 for block in CodeIter(s) {
37 let block = block?;
38
39 if let Some(pos) = block.bytes().position(|b| !b.is_ascii_hexdigit()) {
40 return Err(BytecodeError::InvalidHexDigit(
41 block.chars().nth(pos).expect("valid pos"),
42 ));
43 }
44 }
45
46 Ok(Bytecode(s.to_string()))
47 }
48
49 pub fn link<S>(&mut self, name: S, address: Address) -> Result<(), LinkError>
56 where
57 S: AsRef<str>,
58 {
59 let name = name.as_ref();
60 assert!(name.len() <= 38, "invalid library name for linking");
61
62 let placeholder = format!("__{:_<38}", name);
66 let address = to_fixed_hex(&address);
67 if !self.0.contains(&placeholder) {
68 return Err(LinkError::NotFound(name.to_string()));
69 }
70 self.0 = self.0.replace(&placeholder, &address);
71
72 Ok(())
73 }
74
75 pub fn to_bytes(&self) -> Result<Bytes, LinkError> {
77 match self.undefined_libraries().next() {
78 Some(library) => Err(LinkError::UndefinedLibrary(library.to_string())),
79 None => Ok(Bytes(hex::decode(&self.0).expect("valid hex"))),
80 }
81 }
82
83 pub fn undefined_libraries(&self) -> LibIter<'_> {
85 LibIter {
86 cursor: &self.0,
87 seen: HashSet::new(),
88 }
89 }
90
91 pub fn requires_linking(&self) -> bool {
93 self.undefined_libraries().next().is_some()
94 }
95
96 pub fn is_empty(&self) -> bool {
98 self.0.is_empty()
99 }
100}
101
102struct CodeIter<'a>(&'a str);
105
106impl<'a> Iterator for CodeIter<'a> {
107 type Item = Result<&'a str, BytecodeError>;
108
109 fn next(&mut self) -> Option<Self::Item> {
110 if self.0.is_empty() {
111 return None;
112 }
113
114 match self.0.find("__") {
115 Some(pos) => {
116 let (block, tail) = self.0.split_at(pos);
117 if tail.len() < 40 {
118 Some(Err(BytecodeError::PlaceholderTooShort))
119 } else {
120 self.0 = &tail[40..];
121 Some(Ok(block))
122 }
123 }
124 None => Some(Ok(mem::take(&mut self.0))),
125 }
126 }
127}
128
129pub struct LibIter<'a> {
131 cursor: &'a str,
132 seen: HashSet<&'a str>,
133}
134
135impl<'a> Iterator for LibIter<'a> {
136 type Item = &'a str;
137
138 fn next(&mut self) -> Option<Self::Item> {
139 while let Some(pos) = self.cursor.find("__") {
140 let (placeholder, tail) = self.cursor[pos..].split_at(40);
143 let lib = placeholder.trim_matches('_');
144
145 self.cursor = tail;
146 if self.seen.insert(lib) {
147 return Some(lib);
148 }
149 }
150 None
151 }
152}
153
154impl<'de> Deserialize<'de> for Bytecode {
155 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
156 where
157 D: Deserializer<'de>,
158 {
159 deserializer.deserialize_str(BytecodeVisitor)
160 }
161}
162
163struct BytecodeVisitor;
165
166impl Visitor<'_> for BytecodeVisitor {
167 type Value = Bytecode;
168
169 fn expecting(&self, f: &mut Formatter) -> FmtResult {
170 write!(f, "valid EVM bytecode string representation")
171 }
172
173 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
174 where
175 E: DeError,
176 {
177 Bytecode::from_hex_str(v).map_err(E::custom)
178 }
179}
180
181fn to_fixed_hex(address: &Address) -> String {
182 format!("{:040x}", address)
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn default_bytecode_is_empty() {
191 assert!(Bytecode::default().is_empty());
192 }
193
194 #[test]
195 fn empty_hex_bytecode_is_empty() {
196 assert!(Bytecode::from_hex_str("0x").unwrap().is_empty());
197 }
198
199 #[test]
200 fn unprefixed_hex_bytecode_is_not_empty() {
201 assert!(!Bytecode::from_hex_str("feedface").unwrap().is_empty());
202 }
203
204 #[test]
205 fn to_fixed_hex_() {
206 for (value, expected) in &[
207 (
208 "0x0000000000000000000000000000000000000000",
209 "0000000000000000000000000000000000000000",
210 ),
211 (
212 "0x0102030405060708091020304050607080900001",
213 "0102030405060708091020304050607080900001",
214 ),
215 (
216 "0x9fac3b52be975567103c4695a2835bba40076da1",
217 "9fac3b52be975567103c4695a2835bba40076da1",
218 ),
219 ] {
220 let value: Address = value[2..].parse().unwrap();
221 assert_eq!(to_fixed_hex(&value), *expected);
222 }
223 }
224
225 #[test]
226 fn bytecode_link_success() {
227 let address = Address::zero();
228 let address_encoded = [0u8; 20];
229 let name = "name";
230 let placeholder = format!("__{:_<38}", name);
231 let mut bytecode = Bytecode::from_hex_str(&format!(
232 "0x61{}{}61{}",
233 placeholder, placeholder, placeholder
234 ))
235 .unwrap();
236 bytecode.link(name, address).unwrap();
237 let bytes = bytecode.to_bytes().unwrap();
238 let mut expected = Vec::<u8>::new();
239 expected.extend([0x61]);
240 expected.extend(address_encoded);
241 expected.extend(address_encoded);
242 expected.extend([0x61]);
243 expected.extend(address_encoded);
244 assert_eq!(bytes.0, expected);
245 }
246
247 #[test]
248 fn bytecode_link_fail() {
249 let address = Address::zero();
250 let placeholder = format!("__{:_<38}", "name0");
251 let mut bytecode = Bytecode::from_hex_str(&format!(
252 "0x61{}{}61{}",
253 placeholder, placeholder, placeholder
254 ))
255 .unwrap();
256 match bytecode.link("name1", address) {
258 Err(LinkError::NotFound(_)) => (),
259 _ => panic!("should fail with not found error"),
260 }
261 }
262}