diff --git a/Cargo.lock b/Cargo.lock index b0ecae36..15262e9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1543,6 +1543,12 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +[[package]] +name = "bytecount" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" + [[package]] name = "bytemuck" version = "1.16.1" @@ -2136,6 +2142,19 @@ dependencies = [ "serde", ] +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.17", + "serde", + "serde_json", +] + [[package]] name = "cargo_metadata" version = "0.18.1" @@ -3047,6 +3066,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + [[package]] name = "eth-keystore" version = "0.5.0" @@ -3223,7 +3251,7 @@ checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" dependencies = [ "arrayvec", "bytes", - "cargo_metadata", + "cargo_metadata 0.18.1", "chrono", "const-hex", "elliptic-curve", @@ -3389,9 +3417,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fastrlp" @@ -4995,9 +5023,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libm" @@ -5161,6 +5189,21 @@ dependencies = [ "unicase", ] +[[package]] +name = "mini-moka" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c325dfab65f261f386debee8b0969da215b3fa0037e74c8a1234db7ba986d803" +dependencies = [ + "crossbeam-channel", + "crossbeam-utils", + "dashmap", + "skeptic", + "smallvec", + "tagptr", + "triomphe", +] + [[package]] name = "minilp" version = "0.2.2" @@ -6099,6 +6142,7 @@ dependencies = [ "futures 0.3.28", "hex", "hyper 0.14.27", + "mini-moka", "mockito", "num-traits 0.2.17", "reqwest 0.12.8", @@ -6113,6 +6157,7 @@ dependencies = [ "starknet_in_rust", "strum 0.25.0", "strum_macros 0.25.2", + "tempfile", "thiserror", "tokio", "tokio-tungstenite 0.20.1", @@ -6125,6 +6170,17 @@ dependencies = [ "warp", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags 2.6.0", + "memchr", + "unicase", +] + [[package]] name = "pyo3" version = "0.19.2" @@ -6850,9 +6906,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -7508,6 +7564,21 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +[[package]] +name = "skeptic" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +dependencies = [ + "bytecount", + "cargo_metadata 0.14.2", + "error-chain", + "glob", + "pulldown-cmark", + "tempfile", + "walkdir", +] + [[package]] name = "slab" version = "0.4.8" @@ -8108,6 +8179,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tap" version = "1.0.1" @@ -8122,14 +8199,15 @@ checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -8570,6 +8648,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "triomphe" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" + [[package]] name = "try-lock" version = "0.2.4" @@ -9198,6 +9282,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 1ff9357e..8e693313 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,9 @@ foundry-config = { git = "https://github.com/foundry-rs/foundry", rev = "2544793 foundry-evm = { git = "https://github.com/foundry-rs/foundry", rev = "2544793" } revm-inspectors = { version = "0.5", features = ["serde"] } +mini-moka = "0.10" +tempfile = "3.13.0" + [dev-dependencies] mockito = "1.1.1" warp = "0.3.5" diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 55f161fd..9c373cc9 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -10,6 +10,7 @@ pub mod state; pub mod tycho; pub mod uniswap_v2; pub mod uniswap_v3; +mod vm; /// A trait for converting types to and from `Bytes`. /// diff --git a/src/protocol/vm/mod.rs b/src/protocol/vm/mod.rs new file mode 100644 index 00000000..95adf51c --- /dev/null +++ b/src/protocol/vm/mod.rs @@ -0,0 +1 @@ +mod utils; diff --git a/src/protocol/vm/utils.rs b/src/protocol/vm/utils.rs new file mode 100644 index 00000000..59111f86 --- /dev/null +++ b/src/protocol/vm/utils.rs @@ -0,0 +1,58 @@ +// TODO: remove skip for clippy dead_code check +#![allow(dead_code)] + +use mini_moka::sync::Cache; +use std::{ + fs::File, + io::Read, + path::Path, + sync::{Arc, LazyLock}, +}; + +static BYTECODE_CACHE: LazyLock, Vec>> = LazyLock::new(|| Cache::new(1_000)); + +pub fn get_contract_bytecode(path: &str) -> std::io::Result> { + if let Some(bytecode) = BYTECODE_CACHE.get(&Arc::new(path.to_string())) { + return Ok(bytecode.clone()); + } + + let mut file = File::open(Path::new(path))?; + let mut code = Vec::new(); + + file.read_to_end(&mut code)?; + BYTECODE_CACHE.insert(Arc::new(path.to_string()), code.clone()); + + Ok(code) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::{fs::remove_file, io::Write}; + use tempfile::NamedTempFile; + + #[test] + fn test_get_contract_bytecode() { + // Create a temporary file with some test data + let mut temp_file = NamedTempFile::new().unwrap(); + let test_data = b"Test contract bytecode"; + temp_file.write_all(test_data).unwrap(); + let temp_path = temp_file.path().to_str().unwrap(); + + // First call to get_contract_bytecode + let result1 = get_contract_bytecode(temp_path).unwrap(); + assert_eq!(result1, test_data); + + // Second call to get_contract_bytecode (should use cached data) + // Verify that the cache was used (file is not read twice) + remove_file(&temp_file).unwrap(); // This removes the temporary file + let result2 = get_contract_bytecode(temp_path).unwrap(); + assert_eq!(result2, test_data); + } + + #[test] + fn test_get_contract_bytecode_error() { + let result = get_contract_bytecode("non_existent_file.txt"); + assert!(result.is_err()); + } +}