Skip to content

Commit

Permalink
fixes: total gas_used corrections (#1021)
Browse files Browse the repository at this point in the history
<!--- Please provide a general summary of your changes in the title
above -->

<!-- Give an estimate of the time you spent on this PR in terms of work
days.
Did you spend 0.5 days on this PR or rather 2 days?  -->

Time spent on this PR: 0.5

## Pull request type

<!-- Please try to limit your pull request to one type,
submit multiple pull requests if needed. -->

Please check the type of change your PR introduces:

- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## What is the current behavior?

<!-- Please describe the current behavior that you are modifying,
or link to a relevant issue. -->

Resolves #<Issue number>

## What is the new behavior?

<!-- Please describe the behavior or changes that are being added by
this PR. -->

-
-
-

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg"
height="34" align="absmiddle"
alt="Reviewable"/>](https://reviewable.io/reviews/kkrt-labs/kakarot/1021)
<!-- Reviewable:end -->
  • Loading branch information
enitrat authored Mar 11, 2024
1 parent 6b45cfc commit e676a70
Show file tree
Hide file tree
Showing 16 changed files with 489 additions and 174 deletions.
287 changes: 207 additions & 80 deletions blockchain-tests-skip.yml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/kakarot/evm.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ namespace EVM {
program_counter=self.program_counter,
stopped=TRUE,
gas_left=0,
gas_refund=self.gas_refund,
gas_refund=0,
reverted=Errors.EXCEPTIONAL_HALT,
);
}
Expand Down
13 changes: 11 additions & 2 deletions src/kakarot/gas.cairo
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from starkware.cairo.common.math import split_felt, unsigned_div_rem
from starkware.cairo.common.math_cmp import is_le, is_not_zero, is_nn
from starkware.cairo.common.bool import FALSE
from starkware.cairo.common.uint256 import Uint256, uint256_lt
from starkware.cairo.common.uint256 import Uint256, uint256_lt, uint256_eq

from kakarot.model import model
from utils.utils import Helpers

