Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fifty-eggs-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nomicfoundation/edr": minor
---

Added `Response::traces` method with a backwards compatible raw trace format for EthereumJS' VM
6 changes: 1 addition & 5 deletions Cargo.lock

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

7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,12 @@ c-kzg = { version = "2.1.4", default-features = false, features = [
"ethereum_kzg_settings",
] }

revm-inspectors = { version = "0.39.0", features = ["serde"] }
# Temporary fork adding `StackSnapshotType::Top` on the 0.39.0 line; revert to
# crates.io once paradigmxyz/revm-inspectors#468 is released and EDR is on its
# revm major.
revm-inspectors = { git = "https://github.com/nebasuke/revm-inspectors", branch = "feat/top-of-stack-snapshot-0.39", features = [
"serde",
] }
foundry-fork-db = "0.26"

## ethers
Expand Down
1 change: 0 additions & 1 deletion crates/edr_napi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ edr_solidity_tests.workspace = true
edr_state_api.workspace = true
edr_signer.workspace = true
edr_solidity.workspace = true
edr_tracing.workspace = true
edr_utils_sync.workspace = true
mimalloc = { version = "0.1.39", default-features = false, features = [
"local_dynamic_tls",
Expand Down
128 changes: 44 additions & 84 deletions crates/edr_napi/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,6 @@ export declare class ProviderFactory {

}

export declare class RawTrace {
get trace(): Array<TracingMessage | TracingStep | TracingMessageResult>
}

export declare class Response {
/** Returns the response data as a JSON string or a JSON object. */
get data(): string | any
Expand All @@ -103,6 +99,12 @@ export declare class Response {
* request's call itself.
*/
callTraces(): Array<CallTrace>
/**
* Returns the raw traces of executed contracts. This may contain zero or
* more traces. Uses a function instead of a getter to avoid repeated
* expensive conversions.
*/
traces(): Array<Array<TracingMessage | TracingStep | TracingMessageResult>>
}

export declare class ReturnData {
Expand Down Expand Up @@ -318,11 +320,6 @@ export declare enum CallKind {
Create = 4
}

export interface CallOutput {
/** Return value */
returnValue: Uint8Array
}

/** The result of executing a call override. */
export interface CallOverrideResult {
result: Uint8Array
Expand Down Expand Up @@ -503,13 +500,6 @@ export interface CounterExampleSequence {
/** The instrumentation coverage library file name. */
export const COVERAGE_LIBRARY_FILE_NAME: string

export interface CreateOutput {
/** Return value */
returnValue: Uint8Array
/** Optionally, a 160-bit address */
address?: Uint8Array
}

export interface CustomErrorStackTraceEntry {
type: StackTraceEntryType.CUSTOM_ERROR
message: string
Expand Down Expand Up @@ -605,14 +595,6 @@ export interface ExecutionLog {
data: Uint8Array
}

/** The result of executing a transaction. */
export interface ExecutionResult {
/** The transaction result */
result: SuccessResult | RevertResult | HaltResult
/** Optional contract address if the transaction created a new contract. */
contractAddress?: Uint8Array
}

/** Represents the exit code of the EVM. */
export declare enum ExitCode {
/** Execution was successful. */
Expand Down Expand Up @@ -856,19 +838,6 @@ export const GRANITE: string

export const GRAY_GLACIER: string

/** The result when the EVM terminates due to an exceptional halt. */
export interface HaltResult {
/** The exceptional halt that occurred */
reason: ExceptionalHalt
/**
* Halting will spend all the gas and will thus be equal to the specified
* gas limit
*/
gasUsed: bigint
/** The logs */
logs: Array<ExecutionLog>
}

/** Configuration for a hardfork activation */
export interface HardforkActivation {
/** The condition for the hardfork activation */
Expand Down Expand Up @@ -1383,16 +1352,6 @@ export interface RevertErrorStackTraceEntry {
isInvalidOpcodeError: boolean
}

/** The result when the EVM terminates due to a revert. */
export interface RevertResult {
/** The amount of gas used */
gasUsed: bigint
/** The logs */
logs: Array<ExecutionLog>
/** The transaction output */
output: Uint8Array
}

export const SHANGHAI: string

export type SolidityStackTrace =
Expand Down Expand Up @@ -1779,20 +1738,6 @@ export declare enum SuccessReason {
SelfDestruct = 2
}

/** The result when the EVM terminates successfully. */
export interface SuccessResult {
/** The reason for termination */
reason: SuccessReason
/** The amount of gas used */
gasUsed: bigint
/** The amount of gas refunded */
gasRefunded: bigint
/** The logs */
logs: Array<ExecutionLog>
/** The transaction output */
output: CallOutput | CreateOutput
}

/**
* See [`edr_solidity_tests::result::SuiteResult`]
*
Expand Down Expand Up @@ -1899,47 +1844,62 @@ export interface TracingConfigWithBuffers {
ignoreContracts?: boolean
}

/** Matches Hardhat's `MinimalExecResult` interface. */
export interface TracingExecResult {
/** Whether execution succeeded */
readonly success: boolean
/** Gas used during execution */
readonly executionGasUsed: bigint
/** Address of the created contract, if any */
readonly contractAddress?: Uint8Array
/** The reason for the exit (success or halt) */
readonly reason?: SuccessReason | ExceptionalHalt
/** The output data */
readonly output?: Uint8Array
}

/** Matches Hardhat's `MinimalMessage` interface. */
export interface TracingMessage {
/** Sender address */
readonly caller: Uint8Array
/** Recipient address. None if it is a Create message. */
readonly to?: Uint8Array
/** Whether it's a static call */
readonly isStaticCall: boolean
/** Transaction gas limit */
readonly gasLimit: bigint
/** Depth of the message */
readonly depth: number
/** Input data of the message */
readonly data: Uint8Array
/** Value sent in the message */
readonly value: bigint
/**
* Address of the code that is being executed. Can be different from `to`
* if a delegate call is being done.
*/
readonly codeAddress?: Uint8Array
/** Code of the contract that is being executed. */
readonly code?: Uint8Array
/** Value sent in the message */
readonly value: bigint
/** Input data of the message */
readonly data: Uint8Array
/** Transaction gas limit */
readonly gasLimit: bigint
/** Whether it's a static call */
readonly isStaticCall: boolean
}

/** Matches Hardhat's `MinimalEVMResult` interface. */
export interface TracingMessageResult {
/** Execution result */
readonly executionResult: ExecutionResult
/** The execution result */
readonly execResult: TracingExecResult
}

/** Opcode information for a tracing step. */
export interface TracingOpcode {
/** The name of the opcode */
readonly name: string
}

/** Matches Hardhat's `MinimalInterpreterStep` interface. */
export interface TracingStep {
/** The program counter */
readonly pc: number
/** Call depth */
readonly depth: number
/** The program counter */
readonly pc: bigint
/** The executed op code */
readonly opcode: string
/**
* The entries on the stack. It only contains the top element unless
* verbose tracing is enabled. The vector is empty if there are no elements
* on the stack.
*/
/** The executed opcode */
readonly opcode: TracingOpcode
/** The entries on the stack. */
readonly stack: Array<bigint>
/** The memory at the step. None if verbose tracing is disabled. */
readonly memory?: Uint8Array
Expand Down
1 change: 0 additions & 1 deletion crates/edr_napi/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,6 @@ module.exports.Exit = nativeBinding.Exit
module.exports.Precompile = nativeBinding.Precompile
module.exports.Provider = nativeBinding.Provider
module.exports.ProviderFactory = nativeBinding.ProviderFactory
module.exports.RawTrace = nativeBinding.RawTrace
module.exports.Response = nativeBinding.Response
module.exports.ReturnData = nativeBinding.ReturnData
module.exports.SolidityTestRunnerFactory = nativeBinding.SolidityTestRunnerFactory
Expand Down
1 change: 1 addition & 0 deletions crates/edr_napi/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ impl SyncProvider for MockProvider {
data,
stack_trace_result: None,
call_trace_arenas: Vec::new(),
verbose: false,
})
.map_err(|error| napi::Error::new(napi::Status::GenericFailure, error.to_string()))
}
Expand Down
31 changes: 18 additions & 13 deletions crates/edr_napi/src/provider/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ use napi_derive::napi;

use crate::{
solidity_tests::test_results::{CallTrace, HeuristicFailed, StackTrace, UnexpectedError},
trace::solidity_stack_trace::{
solidity_stack_trace_error_to_napi, solidity_stack_trace_heuristic_failed_to_napi,
solidity_stack_trace_success_to_napi,
trace::{
raw_trace_from_call_trace_arena,
solidity_stack_trace::{
solidity_stack_trace_error_to_napi, solidity_stack_trace_heuristic_failed_to_napi,
solidity_stack_trace_success_to_napi,
},
TracingMessage, TracingMessageResult, TracingStep,
},
};

Expand Down Expand Up @@ -62,14 +66,15 @@ impl Response {
.collect()
}

// TODO(#1288): Add backwards compatibility layer for Hardhat 2
// #[doc = "Returns the raw traces of executed contracts. This maybe contain
// zero or more traces."] #[napi(catch_unwind, getter)]
// pub fn traces(&self) -> Vec<RawTrace> {
// self.inner
// .call_trace_arenas
// .iter()
// .map(|trace| RawTrace::from(trace.clone()))
// .collect()
// }
/// Returns the raw traces of executed contracts. This may contain zero or
/// more traces. Uses a function instead of a getter to avoid repeated
/// expensive conversions.
#[napi(catch_unwind)]
pub fn traces(&self) -> Vec<Vec<Either3<TracingMessage, TracingStep, TracingMessageResult>>> {
self.inner
.call_trace_arenas
.iter()
.map(|arena| raw_trace_from_call_trace_arena(arena, self.inner.verbose))
.collect()
}
}
Loading