Skip to content

Commit

Permalink
⚡ perf: remove String params, reduce clones
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon-Becker committed Jul 14, 2023
1 parent 0e15ed2 commit 827272a
Show file tree
Hide file tree
Showing 29 changed files with 268 additions and 242 deletions.
6 changes: 3 additions & 3 deletions cache/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn prettify_bytes(bytes: u64) -> String {
}
}

pub fn write_file(_path: &String, contents: &String) -> Option<String> {
pub fn write_file(_path: &str, contents: &str) -> Option<String> {
let path = std::path::Path::new(_path);
let prefix = path.parent().unwrap();
match std::fs::create_dir_all(prefix) {
Expand All @@ -50,7 +50,7 @@ pub fn write_file(_path: &String, contents: &String) -> Option<String> {
Some(_path.to_string())
}

pub fn read_file(_path: &String) -> Option<String> {
pub fn read_file(_path: &str) -> Option<String> {
let path = std::path::Path::new(_path);
let mut file = match File::open(path) {
Ok(file) => file,
Expand All @@ -64,7 +64,7 @@ pub fn read_file(_path: &String) -> Option<String> {
Some(contents)
}

pub fn delete_path(_path: &String) -> bool {
pub fn delete_path(_path: &str) -> bool {
let path = match std::path::Path::new(_path).to_str() {
Some(path) => path,
None => return false,
Expand Down
55 changes: 32 additions & 23 deletions common/src/ether/compiler.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
// returns the compiler version used to compile the contract.
// for example: (solc, 0.8.10) or (vyper, 0.2.16)
pub fn detect_compiler(bytecode: String) -> (String, String) {
let mut compiler = "unknown".to_string();
pub fn detect_compiler(bytecode: &str) -> (&'static str, String) {
let mut compiler = "unknown";
let mut version = "unknown".to_string();

// perfom prefix check for rough version matching
if bytecode.starts_with("363d3d373d3d3d363d73") {
compiler = "proxy".to_string();
if bytecode.starts_with("363d3d373d3d3d363d73") || bytecode.starts_with("5f5f365f5f37") {
compiler = "proxy";
version = "minimal".to_string();
} else if bytecode.starts_with("366000600037611000600036600073") {
compiler = "proxy".to_string();
compiler = "proxy";
version = "vyper".to_string();
} else if bytecode.starts_with("6004361015") {
compiler = "vyper".to_string();
compiler = "vyper";
version = "0.2.0-0.2.4,0.2.11-0.3.3".to_string();
} else if bytecode.starts_with("341561000a") {
compiler = "vyper".to_string();
compiler = "vyper";
version = "0.2.5-0.2.8".to_string();
} else if bytecode.starts_with("731bf797") {
compiler = "solc".to_string();
compiler = "solc";
version = "0.4.10-0.4.24".to_string();
} else if bytecode.starts_with("6080604052") {
compiler = "solc".to_string();
compiler = "solc";
version = "0.4.22+".to_string();
} else if bytecode.starts_with("6060604052") {
compiler = "solc".to_string();
compiler = "solc";
version = "0.4.11-0.4.21".to_string();
} else if bytecode.contains("7679706572") {
compiler = "vyper".to_string();
compiler = "vyper";
} else if bytecode.contains("736f6c63") {
compiler = "solc".to_string();
compiler = "solc";
}

// perform metadata check
// check for cbor encoded compiler metadata
// https://cbor.io
if compiler == "solc" {
let compiler_version = bytecode.split("736f6c6343").collect::<Vec<&str>>();

Expand All @@ -45,11 +46,15 @@ pub fn detect_compiler(bytecode: String) -> (String, String) {
.map(|c| c.iter().collect::<String>())
.collect::<Vec<String>>();

version = String::new();
for version_part in version_array {
version
.push_str(&format!("{}.", u8::from_str_radix(&version_part, 16).unwrap()));
}
version = version_array
.iter()
.map(|v| {
u8::from_str_radix(&v, 16)
.expect("Failed to decode cbor encoded metadata.")
.to_string()
})
.collect::<Vec<String>>()
.join(".");
}
}
} else if compiler == "vyper" {
Expand All @@ -64,11 +69,15 @@ pub fn detect_compiler(bytecode: String) -> (String, String) {
.map(|c| c.iter().collect::<String>())
.collect::<Vec<String>>();

version = String::new();
for version_part in version_array {
version
.push_str(&format!("{}.", u8::from_str_radix(&version_part, 16).unwrap()));
}
version = version_array
.iter()
.map(|v| {
u8::from_str_radix(&v, 16)
.expect("Failed to decode cbor encoded metadata.")
.to_string()
})
.collect::<Vec<String>>()
.join(".");
}
}
}
Expand Down
23 changes: 11 additions & 12 deletions common/src/ether/evm/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use crate::{
use super::vm::Instruction;

// decode a string into an ethereum type
pub fn parse_function_parameters(function_signature: String) -> Option<Vec<ParamType>> {
pub fn parse_function_parameters(function_signature: &str) -> Option<Vec<ParamType>> {
let mut function_inputs = Vec::new();

// get only the function input body, removing the name and input wrapping parentheses
let string_inputs = match function_signature.split_once('(') {
Some((_, inputs)) => replace_last(inputs.to_string(), ")", ""),
Some((_, inputs)) => replace_last(&inputs, ")", ""),
None => replace_last(function_signature, ")", ""),
};

Expand Down Expand Up @@ -71,20 +71,19 @@ pub fn parse_function_parameters(function_signature: String) -> Option<Vec<Param
continue
}
if solidity_type.starts_with('(') && !solidity_type.ends_with(']') {
let complex_inputs = match parse_function_parameters(solidity_type.clone()) {
let complex_inputs = match parse_function_parameters(&solidity_type) {
Some(inputs) => inputs,
None => continue,
};
function_inputs.push(ParamType::Tuple(complex_inputs));
continue
}
if solidity_type.ends_with("[]") {
let array_type = match parse_function_parameters(
solidity_type[..solidity_type.len() - 2].to_string(),
) {
Some(types_) => types_,
None => continue,
};
let array_type =
match parse_function_parameters(&solidity_type[..solidity_type.len() - 2]) {
Some(types_) => types_,
None => continue,
};

if array_type.len() == 1 {
function_inputs.push(ParamType::Array(Box::new(array_type[0].clone())));
Expand All @@ -102,7 +101,7 @@ pub fn parse_function_parameters(function_signature: String) -> Option<Vec<Param
None => continue,
};
let array_type = match parse_function_parameters(
solidity_type[..solidity_type.len() - (2 + size.to_string().len())].to_string(),
&solidity_type[..solidity_type.len() - (2 + size.to_string().len())],
) {
Some(types_) => types_,
None => continue,
Expand Down Expand Up @@ -245,9 +244,9 @@ pub fn byte_size_to_type(byte_size: usize) -> (usize, Vec<String>) {
(byte_size, potential_types)
}

pub fn find_cast(line: String) -> (usize, usize, Option<String>) {
pub fn find_cast(line: &str) -> (usize, usize, Option<String>) {
// find the start of the cast
match TYPE_CAST_REGEX.find(&line).unwrap() {
match TYPE_CAST_REGEX.find(&line).expect("Failed to find type cast.") {
Some(m) => {
let start = m.start();
let end = m.end() - 1;
Expand Down
2 changes: 1 addition & 1 deletion common/src/ether/evm/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1530,7 +1530,7 @@ impl VM {
}

// Executes provided calldata until finished
pub fn call(&mut self, calldata: String, value: u128) -> Result {
pub fn call(&mut self, calldata: &str, value: u128) -> Result {
// reset the VM temp state
self.reset();
self.calldata = decode_hex(&calldata.replacen("0x", "", 1)).unwrap();
Expand Down
8 changes: 2 additions & 6 deletions common/src/ether/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use ethers::{
};
use heimdall_cache::{read_cache, store_cache};

pub fn get_code(contract_address: &String, rpc_url: &String, logger: &Logger) -> String {
pub fn get_code(contract_address: &str, rpc_url: &str, logger: &Logger) -> String {
// create new runtime block
let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();

Expand Down Expand Up @@ -60,11 +60,7 @@ pub fn get_code(contract_address: &String, rpc_url: &String, logger: &Logger) ->
})
}

pub fn get_transaction(
transaction_hash: &String,
rpc_url: &String,
logger: &Logger,
) -> Transaction {
pub fn get_transaction(transaction_hash: &str, rpc_url: &str, logger: &Logger) -> Transaction {
let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();

// We are decoding a transaction hash, so we need to fetch the calldata from the RPC provider.
Expand Down
32 changes: 22 additions & 10 deletions common/src/ether/selectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{io::logging::Logger, utils::strings::decode_hex};
use super::{evm::vm::VM, signatures::ResolveSelector};

// find all function selectors in the given EVM assembly.
pub fn find_function_selectors(evm: &VM, assembly: String) -> HashMap<String, u128> {
pub fn find_function_selectors(evm: &VM, assembly: &str) -> HashMap<String, u128> {
let mut function_selectors = HashMap::new();

// search through assembly for PUSHN (where N <= 4) instructions, optimistically assuming that
Expand All @@ -29,7 +29,7 @@ pub fn find_function_selectors(evm: &VM, assembly: String) -> HashMap<String, u1

// get the function's entry point
let function_entry_point =
match resolve_entry_point(&evm.clone(), function_selector.clone()) {
match resolve_entry_point(&evm.clone(), &function_selector) {
0 => continue,
x => x,
};
Expand All @@ -42,12 +42,12 @@ pub fn find_function_selectors(evm: &VM, assembly: String) -> HashMap<String, u1
}

// resolve a selector's function entry point from the EVM bytecode
pub fn resolve_entry_point(evm: &VM, selector: String) -> u128 {
pub fn resolve_entry_point(evm: &VM, selector: &str) -> u128 {
let mut vm = evm.clone();
let mut handled_jumps = HashSet::new();

// execute the EVM call to find the entry point for the given selector
vm.calldata = decode_hex(&selector).unwrap();
vm.calldata = decode_hex(&selector).expect("Failed to decode selector.");
while vm.bytecode.len() >= vm.instruction as usize {
let call = vm.step();

Expand Down Expand Up @@ -93,9 +93,18 @@ where

let mut threads = Vec::new();

resolve_progress.lock().unwrap().enable_steady_tick(Duration::from_millis(100));
resolve_progress.lock().unwrap().set_style(logger.info_spinner());
resolve_progress.lock().unwrap().set_message("resolving selectors");
resolve_progress
.lock()
.expect("Could not obtain lock on resolve_progress.")
.enable_steady_tick(Duration::from_millis(100));
resolve_progress
.lock()
.expect("Could not obtain lock on resolve_progress.")
.set_style(logger.info_spinner());
resolve_progress
.lock()
.expect("Could not obtain lock on resolve_progress.")
.set_message("resolving selectors");

for selector in selectors {
let function_clone = resolved_functions.clone();
Expand All @@ -104,8 +113,10 @@ where
// create a new thread for each selector
threads.push(thread::spawn(move || {
if let Some(function) = T::resolve(&selector) {
let mut _resolved_functions = function_clone.lock().unwrap();
let mut _resolve_progress = resolve_progress.lock().unwrap();
let mut _resolved_functions =
function_clone.lock().expect("Could not obtain lock on function_clone.");
let mut _resolve_progress =
resolve_progress.lock().expect("Could not obtain lock on resolve_progress.");
_resolve_progress
.set_message(format!("resolved {} selectors", _resolved_functions.len()));
_resolved_functions.insert(selector, function);
Expand All @@ -120,6 +131,7 @@ where

resolve_progress.lock().unwrap().finish_and_clear();

let x = resolved_functions.lock().unwrap().clone();
let x =
resolved_functions.lock().expect("Could not obtain lock on resolved_functions.").clone();
x
}
14 changes: 7 additions & 7 deletions common/src/ether/signatures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl ResolveSelector for ResolvedError {
}

// get function possibilities from etherface
let signatures = match get_json_from_url(format!(
let signatures = match get_json_from_url(&format!(
"https://api.etherface.io/v1/signatures/hash/error/{}/1",
&selector
)) {
Expand Down Expand Up @@ -80,7 +80,7 @@ impl ResolveSelector for ResolvedError {
signature_list.push(ResolvedError {
name: function_parts.0.to_string(),
signature: text_signature.to_string(),
inputs: replace_last(function_parts.1.to_string(), ")", "")
inputs: replace_last(&function_parts.1, ")", "")
.split(',')
.map(|input| input.to_string())
.collect(),
Expand Down Expand Up @@ -110,7 +110,7 @@ impl ResolveSelector for ResolvedLog {
}

// get function possibilities from etherface
let signatures = match get_json_from_url(format!(
let signatures = match get_json_from_url(&format!(
"https://api.etherface.io/v1/signatures/hash/event/{}/1",
&selector
)) {
Expand Down Expand Up @@ -145,7 +145,7 @@ impl ResolveSelector for ResolvedLog {
signature_list.push(ResolvedLog {
name: function_parts.0.to_string(),
signature: text_signature.to_string(),
inputs: replace_last(function_parts.1.to_string(), ")", "")
inputs: replace_last(&function_parts.1, ")", "")
.split(',')
.map(|input| input.to_string())
.collect(),
Expand Down Expand Up @@ -175,7 +175,7 @@ impl ResolveSelector for ResolvedFunction {
}

// get function possibilities from etherface
let signatures = match get_json_from_url(format!(
let signatures = match get_json_from_url(&format!(
"https://api.etherface.io/v1/signatures/hash/function/{}/1",
&selector
)) {
Expand Down Expand Up @@ -210,7 +210,7 @@ impl ResolveSelector for ResolvedFunction {
signature_list.push(ResolvedFunction {
name: function_parts.0.to_string(),
signature: text_signature.to_string(),
inputs: replace_last(function_parts.1.to_string(), ")", "")
inputs: replace_last(&function_parts.1, ")", "")
.split(',')
.map(|input| input.to_string())
.collect(),
Expand All @@ -228,7 +228,7 @@ impl ResolveSelector for ResolvedFunction {
}
}

pub fn score_signature(signature: &String) -> u32 {
pub fn score_signature(signature: &str) -> u32 {
// the score starts at 1000
let mut score = 1000;

Expand Down
8 changes: 4 additions & 4 deletions common/src/io/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn short_path(path: &str) -> String {
path.replace(&current_dir, ".")
}

pub fn write_file(_path: &String, contents: &String) -> String {
pub fn write_file(_path: &str, contents: &str) -> String {
let path = std::path::Path::new(_path);
let prefix = path.parent().unwrap();
std::fs::create_dir_all(prefix).unwrap();
Expand All @@ -40,11 +40,11 @@ pub fn write_file(_path: &String, contents: &String) -> String {
_path.to_string()
}

pub fn write_lines_to_file(_path: &String, contents: Vec<String>) {
pub fn write_lines_to_file(_path: &str, contents: Vec<String>) {
write_file(_path, &contents.join("\n"));
}

pub fn read_file(_path: &String) -> String {
pub fn read_file(_path: &str) -> String {
let path = std::path::Path::new(_path);
let mut file = match File::open(path) {
Ok(file) => file,
Expand All @@ -66,7 +66,7 @@ pub fn read_file(_path: &String) -> String {
contents
}

pub fn delete_path(_path: &String) -> bool {
pub fn delete_path(_path: &str) -> bool {
let path = std::path::Path::new(_path);
Command::new("rm").args(["-rf", path.to_str().unwrap()]).output().is_ok()
}
Loading

0 comments on commit 827272a

Please sign in to comment.