diff --git a/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_data.cpp b/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_data.cpp index 2ded216ba3e0..71ec8b4dea49 100644 --- a/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_data.cpp +++ b/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_data.cpp @@ -1,16 +1,60 @@ #include "barretenberg/avm_fuzzer/mutations/tx_data.hpp" + #include "barretenberg/avm_fuzzer/fuzz_lib/constants.hpp" #include "barretenberg/avm_fuzzer/mutations/basic_types/field.hpp" #include "barretenberg/avm_fuzzer/mutations/basic_types/vector.hpp" #include "barretenberg/avm_fuzzer/mutations/fuzzer_data.hpp" #include "barretenberg/avm_fuzzer/mutations/instructions/instruction_block.hpp" +#include "barretenberg/avm_fuzzer/mutations/tx_types/public_call_request.hpp" +#include "barretenberg/vm2/common/avm_io.hpp" #include "barretenberg/vm2/common/aztec_constants.hpp" #include "barretenberg/vm2/common/aztec_types.hpp" #include "barretenberg/vm2/common/tagged_value.hpp" #include "barretenberg/vm2/simulation/lib/contract_crypto.hpp" +#include #include +namespace { + +void mutate_enqueued_calls(std::vector& enqueued_calls, + std::vector& contract_addresses, + std::mt19937_64& rng) +{ + auto mutate_fn = [&](PublicCallRequestWithCalldata& call, std::mt19937_64& rng) { + bb::avm2::fuzzer::mutate_public_call_request(call, contract_addresses, rng); + }; + + auto gen_fn = [&](std::mt19937_64& rng) { + return bb::avm2::fuzzer::generate_public_call_request(contract_addresses, rng); + }; + + mutate_vec(enqueued_calls, rng, mutate_fn, gen_fn, BASIC_VEC_MUTATION_CONFIGURATION); +}; + +void mutate_teardown(std::optional& teardown_call, + std::vector& contract_addresses, + std::mt19937_64& rng) +{ + if (!teardown_call.has_value()) { + // Nothing to mutate, generate a new one + teardown_call = bb::avm2::fuzzer::generate_public_call_request(contract_addresses, rng); + return; + } + + // If we already have a teardown call, there's a 1 in 10 chance we discard it + bool discard = std::uniform_int_distribution(0, 9)(rng) == 0; + if (discard) { + fuzz_info("Discarding teardown enqueued call"); + teardown_call = std::nullopt; + } else { + // Mutate existing teardown call + bb::avm2::fuzzer::mutate_public_call_request(teardown_call.value(), contract_addresses, rng); + } +} + +} // namespace + namespace bb::avm2::fuzzer { // Gas bounds for mutation @@ -29,32 +73,25 @@ constexpr uint32_t AVM_MAX_PROCESSABLE_DA_GAS = (MAX_NOTE_HASHES_PER_TX * AVM_EM void mutate_tx(Tx& tx, std::vector& contract_addresses, std::mt19937_64& rng) { - auto choice = std::uniform_int_distribution(0, 1)(rng); + auto choice = TX_MUTATION_CONFIGURATION.select(rng); switch (choice) { - case 0: + case TxMutationOptions::SetupEnqueuedCalls: // Mutate setup enqueued calls fuzz_info("Mutating setup enqueued calls: ", tx.setup_enqueued_calls.size()); - mutate_vec( - tx.setup_enqueued_calls, - rng, - [&](PublicCallRequestWithCalldata& call, std::mt19937_64& rng) { - mutate_public_call_request(call, contract_addresses, rng); - }, - [&](std::mt19937_64& rng) { return generate_public_call_request(contract_addresses, rng); }, - BASIC_VEC_MUTATION_CONFIGURATION); + mutate_enqueued_calls(tx.setup_enqueued_calls, contract_addresses, rng); break; - case 1: + case TxMutationOptions::AppLogicEnqueuedCalls: // Mutate app logic enqueued calls fuzz_info("Mutating app logic enqueued calls: ", tx.app_logic_enqueued_calls.size()); - mutate_vec( - tx.app_logic_enqueued_calls, - rng, - [&](PublicCallRequestWithCalldata& call, std::mt19937_64& rng) { - mutate_public_call_request(call, contract_addresses, rng); - }, - [&](std::mt19937_64& rng) { return generate_public_call_request(contract_addresses, rng); }, - BASIC_VEC_MUTATION_CONFIGURATION); + mutate_enqueued_calls(tx.app_logic_enqueued_calls, contract_addresses, rng); + break; + case TxMutationOptions::TearDownEnqueuedCall: + // Mutate teardown enqueued call + fuzz_info("Mutating teardown enqueued call"); + mutate_teardown(tx.teardown_enqueued_call, contract_addresses, rng); + break; + // case 2: // // Mutate gas_settings // mutate_gas_settings(tx.gas_settings, rng); @@ -92,10 +129,6 @@ void mutate_tx(Tx& tx, std::vector& contract_addresses, std::mt199 // BASIC_VEC_MUTATION_CONFIGURATION); // break; // break; - // case 7: - // // Mutate teardown enqueued call - // - // break; // case 8: // // Mutate gas_used_by_private // break; @@ -180,20 +213,6 @@ void mutate_gas_fees(GasFees& fees, std::mt19937_64& rng) } } -void mutate_ff_vec(std::vector& vec, std::mt19937_64& rng, size_t max_size) -{ - mutate_vec( - vec, - rng, - [](bb::avm2::FF& value, std::mt19937_64& rng) { mutate_field(value, rng, BASIC_FIELD_MUTATION_CONFIGURATION); }, - generate_random_field, - BASIC_VEC_MUTATION_CONFIGURATION); - - if (vec.size() > max_size) { - vec.resize(max_size); - } -} - void mutate_l2_to_l1_msg(ScopedL2ToL1Message& msg, std::mt19937_64& rng) { auto choice = std::uniform_int_distribution(0, 2)(rng); @@ -222,26 +241,6 @@ ScopedL2ToL1Message generate_l2_to_l1_msg(std::mt19937_64& rng) }; } -void mutate_bool_vec(std::vector& vec, size_t target_size, std::mt19937_64& rng) -{ - // Resize to match target size - while (vec.size() < target_size) { - vec.push_back(std::uniform_int_distribution(0, 1)(rng) == 1); - } - while (vec.size() > target_size) { - vec.pop_back(); - } - - // Flip a random bool with some probability - if (!vec.empty()) { - auto flip_prob = std::uniform_int_distribution(0, 4)(rng); - if (flip_prob == 0) { - auto idx = std::uniform_int_distribution(0, vec.size() - 1)(rng); - vec[idx] = !vec[idx]; - } - } -} - void mutate_fuzzer_data_vec(std::vector& enqueued_calls, std::mt19937_64& rng, size_t max_size) { auto choice = std::uniform_int_distribution(0, 1)(rng); @@ -278,73 +277,4 @@ void mutate_fuzzer_data_vec(std::vector& enqueued_calls, std::mt1993 } } -void mutate_public_call_request([[maybe_unused]] PublicCallRequestWithCalldata& request, - [[maybe_unused]] std::vector& contract_addresses, - [[maybe_unused]] std::mt19937_64& rng) -{ - if (contract_addresses.empty()) { - return; // Nothing to mutate to - } - // fixme(ilyas): this should be weighted since stuff like mutate calldata hash is fail-early - auto choice = std::uniform_int_distribution(0, 0)(rng); - // - switch (choice) { - case 0: - // Mutate contract_address - // This is likely to cause immediate failure, needs to be weighted appropriately - auto contract_address_choice = std::uniform_int_distribution(0, contract_addresses.size() - 1)(rng); - auto contract_address = contract_addresses[contract_address_choice]; - request.request.contract_address = contract_address; - break; - // case 1: - // // Mutate msg_sender - // request.request.msg_sender = generate_random_field(rng); - // break; - // case 2: { - // // Mutate is_static_call - // request.request.is_static_call = !request.request.is_static_call; - // break; - // } - // case 3: - // // Mutate calldata_hash - the intention here is to fail the hash check - // request.request.calldata_hash = generate_random_field(rng); - // break; - // case 4: - // // Mutate calldata - // mutate_ff_vec(request.calldata, rng, 256); - // // fixme: recompute calldata_hash when we start doing tracegen versions - // // request.calldata_hash = compute_calldata_hash(request.calldata); - // break; - } -} - -PublicCallRequestWithCalldata generate_public_call_request(std::vector& contract_addresses, - std::mt19937_64& rng) -{ - fuzz_info("Generating new public call request"); - // Generate random calldata - size_t calldata_size = std::uniform_int_distribution(0, 256)(rng); - std::vector calldata{}; - for (size_t i = 0; i < calldata_size; ++i) { - calldata.push_back(generate_random_field(rng)); - } - - auto contract_address = - contract_addresses.empty() - ? generate_random_field(rng) - : contract_addresses[std::uniform_int_distribution(0, contract_addresses.size() - 1)(rng)]; - fuzz_info("Using contract address: ", contract_address); - FF calldata_hash = simulation::compute_calldata_hash(calldata); - return PublicCallRequestWithCalldata{ - .request = - PublicCallRequest{ - .msg_sender = generate_random_field(rng), - .contract_address = contract_address, - .is_static_call = (std::uniform_int_distribution(0, 1)(rng) == 1), - .calldata_hash = calldata_hash, - }, - .calldata = calldata, - }; -} - } // namespace bb::avm2::fuzzer diff --git a/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_data.hpp b/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_data.hpp index 958b336a1bce..ab7f6f37bf30 100644 --- a/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_data.hpp +++ b/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_data.hpp @@ -1,14 +1,26 @@ #pragma once -#include -#include #include #include +#include "barretenberg/avm_fuzzer/common/weighted_selection.hpp" #include "barretenberg/avm_fuzzer/fuzz_lib/fuzzer_data.hpp" #include "barretenberg/vm2/common/avm_io.hpp" #include "barretenberg/vm2/common/aztec_types.hpp" -#include "barretenberg/vm2/common/field.hpp" + +enum class TxMutationOptions { + SetupEnqueuedCalls, + AppLogicEnqueuedCalls, + TearDownEnqueuedCall, +}; + +using TxMutationConfig = WeightedSelectionConfig; + +constexpr TxMutationConfig TX_MUTATION_CONFIGURATION = TxMutationConfig({ + { TxMutationOptions::SetupEnqueuedCalls, 30 }, + { TxMutationOptions::AppLogicEnqueuedCalls, 30 }, + { TxMutationOptions::TearDownEnqueuedCall, 10 }, +}); namespace bb::avm2::fuzzer { @@ -23,22 +35,10 @@ void mutate_gas(Gas& gas, std::mt19937_64& rng); // GasFees mutation void mutate_gas_fees(GasFees& fees, std::mt19937_64& rng); -// Field vector mutation -void mutate_ff_vec(std::vector& vec, std::mt19937_64& rng, size_t max_size = 10); - // L2ToL1Msg vector mutation void mutate_l2_to_l1_msg(ScopedL2ToL1Message& vec, std::mt19937_64& rng); ScopedL2ToL1Message generate_l2_to_l1_msg(std::mt19937_64& rng); -// Boolean vector mutation -void mutate_bool_vec(std::vector& vec, size_t target_size, std::mt19937_64& rng); - void mutate_fuzzer_data_vec(std::vector& enqueued_calls, std::mt19937_64& rng, size_t max_size = 10); -void mutate_public_call_request(PublicCallRequestWithCalldata& request, - std::vector& contract_addreses, - std::mt19937_64& rng); -PublicCallRequestWithCalldata generate_public_call_request(std::vector& contract_addresses, - std::mt19937_64& rng); - } // namespace bb::avm2::fuzzer diff --git a/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_types/public_call_request.cpp b/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_types/public_call_request.cpp new file mode 100644 index 000000000000..f88b7062b126 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_types/public_call_request.cpp @@ -0,0 +1,105 @@ +#include "barretenberg/avm_fuzzer/mutations/tx_types/public_call_request.hpp" + +#include "barretenberg/avm_fuzzer/fuzz_lib/constants.hpp" +#include "barretenberg/avm_fuzzer/mutations/basic_types/field.hpp" +#include "barretenberg/avm_fuzzer/mutations/basic_types/vector.hpp" +#include "barretenberg/avm_fuzzer/mutations/calldata/calldata_vec.hpp" +#include "barretenberg/avm_fuzzer/mutations/configuration.hpp" +#include "barretenberg/vm2/common/avm_io.hpp" +#include "barretenberg/vm2/simulation/lib/contract_crypto.hpp" + +using bb::avm2::AztecAddress; +using bb::avm2::FF; + +namespace { + +void mutate_contract_address(AztecAddress& address, std::vector& contract_addresses, std::mt19937_64& rng) +{ + if (contract_addresses.empty()) { + address = generate_random_field(rng); + } + // Most of the time we want to pick from the existing contract addresses, since a random address will fail early + auto contract_address_choice = std::uniform_int_distribution(0, contract_addresses.size() - 1)(rng); + address = contract_addresses[contract_address_choice]; + + // 1 in 1000 chance for the contract address to be random + bool random_address = std::uniform_int_distribution(0, 999)(rng) == 0; + if (random_address) { + fuzz_info("Mutating contract address to a random address"); + mutate_field(address, rng, BASIC_FIELD_MUTATION_CONFIGURATION); + } +} + +void mutate_calldata(PublicCallRequestWithCalldata& request, std::mt19937_64& rng) +{ + mutate_calldata_vec(request.calldata, rng); + if (request.calldata.size() > fuzzer::MAX_CALLDATA_SIZE) { + request.calldata.resize(fuzzer::MAX_CALLDATA_SIZE); + } + + request.request.calldata_hash = simulation::compute_calldata_hash(request.calldata); +} + +} // namespace + +namespace bb::avm2::fuzzer { + +void mutate_public_call_request(PublicCallRequestWithCalldata& request, + std::vector& contract_addresses, + std::mt19937_64& rng) +{ + fuzz_info("Mutating public call request"); + auto choice = PUB_REQUEST_MUTATION_CONFIGURATION.select(rng); + + switch (choice) { + case PublicCallRequestMutationOptions::ContractAddress: + // Mutate contract_address + mutate_contract_address(request.request.contract_address, contract_addresses, rng); + break; + case PublicCallRequestMutationOptions::MsgSender: + // Mutate msg_sender + mutate_field(request.request.msg_sender, rng, BASIC_FIELD_MUTATION_CONFIGURATION); + break; + case PublicCallRequestMutationOptions::IsStaticCall: + // Mutate is_static_call + request.request.is_static_call = !request.request.is_static_call; + break; + case PublicCallRequestMutationOptions::Calldata: + // Mutate calldata, this also updates the calldata_hash + mutate_calldata(request, rng); + break; + } +} + +PublicCallRequestWithCalldata generate_public_call_request(std::vector& contract_addresses, + std::mt19937_64& rng) +{ + fuzz_info("Generating new public call request"); + // Generate random calldata + size_t calldata_size = std::uniform_int_distribution(0, MAX_CALLDATA_SIZE)(rng); + std::vector calldata; + calldata.reserve(calldata_size); + for (size_t i = 0; i < calldata_size; ++i) { + calldata.push_back(generate_random_field(rng)); + } + + auto contract_address = + contract_addresses.empty() + ? generate_random_field(rng) + : contract_addresses[std::uniform_int_distribution(0, contract_addresses.size() - 1)(rng)]; + fuzz_info("Using contract address: ", contract_address); + FF calldata_hash = simulation::compute_calldata_hash(calldata); + + return PublicCallRequestWithCalldata{ + .request = + PublicCallRequest{ + .msg_sender = generate_random_field(rng), + .contract_address = contract_address, + .is_static_call = (std::uniform_int_distribution(0, 1)(rng) == 1), + .calldata_hash = calldata_hash, + }, + .calldata = calldata, + }; +} + +} // namespace bb::avm2::fuzzer diff --git a/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_types/public_call_request.hpp b/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_types/public_call_request.hpp new file mode 100644 index 000000000000..e97c1659eed6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/avm_fuzzer/mutations/tx_types/public_call_request.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +#include "barretenberg/avm_fuzzer/common/weighted_selection.hpp" +#include "barretenberg/vm2/common/avm_io.hpp" +#include "barretenberg/vm2/common/aztec_types.hpp" + +namespace bb::avm2::fuzzer { + +constexpr uint16_t MAX_CALLDATA_SIZE = 256; + +enum class PublicCallRequestMutationOptions : uint8_t { + ContractAddress, + MsgSender, + IsStaticCall, + Calldata, +}; + +using PublicCallRequestMutationConfig = WeightedSelectionConfig; + +constexpr PublicCallRequestMutationConfig PUB_REQUEST_MUTATION_CONFIGURATION = PublicCallRequestMutationConfig({ + { PublicCallRequestMutationOptions::ContractAddress, 3 }, + { PublicCallRequestMutationOptions::MsgSender, 1 }, + { PublicCallRequestMutationOptions::IsStaticCall, 3 }, + { PublicCallRequestMutationOptions::Calldata, 5 }, +}); + +PublicCallRequestWithCalldata generate_public_call_request(std::vector& contract_addresses, + std::mt19937_64& rng); + +void mutate_public_call_request(PublicCallRequestWithCalldata& request, + std::vector& contract_addresses, + std::mt19937_64& rng); +} // namespace bb::avm2::fuzzer diff --git a/barretenberg/cpp/src/barretenberg/avm_fuzzer/prover.fuzzer.cpp b/barretenberg/cpp/src/barretenberg/avm_fuzzer/prover.fuzzer.cpp index cf41dd525b76..56a01bda9ec0 100644 --- a/barretenberg/cpp/src/barretenberg/avm_fuzzer/prover.fuzzer.cpp +++ b/barretenberg/cpp/src/barretenberg/avm_fuzzer/prover.fuzzer.cpp @@ -14,7 +14,6 @@ using namespace bb::avm2::fuzzer; extern "C" int LLVMFuzzerInitialize(int*, char***) { FuzzerWorldStateManager::initialize(); - std::filesystem::create_directories("proving_inputs"); return 0; } diff --git a/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/tx_execution.cpp b/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/tx_execution.cpp index 33b8190a5c1f..1b5ef768ef46 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/tx_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/simulation/gadgets/tx_execution.cpp @@ -255,7 +255,8 @@ TxExecutionResult TxExecution::simulate(const Tx& tx) merkle_db.commit_checkpoint(); contract_db.commit_checkpoint(); } catch (const TxExecutionException& e) { - important("Teardown failure while simulating tx ", tx.hash, ": ", e.what()); + // TODO(fcarreiro): move these back to important log once/if we have log levels properly set up. + vinfo("Teardown failure while simulating tx ", tx.hash, ": ", e.what()); tx_context.revert_code = tx_context.revert_code == RevertCode::APP_LOGIC_REVERTED ? RevertCode::BOTH_REVERTED : RevertCode::TEARDOWN_REVERTED;