Skip to content

Commit

Permalink
feat(avm): use hints in gas accounting (circuit) (#6895)
Browse files Browse the repository at this point in the history
  • Loading branch information
fcarreiro authored Jun 5, 2024
1 parent 3e44be5 commit c3746f5
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 41 deletions.
64 changes: 49 additions & 15 deletions barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,6 @@ inline void read(uint8_t const*& it, ContractInstanceHint& hint)
}

struct ExecutionHints {
ExecutionHints() = default;
ExecutionHints(std::vector<std::pair<FF, FF>> storage_value_hints,
std::vector<std::pair<FF, FF>> note_hash_exists_hints,
std::vector<std::pair<FF, FF>> nullifier_exists_hints,
std::vector<std::pair<FF, FF>> l1_to_l2_message_exists_hints,
std::vector<ExternalCallHint> externalcall_hints,
std::map<FF, ContractInstanceHint> contract_instance_hints)
: storage_value_hints(std::move(storage_value_hints))
, note_hash_exists_hints(std::move(note_hash_exists_hints))
, nullifier_exists_hints(std::move(nullifier_exists_hints))
, l1_to_l2_message_exists_hints(std::move(l1_to_l2_message_exists_hints))
, externalcall_hints(std::move(externalcall_hints))
, contract_instance_hints(std::move(contract_instance_hints))
{}

std::vector<std::pair<FF, FF>> storage_value_hints;
std::vector<std::pair<FF, FF>> note_hash_exists_hints;
std::vector<std::pair<FF, FF>> nullifier_exists_hints;
Expand All @@ -105,6 +90,40 @@ struct ExecutionHints {
// TODO(dbanks): not read yet.
std::map<FF, ContractInstanceHint> contract_instance_hints;

ExecutionHints() = default;

// Builder.
ExecutionHints& with_storage_value_hints(std::vector<std::pair<FF, FF>> storage_value_hints)
{
this->storage_value_hints = std::move(storage_value_hints);
return *this;
}
ExecutionHints& with_note_hash_exists_hints(std::vector<std::pair<FF, FF>> note_hash_exists_hints)
{
this->note_hash_exists_hints = std::move(note_hash_exists_hints);
return *this;
}
ExecutionHints& with_nullifier_exists_hints(std::vector<std::pair<FF, FF>> nullifier_exists_hints)
{
this->nullifier_exists_hints = std::move(nullifier_exists_hints);
return *this;
}
ExecutionHints& with_l1_to_l2_message_exists_hints(std::vector<std::pair<FF, FF>> l1_to_l2_message_exists_hints)
{
this->l1_to_l2_message_exists_hints = std::move(l1_to_l2_message_exists_hints);
return *this;
}
ExecutionHints& with_externalcall_hints(std::vector<ExternalCallHint> externalcall_hints)
{
this->externalcall_hints = std::move(externalcall_hints);
return *this;
}
ExecutionHints& with_contract_instance_hints(std::map<FF, ContractInstanceHint> contract_instance_hints)
{
this->contract_instance_hints = std::move(contract_instance_hints);
return *this;
}

static void push_vec_into_map(std::unordered_map<uint32_t, FF>& into_map,
const std::vector<std::pair<FF, FF>>& from_pair_vec)
{
Expand Down Expand Up @@ -148,6 +167,21 @@ struct ExecutionHints {
std::move(nullifier_exists_hints), std::move(l1_to_l2_message_exists_hints),
std::move(externalcall_hints), std::move(contract_instance_hints) };
}

private:
ExecutionHints(std::vector<std::pair<FF, FF>> storage_value_hints,
std::vector<std::pair<FF, FF>> note_hash_exists_hints,
std::vector<std::pair<FF, FF>> nullifier_exists_hints,
std::vector<std::pair<FF, FF>> l1_to_l2_message_exists_hints,
std::vector<ExternalCallHint> externalcall_hints,
std::map<FF, ContractInstanceHint> contract_instance_hints)
: storage_value_hints(std::move(storage_value_hints))
, note_hash_exists_hints(std::move(note_hash_exists_hints))
, nullifier_exists_hints(std::move(nullifier_exists_hints))
, l1_to_l2_message_exists_hints(std::move(l1_to_l2_message_exists_hints))
, externalcall_hints(std::move(externalcall_hints))
, contract_instance_hints(std::move(contract_instance_hints))
{}
};

} // namespace bb::avm_trace
19 changes: 13 additions & 6 deletions barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_gas_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,21 @@ void AvmGasTraceBuilder::constrain_gas_lookup(uint32_t clk, OpCode opcode)
gas_trace.push_back(entry);
}

