Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feat/multichain
Browse files Browse the repository at this point in the history
  • Loading branch information
Wodann committed Oct 22, 2024
2 parents 2eda304 + 498d007 commit 34eb49a
Show file tree
Hide file tree
Showing 24 changed files with 605 additions and 662 deletions.
2 changes: 0 additions & 2 deletions .github/actions/setup-rust/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,3 @@ runs:
# By default, we do not override the toolchain from rust-toolchain.
# The user needs to explicitly use `<cmd> +<toolchain>` for clarity.
override: false

- uses: Swatinem/rust-cache@v2
5 changes: 5 additions & 0 deletions .syncpackrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ const config = {
// latest ethers v5 version
pinVersion: "5.7.2",
},
{
packages: ["**"],
dependencies: ["@nomicfoundation/edr"],
dependencyTypes: ["local"],
},
],
semverGroups: [
{
Expand Down
3 changes: 3 additions & 0 deletions Cargo.lock

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

11 changes: 10 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
[workspace]
members = [
"crates/*",
"crates/edr_defaults",
"crates/edr_eth",
"crates/edr_evm",
"crates/edr_napi",
"crates/edr_provider",
"crates/edr_rpc_client",
"crates/edr_rpc_eth",
"crates/edr_solidity",
"crates/edr_test_utils",
"crates/tools",
]
resolver = "2"

Expand Down
1 change: 1 addition & 0 deletions crates/edr_defaults/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version = "0.3.5"
edition = "2021"

[dependencies]
ruint = "1.12.3"

[lints]
workspace = true
5 changes: 5 additions & 0 deletions crates/edr_defaults/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use ruint::aliases::U256;

/// The default secret keys from which the local accounts will be derived.
pub const SECRET_KEYS: [&str; 20] = [
// these were taken from the standard output of a run of `hardhat node`
Expand Down Expand Up @@ -36,3 +38,6 @@ pub const MIX_HASH_SEED: &str = "randomMixHashSeed";

/// Seed value for the generator of state root hashes.
pub const STATE_ROOT_HASH_SEED: &str = "seed";

/// Terminal total difficulty for the Merge on main net
pub const TERMINAL_TOTAL_DIFFICULTY: U256 = ruint::uint!(58750000000000000000000_U256);
12 changes: 10 additions & 2 deletions crates/edr_evm/src/blockchain/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,13 @@ where
.get_block_by_hash_with_transaction_data(*hash)
.await?
{
// Geth has recently removed the total difficulty field from block RPC
// responses, so we fall back to the terminal total difficulty of main net to
// provide backwards compatibility.
// TODO https://github.com/NomicFoundation/edr/issues/696
let total_difficulty = *block
.total_difficulty()
.expect("Must be present as this is not a pending transaction");
.unwrap_or(&edr_defaults::TERMINAL_TOTAL_DIFFICULTY);

self.fetch_and_cache_block(cache, block).await?;

Expand All @@ -234,9 +238,13 @@ where
cache: RwLockUpgradableReadGuard<'_, SparseBlockchainStorage<BlockT, ChainSpecT>>,
block: ChainSpecT::RpcBlock<ChainSpecT::RpcTransaction>,
) -> Result<BlockT, ForkedBlockchainError<ChainSpecT>> {
// Geth has recently removed the total difficulty field from block RPC
// responses, so we fall back to the terminal total difficulty of main net to
// provide backwards compatibility.
// TODO https://github.com/NomicFoundation/edr/issues/696
let total_difficulty = *block
.total_difficulty()
.expect("Must be present as this is not a pending block");
.unwrap_or(&edr_defaults::TERMINAL_TOTAL_DIFFICULTY);

let block = RemoteBlock::new(block, self.client.clone(), self.runtime.clone())
.map_err(ForkedBlockchainError::BlockCreation)?;
Expand Down
24 changes: 24 additions & 0 deletions crates/edr_evm/src/precompiles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use std::{fmt::Debug, sync::Arc};

use edr_eth::{Address, HashMap};
use revm::ContextPrecompile;

use crate::{db::Database, evm::EvmHandler};

/// Registers custom precompiles.
pub fn register_precompiles_handles<DatabaseT, ContextT>(
handler: &mut EvmHandler<'_, ContextT, DatabaseT>,
precompiles: HashMap<Address, ContextPrecompile<DatabaseT>>,
) where
DatabaseT: Database,
DatabaseT::Error: Debug,
{
let old_handle = handler.pre_execution.load_precompiles();
handler.pre_execution.load_precompiles = Arc::new(move || {
let mut new_handle = old_handle.clone();

new_handle.extend(precompiles.clone());

new_handle
});
}
13 changes: 13 additions & 0 deletions crates/edr_napi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# @nomicfoundation/edr

## 0.6.4

### Patch Changes

- 14620c9: Fix panic due to remote nodes not returning total difficulty by adding fallback value

## 0.6.3

### Patch Changes

- a1cee4f: fix(tracing): Make sure to correctly 0x-prefix hex encoded strings in custom error message
- 7047e6c: Fixed panic from unknown opcode in stack traces

## 0.6.2

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion crates/edr_napi/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nomicfoundation/edr",
"version": "0.6.2",
"version": "0.6.4",
"devDependencies": {
"@napi-rs/cli": "^2.18.4",
"@nomicfoundation/ethereumjs-util": "^9.0.4",
Expand Down
48 changes: 42 additions & 6 deletions crates/edr_napi/src/trace/error_inferrer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1173,7 +1173,7 @@ impl ErrorInferrer {
_ => return Ok(false),
};

let inst = subtrace_bytecode.get_instruction(step.pc)?;
let inst = bytecode.get_instruction(step.pc)?;

// All the remaining locations should be valid, as they are part of the inline
// asm
Expand Down Expand Up @@ -1302,7 +1302,9 @@ impl ErrorInferrer {
.expect("The TS code type-checks this to always have bytecode");
let contract = bytecode.contract.borrow();

let version = Version::parse(&bytecode.compiler_version).unwrap();
let version =
Version::parse(&bytecode.compiler_version).expect("Failed to parse SemVer version");

// this only makes sense when receive functions are available
if version < FIRST_SOLC_VERSION_RECEIVE_FUNCTION {
return Ok(false);
Expand Down Expand Up @@ -1586,7 +1588,11 @@ impl ErrorInferrer {
trace: &CallMessageTrace,
func: &ContractFunction,
) -> napi::Result<bool> {
let last_step = trace.steps.last().unwrap();
let last_step = trace
.steps
.last()
.expect("There should at least be one step");

let last_step = match last_step {
Either4::A(step) => step,
_ => panic!("JS code asserted this is always an EvmStep"),
Expand Down Expand Up @@ -2206,14 +2212,44 @@ fn format_dyn_sol_value(val: &DynSolValue) -> String {
// surround string values with quotes
DynSolValue::String(s) => format!("\"{s}\""),

DynSolValue::Address(address) => format!("\"0x{address}\""),
DynSolValue::Bytes(bytes) => format!("\"0x{}\"", hex::encode(bytes)),
DynSolValue::Address(address) => format!("\"{address}\""),
DynSolValue::Bytes(bytes) => format!("\"{}\"", hex::encode_prefixed(bytes)),
DynSolValue::FixedBytes(word, size) => {
format!("\"0x{}\"", hex::encode(&word.0.as_slice()[..*size]))
format!("\"{}\"", hex::encode_prefixed(&word.0.as_slice()[..*size]))
}
DynSolValue::Bool(b) => b.to_string(),
DynSolValue::Function(_) => "<function>".to_string(),
DynSolValue::Int(int, _bits) => int.to_string(),
DynSolValue::Uint(uint, _bits) => uint.to_string(),
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_sol_value_to_string() {
assert_eq!(
format_dyn_sol_value(&DynSolValue::String("hello".to_string())),
"\"hello\""
);
// Uniform, 0-prefixed hex strings
assert_eq!(
format_dyn_sol_value(&DynSolValue::Address([0u8; 20].into())),
format!(r#""0x{}""#, "0".repeat(2 * 20))
);
assert_eq!(
format_dyn_sol_value(&DynSolValue::Bytes(vec![0u8; 32])),
format!(r#""0x{}""#, "0".repeat(2 * 32))
);
assert_eq!(
format_dyn_sol_value(&DynSolValue::FixedBytes([0u8; 32].into(), 10)),
format!(r#""0x{}""#, "0".repeat(2 * 10))
);
assert_eq!(
format_dyn_sol_value(&DynSolValue::FixedBytes([0u8; 32].into(), 32)),
format!(r#""0x{}""#, "0".repeat(2 * 32))
);
}
}
119 changes: 119 additions & 0 deletions crates/edr_provider/tests/issues/issue_570.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use std::{convert::Infallible, str::FromStr as _};

use edr_eth::{spec::HardforkActivations, SpecId, B256};
use edr_provider::{
hardhat_rpc_types::ForkConfig, test_utils::create_test_config_with_fork, time::CurrentTime,
MethodInvocation, NoopLogger, Provider, ProviderError, ProviderRequest,
};
use edr_test_utils::env::get_alchemy_url;
use serial_test::serial;
use tokio::runtime;

// SAFETY: tests that modify the environment should be run serially.

fn get_provider() -> anyhow::Result<Provider<Infallible>> {
// Base Sepolia Testnet
const CHAIN_ID: u64 = 84532;
const BLOCK_NUMBER: u64 = 13_560_400;

let logger = Box::new(NoopLogger);
let subscriber = Box::new(|_event| {});

let mut config = create_test_config_with_fork(Some(ForkConfig {
json_rpc_url: get_alchemy_url().replace("eth-mainnet", "base-sepolia"),
block_number: Some(BLOCK_NUMBER),
http_headers: None,
}));

config
.chains
.insert(CHAIN_ID, HardforkActivations::with_spec_id(SpecId::CANCUN));

config.chain_id = CHAIN_ID;

Ok(Provider::new(
runtime::Handle::current(),
logger,
subscriber,
config,
CurrentTime,
)?)
}

// `eth_debugTraceTransaction` should return a helpful error message if there is
// a transaction in the block whose type is not supported.
// https://github.com/NomicFoundation/edr/issues/570
#[serial]
#[tokio::test(flavor = "multi_thread")]
async fn issue_570_error_message() -> anyhow::Result<()> {
let provider = get_provider()?;

let transaction_hash =
B256::from_str("0xe565eb3bfd815efcc82bed1eef580117f9dc3d6896db42500572c8e789c5edd4")?;

let result = provider.handle_request(ProviderRequest::Single(
MethodInvocation::DebugTraceTransaction(transaction_hash, None),
));

assert!(matches!(
result,
Err(ProviderError::UnsupportedTransactionTypeInDebugTrace {
requested_transaction_hash,
unsupported_transaction_hash,
..
}) if requested_transaction_hash == transaction_hash && unsupported_transaction_hash != transaction_hash
));

Ok(())
}

// `eth_debugTraceTransaction` should ignore transactions with unsupported types
// if a custom environment variable is set.
// https://github.com/NomicFoundation/edr/issues/570
#[serial]
#[tokio::test(flavor = "multi_thread")]
async fn issue_570_env_var() -> anyhow::Result<()> {
std::env::set_var("__EDR_UNSAFE_SKIP_UNSUPPORTED_TRANSACTION_TYPES", "true");
let provider = get_provider();
std::env::remove_var("__EDR_UNSAFE_SKIP_UNSUPPORTED_TRANSACTION_TYPES");
let provider = provider?;

let transaction_hash =
B256::from_str("0xe565eb3bfd815efcc82bed1eef580117f9dc3d6896db42500572c8e789c5edd4")?;

let result = provider.handle_request(ProviderRequest::Single(
MethodInvocation::DebugTraceTransaction(transaction_hash, None),
))?;

assert!(!result.traces.is_empty());

Ok(())
}

// `eth_debugTraceTransaction` should return a helpful error message if tracing
// is requested for a transaction with an unsupported type. https://github.com/NomicFoundation/edr/issues/570
#[serial]
#[tokio::test(flavor = "multi_thread")]
async fn issue_570_unsupported_requested() -> anyhow::Result<()> {
std::env::set_var("__EDR_UNSAFE_SKIP_UNSUPPORTED_TRANSACTION_TYPES", "true");
let provider = get_provider();
std::env::remove_var("__EDR_UNSAFE_SKIP_UNSUPPORTED_TRANSACTION_TYPES");
let provider = provider?;

let transaction_hash =
B256::from_str("0xa9d8bf76337ac4a72a4085d5fd6456f6950b6b95d9d4aa198707a649268ef91c")?;

let result = provider.handle_request(ProviderRequest::Single(
MethodInvocation::DebugTraceTransaction(transaction_hash, None),
));

assert!(matches!(
result,
Err(ProviderError::UnsupportedTransactionTypeForDebugTrace {
transaction_hash: error_transaction_hash,
..
}) if error_transaction_hash == transaction_hash
));

Ok(())
}
7 changes: 6 additions & 1 deletion crates/edr_solidity/src/contracts_identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ impl BytecodeTrie {
fn is_matching_metadata(code: &[u8], last_byte: u32) -> bool {
let mut byte = 0;
while byte < last_byte {
let opcode = OpCode::new(code[byte as usize]).unwrap();
// It's possible we don't recognize the opcode if it's from an unknown chain, so
// just return false in that case.
let Some(opcode) = OpCode::new(code[byte as usize]) else {
return false;
};

let next = code.get(byte as usize + 1).copied().and_then(OpCode::new);

if opcode == OpCode::REVERT && next == Some(OpCode::INVALID) {
Expand Down
2 changes: 1 addition & 1 deletion crates/tools/js/benchmark/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"eslint-plugin-import": "2.27.5",
"eslint-plugin-mocha": "10.4.1",
"eslint-plugin-prettier": "5.2.1",
"hardhat": "2.22.10",
"hardhat": "2.22.12",
"lodash": "^4.17.11",
"mocha": "^10.0.0",
"prettier": "^3.2.5",
Expand Down
2 changes: 1 addition & 1 deletion hardhat-tests/integration/smock/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"@types/node": "^20.0.0",
"chai": "^4.3.6",
"ethers": "5.7.2",
"hardhat": "2.22.10",
"hardhat": "2.22.12",
"mocha": "^10.0.0"
},
"keywords": [],
Expand Down
3 changes: 2 additions & 1 deletion hardhat-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"author": "Nomic Foundation",
"devDependencies": {
"@metamask/eth-sig-util": "^4.0.0",
"@nomicfoundation/edr": "workspace:*",
"@nomicfoundation/ethereumjs-block": "5.0.4",
"@nomicfoundation/ethereumjs-common": "^4.0.4",
"@nomicfoundation/ethereumjs-tx": "^5.0.4",
Expand Down Expand Up @@ -38,7 +39,7 @@
"ethereumjs-abi": "^0.6.8",
"ethers": "^6.1.0",
"fs-extra": "^7.0.1",
"hardhat": "2.22.10",
"hardhat": "2.22.12",
"mocha": "^10.0.0",
"prettier": "^3.2.5",
"rimraf": "^3.0.2",
Expand Down
Loading

0 comments on commit 34eb49a

Please sign in to comment.