Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
feat: add dummy gen_selfdestruct_ops
Browse files Browse the repository at this point in the history
  • Loading branch information
han0110 committed May 15, 2022
1 parent acfcb58 commit 1536b64
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 99 deletions.
62 changes: 60 additions & 2 deletions bus-mapping/src/circuit_input_builder/input_state_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::{
error::{get_step_reported_error, ExecError},
exec_trace::OperationRef,
operation::{
AccountField, CallContextField, CallContextOp, MemoryOp, Op, OpEnum, Operation, StackOp,
Target, RW,
AccountField, AccountOp, CallContextField, CallContextOp, MemoryOp, Op, OpEnum, Operation,
StackOp, Target, RW,
},
state_db::{CodeDB, StateDB},
Error,
Expand Down Expand Up @@ -265,6 +265,64 @@ impl<'a> CircuitInputStateRef<'a> {
Ok(())
}

/// Push 2 reversible [`AccountOp`] to update `sender` and `receiver`'s
/// balance by `value`, with `sender` being extraly charged with `fee`.
pub fn transfer_with_fee(
&mut self,
step: &mut ExecStep,
sender: Address,
receiver: Address,
value: Word,
fee: Word,
) -> Result<(), Error> {
let (found, sender_account) = self.sdb.get_account(&sender);
if !found {
return Err(Error::AccountNotFound(sender));
}
let sender_balance_prev = sender_account.balance;
let sender_balance = sender_account.balance - value - fee;
self.push_op_reversible(
step,
RW::WRITE,
AccountOp {
address: sender,
field: AccountField::Balance,
value: sender_balance,
value_prev: sender_balance_prev,
},
)?;

let (found, receiver_account) = self.sdb.get_account(&receiver);
if !found {
return Err(Error::AccountNotFound(receiver));
}
let receiver_balance_prev = receiver_account.balance;
let receiver_balance = receiver_account.balance + value;
self.push_op_reversible(
step,
RW::WRITE,
AccountOp {
address: receiver,
field: AccountField::Balance,
value: receiver_balance,
value_prev: receiver_balance_prev,
},
)?;

Ok(())
}

/// Same functionality with `transfer_with_fee` but with `fee` set zero.
pub fn transfer(
&mut self,
step: &mut ExecStep,
sender: Address,
receiver: Address,
value: Word,
) -> Result<(), Error> {
self.transfer_with_fee(step, sender, receiver, value, Word::zero())
}

/// Fetch and return code for the given code hash from the code DB.
pub fn code(&self, code_hash: H256) -> Result<Vec<u8>, Error> {
self.code_db
Expand Down
118 changes: 55 additions & 63 deletions bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
use core::fmt::Debug;
use eth_types::{
evm_types::{GasCost, MAX_REFUND_QUOTIENT_OF_GAS_USED},
GethExecStep, ToWord, Word,
GethExecStep, ToAddress, ToWord, Word,
};
use keccak256::EMPTY_HASH;
use log::warn;
Expand Down Expand Up @@ -203,7 +203,10 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps {
// OpcodeId::STATICCALL => {},
// TODO: Handle REVERT by its own gen_associated_ops.
OpcodeId::REVERT => Stop::gen_associated_ops,
// OpcodeId::SELFDESTRUCT => {},
OpcodeId::SELFDESTRUCT => {
warn!("Using dummy gen_selfdestruct_ops for opcode SELFDESTRUCT");
dummy_gen_selfdestruct_ops
}
OpcodeId::CALLCODE | OpcodeId::DELEGATECALL | OpcodeId::STATICCALL => {
warn!("Using dummy gen_call_ops for opcode {:?}", opcode_id);
dummy_gen_call_ops
Expand Down Expand Up @@ -256,6 +259,7 @@ pub fn gen_begin_tx_ops(state: &mut CircuitInputStateRef) -> Result<ExecStep, Er
);
}

// Increase caller's nonce
let caller_address = call.caller_address;
let nonce_prev = state.sdb.increase_nonce(&caller_address);
state.push_op(
Expand All @@ -269,6 +273,7 @@ pub fn gen_begin_tx_ops(state: &mut CircuitInputStateRef) -> Result<ExecStep, Er
},
);

// Add caller and callee into access list
for address in [call.caller_address, call.address] {
state.sdb.add_account_to_access_list(address);
state.push_op(
Expand All @@ -283,6 +288,7 @@ pub fn gen_begin_tx_ops(state: &mut CircuitInputStateRef) -> Result<ExecStep, Er
);
}

// Calculate intrinsic gas cost
let call_data_gas_cost = state
.tx
.input
Expand All @@ -295,40 +301,18 @@ pub fn gen_begin_tx_ops(state: &mut CircuitInputStateRef) -> Result<ExecStep, Er
} + call_data_gas_cost;
exec_step.gas_cost = GasCost(intrinsic_gas_cost);