void AvmGasTraceBuilder::constrain_gas_for_external_call(uint32_t clk)
void AvmGasTraceBuilder::constrain_gas_for_external_call(uint32_t clk,
uint32_t nested_l2_gas_cost,
uint32_t nested_da_gas_cost)
{
// Arbitrary constants for the moment
uint32_t l2_gas_cost = 6; // This will be hinted
uint32_t da_gas_cost = 23; // This will be hinted
const OpCode opcode = OpCode::CALL;

remaining_l2_gas -= l2_gas_cost;
remaining_da_gas -= da_gas_cost;
// TODO: increase lookup counter for the opcode we are looking up into
// gas_opcode_lookup_counter[opcode]++;

// Get the gas prices for this opcode
uint32_t opcode_l2_gas_cost = GAS_COST_TABLE.at(opcode).l2_fixed_gas_cost;
uint32_t opcode_da_gas_cost = GAS_COST_TABLE.at(opcode).da_fixed_gas_cost;

remaining_l2_gas -= opcode_l2_gas_cost + nested_l2_gas_cost;
remaining_da_gas -= opcode_da_gas_cost + nested_da_gas_cost;

// Decrease the gas left
// Create a gas trace entry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class AvmGasTraceBuilder {
std::vector<GasTraceEntry> finalize();

void constrain_gas_lookup(uint32_t clk, OpCode opcode);
void constrain_gas_for_external_call(uint32_t clk);
void constrain_gas_for_external_call(uint32_t clk, uint32_t nested_l2_gas_cost, uint32_t nested_da_gas_cost);
void set_initial_gas(uint32_t l2_gas, uint32_t da_gas);

uint32_t get_l2_gas_left();
Expand Down
12 changes: 7 additions & 5 deletions barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ void AvmTraceBuilder::reset()
keccak_trace_builder.reset();
pedersen_trace_builder.reset();

return_data_counter = 0;
external_call_counter = 0;
}

AvmTraceBuilder::IndirectThreeResolution AvmTraceBuilder::resolve_ind_three(
Expand Down Expand Up @@ -2393,10 +2393,12 @@ void AvmTraceBuilder::op_call([[maybe_unused]] uint8_t indirect,
uint32_t function_selector_offset)
{
auto clk = static_cast<uint32_t>(main_trace.size()) + 1;
const ExternalCallHint& hint = execution_hints.externalcall_hints.at(external_call_counter);
// We can load up to 4 things per row
auto register_order = std::array{ IntermRegister::IA, IntermRegister::IB, IntermRegister::IC, IntermRegister::ID };
// Constrain gas cost
gas_trace_builder.constrain_gas_for_external_call(clk);
gas_trace_builder.constrain_gas_for_external_call(
clk, static_cast<uint32_t>(hint.l2_gas_used), static_cast<uint32_t>(hint.da_gas_used));
// Indirect is ZEROTH, SECOND and FOURTH bit COME BACK TO MAKING THIS ALL SUPPORTED
auto read_ind_gas_offset =
mem_trace_builder.indirect_read_and_load_from_memory(call_ptr, clk, IndirectRegister::IND_A, gas_offset);
Expand Down Expand Up @@ -2487,11 +2489,11 @@ void AvmTraceBuilder::op_call([[maybe_unused]] uint8_t indirect,
AvmMemoryTag::U0,
AvmMemoryTag::FF,
internal_return_ptr,
execution_hints.externalcall_hints.at(return_data_counter).return_data);
return_data_counter++;
hint.return_data);
clk++;
write_slice_to_memory(
call_ptr, clk, success_offset, AvmMemoryTag::U0, AvmMemoryTag::U8, internal_return_ptr, { FF(1) });
call_ptr, clk, success_offset, AvmMemoryTag::U0, AvmMemoryTag::U8, internal_return_ptr, { hint.success });
external_call_counter++;
}

void AvmTraceBuilder::op_get_contract_instance(uint8_t indirect, uint32_t address_offset, uint32_t dst_offset)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ class AvmTraceBuilder {
// Side effect counter will incremenent when any state writing values are
// encountered
uint32_t side_effect_counter = 0;
uint32_t return_data_counter = 0;
uint32_t external_call_counter = 0;

// Execution hints aid witness solving for instructions that require auxiliary information to construct
// Mapping of side effect counter -> value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1773,7 +1773,7 @@ TEST_F(AvmExecutionTests, kernelOutputStorageOpcodes)

// Generate Hint for Sload operation
// side effect counter 0 = value 42
ExecutionHints execution_hints({ { 0, 42 } }, {}, {}, {}, {}, {});
auto execution_hints = ExecutionHints().with_storage_value_hints({ { 0, 42 } });

auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec, execution_hints);

Expand Down Expand Up @@ -1854,7 +1854,7 @@ TEST_F(AvmExecutionTests, kernelOutputHashExistsOpcodes)
std::vector<FF> returndata = {};

