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

feat(avm): trace contract class and contract instance #8840

Merged
merged 1 commit into from
Oct 25, 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
12 changes: 5 additions & 7 deletions barretenberg/cpp/src/barretenberg/bb/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -953,18 +953,17 @@ void vk_as_fields(const std::string& vk_path, const std::string& output_path)
* @param hints_path Path to the file containing the serialised avm circuit hints
* @param output_path Path (directory) to write the output proof and verification keys
*/
void avm_prove(const std::filesystem::path& bytecode_path,
const std::filesystem::path& calldata_path,
void avm_prove(const std::filesystem::path& calldata_path,
const std::filesystem::path& public_inputs_path,
const std::filesystem::path& hints_path,
const std::filesystem::path& output_path)
{
std::vector<uint8_t> const bytecode = read_file(bytecode_path);
std::vector<fr> const calldata = many_from_buffer<fr>(read_file(calldata_path));
std::vector<fr> const public_inputs_vec = many_from_buffer<fr>(read_file(public_inputs_path));
auto const avm_hints = bb::avm_trace::ExecutionHints::from(read_file(hints_path));

vinfo("bytecode size: ", bytecode.size());
// Using [0] is fine now for the top-level call, but we might need to index by address in future
vinfo("bytecode size: ", avm_hints.all_contract_bytecode[0].bytecode.size());
vinfo("calldata size: ", calldata.size());
vinfo("public_inputs size: ", public_inputs_vec.size());
vinfo("hints.storage_value_hints size: ", avm_hints.storage_value_hints.size());
Expand All @@ -979,7 +978,7 @@ void avm_prove(const std::filesystem::path& bytecode_path,

// Prove execution and return vk
auto const [verification_key, proof] =
AVM_TRACK_TIME_V("prove/all", avm_trace::Execution::prove(bytecode, calldata, public_inputs_vec, avm_hints));
AVM_TRACK_TIME_V("prove/all", avm_trace::Execution::prove(calldata, public_inputs_vec, avm_hints));

std::vector<fr> vk_as_fields = verification_key.to_field_elements();

Expand Down Expand Up @@ -1526,7 +1525,6 @@ int main(int argc, char* argv[])
write_recursion_inputs_honk<UltraFlavor>(bytecode_path, witness_path, output_path);
#ifndef DISABLE_AZTEC_VM
} else if (command == "avm_prove") {
std::filesystem::path avm_bytecode_path = get_option(args, "--avm-bytecode", "./target/avm_bytecode.bin");
std::filesystem::path avm_calldata_path = get_option(args, "--avm-calldata", "./target/avm_calldata.bin");
std::filesystem::path avm_public_inputs_path =
get_option(args, "--avm-public-inputs", "./target/avm_public_inputs.bin");
Expand All @@ -1535,7 +1533,7 @@ int main(int argc, char* argv[])
std::filesystem::path output_path = get_option(args, "-o", "./proofs");
extern std::filesystem::path avm_dump_trace_path;
avm_dump_trace_path = get_option(args, "--avm-dump-trace", "");
avm_prove(avm_bytecode_path, avm_calldata_path, avm_public_inputs_path, avm_hints_path, output_path);
avm_prove(avm_calldata_path, avm_public_inputs_path, avm_hints_path, output_path);
} else if (command == "avm_verify") {
return avm_verify(proof_path, vk_path) ? 0 : 1;
#endif
Expand Down
114 changes: 68 additions & 46 deletions barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,9 @@ class AvmExecutionTests : public ::testing::Test {
Execution::set_trace_builder_constructor([](VmPublicInputsNT public_inputs,
ExecutionHints execution_hints,
uint32_t side_effect_counter,
std::vector<FF> calldata,
const std::vector<std::vector<uint8_t>>& all_contracts_bytecode) {
return AvmTraceBuilder(std::move(public_inputs),
std::move(execution_hints),
side_effect_counter,
std::move(calldata),
all_contracts_bytecode)
std::vector<FF> calldata) {
return AvmTraceBuilder(
std::move(public_inputs), std::move(execution_hints), side_effect_counter, std::move(calldata))
.set_full_precomputed_tables(false)
.set_range_check_required(false);
});
Expand All @@ -57,7 +53,8 @@ class AvmExecutionTests : public ::testing::Test {
srs::init_crs_factory("../srs_db/ignition");
public_inputs_vec.at(DA_START_GAS_LEFT_PCPI_OFFSET) = DEFAULT_INITIAL_DA_GAS;
public_inputs_vec.at(L2_START_GAS_LEFT_PCPI_OFFSET) = DEFAULT_INITIAL_L2_GAS;
public_inputs = convert_public_inputs(public_inputs_vec);
public_inputs_vec.at(ADDRESS_KERNEL_INPUTS_COL_OFFSET) = 0xdeadbeef;
public_inputs = avm_trace::convert_public_inputs(public_inputs_vec);
};

/**
Expand All @@ -71,7 +68,21 @@ class AvmExecutionTests : public ::testing::Test {
std::vector<FF> calldata{};
std::vector<FF> returndata{};

return Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints());
auto execution_hints = ExecutionHints().with_avm_contract_bytecode({ bytecode });
execution_hints.all_contract_bytecode[0].contract_instance.address = 0xdeadbeef;

return AvmExecutionTests::gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);
}

std::vector<Row> gen_trace(std::vector<uint8_t> bytecode,
std::vector<FF> const& calldata,
std::vector<FF> const& public_inputs_vec,
std::vector<FF>& returndata,
ExecutionHints& execution_hints) const
{
execution_hints.all_contract_bytecode = { bytecode };
execution_hints.all_contract_bytecode[0].contract_instance.address = 0xdeadbeef;
return Execution::gen_trace(calldata, public_inputs_vec, returndata, execution_hints);
}

void feed_output(uint32_t output_offset, FF const& value, FF const& side_effect_counter, FF const& metadata)
Expand Down Expand Up @@ -474,8 +485,8 @@ TEST_F(AvmExecutionTests, jumpAndCalldatacopy)
Field(&Instruction::operands, ElementsAre(VariantWith<uint16_t>(5)))));

std::vector<FF> returndata;
auto trace =
Execution::gen_trace(bytecode, std::vector<FF>{ 13, 156 }, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace = gen_trace(bytecode, std::vector<FF>{ 13, 156 }, public_inputs_vec, returndata, execution_hints);

// Expected sequence of PCs during execution
std::vector<FF> pc_sequence{
Expand Down Expand Up @@ -564,10 +575,9 @@ TEST_F(AvmExecutionTests, jumpiAndCalldatacopy)
ElementsAre(VariantWith<uint8_t>(0), VariantWith<uint16_t>(6), VariantWith<uint16_t>(10)))));

std::vector<FF> returndata;
auto trace_jump =
Execution::gen_trace(bytecode, std::vector<FF>{ 9873123 }, public_inputs_vec, returndata, ExecutionHints());
auto trace_no_jump =
Execution::gen_trace(bytecode, std::vector<FF>{ 0 }, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace_jump = gen_trace(bytecode, std::vector<FF>{ 9873123 }, public_inputs_vec, returndata, execution_hints);
auto trace_no_jump = gen_trace(bytecode, std::vector<FF>{ 0 }, public_inputs_vec, returndata, execution_hints);

// Expected sequence of PCs during execution with jump
std::vector<FF> pc_sequence_jump{ 0, 1, 2, 3, 4, 6, 7 };
Expand Down Expand Up @@ -774,8 +784,9 @@ TEST_F(AvmExecutionTests, toRadixLeOpcode)

// Assign a vector that we will mutate internally in gen_trace to store the return values;
std::vector<FF> returndata;
auto trace = Execution::gen_trace(
bytecode, std::vector<FF>{ FF::modulus - FF(1) }, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace =
gen_trace(bytecode, std::vector<FF>{ FF::modulus - FF(1) }, public_inputs_vec, returndata, execution_hints);

// Find the first row enabling the TORADIXLE selector
// Expected output is bitwise decomposition of MODULUS - 1..could hardcode the result but it's a bit long
Expand Down Expand Up @@ -840,8 +851,9 @@ TEST_F(AvmExecutionTests, toRadixLeOpcodeBitsMode)

// Assign a vector that we will mutate internally in gen_trace to store the return values;
std::vector<FF> returndata;
auto trace = Execution::gen_trace(
bytecode, std::vector<FF>{ FF::modulus - FF(1) }, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace =
gen_trace(bytecode, std::vector<FF>{ FF::modulus - FF(1) }, public_inputs_vec, returndata, execution_hints);

// Find the first row enabling the TORADIXLE selector
// Expected output is bitwise decomposition of MODULUS - 1..could hardcode the result but it's a bit long
Expand Down Expand Up @@ -915,7 +927,8 @@ TEST_F(AvmExecutionTests, sha256CompressionOpcode)
// 4091010797,3974542186]),
std::vector<FF> expected_output = { 1862536192, 526086805, 2067405084, 593147560,
726610467, 813867028, 4091010797ULL, 3974542186ULL };
auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace = gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);

EXPECT_EQ(returndata, expected_output);

Expand Down Expand Up @@ -976,7 +989,8 @@ TEST_F(AvmExecutionTests, poseidon2PermutationOpCode)
FF(std::string("0x018555a8eb50cf07f64b019ebaf3af3c925c93e631f3ecd455db07bbb52bbdd3")),
FF(std::string("0x0cbea457c91c22c6c31fd89afd2541efc2edf31736b9f721e823b2165c90fd41"))
};
auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace = gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);

EXPECT_EQ(returndata, expected_output);

Expand Down Expand Up @@ -1043,7 +1057,8 @@ TEST_F(AvmExecutionTests, keccakf1600OpCode)
// Assign a vector that we will mutate internally in gen_trace to store the return values;
std::vector<FF> calldata = std::vector<FF>();
std::vector<FF> returndata = std::vector<FF>();
auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace = gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);

EXPECT_EQ(returndata, expected_output);

Expand Down Expand Up @@ -1110,7 +1125,8 @@ TEST_F(AvmExecutionTests, embeddedCurveAddOpCode)
// Assign a vector that we will mutate internally in gen_trace to store the return values;
std::vector<FF> returndata;
std::vector<FF> calldata = { a.x, a.y, FF(a_is_inf ? 1 : 0), b.x, b.y, FF(b_is_inf ? 1 : 0) };
auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace = gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);

EXPECT_EQ(returndata, expected_output);

Expand Down Expand Up @@ -1197,7 +1213,8 @@ TEST_F(AvmExecutionTests, msmOpCode)

// Assign a vector that we will mutate internally in gen_trace to store the return values;
std::vector<FF> returndata;
auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace = gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);

EXPECT_EQ(returndata, expected_output);

Expand Down Expand Up @@ -1355,16 +1372,16 @@ TEST_F(AvmExecutionTests, kernelInputOpcodes)
std::vector<FF> calldata;

FF sender = 1;
FF address = 2;
FF function_selector = 3;
FF transaction_fee = 4;
FF chainid = 5;
FF version = 6;
FF blocknumber = 7;
FF timestamp = 8;
FF feeperl2gas = 9;
FF feeperdagas = 10;
FF is_static_call = 11;
FF address = 0xdeadbeef;
FF function_selector = 4;
FF transaction_fee = 5;
FF chainid = 6;
FF version = 7;
FF blocknumber = 8;
FF timestamp = 9;
FF feeperl2gas = 10;
FF feeperdagas = 11;
FF is_static_call = 12;

// The return data for this test should be a the opcodes in sequence, as the opcodes dst address lines up with
// this array The returndata call above will then return this array
Expand Down Expand Up @@ -1393,7 +1410,8 @@ TEST_F(AvmExecutionTests, kernelInputOpcodes)
public_inputs_vec[FEE_PER_L2_GAS_PCPI_OFFSET] = feeperl2gas;

std::vector<FF> returndata;
auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace = gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);

// Validate returndata
EXPECT_EQ(returndata, expected_returndata);
Expand Down Expand Up @@ -1559,7 +1577,8 @@ TEST_F(AvmExecutionTests, ExecutorThrowsWithTooMuchGasAllocated)
auto bytecode = hex_to_bytes(bytecode_hex);
auto instructions = Deserialization::parse(bytecode);

EXPECT_THROW_WITH_MESSAGE(Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints()),
ExecutionHints execution_hints;
EXPECT_THROW_WITH_MESSAGE(gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints),
"Cannot allocate more than MAX_L2_GAS_PER_ENQUEUED_CALL to the AVM for "
"execution of an enqueued call");
}
Expand All @@ -1578,7 +1597,8 @@ TEST_F(AvmExecutionTests, ExecutorThrowsWithIncorrectNumberOfPublicInputs)
auto bytecode = hex_to_bytes(bytecode_hex);
auto instructions = Deserialization::parse(bytecode);

EXPECT_THROW_WITH_MESSAGE(Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints()),
ExecutionHints execution_hints;
EXPECT_THROW_WITH_MESSAGE(gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints),
"Public inputs vector is not of PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH");
}

Expand Down Expand Up @@ -1621,7 +1641,8 @@ TEST_F(AvmExecutionTests, kernelOutputEmitOpcodes)

std::vector<FF> calldata = {};
std::vector<FF> returndata = {};
auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace = gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);

// CHECK EMIT NOTE HASH
// Check output data + side effect counters have been set correctly
Expand Down Expand Up @@ -1656,7 +1677,7 @@ TEST_F(AvmExecutionTests, kernelOutputEmitOpcodes)
auto emit_log_row =
std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_emit_unencrypted_log == 1; });
// Trust me bro for now, this is the truncated sha output
FF expected_hash = FF(std::string("0x006db65fd59fd356f6729140571b5bcd6bb3b83492a16e1bf0a3884442fc3c8a"));
FF expected_hash = FF(std::string("0x003383cbb254941b33c0aaf8476c4b9b532d70a2fb105ee908dd332f7d942df6"));
EXPECT_EQ(emit_log_row->main_ia, expected_hash);
EXPECT_EQ(emit_log_row->main_side_effect_counter, 2);
// Value is 40 = 32 * log_length + 40 (and log_length is 0 in this case).
Expand Down Expand Up @@ -1722,7 +1743,7 @@ TEST_F(AvmExecutionTests, kernelOutputStorageLoadOpcodeSimple)
// side effect counter 0 = value 42
auto execution_hints = ExecutionHints().with_storage_value_hints({ { 0, 42 } });

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

// CHECK SLOAD
// Check output data + side effect counters have been set correctly
Expand Down Expand Up @@ -1776,7 +1797,8 @@ TEST_F(AvmExecutionTests, kernelOutputStorageStoreOpcodeSimple)

std::vector<FF> returndata;

auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, ExecutionHints());
ExecutionHints execution_hints;
auto trace = gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);
// CHECK SSTORE
auto sstore_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_sstore == 1; });
EXPECT_EQ(sstore_row->main_ia, 42); // Read value
Expand Down Expand Up @@ -1839,7 +1861,7 @@ TEST_F(AvmExecutionTests, kernelOutputStorageOpcodes)
// side effect counter 0 = value 42
auto execution_hints = ExecutionHints().with_storage_value_hints({ { 0, 42 } });

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

// CHECK SLOAD
// Check output data + side effect counters have been set correctly
Expand Down Expand Up @@ -1922,7 +1944,7 @@ TEST_F(AvmExecutionTests, kernelOutputHashExistsOpcodes)
.with_storage_value_hints({ { 0, 1 }, { 1, 1 }, { 2, 1 } })
.with_note_hash_exists_hints({ { 0, 1 }, { 1, 1 }, { 2, 1 } });

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

// CHECK NOTEHASHEXISTS
auto note_hash_row =
Expand Down Expand Up @@ -2056,10 +2078,10 @@ TEST_F(AvmExecutionTests, opCallOpcodes)
.l2_gas_used = 0,
.da_gas_used = 0,
.end_side_effect_counter = 0,
.bytecode = {},
.contract_address = 0,
} });

auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);
auto trace = gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);
EXPECT_EQ(returndata, std::vector<FF>({ 9, 8, 1 })); // The 1 represents the success

validate_trace(std::move(trace), public_inputs, calldata, returndata);
Expand Down Expand Up @@ -2116,7 +2138,7 @@ TEST_F(AvmExecutionTests, opGetContractInstanceOpcodes)
auto execution_hints =
ExecutionHints().with_contract_instance_hints({ { address, { address, 1, 2, 3, 4, 5, public_keys_hints } } });

auto trace = Execution::gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);
auto trace = gen_trace(bytecode, calldata, public_inputs_vec, returndata, execution_hints);
EXPECT_EQ(returndata, std::vector<FF>({ 1, 2, 3, 4, 5, returned_point.x })); // The first one represents true

validate_trace(std::move(trace), public_inputs, calldata, returndata);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace bb::avm_trace {
using poseidon2 = crypto::Poseidon2<crypto::Poseidon2Bn254ScalarFieldParams>;
AvmBytecodeTraceBuilder::AvmBytecodeTraceBuilder(const std::vector<std::vector<uint8_t>>& all_contracts_bytecode)
AvmBytecodeTraceBuilder::AvmBytecodeTraceBuilder(const std::vector<AvmContractBytecode>& all_contracts_bytecode)
: all_contracts_bytecode(all_contracts_bytecode)
{}

Expand All @@ -31,7 +31,7 @@ void AvmBytecodeTraceBuilder::build_bytecode_columns()
// This is the main loop that will generate the bytecode trace
for (auto& contract_bytecode : all_contracts_bytecode) {
FF running_hash = FF::zero();
auto packed_bytecode = pack_bytecode(contract_bytecode);
auto packed_bytecode = pack_bytecode(contract_bytecode.bytecode);
// This size is already based on the number of fields
for (size_t i = 0; i < packed_bytecode.size(); ++i) {
bytecode_trace.push_back(BytecodeTraceEntry{
Expand Down
Loading
Loading