Skip to content

Commit 319dbf1

Browse files
committed
add basic gasleft comparison, simplify by not allowing nested snapshots
1 parent 7d8b793 commit 319dbf1

File tree

3 files changed

+72
-57
lines changed

3 files changed

+72
-57
lines changed

crates/cheatcodes/src/evm.rs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub struct DealRecord {
6464
}
6565

6666
/// Records the `snapshotGas*` cheatcodes.
67-
#[derive(Clone, Debug)]
67+
#[derive(Default, Clone, Debug)]
6868
pub struct GasRecord {
6969
/// The group name of the gas snapshot.
7070
pub group: String,
@@ -818,22 +818,18 @@ fn inner_start_gas_snapshot<DB: DatabaseExt>(
818818
);
819819
let name = name.as_deref().unwrap_or("default").to_string();
820820

821-
if ccx
822-
.state
823-
.gas_metering
824-
.gas_records
825-
.iter()
826-
.any(|record| record.group == group && record.name == name)
821+
if ccx.state.gas_metering.gas_record.group == group &&
822+
ccx.state.gas_metering.gas_record.name == name
827823
{
828824
bail!("gas snapshot already active: {name} in group: {group}");
829825
}
830826

831-
ccx.state.gas_metering.gas_records.push(GasRecord {
827+
ccx.state.gas_metering.gas_record = GasRecord {
832828
group: group.to_string(),
833829
name: name.clone(),
834830
gas_used: 0,
835831
depth: ccx.ecx.journaled_state.depth() - 1,
836-
});
832+
};
837833

838834
ccx.state.gas_metering.last_snapshot_name = Some(name);
839835

@@ -847,21 +843,17 @@ fn inner_stop_gas_snapshot<DB: DatabaseExt>(
847843
group: Option<String>,
848844
name: Option<String>,
849845
) -> Result {
850-
ccx.state.gas_metering.stop();
851-
852846
let group = group.as_deref().unwrap_or(
853847
ccx.state.config.running_contract.as_deref().expect("expected running contract"),
854848
);
855849
let name = name.as_deref().unwrap_or("default").to_string();
856850

857-
if let Some(record) = ccx
858-
.state
859-
.gas_metering
860-
.gas_records
861-
.iter_mut()
862-
.find(|record| record.group == group && record.name == name)
851+
if ccx.state.gas_metering.gas_record.group == group &&
852+
ccx.state.gas_metering.gas_record.name == name
863853
{
864-
let value = record.gas_used;
854+
ccx.state.gas_metering.stop();
855+
856+
let value = ccx.state.gas_metering.gas_record.gas_used;
865857

866858
ccx.state
867859
.gas_snapshots

crates/cheatcodes/src/inspector.rs

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,8 @@ pub struct GasMetering {
241241
pub recording: bool,
242242
/// The gas used in the last frame.
243243
pub last_gas_used: u64,
244-
/// Gas records for the active snapshots.
245-
pub gas_records: Vec<GasRecord>,
244+
/// The gas record for the current snapshot.
245+
pub gas_record: GasRecord,
246246
}
247247

248248
impl GasMetering {
@@ -253,13 +253,6 @@ impl GasMetering {
253253

254254
/// Stop the gas recording.
255255
pub fn stop(&mut self) {
256-
println!("gas records: {:?}", self.gas_records);
257-
258-
// self.gas_records.iter_mut().for_each(|record| {
259-
// record.gas_used.saturating_add(self.recorded_frames.iter().sum::<u64>());
260-
// });
261-
262-
// reduce sum of gas frames to a single value
263256
self.recording = false;
264257
}
265258

@@ -786,11 +779,10 @@ impl Cheatcodes {
786779
}
787780

788781
// Store the total gas used for all active gas records started by `startSnapshotGas`.
789-
self.gas_metering.gas_records.iter_mut().for_each(|record| {
790-
if ecx.journaled_state.depth() == record.depth + 1 {
791-
record.gas_used = record.gas_used.saturating_add(outcome.result.gas.spent());
792-
}
793-
});
782+
if ecx.journaled_state.depth() == self.gas_metering.gas_record.depth + 1 {
783+
self.gas_metering.gas_record.gas_used =
784+
self.gas_metering.gas_record.gas_used.saturating_add(outcome.result.gas.spent());
785+
}
794786

795787
// If `startStateDiffRecording` has been called, update the `reverted` status of the
796788
// previous call depth's recorded accesses, if any
@@ -1352,11 +1344,10 @@ impl<DB: DatabaseExt> Inspector<DB> for Cheatcodes {
13521344
});
13531345

13541346
// Store the total gas used for all active gas records started by `startSnapshotGas`.
1355-
self.gas_metering.gas_records.iter_mut().for_each(|record| {
1356-
if ecx.journaled_state.depth() == record.depth + 1 {
1357-
record.gas_used = record.gas_used.saturating_add(gas.spent());
1358-
}
1359-
});
1347+
if ecx.journaled_state.depth() == self.gas_metering.gas_record.depth + 1 {
1348+
self.gas_metering.gas_record.gas_used =
1349+
self.gas_metering.gas_record.gas_used.saturating_add(gas.spent());
1350+
}
13601351

13611352
// If `startStateDiffRecording` has been called, update the `reverted` status of the
13621353
// previous call depth's recorded accesses, if any
@@ -1624,27 +1615,30 @@ impl Cheatcodes {
16241615
self.gas_metering.last_gas_used = 0;
16251616
}
16261617
_ => {
1627-
self.gas_metering.gas_records.iter_mut().for_each(|record| {
1628-
if ecx.journaled_state.depth() == record.depth + 1 {
1629-
// Initialize after new frame, use this as the starting point.
1630-
if self.gas_metering.last_gas_used == 0 {
1631-
self.gas_metering.last_gas_used = interpreter.gas.spent();
1632-
return;
1633-
}
1618+
if ecx.journaled_state.depth() == self.gas_metering.gas_record.depth + 1 {
1619+
// Initialize after new frame, use this as the starting point.
1620+
if self.gas_metering.last_gas_used == 0 {
1621+
self.gas_metering.last_gas_used = interpreter.gas.spent();
1622+
return;
1623+
}
16341624

1635-
// Calculate the gas difference between the last and current frame.
1636-
let gas_diff = interpreter
1637-
.gas
1638-
.spent()
1639-
.saturating_sub(self.gas_metering.last_gas_used);
1625+
// Calculate the gas difference between the last and current frame.
1626+
let gas_diff =
1627+
interpreter.gas.spent().saturating_sub(self.gas_metering.last_gas_used);
16401628

1641-
// Update the gas record.
1642-
record.gas_used = record.gas_used.saturating_add(gas_diff);
1629+
println!(
1630+
"opcode: {:?}, gas_diff: {}",
1631+
interpreter.current_opcode(),
1632+
gas_diff
1633+
);
16431634

1644-
// Update for next iteration.
1645-
self.gas_metering.last_gas_used = interpreter.gas.spent();
1646-
}
1647-
});
1635+
// Update the gas record.
1636+
self.gas_metering.gas_record.gas_used =
1637+
self.gas_metering.gas_record.gas_used.saturating_add(gas_diff);
1638+
1639+
// Update for next iteration.
1640+
self.gas_metering.last_gas_used = interpreter.gas.spent();
1641+
}
16481642
}
16491643
}
16501644
}

testdata/default/cheats/GasSnapshot.t.sol

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ pragma solidity 0.8.18;
33

44
import "ds-test/test.sol";
55
import "cheats/Vm.sol";
6+
import "../logs/console.sol";
67

78
contract GasSnapshotTest is DSTest {
89
uint256 public slot0;
10+
uint256 public cachedGas = 0;
911

1012
Vm constant vm = Vm(HEVM_ADDRESS);
1113

@@ -48,11 +50,38 @@ contract GasSnapshotTest is DSTest {
4850
function testGasComplex() public {
4951
TargetB target = new TargetB();
5052

53+
// Warm up the cache.
54+
target.update(1);
55+
56+
// Start a cheatcode snapshot.
5157
vm.startSnapshotGas("testAssertGasComplexA");
5258

53-
target.update(1);
59+
target.update(2);
5460

55-
vm.stopSnapshotGas();
61+
uint256 gasA = vm.stopSnapshotGas();
62+
console.log("gas native A", gasA);
63+
64+
// Start a comparitive Solidity snapshot.
65+
66+
// Warm up the cache.
67+
cachedGas = 1;
68+
69+
// Start the Solidity snapshot.
70+
cachedGas = gasleft();
71+
72+
target.update(3);
73+
74+
uint256 gasAfter = gasleft();
75+
76+
console.log("gas solidity", cachedGas - gasAfter - 100);
77+
78+
// Start a cheatcode snapshot.
79+
vm.startSnapshotGas("testAssertGasComplexB");
80+
81+
target.update(4);
82+
83+
uint256 gasB = vm.stopSnapshotGas();
84+
console.log("gas native B", gasB);
5685
}
5786

5887
// Writes to `GasSnapshotTest` group with custom names.

0 commit comments

Comments
 (0)