namespace Gas {
const JUMPDEST = 1;
Expand Down Expand Up @@ -102,7 +103,8 @@ namespace Gas {
func memory_expansion_cost_saturated{range_check_ptr}(
words_len: felt, offset: Uint256, size: Uint256
) -> model.MemoryExpansion {
if (size.low == 0) {
let (is_zero) = uint256_eq(size, Uint256(low=0, high=0));
if (is_zero != FALSE) {
let expansion = model.MemoryExpansion(cost=0, new_words_len=words_len);
return expansion;
}
Expand Down Expand Up @@ -134,6 +136,13 @@ namespace Gas {
words_len: felt, offset_1: Uint256*, size_1: Uint256*, offset_2: Uint256*, size_2: Uint256*
) -> model.MemoryExpansion {
alloc_locals;
let (is_zero_1) = uint256_eq([size_1], Uint256(0, 0));
let (is_zero_2) = uint256_eq([size_2], Uint256(0, 0));
let is_zero = is_zero_1 * is_zero_2;
if (is_zero != FALSE) {
let expansion = model.MemoryExpansion(cost=0, new_words_len=words_len);
return expansion;
}
let max_expansion_is_2 = is_le(offset_1.low + size_1.low, offset_2.low + size_2.low);
let max_expansion = max_expansion_is_2 * (offset_2.low + size_2.low) + (
1 - max_expansion_is_2
Expand Down
127 changes: 97 additions & 30 deletions src/kakarot/instructions/environmental_information.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ from starkware.cairo.common.cairo_keccak.keccak import cairo_keccak_bigend, fina
from starkware.cairo.common.memset import memset
from starkware.cairo.common.math import unsigned_div_rem, split_felt
from starkware.cairo.common.math_cmp import is_not_zero, is_le
from starkware.cairo.common.uint256 import Uint256, uint256_le, uint256_add
from starkware.cairo.common.uint256 import Uint256, uint256_le, uint256_add, uint256_eq

from kakarot.account import Account
from kakarot.evm import EVM
Expand Down Expand Up @@ -152,7 +152,7 @@ namespace EnvironmentalInformation {
return evm;
}

func exec_copy{
func exec_returndatacopy{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
Expand All @@ -163,13 +163,15 @@ namespace EnvironmentalInformation {
}(evm: model.EVM*) -> model.EVM* {
alloc_locals;

// STACK
let (popped) = Stack.pop_n(3);
let dest_offset = popped[0];
let offset = popped[1];
let memory_offset = popped[0];
let returndata_offset = popped[1];
let size = popped[2];

// GAS
let memory_expansion = Gas.memory_expansion_cost_saturated(
memory.words_len, dest_offset, size
memory.words_len, memory_offset, size
);

// Any size upper than 2**128 will cause an OOG error, considering the maximum gas for a transaction.
Expand All @@ -186,17 +188,18 @@ namespace EnvironmentalInformation {
return evm;
}

let opcode_number = [evm.message.bytecode + evm.program_counter];
// OPERATION
tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
words_len=memory_expansion.new_words_len,
);

// Offset.high != 0 means that the sliced data is surely 0x00...00
// And storing 0 in Memory is just doing nothing.
if (offset.high != 0) {
if (opcode_number != 0x3e) {
return evm;
}

if (returndata_offset.high != 0) {
// We still check for OOB returndatacopy
let (max_index, carry) = uint256_add(offset, size);
let (max_index, carry) = uint256_add(returndata_offset, size);
let (high, low) = split_felt(evm.return_data_len);
let (is_in_bounds) = uint256_le(max_index, Uint256(low=low, high=high));
let is_in_bounds = is_in_bounds * (1 - carry);
Expand All @@ -208,9 +211,81 @@ namespace EnvironmentalInformation {
return evm;
}

let (sliced_data: felt*) = alloc();
tempvar is_in_bounds = is_le(returndata_offset.low + size.low, evm.return_data_len);
if (is_in_bounds == FALSE) {
let (revert_reason_len, revert_reason) = Errors.outOfBoundsRead();
let evm = EVM.stop(evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT);
return evm;
}
slice(sliced_data, evm.return_data_len, evm.return_data, returndata_offset.low, size.low);

Memory.store_n(size.low, sliced_data, memory_offset.low);

return evm;
}

func exec_copy{
syscall_ptr: felt*,
pedersen_ptr: HashBuiltin*,
range_check_ptr,
bitwise_ptr: BitwiseBuiltin*,
stack: model.Stack*,
memory: model.Memory*,
state: model.State*,
}(evm: model.EVM*) -> model.EVM* {
alloc_locals;

// STACK
let (popped) = Stack.pop_n(3);
let dest_offset = popped[0];
let offset = popped[1];
let size = popped[2];

// if size == 0, we can optimize by returning early
// fixed opcode cost has already been charged as both
// calldatacopy and codecopy don't have additional checks
let (is_zero) = uint256_eq(size, Uint256(low=0, high=0));
if (is_zero != FALSE) {
return evm;
}

// GAS
let memory_expansion = Gas.memory_expansion_cost_saturated(
memory.words_len, dest_offset, size
);

// Any size upper than 2**128 will cause an OOG error, considering the maximum gas for a transaction.
let upper_bytes_bound = size.low + 31;
let (words, _) = unsigned_div_rem(upper_bytes_bound, 32);
let copy_gas_cost_low = words * Gas.COPY;
tempvar copy_gas_cost_high = is_not_zero(size.high) * 2 ** 128;

// static cost handled in jump table
let evm = EVM.charge_gas(
evm, memory_expansion.cost + copy_gas_cost_low + copy_gas_cost_high
);
if (evm.reverted != FALSE) {
return evm;
}

// OPERATION
tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
words_len=memory_expansion.new_words_len,
);

let opcode_number = [evm.message.bytecode + evm.program_counter];

// Offset.high != 0 means that the sliced data is surely 0x00...00
// And storing 0 in Memory is just doing nothing.
if (offset.high != 0) {
return evm;
}

// 0x37: calldatacopy
// 0x39: codecopy
// 0x3e: returndatacopy
let (sliced_data: felt*) = alloc();
local data_len;
local data: felt*;
Expand All @@ -219,23 +294,9 @@ namespace EnvironmentalInformation {
assert data = evm.message.calldata;
tempvar range_check_ptr = range_check_ptr;
} else {
if (opcode_number == 0x39) {
assert data_len = evm.message.bytecode_len;
assert data = evm.message.bytecode;
tempvar range_check_ptr = range_check_ptr;
} else {
tempvar is_in_bounds = is_le(offset.low + size.low, evm.return_data_len);
if (is_in_bounds == FALSE) {
let (revert_reason_len, revert_reason) = Errors.outOfBoundsRead();
let evm = EVM.stop(
evm, revert_reason_len, revert_reason, Errors.EXCEPTIONAL_HALT
);
return evm;
}
assert data_len = evm.return_data_len;
assert data = evm.return_data;
tempvar range_check_ptr = range_check_ptr;
}
assert data_len = evm.message.bytecode_len;
assert data = evm.message.bytecode;
tempvar range_check_ptr = range_check_ptr;
}
let range_check_ptr = [ap - 1];
slice(sliced_data, data_len, data, offset.low, size.low);
Expand Down Expand Up @@ -346,6 +407,12 @@ namespace EnvironmentalInformation {
return evm;
}

tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
words_len=memory_expansion.new_words_len,
);

// Offset.high != 0 means that the sliced data is surely 0x00...00
// And storing 0 in Memory is just doing nothing
if (offset.high != 0) {
Expand Down
5 changes: 5 additions & 0 deletions src/kakarot/instructions/logging_operations.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ namespace LoggingOperations {
if (evm.reverted != FALSE) {
return evm;
}
tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
words_len=memory_expansion.new_words_len,
);
let (data: felt*) = alloc();
Memory.load_n(size.low, data, offset.low);
EVM.push_event(evm, topics_len, popped + 4, size.low, data);
Expand Down
16 changes: 16 additions & 0 deletions src/kakarot/instructions/memory_operations.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ namespace MemoryOperations {
return evm;
}

tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
words_len=memory_expansion.new_words_len,
);

let value = Memory.load(offset.low);
Stack.push_uint256(value);

Expand Down Expand Up @@ -68,6 +74,11 @@ namespace MemoryOperations {
if (evm.reverted != FALSE) {
return evm;
}
tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
words_len=memory_expansion.new_words_len,
);
Memory.store(value, offset.low);

return evm;
Expand Down Expand Up @@ -208,6 +219,11 @@ namespace MemoryOperations {
let (value_pointer: felt*) = alloc();
assert [value_pointer] = remainder.low;

tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
words_len=memory_expansion.new_words_len,
);
Memory.store_n(1, value_pointer, offset.low);

return evm;
Expand Down
8 changes: 8 additions & 0 deletions src/kakarot/instructions/sha3.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace Sha3 {
let offset = popped[0];
let size = popped[1];

// GAS
let memory_expansion = Gas.memory_expansion_cost_saturated(memory.words_len, offset, size);
let (words, _) = unsigned_div_rem(size.low + 31, 32);
let words_gas_cost_low = Gas.KECCAK256_WORD * words;
Expand All @@ -44,6 +45,13 @@ namespace Sha3 {
return evm;
}

// OPERATION
tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
words_len=memory_expansion.new_words_len,
);

let (bigendian_data: felt*) = alloc();
Memory.load_n(size.low, bigendian_data, offset.low);

Expand Down
32 changes: 28 additions & 4 deletions src/kakarot/instructions/system_operations.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,27 @@ namespace SystemOperations {
}

// Load bytecode
tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
memory_expansion.new_words_len,
);
let (bytecode: felt*) = alloc();
Memory.load_n(size.low, bytecode, offset.low);

let (return_data) = alloc();

tempvar evm = new model.EVM(
message=evm.message,
return_data_len=0,
return_data=return_data,
program_counter=evm.program_counter,
stopped=evm.stopped,
gas_left=evm.gas_left,
gas_refund=evm.gas_refund,
reverted=evm.reverted,
);

let target_address = CreateHelper.get_evm_address(
evm.message.address.evm, popped_len, popped, size.low, bytecode
);
Expand Down Expand Up @@ -109,10 +127,6 @@ namespace SystemOperations {
let evm = EVM.charge_gas(evm, gas_limit);

// Operation
tempvar memory = new model.Memory(
memory.word_dict_start, memory.word_dict, memory_expansion.new_words_len
);

// Check target account availability
let is_collision = Account.has_code_or_nonce(target_account);
if (is_collision != 0) {
Expand Down Expand Up @@ -240,6 +254,11 @@ namespace SystemOperations {
return evm;
}

tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
memory_expansion.new_words_len,
);
let (local return_data: felt*) = alloc();
Memory.load_n(size.low, return_data, offset.low);

Expand Down Expand Up @@ -279,6 +298,11 @@ namespace SystemOperations {

// Load revert reason from offset
let (return_data: felt*) = alloc();
tempvar memory = new model.Memory(
word_dict_start=memory.word_dict_start,
word_dict=memory.word_dict,
memory_expansion.new_words_len,
);
Memory.load_n(size.low, return_data, offset.low);

let evm = EVM.stop(evm, size.low, return_data, Errors.REVERT);
Expand Down
Loading

0 comments on commit e676a70

Please sign in to comment.