// Generate Hint for Sload operation
ExecutionHints execution_hints({ { 0, 1 }, { 1, 1 }, { 2, 1 } }, {}, {}, {}, {}, {});
auto execution_hints = ExecutionHints().with_storage_value_hints({ { 0, 1 }, { 1, 1 }, { 2, 1 } });

auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec, execution_hints);

Expand Down Expand Up @@ -1962,9 +1962,8 @@ TEST_F(AvmExecutionTests, opCallOpcodes)
std::vector<FF> returndata = {};

// Generate Hint for call operation
ExecutionHints execution_hints;
execution_hints.externalcall_hints.push_back(
{ .success = 1, .return_data = { 9, 8 }, .l2_gas_used = 0, .da_gas_used = 0 });
auto execution_hints = ExecutionHints().with_externalcall_hints(
{ { .success = 1, .return_data = { 9, 8 }, .l2_gas_used = 0, .da_gas_used = 0 } });

auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec, execution_hints);
EXPECT_EQ(returndata, std::vector<FF>({ 9, 8, 1 })); // The 1 represents the success
Expand Down Expand Up @@ -2001,9 +2000,7 @@ TEST_F(AvmExecutionTests, opGetContractInstanceOpcodes)
std::vector<FF> returndata = {};

// Generate Hint for call operation
ExecutionHints execution_hints = {};
ContractInstanceHint contract_instance_hint = { 1, 1, 2, 3, 4, 5 }; // The first one represents true
execution_hints.contract_instance_hints.insert({ address, contract_instance_hint });
auto execution_hints = ExecutionHints().with_contract_instance_hints({ { address, { 1, 1, 2, 3, 4, 5 } } });

auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec, execution_hints);
EXPECT_EQ(returndata, std::vector<FF>({ 1, 1, 2, 3, 4, 5 })); // The first one represents true
Expand Down
10 changes: 5 additions & 5 deletions barretenberg/cpp/src/barretenberg/vm/tests/avm_kernel.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,7 @@ TEST_F(AvmKernelOutputPositiveTests, kernelSload)
auto slot = 12345;

// Provide a hint for sload value slot
ExecutionHints execution_hints({ { 0, value } }, {}, {}, {}, {}, {});
auto execution_hints = ExecutionHints().with_storage_value_hints({ { 0, value } });

auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) {
trace_builder.op_set(0, static_cast<uint128_t>(slot), slot_offset, AvmMemoryTag::FF);
Expand Down Expand Up @@ -852,7 +852,7 @@ TEST_F(AvmKernelOutputPositiveTests, kernelNoteHashExists)
uint32_t metadata_offset = 420;
auto exists = 1;

ExecutionHints execution_hints({ { 0, exists } }, {}, {}, {}, {}, {});
auto execution_hints = ExecutionHints().with_note_hash_exists_hints({ { 0, exists } });

auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) {
trace_builder.op_set(0, static_cast<uint128_t>(value), value_offset, AvmMemoryTag::FF);
Expand Down Expand Up @@ -890,7 +890,7 @@ TEST_F(AvmKernelOutputPositiveTests, kernelNullifierExists)
uint32_t metadata_offset = 420;
auto exists = 1;

ExecutionHints execution_hints({ { 0, exists } }, {}, {}, {}, {}, {});
auto execution_hints = ExecutionHints().with_nullifier_exists_hints({ { 0, exists } });

auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) {
trace_builder.op_set(0, static_cast<uint128_t>(value), value_offset, AvmMemoryTag::FF);
Expand Down Expand Up @@ -927,7 +927,7 @@ TEST_F(AvmKernelOutputPositiveTests, kernelNullifierNonExists)
uint32_t metadata_offset = 420;
auto exists = 0;

ExecutionHints execution_hints({}, { { 0, exists } }, {}, {}, {}, {});
auto execution_hints = ExecutionHints().with_nullifier_exists_hints({ { 0, exists } });

auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) {
trace_builder.op_set(0, static_cast<uint128_t>(value), value_offset, AvmMemoryTag::FF);
Expand Down Expand Up @@ -965,7 +965,7 @@ TEST_F(AvmKernelOutputPositiveTests, kernelL1ToL2MsgExists)
auto exists = 1;

// Create an execution hints object with the result of the operation
ExecutionHints execution_hints({ { 0, exists } }, {}, {}, {}, {}, {});
auto execution_hints = ExecutionHints().with_l1_to_l2_message_exists_hints({ { 0, exists } });

auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) {
trace_builder.op_set(0, static_cast<uint128_t>(value), value_offset, AvmMemoryTag::FF);
Expand Down

0 comments on commit c3746f5

Please sign in to comment.