Skip to content

Commit b2de7a9

Browse files
committed
Merge branch 'rethnet/main' into hardhat-edr-merge
2 parents a85cca3 + 8d6f024 commit b2de7a9

File tree

9 files changed

+105
-39
lines changed

9 files changed

+105
-39
lines changed

.github/workflows/hardhat-core-ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ jobs:
7575
# disable until actions/virtual-environments#4896 is fixed
7676
# os: ["macos-latest", "ubuntu-latest", "windows-latest"]
7777
os: ["ubuntu-latest", "windows-latest"]
78-
vm: ["dual", "rethnet"]
78+
vm: ["dual", "ethereumjs", "rethnet"]
7979
steps:
8080
- uses: actions/checkout@v3
8181

crates/rethnet_evm/src/trace.rs

+9-21
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use revm::{
66
instruction_result::SuccessOrHalt, opcode, return_revert, CallInputs, CreateInputs, Gas,
77
InstructionResult, Interpreter,
88
},
9-
primitives::{AccountInfo, Bytecode, ExecutionResult, Output},
9+
primitives::{Bytecode, ExecutionResult, Output},
1010
EVMData, Inspector,
1111
};
1212

@@ -56,8 +56,10 @@ pub struct Step {
5656
pub pc: u64,
5757
/// The call depth
5858
pub depth: u64,
59-
// /// The executed op code
60-
// pub opcode: u8,
59+
/// The executed op code
60+
pub opcode: u8,
61+
/// The top entry on the stack. None if the stack is empty.
62+
pub stack_top: Option<U256>,
6163
// /// The amount of gas that was used by the step
6264
// pub gas_cost: u64,
6365
// /// The amount of gas that was refunded by the step
@@ -80,21 +82,12 @@ impl Trace {
8082
}
8183

8284
/// Adds a VM step to the trace.
83-
pub fn add_step(
84-
&mut self,
85-
depth: u64,
86-
pc: usize,
87-
_opcode: u8,
88-
_gas: &Gas,
89-
_contract: &AccountInfo,
90-
_contract_address: &Address,
91-
) {
85+
pub fn add_step(&mut self, depth: u64, pc: usize, opcode: u8, stack_top: Option<U256>) {
9286
self.messages.push(TraceMessage::Step(Step {
9387
pc: pc as u64,
9488
depth,
95-
// opcode,
96-
// contract: contract.clone(),
97-
// contract_address: *contract_address,
89+
opcode,
90+
stack_top,
9891
}));
9992
}
10093
}
@@ -302,12 +295,7 @@ where
302295
data.journaled_state().depth(),
303296
interp.program_counter(),
304297
interp.current_opcode(),
305-
interp.gas(),
306-
&data
307-
.journaled_state()
308-
.account(interp.contract().address)
309-
.info,
310-
&interp.contract().address,
298+
interp.stack.data().last().cloned(),
311299
);
312300
}
313301

