Skip to content

Commit

Permalink
use ahash and indexmap in new mod collections - hashes without random
Browse files Browse the repository at this point in the history
  • Loading branch information
cdump committed Feb 18, 2025
1 parent 3aa634a commit cb9bfe0
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 33 deletions.
22 changes: 18 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ exclude = ["/javascript", "/python", "/benchmark", "/.github"]
[dependencies]
alloy-primitives = "0.8"
alloy-dyn-abi = "0.8"
ahash = { version = "0.8", default-features = false }
indexmap = "2.7"

pyo3 = { version = "0.23", features = ["extension-module"], optional = true }
wasm-bindgen = { version = "0.2", optional = true }
Expand Down
7 changes: 5 additions & 2 deletions benchmark/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,9 @@ def process_flow(dname: str, providers: list[str], results_dir: str) -> dict:
missing_edges = len(reference_flows - curr_edges)
extra_edges = len(curr_edges - reference_flows)

# if missing_edges > 0:
# print(fname, total_edges, reference_flows - curr_edges)

provider_stats.append((total_blocks, total_edges, missing_edges, extra_edges))

# print(fname, provider_stats)
Expand All @@ -332,8 +335,8 @@ def show_flow(providers: list[str], all_results: list, show_errors: bool):
print(f' time: {dataset_result["timings"][provider_idx]:.1f}s')
print(f' blks: {blocks}')
print(f' edges: {edges}')
print(f' miss: {e1}')
print(f' extr: {e2}')
print(f' miss: {e1}')
print(f' extr: {e2}')

def show_arguments_or_mutability(providers: list[str], all_results: list, show_errors: bool):
for dataset_result in all_results:
Expand Down
2 changes: 1 addition & 1 deletion benchmark/providers/evmole-js/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# syntax=docker/dockerfile:1

FROM node:22 AS build
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.84
COPY ./rust /workdir
WORKDIR /workdir/javascript
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.84
ENV PATH=/root/.cargo/bin:$PATH
RUN npm ci && npm run build && npm pack

Expand Down
15 changes: 14 additions & 1 deletion benchmark/providers/evmole-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions src/arguments/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ use crate::{
vm::{StepResult, Vm},
U256, VAL_0_B, VAL_1, VAL_1_B, VAL_32_B,
},
collections::HashSet,
utils::{and_mask_to_type, elabel, execute_until_function_start, match_first_two},
DynSolType, Selector,
};
use alloy_primitives::uint;
use std::{
cmp::max,
collections::{BTreeMap, BTreeSet},
collections::BTreeMap,
};

