Skip to content
Open
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 @@ -237,4 +237,10 @@ void FuzzerWorldStateManager::write_fee_payer_balance(const AztecAddress& fee_pa
ws->update_public_data(PublicDataLeafValue(leaf_slot, balance), fork_id);
}

void FuzzerWorldStateManager::public_data_write(const bb::crypto::merkle_tree::PublicDataLeafValue& public_data)
{
auto fork_id = fork_ids.top();
ws->update_public_data(public_data, fork_id);
}

} // namespace bb::avm2::fuzzer
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class FuzzerWorldStateManager {
void reset_world_state();
void register_contract_address(const AztecAddress& contract_address);
void write_fee_payer_balance(const AztecAddress& fee_payer, const FF& balance);
void public_data_write(const bb::crypto::merkle_tree::PublicDataLeafValue& public_data);

world_state::WorldStateRevision get_current_revision() const;
world_state::WorldStateRevision fork();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ SimulatorResult fuzz_against_ts_simulator(FuzzerData& fuzzer_data, FuzzerContext

try {
ws_mgr->checkpoint();
cpp_result = cpp_simulator.simulate(*ws_mgr, contract_db, tx);
cpp_result = cpp_simulator.simulate(*ws_mgr, contract_db, tx, /*public_data_writes=*/{});
ws_mgr->revert();
} catch (const std::exception& e) {
throw std::runtime_error(std::string("CppSimulator threw an exception: ") + e.what());
}

ws_mgr->checkpoint();
auto js_result = js_simulator->simulate(*ws_mgr, contract_db, tx);
auto js_result = js_simulator->simulate(*ws_mgr, contract_db, tx, /*public_data_writes=*/{});

context.reset();

Expand Down
32 changes: 20 additions & 12 deletions barretenberg/cpp/src/barretenberg/avm_fuzzer/fuzz_lib/simulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ using namespace bb::avm2::simulation;
using namespace bb::avm2::fuzzer;
using namespace bb::world_state;

const auto MAX_RETURN_DATA_SIZE_IN_FIELDS = 1024;
constexpr auto MAX_RETURN_DATA_SIZE_IN_FIELDS = 1024;

// Helper function to serialize simulation request via msgpack
std::string serialize_simulation_request(const Tx& tx,
const GlobalVariables& globals,
const FuzzerContractDB& contract_db)
std::string serialize_simulation_request(
const Tx& tx,
const GlobalVariables& globals,
const FuzzerContractDB& contract_db,
const std::vector<bb::crypto::merkle_tree::PublicDataLeafValue>& public_data_writes)
{
// Build vectors from contract_db
std::vector<ContractClass> classes_vec = contract_db.get_contract_classes();
Expand All @@ -49,6 +51,7 @@ std::string serialize_simulation_request(const Tx& tx,
.globals = globals,
.contract_classes = std::move(classes_vec),
.contract_instances = std::move(instances_vec),
.public_data_writes = public_data_writes,
};

auto [buffer, size] = msgpack_encode_buffer(request);
Expand All @@ -72,10 +75,13 @@ GlobalVariables create_default_globals()
};
}

SimulatorResult CppSimulator::simulate(fuzzer::FuzzerWorldStateManager& ws_mgr,
fuzzer::FuzzerContractDB& contract_db,
const Tx& tx)
SimulatorResult CppSimulator::simulate(
fuzzer::FuzzerWorldStateManager& ws_mgr,
fuzzer::FuzzerContractDB& contract_db,
const Tx& tx,
[[maybe_unused]] const std::vector<bb::crypto::merkle_tree::PublicDataLeafValue>& public_data_writes)
{
// Note: public_data_writes are already applied to C++ world state in setup_fuzzer_state

const PublicSimulatorConfig config{
.skip_fee_enforcement = false,
Expand Down Expand Up @@ -143,13 +149,15 @@ void JsSimulator::initialize(std::string& simulator_path)
instance = new JsSimulator(simulator_path);
}

SimulatorResult JsSimulator::simulate([[maybe_unused]] fuzzer::FuzzerWorldStateManager& ws_mgr,
fuzzer::FuzzerContractDB& contract_db,
const Tx& tx)
SimulatorResult JsSimulator::simulate(
[[maybe_unused]] fuzzer::FuzzerWorldStateManager& ws_mgr,
fuzzer::FuzzerContractDB& contract_db,
const Tx& tx,
const std::vector<bb::crypto::merkle_tree::PublicDataLeafValue>& public_data_writes)
{
auto globals = create_default_globals();

std::string serialized = serialize_simulation_request(tx, globals, contract_db);
std::string serialized = serialize_simulation_request(tx, globals, contract_db, public_data_writes);

// Send the request
process.write_line(serialized);
Expand All @@ -172,7 +180,7 @@ SimulatorResult JsSimulator::simulate([[maybe_unused]] fuzzer::FuzzerWorldStateM
bool compare_simulator_results(SimulatorResult& result1, SimulatorResult& result2)
{
// Since the simulator results are interchangeable between TS and C++, we limit the return data size for comparison
// todo(ilyas): we ideally specfify one param as the TS result and truncate only that one
// todo(ilyas): we ideally specify one param as the TS result and truncate only that one
if (result1.output.size() > MAX_RETURN_DATA_SIZE_IN_FIELDS) {
result1.output.resize(MAX_RETURN_DATA_SIZE_IN_FIELDS);
}
Expand Down
30 changes: 20 additions & 10 deletions barretenberg/cpp/src/barretenberg/avm_fuzzer/fuzz_lib/simulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "barretenberg/avm_fuzzer/common/interfaces/dbs.hpp"
#include "barretenberg/avm_fuzzer/common/process.hpp"
#include "barretenberg/crypto/merkle_tree/indexed_tree/indexed_leaf.hpp"
#include "barretenberg/vm2/common/avm_io.hpp"
#include "barretenberg/vm2/common/aztec_types.hpp"
#include "barretenberg/vm2/common/field.hpp"
Expand All @@ -24,8 +25,11 @@ struct FuzzerSimulationRequest {
std::vector<ContractClass> contract_classes;
// Having addresses here avoids doing re-work in TS.
std::vector<std::pair<AztecAddress, ContractInstance>> contract_instances;
// Public data tree writes to apply before simulation (e.g., for bytecode upgrades)
std::vector<bb::crypto::merkle_tree::PublicDataLeafValue> public_data_writes;

MSGPACK_CAMEL_CASE_FIELDS(ws_data_dir, ws_map_size_kb, tx, globals, contract_classes, contract_instances);
MSGPACK_CAMEL_CASE_FIELDS(
ws_data_dir, ws_map_size_kb, tx, globals, contract_classes, contract_instances, public_data_writes);
};

struct SimulatorResult {
Expand All @@ -45,17 +49,21 @@ class Simulator {
Simulator(Simulator&&) = delete;
Simulator& operator=(Simulator&&) = delete;
Simulator() = default;
virtual SimulatorResult simulate(fuzzer::FuzzerWorldStateManager& ws_mgr,
fuzzer::FuzzerContractDB& contract_db,
const Tx& tx) = 0;
virtual SimulatorResult simulate(
fuzzer::FuzzerWorldStateManager& ws_mgr,
fuzzer::FuzzerContractDB& contract_db,
const Tx& tx,
const std::vector<bb::crypto::merkle_tree::PublicDataLeafValue>& public_data_writes) = 0;
};

/// @brief uses barretenberg/vm2 to simulate the bytecode
class CppSimulator : public Simulator {
public:
SimulatorResult simulate(fuzzer::FuzzerWorldStateManager& ws_mgr,
fuzzer::FuzzerContractDB& contract_db,
const Tx& tx) override;
SimulatorResult simulate(
fuzzer::FuzzerWorldStateManager& ws_mgr,
fuzzer::FuzzerContractDB& contract_db,
const Tx& tx,
const std::vector<bb::crypto::merkle_tree::PublicDataLeafValue>& public_data_writes) override;
};

/// @brief uses the yarn-project/simulator to simulate the bytecode
Expand All @@ -77,9 +85,11 @@ class JsSimulator : public Simulator {
static JsSimulator* getInstance();
static void initialize(std::string& simulator_path);

SimulatorResult simulate(fuzzer::FuzzerWorldStateManager& ws_mgr,
fuzzer::FuzzerContractDB& contract_db,
const Tx& tx) override;
SimulatorResult simulate(
fuzzer::FuzzerWorldStateManager& ws_mgr,
fuzzer::FuzzerContractDB& contract_db,
const Tx& tx,
const std::vector<bb::crypto::merkle_tree::PublicDataLeafValue>& public_data_writes) override;
};

GlobalVariables create_default_globals();
Expand Down
65 changes: 49 additions & 16 deletions barretenberg/cpp/src/barretenberg/avm_fuzzer/fuzzer_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "barretenberg/avm_fuzzer/fuzzer_comparison_helper.hpp"
#include "barretenberg/avm_fuzzer/mutations/fuzzer_data.hpp"
#include "barretenberg/avm_fuzzer/mutations/tx_data.hpp"
#include "barretenberg/avm_fuzzer/mutations/tx_types/gas.hpp"
#include "barretenberg/common/log.hpp"
#include "barretenberg/vm2/avm_api.hpp"
#include "barretenberg/vm2/common/avm_io.hpp"
Expand All @@ -24,23 +25,34 @@ using namespace bb::avm2::fuzzer;
using namespace bb::avm2::simulation;
using namespace bb::world_state;

extern size_t LLVMFuzzerMutate(uint8_t* Data, size_t Size, size_t MaxSize);

void setup_fuzzer_state(FuzzerWorldStateManager& ws_mgr, FuzzerContractDB& contract_db, const FuzzerTxData& tx_data)
{
// Add all contract classes and instances to the contract DB
// There may be more classes than instances because of the possibility of mutated bytecodes that are used in
// upgrades - these are not directly instantiated
for (size_t i = 0; i < tx_data.contract_classes.size(); ++i) {
const auto& contract_class = tx_data.contract_classes[i];
contract_db.add_contract_class(contract_class.id, contract_class);
}

// Add contract instances to the contract DB
for (size_t i = 0; i < tx_data.contract_instances.size(); ++i) {
const auto& contract_instance = tx_data.contract_instances[i];
auto contract_address = tx_data.contract_addresses[i];
contract_db.add_contract_class(contract_class.id, contract_class);
contract_db.add_contract_instance(contract_address, contract_instance);
}

// Register the de-duplicated set of contract addresses to the world state (in insertion order)
std::unordered_set<AztecAddress> seen_addresses;
// Register contract addresses in the world state
for (const auto& addr : tx_data.contract_addresses) {
if (seen_addresses.insert(addr).second) {
fuzz_info("Registering contract address in world state: ", addr);
ws_mgr.register_contract_address(addr);
ws_mgr.register_contract_address(addr);
}

// Apply public data tree writes (e.g., for contract instance upgrades)
if (!tx_data.public_data_writes.empty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do just

for (const auto& write : tx_data.public_data_writes) {
    ws_mgr.public_data_write(write);
}

for (const auto& write : tx_data.public_data_writes) {
ws_mgr.public_data_write(write);
}
}
}
Expand Down Expand Up @@ -68,7 +80,9 @@ SimulatorResult fuzz_tx(FuzzerWorldStateManager& ws_mgr, FuzzerContractDB& contr

try {
ws_mgr.checkpoint();
cpp_result = cpp_simulator.simulate(ws_mgr, contract_db, tx_data.tx);
cpp_result = cpp_simulator.simulate(ws_mgr, contract_db, tx_data.tx, tx_data.public_data_writes);
fuzz_info("CppSimulator completed without exception");
fuzz_info("CppSimulator result: ", cpp_result);
ws_mgr.revert();
} catch (const std::exception& e) {
fuzz_info("CppSimulator threw an exception: ", e.what());
Expand All @@ -82,7 +96,7 @@ SimulatorResult fuzz_tx(FuzzerWorldStateManager& ws_mgr, FuzzerContractDB& contr
}

ws_mgr.checkpoint();
auto js_result = js_simulator->simulate(ws_mgr, contract_db, tx_data.tx);
auto js_result = js_simulator->simulate(ws_mgr, contract_db, tx_data.tx, tx_data.public_data_writes);

// If the results do not match
if (!compare_simulator_results(cpp_result, js_result)) {
Expand Down Expand Up @@ -270,14 +284,23 @@ size_t mutate_tx_data(FuzzerContext& context,
tx_data.contract_classes.clear();
tx_data.contract_instances.clear();
tx_data.contract_addresses.clear();
tx_data.public_data_writes.clear();
std::vector<AztecAddress> contract_addresses;

std::unordered_set<AztecAddress> seen_addresses;
for (auto& fuzzer_data : tx_data.input_programs) {
const auto [bytecode, contract_class, contract_instance] = build_bytecode_and_artifacts(fuzzer_data);

auto contract_address = simulation::compute_contract_address(contract_instance);
contract_addresses.push_back(contract_address);

// Skip duplicate addresses - multiple input_programs can generate the same address
if (seen_addresses.contains(contract_address)) {
fuzz_info("Skipping duplicate contract address: ", contract_address);
continue;
}
seen_addresses.insert(contract_address);

contract_addresses.push_back(contract_address);
tx_data.contract_classes.push_back(contract_class);
tx_data.contract_instances.push_back(contract_instance);
}
Expand All @@ -297,17 +320,21 @@ size_t mutate_tx_data(FuzzerContext& context,
}

// Select mutation type (weighted against bytecode mutations) -- todo
auto mutation_type = std::uniform_int_distribution<uint8_t>(0, 0);
TxDataMutationType mutation_choice = static_cast<TxDataMutationType>(mutation_type(rng));
FuzzerTxDataMutationType mutation_choice = FUZZER_TX_DATA_MUTATION_CONFIGURATION.select(rng);

switch (mutation_choice) {
case TxDataMutationType::TxMutation:
case FuzzerTxDataMutationType::TxMutation:
mutate_tx(tx_data.tx, contract_addresses, rng);
break;
// case TxDataMutationType::BytecodeMutation:
// // todo: Maybe here we can do some direct mutations on the bytecode
// // Mutations here are likely to cause immediate failure
// break;
case FuzzerTxDataMutationType::BytecodeMutation: {
// Mutate bytecode and append public data writes for world state setup
mutate_bytecode(tx_data.contract_classes,
tx_data.contract_instances,
tx_data.contract_addresses,
tx_data.public_data_writes,
rng);
break;
}
// case TxDataMutationType::ContractClassMutation:
// // Mutations here are likely to cause immediate failure
// break;
Expand All @@ -333,6 +360,12 @@ size_t mutate_tx_data(FuzzerContext& context,
.calldata_hash = calldata_hash },
.calldata = calldata });
}

// Compute effective gas fees matching TS computeEffectiveGasFees
// This must be done after any mutation that could affect gas settings or global variables
tx_data.tx.effective_gas_fees =
compute_effective_gas_fees(tx_data.global_variables.gas_fees, tx_data.tx.gas_settings);

auto [mutated_serialized_fuzzer_data, mutated_serialized_fuzzer_data_size] = msgpack_encode_buffer(tx_data);
if (mutated_serialized_fuzzer_data_size > max_size) {
delete[] mutated_serialized_fuzzer_data;
Expand Down
21 changes: 17 additions & 4 deletions barretenberg/cpp/src/barretenberg/avm_fuzzer/fuzzer_lib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#include "barretenberg/avm_fuzzer/fuzz_lib/fuzzer_context.hpp"
#include "barretenberg/avm_fuzzer/fuzz_lib/fuzzer_data.hpp"
#include "barretenberg/avm_fuzzer/fuzz_lib/simulator.hpp"
#include "barretenberg/avm_fuzzer/mutations/bytecode.hpp"
#include "barretenberg/avm_fuzzer/mutations/tx_data.hpp"
#include "barretenberg/crypto/merkle_tree/indexed_tree/indexed_leaf.hpp"
#include "barretenberg/serialize/msgpack_impl.hpp"
#include "barretenberg/vm2/common/avm_io.hpp"
#include "barretenberg/vm2/common/aztec_types.hpp"
Expand All @@ -28,13 +31,17 @@ struct FuzzerTxData {
GlobalVariables global_variables;
ProtocolContracts protocol_contracts;

// Public data tree writes to be applied during state setup (e.g., for bytecode upgrades)
std::vector<bb::crypto::merkle_tree::PublicDataLeafValue> public_data_writes;

MSGPACK_FIELDS(input_programs,
contract_classes,
contract_instances,
contract_addresses,
tx,
global_variables,
protocol_contracts);
protocol_contracts,
public_data_writes);
};

inline std::ostream& operator<<(std::ostream& os, const FuzzerTxData& data)
Expand All @@ -51,16 +58,22 @@ using ContractArtifacts = std::tuple<Bytecode, ContractClass, ContractInstance>;
using FuzzerContext = bb::avm2::fuzzer::FuzzerContext;

// Mutation configuration
enum class TxDataMutationType : uint8_t {
enum class FuzzerTxDataMutationType : uint8_t {
TxMutation,
// todo: implement other mutation types
// BytecodeMutation,
BytecodeMutation,
// ContractClassMutation,
// ContractInstanceMutation,
// GlobalVariablesMutation,
// ProtocolContractsMutation
};

using FuzzerTxDataMutationConfig = WeightedSelectionConfig<FuzzerTxDataMutationType, 2>;

constexpr FuzzerTxDataMutationConfig FUZZER_TX_DATA_MUTATION_CONFIGURATION = FuzzerTxDataMutationConfig({
{ FuzzerTxDataMutationType::TxMutation, 10 },
{ FuzzerTxDataMutationType::BytecodeMutation, 1 },
});

// Build bytecode and contract artifacts from fuzzer data
ContractArtifacts build_bytecode_and_artifacts(FuzzerData& fuzzer_data);

Expand Down
Loading
Loading