Skip to content

Commit ce61df3

Browse files
SDartayetJereSalo
andauthored
refactor(levm): moved retdata from vm to callframe (#2694)
**Motivation** Make code more readable by coupling related behaviour. **Description** Some fields in retdata were repeated in the callframe, and the retdata was always being popped alongside the current call frame. This PR deletes the retdata struct, and moves the fields that weren't redundant to the call frame, refactoring the code where appropriate. It also removes `gas_used` from `CallFrame::new()` because we were always setting it to zero. Closes #2571, Closes #2720 --------- Co-authored-by: JereSalo <[email protected]> Co-authored-by: Jeremías Salomón <[email protected]>
1 parent 00f6389 commit ce61df3

File tree

3 files changed

+48
-60
lines changed

3 files changed

+48
-60
lines changed

crates/vm/levm/src/call_frame.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ pub struct CallFrame {
9494
pub create_op_called: bool,
9595
/// Everytime we want to write an account during execution of a callframe we store the pre-write state so that we can restore if it reverts
9696
pub call_frame_backup: CallFrameBackup,
97+
/// Return data offset
98+
pub ret_offset: U256,
99+
/// Return data size
100+
pub ret_size: usize,
101+
/// If true then transfer value from caller to callee
102+
pub should_transfer_value: bool,
97103
}
98104

99105
#[derive(Debug, Clone, Eq, PartialEq, Default)]
@@ -113,9 +119,11 @@ impl CallFrame {
113119
calldata: Bytes,
114120
is_static: bool,
115121
gas_limit: u64,
116-
gas_used: u64,
117122
depth: usize,
123+
should_transfer_value: bool,
118124
create_op_called: bool,
125+
ret_offset: U256,
126+
ret_size: usize,
119127
) -> Self {
120128
let valid_jump_destinations = get_valid_jump_destinations(&bytecode).unwrap_or_default();
121129
Self {
@@ -128,9 +136,11 @@ impl CallFrame {
128136
calldata,
129137
is_static,
130138
depth,
131-
gas_used,
132139
valid_jump_destinations,
140+
should_transfer_value,
133141
create_op_called,
142+
ret_offset,
143+
ret_size,
134144
..Default::default()
135145
}
136146
}

crates/vm/levm/src/opcode_handlers/system.rs

Lines changed: 33 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
memory::{self, calculate_memory_size},
88
precompiles::is_precompile,
99
utils::{address_to_word, word_to_address, *},
10-
vm::{RetData, StateBackup, VM},
10+
vm::{StateBackup, VM},
1111
};
1212
use bytes::Bytes;
1313
use ethrex_common::{
@@ -715,24 +715,16 @@ impl<'a> VM<'a> {
715715
Bytes::new(),
716716
false,
717717
max_message_call_gas,
718-
0,
719718
new_depth,
720719
true,
720+
true,
721+
U256::zero(),
722+
0,
721723
);
722724
self.call_frames.push(new_call_frame);
723725

724726
self.accrued_substate.created_accounts.insert(new_address); // Mostly for SELFDESTRUCT during initcode.
725727

726-
self.return_data.push(RetData {
727-
is_create: true,
728-
ret_offset: U256::zero(),
729-
ret_size: 0,
730-
should_transfer_value: true,
731-
to: new_address,
732-
msg_sender: deployer_address,
733-
value: value_in_wei_to_send,
734-
max_message_call_gas,
735-
});
736728
// Backup of Database, Substate, Gas Refunds and Transient Storage if sub-context is reverted
737729
let backup = StateBackup::new(
738730
self.accrued_substate.clone(),
@@ -823,16 +815,6 @@ impl<'a> VM<'a> {
823815
self.increase_account_balance(to, value)?;
824816
}
825817

826-
self.return_data.push(RetData {
827-
is_create: false,
828-
ret_offset,
829-
ret_size,
830-
should_transfer_value,
831-
to,
832-
msg_sender,
833-
value,
834-
max_message_call_gas: gas_limit,
835-
});
836818
let new_call_frame = CallFrame::new(
837819
msg_sender,
838820
to,
@@ -842,9 +824,11 @@ impl<'a> VM<'a> {
842824
calldata.into(),
843825
is_static,
844826
gas_limit,
845-
0,
846827
new_depth,
828+
should_transfer_value,
847829
false,
830+
ret_offset,
831+
ret_size,
848832
);
849833
self.call_frames.push(new_call_frame);
850834
// Backup of Database, Substate, Gas Refunds and Transient Storage if sub-context is reverted
@@ -870,22 +854,17 @@ impl<'a> VM<'a> {
870854
self.call_frames.push(executed_call_frame.clone());
871855
return Ok(false);
872856
}
873-
let retdata = self
874-
.return_data
875-
.pop()
876-
.ok_or(VMError::Internal(InternalError::CouldNotPopCallframe))?;
877-
if retdata.is_create {
878-
self.handle_return_create(executed_call_frame, tx_report, retdata)?;
857+
if executed_call_frame.create_op_called {
858+
self.handle_return_create(executed_call_frame, tx_report)?;
879859
} else {
880-
self.handle_return_call(executed_call_frame, tx_report, retdata)?;
860+
self.handle_return_call(executed_call_frame, tx_report)?;
881861
}
882862
Ok(true)
883863
}
884864
pub fn handle_return_call(
885865
&mut self,
886866
executed_call_frame: &CallFrame,
887867
tx_report: &ExecutionReport,
888-
retdata: RetData,
889868
) -> Result<(), VMError> {
890869
// Return gas left from subcontext
891870
let gas_left_from_new_call_frame = executed_call_frame
@@ -902,8 +881,8 @@ impl<'a> VM<'a> {
902881
parent_call_frame.logs.extend(tx_report.logs.clone());
903882
memory::try_store_range(
904883
&mut parent_call_frame.memory,
905-
retdata.ret_offset,
906-
retdata.ret_size,
884+
executed_call_frame.ret_offset,
885+
executed_call_frame.ret_size,
907886
&tx_report.output,
908887
)?;
909888
parent_call_frame.sub_return_data = tx_report.output.clone();
@@ -919,10 +898,16 @@ impl<'a> VM<'a> {
919898
}
920899
TxResult::Revert(_) => {
921900
// Revert value transfer
922-
if retdata.should_transfer_value {
923-
self.decrease_account_balance(retdata.to, retdata.value)?;
924-
925-
self.increase_account_balance(retdata.msg_sender, retdata.value)?;
901+
if executed_call_frame.should_transfer_value {
902+
self.decrease_account_balance(
903+
executed_call_frame.to,
904+
executed_call_frame.msg_value,
905+
)?;
906+
907+
self.increase_account_balance(
908+
executed_call_frame.msg_sender,
909+
executed_call_frame.msg_value,
910+
)?;
926911
}
927912
// Push 0 to stack
928913
self.current_call_frame_mut()?.stack.push(REVERT_FOR_CALL)?;
@@ -934,10 +919,9 @@ impl<'a> VM<'a> {
934919
&mut self,
935920
executed_call_frame: &CallFrame,
936921
tx_report: &ExecutionReport,
937-
retdata: RetData,
938922
) -> Result<(), VMError> {
939-
let unused_gas = retdata
940-
.max_message_call_gas
923+
let unused_gas = executed_call_frame
924+
.gas_limit
941925
.checked_sub(tx_report.gas_used)
942926
.ok_or(InternalError::GasOverflow)?;
943927

@@ -956,16 +940,21 @@ impl<'a> VM<'a> {
956940
TxResult::Success => {
957941
self.current_call_frame_mut()?
958942
.stack
959-
.push(address_to_word(retdata.to))?;
943+
.push(address_to_word(executed_call_frame.to))?;
960944
self.merge_call_frame_backup_with_parent(&executed_call_frame.call_frame_backup)?;
961945
}
962946
TxResult::Revert(err) => {
963947
// Return value to sender
964-
self.increase_account_balance(retdata.msg_sender, retdata.value)?;
948+
self.increase_account_balance(
949+
executed_call_frame.msg_sender,
950+
executed_call_frame.msg_value,
951+
)?;
965952

966953
// Deployment failed so account shouldn't exist
967-
cache::remove_account(&mut self.db.cache, &retdata.to);
968-
self.accrued_substate.created_accounts.remove(&retdata.to);
954+
cache::remove_account(&mut self.db.cache, &executed_call_frame.to);
955+
self.accrued_substate
956+
.created_accounts
957+
.remove(&executed_call_frame.to);
969958

970959
let current_call_frame = self.current_call_frame_mut()?;
971960
// If revert we have to copy the return_data

crates/vm/levm/src/vm.rs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -159,23 +159,11 @@ pub struct VM<'a> {
159159
pub access_list: AccessList,
160160
pub authorization_list: Option<AuthorizationList>,
161161
pub hooks: Vec<Arc<dyn Hook>>,
162-
pub return_data: Vec<RetData>,
163162
pub backups: Vec<StateBackup>,
164163
/// Original storage values before the transaction. Used for gas calculations in SSTORE.
165164
pub storage_original_values: HashMap<Address, HashMap<H256, U256>>,
166165
}
167166

168-
pub struct RetData {
169-
pub is_create: bool,
170-
pub ret_offset: U256,
171-
pub ret_size: usize,
172-
pub should_transfer_value: bool,
173-
pub to: Address,
174-
pub msg_sender: Address,
175-
pub value: U256,
176-
pub max_message_call_gas: u64,
177-
}
178-
179167
impl<'a> VM<'a> {
180168
pub fn new(
181169
env: Environment,
@@ -280,8 +268,10 @@ impl<'a> VM<'a> {
280268
false,
281269
env.gas_limit,
282270
0,
283-
0,
271+
true,
284272
false,
273+
U256::zero(),
274+
0,
285275
);
286276

287277
Ok(Self {
@@ -293,7 +283,6 @@ impl<'a> VM<'a> {
293283
access_list: tx.access_list(),
294284
authorization_list: tx.authorization_list(),
295285
hooks,
296-
return_data: vec![],
297286
backups: vec![],
298287
storage_original_values: HashMap::new(),
299288
})

0 commit comments

Comments
 (0)