Skip to content

460 state circuit #483

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

Merged
merged 1 commit into from
Jun 25, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,6 @@ namespace nil {
}
}

if (verbose) {
BOOST_LOG_TRIVIAL(info) << " ";
}

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ namespace nil::blueprint::bbf::zkevm_big_field{
opcode_impls[current_opcode]->rows_amount();
std::size_t current_opcode_rows_amount = std::ceil(float(current_opcode_bare_rows_amount)/2) * 2;
BOOST_ASSERT(current_opcode_rows_amount <= max_opcode_height);

TYPE o4 = opcode_selectors[1][opcode_num/4];
TYPE parity = opcode_num%2 ? all_states[1].opcode_parity: 1 - all_states[1].opcode_parity;
TYPE is_even = all_states[1].is_even;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -675,9 +675,15 @@ namespace nil {
}

virtual void mstore(){
std::size_t offset = std::size_t(stack.back()); stack.pop_back();
auto full_offset = stack.back(); stack.pop_back();
auto value = stack.back(); stack.pop_back();
if( full_offset > (1 << 25) - 32 ) {
decrease_gas(gas+1);
pc++;
return;
}

std::size_t offset = std::size_t(full_offset);
std::size_t new_mem_size = std::max(offset + 32, memory.size());
std::size_t memory_expansion = memory_expansion_cost(new_mem_size, memory.size());

Expand All @@ -694,14 +700,20 @@ namespace nil {
}

virtual void mstore8(){
std::size_t offset = std::size_t(stack.back()); stack.pop_back();
auto full_offset = stack.back(); stack.pop_back();
auto value = stack.back(); stack.pop_back();
if( full_offset > (1 << 25) - 1 ) {
decrease_gas(gas+1);
pc++;
return;
}

std::size_t offset = std::size_t(full_offset);
std::size_t memory_size_word = (memory.size() + 31) / 32;
std::size_t last_memory_cost = memory_size_word * memory_size_word / 512 + (3*memory_size_word);

if( memory.size() < offset + 1) memory.resize(offset + 1);
memory[offset] = std::uint8_t(std::size_t(value % 256));
memory[offset] = std::uint8_t(std::size_t(value % 256));

memory_size_word = (memory.size() + 31) / 32;
std::size_t new_memory_cost = memory_size_word * memory_size_word / 512 + (3*memory_size_word);
Expand Down Expand Up @@ -1542,21 +1554,38 @@ namespace nil {
}

virtual void codecopy() {
// 6M memory bytes gives 60M+ gas cost
// max gas cost is 36M for now, might go up to 60M
constexpr static const std::size_t max_dest_offset = 8388608; // 2^23
// max contract size is 24,576 bytes, so offset and length need to fit in
// first chunk
constexpr static const std::size_t max_offset = 65536;
constexpr static const std::size_t max_length = 65536;
std::size_t dst = std::size_t(stack.back()); stack.pop_back();
std::size_t src = std::size_t(stack.back()); stack.pop_back();
std::size_t length = std::size_t(stack.back()); stack.pop_back();

bool overflow = (dst > max_dest_offset) ||
(src > max_offset) ||
(length > max_length);

std::size_t minimum_word_size = (length + 31) / 32;
std::size_t next_mem = std::max(dst + length, memory.size());
std::size_t memory_expansion = memory_expansion_cost(next_mem, memory.size());
std::size_t next_memory_size = (memory_size_word_util(next_mem))*32;
std::size_t next_memory_size = memory_size_word_util(next_mem) * 32;

if( memory.size() < dst + length) memory.resize(dst + length, 0);
for( std::size_t i = 0; i < length; i++){
memory[dst+i] = src + i < bytecode.size()? bytecode[src+i]: 0;
}

decrease_gas(3 + 3 * minimum_word_size + memory_expansion); //dynamic gas
if (overflow) {
memory.resize(memory.size() - 1);
increase_gas(1);
}
else {
if( memory.size() < dst + length) memory.resize(next_memory_size);
for( std::size_t i = 0; i < length; i++){
memory[dst+i] = src + i < bytecode.size()? bytecode[src+i]: 0;
}
decrease_gas(3 + 3 * minimum_word_size + memory_expansion); //dynamic gas
}
pc++;
}

Expand Down Expand Up @@ -1788,6 +1817,7 @@ namespace nil {
}

virtual void end_transaction(){
BOOST_LOG_TRIVIAL(trace) << "basic_evm::End transaction" << std::endl;
auto returned_call = _call_stack.back();
_call_stack.pop_back();
depth--;
Expand All @@ -1807,6 +1837,7 @@ namespace nil {
}

virtual void end_block(){
BOOST_LOG_TRIVIAL(trace) << "basic_evm::End block" << std::endl;
depth--;
pc = 0;
gas = 0;
Expand Down Expand Up @@ -1869,6 +1900,10 @@ namespace nil {
}
}

void increase_gas(std::size_t cost) {
gas += cost;
}

// Should be called *after* memory expansion, address access
// and transfer fees are deducted.
size_t cap_call_gas(zkevm_word_type gas_sent) {
Expand Down Expand Up @@ -1897,4 +1932,3 @@ namespace nil {
} // namespace bbf
} // namespace blueprint
} // namespace nil

Original file line number Diff line number Diff line change
Expand Up @@ -515,35 +515,41 @@ namespace nil {
}

virtual void mstore() override{
std::size_t offset = std::size_t(stack.back());

zkevm_word_type full_offset = stack.back();
_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::mstore();
for( std::size_t i = 0; i < 32; i++){
_short_rw_operations.push_back(memory_rw_operation(
call_id,
offset + i,
rw_counter++,
true,
memory[offset + i]
));

if( full_offset < (1 << 25) - 31 ){
std::size_t offset = std::size_t(full_offset);
for( std::size_t i = 0; i < 32; i++){
_short_rw_operations.push_back(memory_rw_operation(
call_id,
offset + i,
rw_counter++,
true,
memory[offset + i]
));
}
}
}

virtual void mstore8() override{
std::size_t offset = std::size_t(stack.back());

zkevm_word_type full_offset = stack.back();
_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::mstore8();
_short_rw_operations.push_back(memory_rw_operation(
call_id,
offset,
rw_counter++,
true,
memory[offset]
));

if( full_offset < (1 << 25) ){
std::size_t offset = std::size_t(full_offset);
_short_rw_operations.push_back(memory_rw_operation(
call_id,
offset,
rw_counter++,
true,
memory[offset]
));
}
}

virtual void tload() override{
Expand Down Expand Up @@ -788,103 +794,91 @@ namespace nil {
}

virtual void shr() override{

_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::shr();
append_stack_writes(1);
}

virtual void shl() override{

_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::shl();
append_stack_writes(1);
}

virtual void sar() override{

_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::sar();
append_stack_writes(1);
}

virtual void lt() override{

_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::lt();
append_stack_writes(1);
}

virtual void gt() override{

_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::gt();
append_stack_writes(1);
}

virtual void slt() override{

_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::slt();
append_stack_writes(1);
}

virtual void sgt() override{

_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::sgt();
append_stack_writes(1);
}

virtual void byte() override{

_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::byte();
append_stack_writes(1);
}

virtual void signextend() override{

_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::signextend();
append_stack_writes(1);
}

virtual void jump() override{

_zkevm_states.back().load_stack(stack,1);
append_stack_reads(1);
zkevm_basic_evm::jump();
}

virtual void jumpi() override{

_zkevm_states.back().load_stack(stack,2);
append_stack_reads(2);
zkevm_basic_evm::jumpi();
}

virtual void jumpdest() override{

zkevm_basic_evm::jumpdest();
}

virtual void pc_opcode() override{

zkevm_basic_evm::pc_opcode();
append_stack_writes(1);
}

virtual void gas_error() override{
BOOST_LOG_TRIVIAL(trace) << "Gas error";
_short_rw_operations.push_back(call_context_header_operation(
call_id,
call_context_field::call_status,
Expand Down Expand Up @@ -1008,21 +1002,23 @@ namespace nil {
append_stack_reads(3);

zkevm_basic_evm::codecopy();
copy_event cpy = codecopy_copy_event(
bytecode_hash,
src,
call_id,
dst,
rw_counter,
length
);
for( std::size_t i = 0; i < length; i++){
_short_rw_operations.push_back(memory_rw_operation(
call_id, dst + i, rw_counter++, true, memory[dst + i]
));
cpy.push_byte(memory[dst+i]);
if (memory.size() % 32 == 0) {
copy_event cpy = codecopy_copy_event(
bytecode_hash,
src,
call_id,
dst,
rw_counter,
length
);
for( std::size_t i = 0; i < length; i++){
_short_rw_operations.push_back(memory_rw_operation(
call_id, dst + i, rw_counter++, true, memory[dst + i]
));
cpy.push_byte(memory[dst+i]);
}
if( length > 0 ) _copy_events.push_back(cpy);
}
if( length > 0 ) _copy_events.push_back(cpy);
}

virtual void dupx( std::size_t d) override {
Expand Down Expand Up @@ -1319,6 +1315,7 @@ namespace nil {
}

virtual void end_transaction() override{
BOOST_LOG_TRIVIAL(trace) << "End transaction";
after_call_last_state_operation_update();
zkevm_basic_evm::end_transaction();
_short_rw_operations.push_back(call_context_header_operation(
Expand All @@ -1339,6 +1336,7 @@ namespace nil {
}

virtual void end_block() override{
BOOST_LOG_TRIVIAL(trace) << "End block";
zkevm_basic_evm::end_block();
_zkevm_states.push_back(zkevm_state(
call_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ namespace nil {

// This is a class that bytecodes as a sequence of bytes.
// It emulates contract if we don't want to compile contract from the solidity code e t.c.

class zkevm_opcode_tester{
public:
zkevm_opcode_tester(){}
Expand Down Expand Up @@ -83,6 +84,22 @@ namespace nil {
}
}

void push_metadata(const std::vector<std::uint8_t> &metadata) {
BOOST_LOG_TRIVIAL(trace) << "Adding metadata of size " << metadata.size() << " bytes" << std::endl;

// Add metadata bytes to bytecode
bytecode.insert(bytecode.end(), metadata.begin(), metadata.end());

// Add metadata length as last 2 bytes (big-endian format)
// Assuming metadata.size() fits in 16 bits (max 65535 bytes)
BOOST_ASSERT(metadata.size() <= 0xFFFF);

std::uint16_t metadata_length = static_cast<std::uint16_t>(metadata.size());
bytecode.push_back(static_cast<std::uint8_t>((metadata_length >> 8) & 0xFF)); // High byte
bytecode.push_back(static_cast<std::uint8_t>(metadata_length & 0xFF)); // Low byte

BOOST_LOG_TRIVIAL(trace) << "Metadata added. Total bytecode size: " << bytecode.size() << std::endl;
}
const std::vector<std::uint8_t> &get_bytecode() const {
return bytecode;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ namespace nil {
block.timestamp = atoi(bt.get_child("block.timestamp").data().c_str());
block.parent_hash = zkevm_word_from_string(bt.get_child("block.parentHash").data());

BOOST_LOG_TRIVIAL(trace) << "ZKEVM HARDHAT INPUT GENERATOR loaded" << std::endl;
BOOST_LOG_TRIVIAL(trace) << "ZKEVM DEBUGTT INPUT GENERATOR loaded" << std::endl;
// 1. Load eth_accounts. Not good that we have only one initial state for all blocks
for( auto &account: bt.get_child("eth_accounts")){
BOOST_LOG_TRIVIAL(trace) << "Account " << account.first.data() << std::endl;
Expand Down
Loading