crates/rethnet_evm_napi/index.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,10 @@ export interface TracingStep {
247247
readonly depth: number
248248
/** The program counter */
249249
readonly pc: bigint
250+
/** The executed op code */
251+
readonly opcode: string
252+
/** The top entry on the stack. None if the stack is empty. */
253+
readonly stackTop?: bigint
250254
}
251255
export interface TracingMessageResult {
252256
/** Execution result */

crates/rethnet_evm_napi/src/trace.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use napi::{
66
};
77
use napi_derive::napi;
88
use rethnet_evm::trace::BeforeMessage;
9+
use rethnet_evm::OPCODE_JUMPMAP;
910

1011
use crate::transaction::result::ExecutionResult;
1112

@@ -93,9 +94,12 @@ pub struct TracingStep {
9394
/// The program counter
9495
#[napi(readonly)]
9596
pub pc: BigInt,
96-
// /// The executed op code
97-
// #[napi(readonly)]
98-
// pub opcode: String,
97+
/// The executed op code
98+
#[napi(readonly)]
99+
pub opcode: String,
100+
/// The top entry on the stack. None if the stack is empty.
101+
#[napi(readonly)]
102+
pub stack_top: Option<BigInt>,
99103
// /// The return value of the step
100104
// #[napi(readonly)]
101105
// pub return_value: u8,
@@ -130,9 +134,13 @@ impl TracingStep {
130134
Self {
131135
depth: step.depth as u8,
132136
pc: BigInt::from(step.pc),
133-
// opcode: OPCODE_JUMPMAP[usize::from(step.opcode)]
134-
// .unwrap_or("")
135-
// .to_string(),
137+
opcode: OPCODE_JUMPMAP[usize::from(step.opcode)]
138+
.unwrap_or("")
139+
.to_string(),
140+
stack_top: step.stack_top.map(|v| BigInt {
141+
sign_bit: false,
142+
words: v.into_limbs().to_vec(),
143+
}),
136144
// gas_cost: BigInt::from(0u64),
137145
// gas_refunded: BigInt::from(0u64),
138146
// gas_left: BigInt::from(0u64),

packages/hardhat-core/src/internal/hardhat-network/provider/context/rethnet.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { Blockchain, RethnetContext, SpecId } from "@ignored/edr";
2+
import { AsyncEventEmitter } from "@nomicfoundation/ethereumjs-util";
23
import { BlockchainAdapter } from "../blockchain";
34
import { RethnetBlockchain } from "../blockchain/rethnet";
45
import { EthContextAdapter } from "../context";
56
import { MemPoolAdapter } from "../mem-pool";
67
import { BlockMinerAdapter } from "../miner";
78
import { VMAdapter } from "../vm/vm-adapter";
89
import { RethnetMiner } from "../miner/rethnet";
9-
import { RethnetAdapter } from "../vm/rethnet";
10+
import { RethnetAdapter, VMStub } from "../vm/rethnet";
1011
import { NodeConfig, isForkedNodeConfig } from "../node-types";
1112
import {
1213
ethereumjsHeaderDataToRethnetBlockOptions,
@@ -139,13 +140,20 @@ export class RethnetEthContext implements EthContextAdapter {
139140
? UNLIMITED_CONTRACT_SIZE_VALUE
140141
: undefined;
141142

143+
const vmStub: VMStub = {
144+
evm: {
145+
events: new AsyncEventEmitter(),
146+
},
147+
};
148+
142149
const vm = new RethnetAdapter(
143150
blockchain.asInner(),
144151
state,
145152
common,
146153
limitContractCodeSize,
147154
limitInitcodeSize,
148-
config.enableTransientStorage
155+
config.enableTransientStorage,
156+
vmStub
149157
);
150158

151159
const memPool = new RethnetMemPool(
@@ -161,7 +169,8 @@ export class RethnetEthContext implements EthContextAdapter {
161169
common,
162170
limitContractCodeSize,
163171
ethereumjsMempoolOrderToRethnetMineOrdering(config.mempoolOrder),
164-
prevRandaoGenerator
172+
prevRandaoGenerator,
173+
vmStub
165174
);
166175

167176
return new RethnetEthContext(blockchain, memPool, miner, vm);

packages/hardhat-core/src/internal/hardhat-network/provider/miner/rethnet.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { RethnetBlockchain } from "../blockchain/rethnet";
1515
import { RethnetStateManager } from "../RethnetState";
1616
import { RethnetMemPool } from "../mem-pool/rethnet";
1717
import { RandomBufferGenerator } from "../utils/random";
18+
import { VMStub } from "../vm/rethnet";
1819

1920
export class RethnetMiner implements BlockMinerAdapter {
2021
constructor(
@@ -24,7 +25,8 @@ export class RethnetMiner implements BlockMinerAdapter {
2425
private readonly _common: Common,
2526
private readonly _limitContractCodeSize: bigint | undefined,
2627
private _mineOrdering: MineOrdering,
27-
private _prevRandaoGenerator: RandomBufferGenerator
28+
private _prevRandaoGenerator: RandomBufferGenerator,
29+
private _vmStub: VMStub
2830
) {}
2931

3032
public async mineBlock(
@@ -74,6 +76,14 @@ export class RethnetMiner implements BlockMinerAdapter {
7476
for (const traceItem of mineTrace) {
7577
if ("pc" in traceItem) {
7678
await vmTracer.addStep(traceItem);
79+
80+
// For solidity-coverage compatibility
81+
this._vmStub.evm.events.emit("step", {
82+
pc: Number(traceItem.pc),
83+
depth: traceItem.depth,
84+
opcode: { name: traceItem.opcode },
85+
stackTop: traceItem.stackTop,
86+
});
7787
} else if ("executionResult" in traceItem) {
7888
await vmTracer.addAfterMessage(traceItem);
7989
} else {

packages/hardhat-core/src/internal/hardhat-network/provider/vm/creation.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ export async function createContext(
1616

1717
const prevRandaoGenerator = RandomBufferGenerator.create("randomMixHashSeed");
1818

19-
if (vmModeEnvVar === "ethereumjs") {
20-
return HardhatEthContext.create(config, prevRandaoGenerator);
21-
} else if (vmModeEnvVar === "rethnet") {
19+
if (vmModeEnvVar === "edr") {
2220
return RethnetEthContext.create(config);
23-
} else {
21+
} else if (vmModeEnvVar === "dual") {
2422
return DualEthContext.create(config, prevRandaoGenerator);
23+
} else {
24+
return HardhatEthContext.create(config, prevRandaoGenerator);
2525
}
2626
}

packages/hardhat-core/src/internal/hardhat-network/provider/vm/ethereumjs.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ export class EthereumJSAdapter implements VMAdapter {
706706
await this._vmTracer.addStep({
707707
depth: step.depth,
708708
pc: BigInt(step.pc),
709-
// opcode: step.opcode.name,
709+
opcode: step.opcode.name,
710710
// returnValue: 0, // Do we have error values in ethereumjs?
711711
// gasCost: BigInt(step.opcode.fee) + (step.opcode.dynamicFee ?? 0n),
712712
// gasRefunded: step.gasRefund,

packages/hardhat-core/src/internal/hardhat-network/provider/vm/rethnet.ts

+49-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { Block } from "@nomicfoundation/ethereumjs-block";
22
import { Common } from "@nomicfoundation/ethereumjs-common";
3+
import { InterpreterStep } from "@nomicfoundation/ethereumjs-evm";
34
import {
45
Account,
56
Address,
7+
AsyncEventEmitter,
68
KECCAK256_NULL,
79
} from "@nomicfoundation/ethereumjs-util";
810
import { TypedTransaction } from "@nomicfoundation/ethereumjs-tx";
@@ -59,7 +61,9 @@ export class RethnetAdapter implements VMAdapter {
5961
private readonly _common: Common,
6062
private readonly _limitContractCodeSize: bigint | undefined,
6163
private readonly _limitInitcodeSize: bigint | undefined,
62-
private readonly _enableTransientStorage: boolean
64+
private readonly _enableTransientStorage: boolean,
65+
// For solidity-coverage compatibility. Name cannot be changed.
66+
private _vm: VMStub
6367
) {
6468
this._vmTracer = new VMTracer(_common, false);
6569
}
@@ -93,13 +97,20 @@ export class RethnetAdapter implements VMAdapter {
9397
? UNLIMITED_CONTRACT_SIZE_VALUE
9498
: undefined;
9599

100+
const vmStub: VMStub = {
101+
evm: {
102+
events: new AsyncEventEmitter(),
103+
},
104+
};
105+
96106
return new RethnetAdapter(
97107
blockchain,
98108
state,
99109
common,
100110
limitContractCodeSize,
101111
limitInitcodeSize,
102-
config.enableTransientStorage
112+
config.enableTransientStorage,
113+
vmStub
103114
);
104115
}
105116

@@ -184,6 +195,16 @@ export class RethnetAdapter implements VMAdapter {
184195
}
185196
}
186197

198+
// For solidity-coverage compatibility
199+
for (const step of this._vmTracer.tracingSteps) {
200+
this._vm.evm.events.emit("step", {
201+
pc: Number(step.pc),
202+
depth: step.depth,
203+
opcode: { name: step.opcode },
204+
stackTop: step.stackTop,
205+
});
206+
}
207+
187208
try {
188209
const result = rethnetResultToRunTxResult(
189210
rethnetResult.result,
@@ -415,6 +436,16 @@ export class RethnetAdapter implements VMAdapter {
415436
}
416437
}
417438

439+
// For solidity-coverage compatibility
440+
for (const step of this._vmTracer.tracingSteps) {
441+
this._vm.evm.events.emit("step", {
442+
pc: Number(step.pc),
443+
depth: step.depth,
444+
opcode: { name: step.opcode },
445+
stackTop: step.stackTop,
446+
});
447+
}
448+
418449
try {
419450
const result = rethnetResultToRunTxResult(
420451
rethnetResult.result,
@@ -623,3 +654,19 @@ export class RethnetAdapter implements VMAdapter {
623654
return undefined;
624655
}
625656
}
657+
658+
type InterpreterStepStub = Pick<InterpreterStep, "pc" | "depth"> & {
659+
opcode: { name: string };
660+
stackTop?: bigint;
661+
};
662+
663+
interface EVMStub {
664+
events: AsyncEventEmitter<{
665+
step: (data: InterpreterStepStub, resolve?: (result?: any) => void) => void;
666+
}>;
667+
}
668+
669+
// For compatibility with solidity-coverage that attaches a listener to the step event.
670+
export interface VMStub {
671+
evm: EVMStub;
672+
}

0 commit comments

Comments
 (0)