let (found, caller_account) = state.sdb.get_account(&call.caller_address);
if !found {
return Err(Error::AccountNotFound(call.caller_address));
}
let caller_balance_prev = caller_account.balance;
let caller_balance = caller_account.balance - call.value - state.tx.gas_price * state.tx.gas;
state.push_op_reversible(
// Transfer with fee
state.transfer_with_fee(
&mut exec_step,
RW::WRITE,
AccountOp {
address: call.caller_address,
field: AccountField::Balance,
value: caller_balance,
value_prev: caller_balance_prev,
},
call.caller_address,
call.address,
call.value,
state.tx.gas_price * state.tx.gas,
)?;

let (found, callee_account) = state.sdb.get_account(&call.address);
if !found {
return Err(Error::AccountNotFound(call.address));
}
let callee_balance_prev = callee_account.balance;
let callee_balance = callee_account.balance + call.value;
// Get code_hash of callee
let (_, callee_account) = state.sdb.get_account(&call.address);
let code_hash = callee_account.code_hash;
state.push_op_reversible(
&mut exec_step,
RW::WRITE,
AccountOp {
address: call.address,
field: AccountField::Balance,
value: callee_balance,
value_prev: callee_balance_prev,
},
)?;

// There are 4 branches from here.
match (
Expand Down Expand Up @@ -641,38 +625,11 @@ fn dummy_gen_create_ops(
},
)?;

let (found, caller_account) = state.sdb.get_account(&call.caller_address);
if !found {
return Err(Error::AccountNotFound(call.caller_address));
}
let caller_balance_prev = caller_account.balance;
let caller_balance = caller_account.balance - call.value;
state.push_op_reversible(
&mut exec_step,
RW::WRITE,
AccountOp {
address: call.caller_address,
field: AccountField::Balance,
value: caller_balance,
value_prev: caller_balance_prev,
},
)?;

let (found, callee_account) = state.sdb.get_account(&call.address);
if !found {
return Err(Error::AccountNotFound(call.address));
}
let callee_balance_prev = callee_account.balance;
let callee_balance = callee_account.balance + call.value;
state.push_op_reversible(
state.transfer(
&mut exec_step,
RW::WRITE,
AccountOp {
address: call.address,
field: AccountField::Balance,
value: callee_balance,
value_prev: callee_balance_prev,
},
call.caller_address,
call.address,
call.value,
)?;

if call.code_hash.to_fixed_bytes() == *EMPTY_HASH {
Expand All @@ -684,3 +641,38 @@ fn dummy_gen_create_ops(
Ok(vec![exec_step])
}
}

fn dummy_gen_selfdestruct_ops(
state: &mut CircuitInputStateRef,
geth_steps: &[GethExecStep],
) -> Result<Vec<ExecStep>, Error> {
let geth_step = &geth_steps[0];
let mut exec_step = state.new_step(geth_step)?;
let sender = state.call()?.address;
let receiver = geth_step.stack.last()?.to_address();

let is_warm = state.sdb.check_account_in_access_list(&receiver);
state.push_op_reversible(
&mut exec_step,
RW::WRITE,
TxAccessListAccountOp {
tx_id: state.tx_ctx.id(),
address: receiver,
is_warm: true,
is_warm_prev: is_warm,
},
)?;

let (found, receiver_account) = state.sdb.get_account(&receiver);
if !found {
return Err(Error::AccountNotFound(receiver));
}
let value = receiver_account.balance;
state.transfer(&mut exec_step, sender, receiver, value)?;

if state.call()?.is_persistent {
state.sdb.destruct_account(sender);
}

Ok(vec![exec_step])
}
41 changes: 7 additions & 34 deletions bus-mapping/src/evm/opcodes/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,44 +119,17 @@ impl Opcode for Call {
);
}

let (found, caller_account) = state.sdb.get_account(&call.caller_address);
if !found {
return Err(Error::AccountNotFound(call.caller_address));
}
let caller_balance_prev = caller_account.balance;
let caller_balance = caller_account.balance - call.value;
state.push_op_reversible(
state.transfer(
&mut exec_step,
RW::WRITE,
AccountOp {
address: call.caller_address,
field: AccountField::Balance,
value: caller_balance,
value_prev: caller_balance_prev,
},
call.caller_address,
call.address,
call.value,
)?;

let (found, callee_account) = state.sdb.get_account(&call.address);
if !found {
return Err(Error::AccountNotFound(call.address));
}
let (_, callee_account) = state.sdb.get_account(&call.address);
let is_account_empty = callee_account.is_empty();
let callee_balance_prev = callee_account.balance;
let callee_balance = callee_account.balance + call.value;
state.push_op_reversible(
&mut exec_step,
RW::WRITE,
AccountOp {
address: call.address,
field: AccountField::Balance,
value: callee_balance,
value_prev: callee_balance_prev,
},
)?;

let (_, account) = state.sdb.get_account(&call.address);
let callee_nonce = account.nonce;
let callee_code_hash = account.code_hash;
let callee_nonce = callee_account.nonce;
let callee_code_hash = callee_account.code_hash;
for (field, value) in [
(AccountField::Nonce, callee_nonce),
(AccountField::CodeHash, callee_code_hash.to_word()),
Expand Down
13 changes: 13 additions & 0 deletions bus-mapping/src/state_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ pub struct StateDB {
// state before current transaction, to calculate gas cost for some opcodes like sstore.
// So both dirty storage and committed storage are needed.
dirty_storage: HashMap<(Address, Word), Word>,
// Accounts that have been through `SELFDESTRUCT` under the situation that `is_persistent` is
// `true`. These accounts will be reset once `commit_tx` is called.
destructed_account: HashSet<Address>,
refund: u64,
}

Expand All @@ -94,6 +97,7 @@ impl StateDB {
access_list_account: HashSet::new(),
access_list_account_storage: HashSet::new(),
dirty_storage: HashMap::new(),
destructed_account: HashSet::new(),
refund: 0,
}
}
Expand Down Expand Up @@ -221,6 +225,11 @@ impl StateDB {
debug_assert!(exist);
}

/// Set account as self destructed.
pub fn destruct_account(&mut self, addr: Address) {
self.destructed_account.insert(addr);
}

/// Retrieve refund.
pub fn refund(&self) -> u64 {
self.refund
Expand All @@ -242,6 +251,10 @@ impl StateDB {
*ptr = value;
}
self.dirty_storage = HashMap::new();
for addr in self.destructed_account.clone() {
let (_, account) = self.get_account_mut(&addr);
*account = ACCOUNT_ZERO.clone();
}
self.refund = 0;
}
}
Expand Down

0 comments on commit 1536b64

Please sign in to comment.