mod calldata;
Expand Down Expand Up @@ -131,7 +132,7 @@ impl Info {
#[derive(Default, Debug)]
struct ArgsResult {
data: Info,
not_bool: BTreeSet<Vec<u32>>,
not_bool: HashSet<Vec<u32>>,
}

impl ArgsResult {
Expand Down
22 changes: 22 additions & 0 deletions src/collections.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use ahash::RandomState;

#[derive(Clone)]
pub (crate) struct MyHashBuilder {
state: RandomState,
}

impl Default for MyHashBuilder {
fn default() -> Self {
Self{state: RandomState::with_seed(42)}
}
}
impl std::hash::BuildHasher for MyHashBuilder {
type Hasher = <RandomState as std::hash::BuildHasher>::Hasher;
fn build_hasher(&self) -> Self::Hasher {
self.state.build_hasher()
}
}

pub(crate) type HashMap<K, V> = std::collections::HashMap<K, V, MyHashBuilder>;
pub(crate) type HashSet<K> = std::collections::HashSet<K, MyHashBuilder>;
pub(crate) type IndexMap<K, V> = indexmap::IndexMap<K, V, MyHashBuilder>;
4 changes: 3 additions & 1 deletion src/control_flow_graph/initial.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::collections::{BTreeMap, HashSet};
use std::collections::BTreeMap;

use crate::collections::HashSet;

use crate::evm::{
code_iterator::{iterate_code, CodeOp},
Expand Down
12 changes: 7 additions & 5 deletions src/control_flow_graph/reachable.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::collections::{BTreeMap, HashSet};
use std::collections::BTreeMap;

use crate::collections::HashSet;

use super::{Block, BlockType, INVALID_JUMP_START};

Expand All @@ -10,7 +12,7 @@ pub fn get_reachable_nodes(
let mut global_visited = initial_visited.unwrap_or_default();
loop {
let before = global_visited.len();
let mut visited = HashSet::new();
let mut visited = HashSet::default();
let mut queue = vec![from];
while let Some(current) = queue.pop() {
if current >= INVALID_JUMP_START {
Expand Down Expand Up @@ -78,7 +80,7 @@ mod tests {
blocks.insert(1, create_basic_block(BlockType::Terminate { success: false }));

let reachable = get_reachable_nodes(&blocks, 0, None);
assert_eq!(reachable, HashSet::from([0, 1]));
assert_eq!(reachable, HashSet::from_iter([0, 1]));
}

#[test]
Expand All @@ -89,7 +91,7 @@ mod tests {
blocks.insert(2, create_basic_block(BlockType::Terminate { success: false }));

let reachable = get_reachable_nodes(&blocks, 0, None);
assert_eq!(reachable, HashSet::from([0, 1, 2]));
assert_eq!(reachable, HashSet::from_iter([0, 1, 2]));
}

#[test]
Expand All @@ -107,6 +109,6 @@ mod tests {
blocks.insert(2, create_basic_block(BlockType::Terminate { success: false }));

let reachable = get_reachable_nodes(&blocks, 0, None);
assert_eq!(reachable, HashSet::from([0, 1, 2]));
assert_eq!(reachable, HashSet::from_iter([0, 1, 2]));
}
}
33 changes: 17 additions & 16 deletions src/control_flow_graph/resolver.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::{BTreeMap, HashMap, HashSet};
use std::collections::BTreeMap;

use crate::collections::{HashMap, HashSet, IndexMap};

use super::{
reachable::get_reachable_nodes,
Expand All @@ -13,7 +14,7 @@ struct RevIdx {
states: HashMap<usize /*start*/, State>,

/// Maps a destination to all parent paths (each as a vector of block addresses) and their associated state.
parents: HashMap<usize /*to*/, HashMap<Vec<usize> /*path*/, State>>,
parents: HashMap<usize /*to*/, IndexMap<Vec<usize> /*path*/, State>>,

/// Intermediate states: maps a block (by its last element) to states and the set of jump symbols encountered so far.
istate: HashMap<usize, HashMap<State, HashSet<StackSym>>>,
Expand Down Expand Up @@ -99,7 +100,7 @@ impl RevIdx {
}
st.insert(jmp.to_owned());
} else {
entry.insert(state.to_owned(), HashSet::from([jmp.to_owned()]));
entry.insert(state.to_owned(), HashSet::from_iter([jmp.to_owned()]));
}
true
}
Expand All @@ -121,7 +122,7 @@ fn resolve_dynamic_jump_path(rev_idx: &mut RevIdx, path: Vec<usize>, stack_pos:

let parents = rev_idx.get_parents(current);

// eprintln!("parents for {} : {:?}", cur, parents);
// crate::utils::log(format!("parents for {} : {:?}", current, parents));

for (parent_path, parent_state) in parents.into_iter() {
energy_used += 1;
Expand Down Expand Up @@ -162,7 +163,7 @@ fn resolve_dynamic_jump_path(rev_idx: &mut RevIdx, path: Vec<usize>, stack_pos:
}

StackSym::Jumpdest(to) => {
// eprintln!("found {} from {:?}", to, newpath);
// crate::utils::log(format!("found {} from {:?}", to, new_path));
if rev_idx.insert_path_parent(to, &new_path, new_state) {
dynamic_jumps.push(DynamicJump {
path: new_path,
Expand Down Expand Up @@ -205,10 +206,10 @@ fn resolve_dynamic_jump_path(rev_idx: &mut RevIdx, path: Vec<usize>, stack_pos:
pub fn resolve_dynamic_jumps(code: &[u8], mut blocks: BTreeMap<usize, Block>) -> BTreeMap<usize, Block> {

// Map block start addresses to the initial stack position extracted from the block.
let mut stack_pos: HashMap<usize, usize> = HashMap::new();
let mut stack_pos: Vec<(usize, usize)> = Vec::default();

let mut rev_idx = RevIdx::default();
rev_idx.set_reachable0(HashSet::from([0]));
rev_idx.set_reachable0(HashSet::from_iter([0]));

// First stage resolve
for block in blocks.values_mut() {
Expand All @@ -227,7 +228,7 @@ pub fn resolve_dynamic_jumps(code: &[u8], mut blocks: BTreeMap<usize, Block>) ->
}
}
Some(StackSym::Before(new_stack_pos)) => {
stack_pos.insert(block.start, new_stack_pos);
stack_pos.push((block.start, new_stack_pos));
}
_ => {}
}
Expand Down Expand Up @@ -270,18 +271,18 @@ pub fn resolve_dynamic_jumps(code: &[u8], mut blocks: BTreeMap<usize, Block>) ->

let mut found_new_paths = false;

for (&start, &stack_pos) in &stack_pos {
if !reachable.contains(&start) {
for (start, stack_pos) in &stack_pos {
if !reachable.contains(start) {
continue;
}

let state = rev_idx.get_state(code, start).to_owned();
let (jumps, energy_used) = resolve_dynamic_jump_path(&mut rev_idx, vec![start], stack_pos, state, ENERGY_LIMIT - total_energy_used);
let state = rev_idx.get_state(code, *start).to_owned();
let (jumps, energy_used) = resolve_dynamic_jump_path(&mut rev_idx, vec![*start], *stack_pos, state, ENERGY_LIMIT - total_energy_used);
total_energy_used += energy_used;

if !jumps.is_empty() {
found_new_paths = true;
match blocks.get_mut(&start).unwrap().btype {
match blocks.get_mut(start).unwrap().btype {
BlockType::DynamicJump{ref mut to} => {
to.extend(jumps);
}
Expand All @@ -299,10 +300,10 @@ pub fn resolve_dynamic_jumps(code: &[u8], mut blocks: BTreeMap<usize, Block>) ->
}

// Merge jump targets if all resolved dynamic jumps from a block lead to the same target.
for start in stack_pos.keys() {
for (start, _) in stack_pos {
let mut one_to = None;

if let BlockType::DynamicJump{to: ref dj} = blocks.get(start).unwrap().btype {
if let BlockType::DynamicJump{to: ref dj} = blocks.get(&start).unwrap().btype {
if !dj.is_empty() && dj.iter().all(|v| v.to.is_some()) {
let first_to = dj[0].to;
if dj.iter().all(|v| v.to == first_to) {
Expand All @@ -311,7 +312,7 @@ pub fn resolve_dynamic_jumps(code: &[u8], mut blocks: BTreeMap<usize, Block>) ->
}
}
if let Some(to) = one_to {
blocks.get_mut(start).unwrap().btype = BlockType::Jump{to};
blocks.get_mut(&start).unwrap().btype = BlockType::Jump{to};
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/evm/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ macro_rules! declare_opcodes {
};
}

pub fn info(op: OpCode) -> &'static OpCodeInfo {
pub const fn info(op: OpCode) -> &'static OpCodeInfo {
&INFOS[op as usize]
}

Expand Down
6 changes: 6 additions & 0 deletions src/interface_js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ use alloy_primitives::hex;
use serde::Deserialize;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
pub fn log(s: &str);
}

fn decode_hex_code(input: &str) -> Result<Vec<u8>, JsError> {
hex::decode(input).map_err(|e| JsError::new(&format!("Failed to decode code hex input: {e}")))
}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod selectors;
mod state_mutability;
mod storage;
mod utils;
mod collections;
pub mod control_flow_graph;

#[cfg(feature = "serde")]
Expand Down
9 changes: 9 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ pub fn and_mask_to_type(mask: U256) -> Option<DynSolType> {
None
}

#[allow(dead_code)]
pub fn log(s: String) {
#[cfg(feature = "javascript")]
crate::interface_js::log(&s);

#[cfg(not(feature = "javascript"))]
eprintln!("{}", s);
}

#[cfg(test)]
mod tests {
use alloy_primitives::uint;
Expand Down

0 comments on commit cb9bfe0

Please sign in to comment.