Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev: use checked math #1009

Merged
merged 1 commit into from
Oct 2, 2024
Merged
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
17 changes: 12 additions & 5 deletions crates/evm/src/create_helpers.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::num::traits::Bounded;
use core::num::traits::CheckedAdd;
use core::num::traits::Zero;
use core::starknet::EthAddress;
use crate::errors::{ensure, EVMError};
Expand All @@ -18,7 +19,6 @@ use utils::set::SetTrait;
use utils::traits::{
BoolIntoNumeric, EthAddressIntoU256, U256TryIntoResult, SpanU8TryIntoResultEthAddress
};

/// Helper struct to prepare CREATE and CREATE2 opcodes
#[derive(Drop)]
pub struct CreateArgs {
Expand Down Expand Up @@ -46,13 +46,20 @@ pub impl CreateHelpersImpl of CreateHelpers {
self.memory.ensure_length(memory_expansion.new_size);
let init_code_gas = gas::init_code_cost(size);
let charged_gas = match create_type {
CreateType::Create => gas::CREATE + memory_expansion.expansion_cost + init_code_gas,
CreateType::Create => gas::CREATE
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?
.checked_add(init_code_gas)
.ok_or(EVMError::OutOfGas)?,
CreateType::Create2 => {
let calldata_words = bytes_32_words_size(size);
gas::CREATE
+ gas::KECCAK256WORD * calldata_words.into()
+ memory_expansion.expansion_cost
+ init_code_gas
.checked_add(gas::KECCAK256WORD * calldata_words.into())
.ok_or(EVMError::OutOfGas)?
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?
.checked_add(init_code_gas)
.ok_or(EVMError::OutOfGas)?
},
};
self.charge_gas(charged_gas)?;
Expand Down
3 changes: 2 additions & 1 deletion crates/evm/src/gas.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::errors::EVMError;
use utils::eth_transaction::common::TxKindTrait;
use utils::eth_transaction::eip2930::{AccessListItem};
use utils::eth_transaction::transaction::{Transaction, TransactionTrait};
use utils::helpers::bytes_32_words_size;
use utils::helpers;

//! Gas costs for EVM operations
Expand Down Expand Up @@ -153,7 +154,7 @@ pub fn calculate_message_call_gas(
/// * `total_gas_cost` - The gas cost for storing data in memory.
pub fn calculate_memory_gas_cost(size_in_bytes: usize) -> u64 {
let _512: NonZero<u64> = 512_u64.try_into().unwrap();
let size_in_words = (size_in_bytes + 31) / 32;
let size_in_words = bytes_32_words_size(size_in_bytes);
let linear_cost = size_in_words.into() * MEMORY;

let (q0, r0) = DivRem::div_rem(size_in_words.into(), _512);
Expand Down
3 changes: 2 additions & 1 deletion crates/evm/src/instructions/duplication_operations.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use crate::stack::StackTrait;

/// Generic DUP operation
#[inline(always)]
fn exec_dup_i(ref self: VM, i: u8) -> Result<(), EVMError> {
fn exec_dup_i(ref self: VM, i: NonZero<u8>) -> Result<(), EVMError> {
self.charge_gas(gas::VERYLOW)?;
let i: u8 = i.into();
let item = self.stack.peek_at((i - 1).into())?;
self.stack.push(item)
}
Expand Down
51 changes: 39 additions & 12 deletions crates/evm/src/instructions/environmental_information.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::num::traits::OverflowingAdd;
use core::num::traits::Zero;
use core::num::traits::{CheckedAdd, CheckedSub};
use crate::errors::{ensure, EVMError};
use crate::gas;
use crate::memory::MemoryTrait;
Expand Down Expand Up @@ -79,12 +80,17 @@ pub impl EnvironmentInformationImpl of EnvironmentInformationTrait {
let calldata_len = calldata.len();

// All bytes after the end of the calldata are set to 0.
if offset >= calldata_len {
return self.stack.push(0);
}
let bytes_len = match calldata_len.checked_sub(offset) {
Option::None => { return self.stack.push(0); },
Option::Some(remaining_len) => {
if remaining_len == 0 {
return self.stack.push(0);
}
core::cmp::min(32, remaining_len)
}
};

// Slice the calldata
let bytes_len = core::cmp::min(32, calldata_len - offset);
let sliced = calldata.slice(offset, bytes_len);

let mut data_to_load: u256 = sliced
Expand Down Expand Up @@ -122,7 +128,13 @@ pub impl EnvironmentInformationImpl of EnvironmentInformationTrait {
self.memory.size(), [(dest_offset, size)].span()
)?;
self.memory.ensure_length(memory_expansion.new_size);
self.charge_gas(gas::VERYLOW + copy_gas_cost + memory_expansion.expansion_cost)?;

let total_cost = gas::VERYLOW
.checked_add(copy_gas_cost)
.ok_or(EVMError::OutOfGas)?
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

let calldata: Span<u8> = self.message().data;
copy_bytes_to_memory(ref self, calldata, dest_offset, offset, size);
Expand Down Expand Up @@ -152,7 +164,13 @@ pub impl EnvironmentInformationImpl of EnvironmentInformationTrait {
self.memory.size(), [(dest_offset, size)].span()
)?;
self.memory.ensure_length(memory_expansion.new_size);
self.charge_gas(gas::VERYLOW + copy_gas_cost + memory_expansion.expansion_cost)?;

let total_cost = gas::VERYLOW
.checked_add(copy_gas_cost)
.ok_or(EVMError::OutOfGas)?
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

let bytecode: Span<u8> = self.message().code;

Expand Down Expand Up @@ -208,7 +226,12 @@ pub impl EnvironmentInformationImpl of EnvironmentInformationTrait {
self.accessed_addresses.add(evm_address);
gas::COLD_ACCOUNT_ACCESS_COST
};
self.charge_gas(access_gas_cost + copy_gas_cost + memory_expansion.expansion_cost)?;
let total_cost = access_gas_cost
.checked_add(copy_gas_cost)
.ok_or(EVMError::OutOfGas)?
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

let bytecode = self.env.state.get_account(evm_address).code;
copy_bytes_to_memory(ref self, bytecode, dest_offset, offset, size);
Expand Down Expand Up @@ -246,7 +269,12 @@ pub impl EnvironmentInformationImpl of EnvironmentInformationTrait {
self.memory.size(), [(dest_offset, size)].span()
)?;
self.memory.ensure_length(memory_expansion.new_size);
self.charge_gas(gas::VERYLOW + copy_gas_cost + memory_expansion.expansion_cost)?;
let total_cost = gas::VERYLOW
.checked_add(copy_gas_cost)
.ok_or(EVMError::OutOfGas)?
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

let data_to_copy: Span<u8> = return_data.slice(offset, size);
self.memory.store_n(data_to_copy, dest_offset);
Expand Down Expand Up @@ -287,10 +315,9 @@ pub impl EnvironmentInformationImpl of EnvironmentInformationTrait {
fn copy_bytes_to_memory(
ref self: VM, bytes: Span<u8>, dest_offset: usize, offset: usize, size: usize
) {
let bytes_slice = if offset < bytes.len() {
bytes.slice(offset, core::cmp::min(size, bytes.len() - offset))
} else {
[].span()
let bytes_slice = match bytes.len().checked_sub(offset) {
Option::Some(remaining) => bytes.slice(offset, core::cmp::min(size, remaining)),
Option::None => [].span()
};

self.memory.store_padded_segment(dest_offset, size, bytes_slice);
Expand Down
16 changes: 9 additions & 7 deletions crates/evm/src/instructions/logging_operations.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Logging Operations.

use core::num::traits::CheckedAdd;
use crate::errors::{EVMError, ensure};
use crate::gas;
use crate::memory::MemoryTrait;
Expand Down Expand Up @@ -68,13 +69,14 @@ fn exec_log_i(ref self: VM, topics_len: u8) -> Result<(), EVMError> {
self.memory.ensure_length(memory_expansion.new_size);

// TODO: avoid addition overflows here. We should use checked arithmetic.
self
.charge_gas(
gas::LOG
+ topics_len.into() * gas::LOGTOPIC
+ size.into() * gas::LOGDATA
+ memory_expansion.expansion_cost
)?;
let total_cost = gas::LOG
.checked_add(topics_len.into() * gas::LOGTOPIC)
.ok_or(EVMError::OutOfGas)?
.checked_add(size.into() * gas::LOGDATA)
.ok_or(EVMError::OutOfGas)?
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

let mut data: Array<u8> = Default::default();
self.memory.load_n(size, ref data, offset);
Expand Down
25 changes: 19 additions & 6 deletions crates/evm/src/instructions/memory_operations.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::cmp::max;
use core::num::traits::CheckedAdd;
use crate::backend::starknet_backend::fetch_original_storage;
//! Stack Memory Storage and Flow Operations.
use crate::errors::{EVMError, ensure};
Expand All @@ -9,7 +10,6 @@ use crate::stack::StackTrait;
use crate::state::StateTrait;
use utils::helpers::bytes_32_words_size;
use utils::set::SetTrait;

#[inline(always)]
fn jump(ref self: VM, index: usize) -> Result<(), EVMError> {
match self.message().code.get(index) {
Expand Down Expand Up @@ -42,7 +42,10 @@ pub impl MemoryOperation of MemoryOperationTrait {

let memory_expansion = gas::memory_expansion(self.memory.size(), [(offset, 32)].span())?;
self.memory.ensure_length(memory_expansion.new_size);
self.charge_gas(gas::VERYLOW + memory_expansion.expansion_cost)?;
let total_cost = gas::VERYLOW
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

let result = self.memory.load(offset);
self.stack.push(result)
Expand All @@ -58,7 +61,10 @@ pub impl MemoryOperation of MemoryOperationTrait {
let value: u256 = self.stack.pop()?;
let memory_expansion = gas::memory_expansion(self.memory.size(), [(offset, 32)].span())?;
self.memory.ensure_length(memory_expansion.new_size);
self.charge_gas(gas::VERYLOW + memory_expansion.expansion_cost)?;
let total_cost = gas::VERYLOW
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

self.memory.store(value, offset);
Result::Ok(())
Expand All @@ -74,7 +80,10 @@ pub impl MemoryOperation of MemoryOperationTrait {

let memory_expansion = gas::memory_expansion(self.memory.size(), [(offset, 1)].span())?;
self.memory.ensure_length(memory_expansion.new_size);
self.charge_gas(gas::VERYLOW + memory_expansion.expansion_cost)?;
let total_cost = gas::VERYLOW
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

self.memory.store_byte(value, offset);

Expand Down Expand Up @@ -294,8 +303,12 @@ pub impl MemoryOperation of MemoryOperationTrait {
self.memory.size(), [(max(dest_offset, source_offset), size)].span()
)?;
self.memory.ensure_length(memory_expansion.new_size);
//TODO: handle add overflows
self.charge_gas(gas::VERYLOW + copy_gas_cost + memory_expansion.expansion_cost)?;
let total_cost = gas::VERYLOW
.checked_add(copy_gas_cost)
.ok_or(EVMError::OutOfGas)?
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

if size == 0 {
return Result::Ok(());
Expand Down
9 changes: 7 additions & 2 deletions crates/evm/src/instructions/sha3.cairo
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::cmp::min;
//! SHA3.
use core::keccak::{cairo_keccak};
use core::num::traits::CheckedAdd;

// Internal imports
use crate::errors::EVMError;
Expand All @@ -11,7 +12,6 @@ use crate::stack::StackTrait;
use utils::helpers::bytes_32_words_size;
use utils::traits::array::ArrayExtTrait;
use utils::traits::integer::U256Trait;

#[generate_trait]
pub impl Sha3Impl of Sha3Trait {
/// SHA3 operation : Hashes n bytes in memory at a given offset in memory
Expand All @@ -32,7 +32,12 @@ pub impl Sha3Impl of Sha3Trait {
let word_gas_cost = gas::KECCAK256WORD * words_size;
let memory_expansion = gas::memory_expansion(self.memory.size(), [(offset, size)].span())?;
self.memory.ensure_length(memory_expansion.new_size);
self.charge_gas(gas::KECCAK256 + word_gas_cost + memory_expansion.expansion_cost)?;
let total_cost = gas::KECCAK256
.checked_add(word_gas_cost)
.ok_or(EVMError::OutOfGas)?
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

let mut to_hash: Array<u64> = Default::default();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Stop and Arithmetic Operations.
use core::integer::{u512_safe_div_rem_by_u256};
use core::math::u256_mul_mod_n;
use core::num::traits::CheckedAdd;
use core::num::traits::{OverflowingAdd, OverflowingMul, OverflowingSub};
use crate::errors::EVMError;
use crate::gas;
Expand Down Expand Up @@ -164,7 +165,6 @@ pub impl StopAndArithmeticOperations of StopAndArithmeticOperationsTrait {

let result: u256 = match TryInto::<u256, NonZero<u256>>::try_into(n) {
Option::Some(nonzero_n) => {
// This is more gas efficient than computing (a mod N) + (b mod N) mod N
let sum = u256_wide_add(a, b);
let (_, r) = u512_safe_div_rem_by_u256(sum, nonzero_n);
r
Expand Down Expand Up @@ -204,7 +204,10 @@ pub impl StopAndArithmeticOperations of StopAndArithmeticOperationsTrait {

// Gas
let bytes_used = exponent.bytes_used();
self.charge_gas(gas::EXP + gas::EXP_GAS_PER_BYTE * bytes_used.into())?;
let total_cost = gas::EXP
.checked_add(gas::EXP_GAS_PER_BYTE * bytes_used.into())
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

let result = base.wrapping_pow(exponent);

Expand Down Expand Up @@ -238,6 +241,7 @@ pub impl StopAndArithmeticOperations of StopAndArithmeticOperationsTrait {

let result = if b < 32 {
let s = 8 * b + 7;
//TODO: use POW_2 table for optimization
let two_pow_s = 2.pow(s);
// Get v, the t-th bit of x. To do this we bitshift x by s bits to the right and apply a
// mask to get the last bit.
Expand Down
12 changes: 10 additions & 2 deletions crates/evm/src/instructions/system_operations.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ pub impl SystemOperations of SystemOperationsTrait {
memory_expansion.expansion_cost,
access_gas_cost + transfer_gas_cost + create_gas_cost
)?;
self.charge_gas(message_call_gas.cost + memory_expansion.expansion_cost)?;
let total_cost = message_call_gas
.cost
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;
// Only the transfer gas is left to charge.

let read_only = self.message().read_only;
Expand Down Expand Up @@ -213,7 +217,11 @@ pub impl SystemOperations of SystemOperationsTrait {
let message_call_gas = gas::calculate_message_call_gas(
0, gas, self.gas_left(), memory_expansion.expansion_cost, access_gas_cost
)?;
self.charge_gas(message_call_gas.cost + memory_expansion.expansion_cost)?;
let total_cost = message_call_gas
.cost
.checked_add(memory_expansion.expansion_cost)
.ok_or(EVMError::OutOfGas)?;
self.charge_gas(total_cost)?;

self
.generic_call(
Expand Down
2 changes: 1 addition & 1 deletion crates/evm/src/interpreter.cairo
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use contracts::kakarot_core::KakarotCore;
use contracts::kakarot_core::interface::IKakarotCore;
use core::num::traits::{Bounded, Zero};
use core::num::traits::Zero;
use core::ops::SnapshotDeref;
use core::starknet::EthAddress;
use core::starknet::storage::{StoragePointerReadAccess};
Expand Down
5 changes: 3 additions & 2 deletions crates/evm/src/precompiles/identity.cairo
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::starknet::EthAddress;
use crate::errors::EVMError;
use crate::precompiles::Precompile;
use utils::helpers::bytes_32_words_size;

const BASE_COST: u64 = 15;
const COST_PER_WORD: u64 = 3;
Expand All @@ -12,8 +13,8 @@ pub impl Identity of Precompile {
}

fn exec(input: Span<u8>) -> Result<(u64, Span<u8>), EVMError> {
let data_word_size = ((input.len() + 31) / 32).into();
let gas = BASE_COST + data_word_size * COST_PER_WORD;
let data_word_size = bytes_32_words_size(input.len());
let gas = BASE_COST + data_word_size.into() * COST_PER_WORD;

return Result::Ok((gas, input));
}
Expand Down
Loading
Loading