Skip to content

Commit 4cec7ae

Browse files
authored
feat: merge-train/avm (#19142)
BEGIN_COMMIT_OVERRIDE fix(avm)!: emit unencrypted log memory underflow (#19076) feat(avm_fuzzing): external calls (#19055) feat: avm allow and ignore list for fuzzer preset (#19088) feat(avm): seeding of fuzzer fee payer balance (#19089) END_COMMIT_OVERRIDE
2 parents f317fc7 + e310bc8 commit 4cec7ae

31 files changed

+697
-172
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Instrument vm2
2+
src:*/vm2/*
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Fuzzer instrumentation blocklist for AVM fuzzing
2+
# These directories contain heavy constraint/circuit code that we don't want instrumented
3+
# Format: src:<pattern> to match source files
4+
5+
# Exclude constraining code (circuit constraint generation)
6+
src:*barretenberg/vm2/constraining/*
7+
8+
# Exclude generated code (auto-generated circuit definitions)
9+
src:*barretenberg/vm2/generated/*

barretenberg/cpp/cmake/module.cmake

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ function(barretenberg_module_with_sources MODULE_NAME)
9191
PRIVATE
9292
-fsanitize=fuzzer-no-link
9393
)
94+
if(FUZZING_AVM)
95+
target_compile_options(
96+
${MODULE_NAME}_objects
97+
PRIVATE
98+
-fsanitize-coverage-allowlist=${CMAKE_SOURCE_DIR}/cmake/fuzzing-avm-allowlist.txt
99+
-fsanitize-coverage-ignorelist=${CMAKE_SOURCE_DIR}/cmake/fuzzing-avm-ignorelist.txt
100+
)
101+
endif()
94102
endif()
95103

96104
# enable msgpack downloading via dependency (solves race condition)

barretenberg/cpp/pil/vm2/opcodes/emit_unencrypted_log.pil

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,14 @@ namespace emit_unencrypted_log;
123123
pol commit error_out_of_bounds; // Constrained to be boolean by the lookup into gt. (provided that start == 1).
124124

125125
// TODO: Column needed until we support constants in lookups
126-
pol commit max_mem_addr;
127-
start * (max_mem_addr - constants.AVM_HIGHEST_MEM_ADDRESS) = 0;
126+
pol commit max_mem_size;
127+
start * (max_mem_size - constants.AVM_MEMORY_SIZE) = 0;
128128

129-
pol commit end_log_address;
130-
start * (log_address + log_size - 1 - end_log_address) = 0;
129+
pol commit end_log_address_upper_bound;
130+
start * (log_address + log_size - end_log_address_upper_bound) = 0;
131131

132132
#[CHECK_MEMORY_OUT_OF_BOUNDS]
133-
start { end_log_address, max_mem_addr, error_out_of_bounds }
133+
start { end_log_address_upper_bound, max_mem_size, error_out_of_bounds }
134134
in
135135
gt.sel_others { gt.input_a, gt.input_b, gt.res };
136136

barretenberg/cpp/src/barretenberg/avm_fuzzer/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
if(AVM AND FUZZING)
1+
if(FUZZING_AVM)
22
# Collect source files, excluding the harness subdirectory to avoid duplicate targets
33
file(GLOB_RECURSE SOURCE_FILES
44
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"

barretenberg/cpp/src/barretenberg/avm_fuzzer/avm.fuzzer.cpp renamed to barretenberg/cpp/src/barretenberg/avm_fuzzer/avm_differential.fuzzer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <vector>
66

77
#include "barretenberg/avm_fuzzer/common/interfaces/dbs.hpp"
8+
#include "barretenberg/avm_fuzzer/fuzz_lib/constants.hpp"
9+
#include "barretenberg/avm_fuzzer/fuzz_lib/contract_db_proxy.hpp"
810
#include "barretenberg/avm_fuzzer/fuzz_lib/control_flow.hpp"
911
#include "barretenberg/avm_fuzzer/fuzz_lib/fuzz.hpp"
1012
#include "barretenberg/avm_fuzzer/fuzz_lib/fuzzer_data.hpp"
@@ -40,7 +42,7 @@ SimulatorResult fuzz(const uint8_t* buffer, size_t size)
4042

4143
FuzzerWorldStateManager* ws_mgr = FuzzerWorldStateManager::getInstance();
4244
ws_mgr->fork();
43-
auto res = fuzz(deserialized_data);
45+
auto res = fuzz_against_ts_simulator(deserialized_data);
4446
ws_mgr->reset_world_state();
4547

4648
return res;

barretenberg/cpp/src/barretenberg/avm_fuzzer/common/interfaces/dbs.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55

66
#include "barretenberg/common/throw_or_abort.hpp"
77
#include "barretenberg/crypto/merkle_tree/indexed_tree/indexed_leaf.hpp"
8+
#include "barretenberg/crypto/poseidon2/poseidon2.hpp"
9+
#include "barretenberg/vm2/common/aztec_constants.hpp"
810
#include "barretenberg/vm2/common/aztec_types.hpp"
911

1012
using namespace bb::avm2::simulation;
13+
using Poseidon2 = bb::crypto::Poseidon2<bb::crypto::Poseidon2Bn254ScalarFieldParams>;
1114
using namespace bb::crypto::merkle_tree;
1215
using namespace bb::world_state;
1316

@@ -237,11 +240,13 @@ void FuzzerContractDB::add_contracts(const ContractDeploymentData& contract_depl
237240
void FuzzerContractDB::add_contract_class(const ContractClassId& class_id, const ContractClass& contract_class)
238241
{
239242
contract_classes[class_id] = contract_class;
243+
contract_classes_vector.push_back(contract_class);
240244
}
241245

242246
void FuzzerContractDB::add_contract_instance(const AztecAddress& address, const ContractInstance& contract_instance)
243247
{
244248
contract_instances[address] = contract_instance;
249+
contract_instances_vector.push_back({ address, contract_instance });
245250
}
246251

247252
// Based on fromLogs in yarn-project/protocol-contracts/src/class-registry/contract_class_published_event.ts
@@ -378,4 +383,18 @@ void FuzzerWorldStateManager::register_contract_address(const AztecAddress& cont
378383
ws->insert_indexed_leaves<NullifierLeafValue>(MerkleTreeId::NULLIFIER_TREE, { contract_nullifier }, fork_id);
379384
}
380385

386+
void FuzzerWorldStateManager::write_fee_payer_balance(const AztecAddress& fee_payer, const FF& balance)
387+
{
388+
if (fee_payer == 0) {
389+
return;
390+
}
391+
FF fee_juice_balance_slot = Poseidon2::hash({ FEE_JUICE_BALANCES_SLOT, fee_payer });
392+
FF leaf_slot =
393+
Poseidon2::hash({ GENERATOR_INDEX__PUBLIC_LEAF_INDEX, FF(FEE_JUICE_ADDRESS), fee_juice_balance_slot });
394+
395+
// Write to public data tree using current fork
396+
auto fork_id = fork_ids.top();
397+
ws->update_public_data(PublicDataLeafValue(leaf_slot, balance), fork_id);
398+
}
399+
381400
} // namespace bb::avm2::fuzzer

barretenberg/cpp/src/barretenberg/avm_fuzzer/common/interfaces/dbs.hpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ class FuzzerContractDB : public simulation::ContractDBInterface {
8383
void revert_checkpoint() override;
8484

8585
// Getters for serialization
86-
const std::unordered_map<ContractClassId, ContractClass>& get_contract_classes() const { return contract_classes; }
87-
const std::unordered_map<AztecAddress, ContractInstance>& get_contract_instances() const
86+
const std::vector<ContractClass>& get_contract_classes() const { return contract_classes_vector; }
87+
const std::vector<std::pair<AztecAddress, ContractInstance>>& get_contract_instances() const
8888
{
89-
return contract_instances;
89+
return contract_instances_vector;
9090
}
9191

9292
private:
@@ -96,6 +96,10 @@ class FuzzerContractDB : public simulation::ContractDBInterface {
9696
std::unordered_map<ContractClassId, ContractClass> contract_classes;
9797
std::unordered_map<AztecAddress, ContractInstance> contract_instances;
9898

99+
// Used for serialization keeping track of the order of the contracts and instances
100+
std::vector<ContractClass> contract_classes_vector;
101+
std::vector<std::pair<AztecAddress, ContractInstance>> contract_instances_vector;
102+
99103
struct Checkpoint {
100104
std::unordered_map<ContractClassId, ContractClass> contract_classes;
101105
std::unordered_map<AztecAddress, ContractInstance> contract_instances;
@@ -135,6 +139,7 @@ class FuzzerWorldStateManager {
135139

136140
void reset_world_state();
137141
void register_contract_address(const AztecAddress& contract_address);
142+
void write_fee_payer_balance(const AztecAddress& fee_payer, const FF& balance);
138143

139144
world_state::WorldStateRevision get_current_revision() const;
140145
world_state::WorldStateRevision fork();

barretenberg/cpp/src/barretenberg/avm_fuzzer/fuzz_lib/constants.hpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ const FF SLOT_NUMBER = 1;
1818
const uint64_t TIMESTAMP = 1000000;
1919
const EthAddress COINBASE = EthAddress{ 0 };
2020
const AztecAddress FEE_RECIPIENT = AztecAddress{ 0 };
21-
const uint128_t FEE_PER_DA_GAS = 1;
22-
const uint128_t FEE_PER_L2_GAS = 1;
21+
constexpr uint128_t FEE_PER_DA_GAS = 1;
22+
constexpr uint128_t FEE_PER_L2_GAS = 1;
2323
const std::string TRANSACTION_HASH = "0xdeadbeef";
24-
const GasFees EFFECTIVE_GAS_FEES = GasFees{ .fee_per_da_gas = 0, .fee_per_l2_gas = 0 };
24+
constexpr GasFees EFFECTIVE_GAS_FEES = GasFees{ .fee_per_da_gas = FEE_PER_DA_GAS, .fee_per_l2_gas = FEE_PER_L2_GAS };
2525
const FF FIRST_NULLIFIER = FF("0x00000000000000000000000000000000000000000000000000000000deadbeef");
2626
const std::vector<FF> NON_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS = { FIRST_NULLIFIER };
2727
const std::vector<FF> NON_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES = {};
@@ -49,3 +49,10 @@ inline void fuzz_info_(std::function<std::string()> func)
4949
}
5050

5151
#define fuzz_info(...) fuzz_info_([&]() { return format(__VA_ARGS__); })
52+
53+
// =========== Pre defined functions ===========
54+
// Taken from ADD_8 test in fuzz.test.cpp
55+
const std::vector<uint8_t> ADD_8_BYTECODE = { 39, 0, 0, 2, 5, 39, 0, 1, 2, 2, 0, 0, 0, 1,
56+
2, 40, 0, 0, 5, 4, 0, 1, 59, 0, 0, 5, 0, 2 };
57+
58+
const std::vector<std::vector<uint8_t>> PREDEFINED_FUNCTIONS = { ADD_8_BYTECODE };
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#include "barretenberg/avm_fuzzer/fuzz_lib/contract_db_proxy.hpp"
2+
3+
#include "barretenberg/avm_fuzzer/common/interfaces/dbs.hpp"
4+
#include "barretenberg/avm_fuzzer/fuzz_lib/constants.hpp"
5+
#include "barretenberg/avm_fuzzer/fuzz_lib/control_flow.hpp"
6+
#include "barretenberg/avm_fuzzer/fuzz_lib/fuzzer_data.hpp"
7+
#include "barretenberg/avm_fuzzer/fuzz_lib/simulator.hpp"
8+
#include "barretenberg/common/log.hpp"
9+
#include "barretenberg/vm2/simulation/lib/contract_crypto.hpp"
10+
11+
using namespace bb::avm2::fuzzer;
12+
13+
// Temp Helper function to create a default contract class from bytecode
14+
ContractClass create_default_class(const std::vector<uint8_t>& bytecode)
15+
{
16+
// This isn't strictly needed for pure simulation, but if we want to re-use inputs in proving we need valid
17+
// commitment
18+
auto bytecode_commitment = simulation::compute_public_bytecode_commitment(bytecode);
19+
auto class_id =
20+
simulation::compute_contract_class_id(/*artifact_hash=*/0, /*private_fn_root=*/0, bytecode_commitment);
21+
return ContractClass{
22+
.id = class_id,
23+
.artifact_hash = 0,
24+
.private_functions_root = 0,
25+
.packed_bytecode = bytecode,
26+
};
27+
}
28+
29+
// Temp Helper function to create a default contract instance from a class ID
30+
ContractInstance create_default_instance(const ContractClassId& class_id)
31+
{
32+
return ContractInstance{
33+
.salt = 0,
34+
.deployer = MSG_SENDER,
35+
.current_contract_class_id = class_id,
36+
.original_contract_class_id = class_id,
37+
.initialization_hash = 0,
38+
.public_keys = PublicKeys{},
39+
};
40+
}
41+
42+
// Temp Helper function to compute contract address from instance
43+
AztecAddress compute_contract_address(const ContractInstance& instance)
44+
{
45+
// This isn't strictly needed for pure simulation, but if we want to re-use inputs in proving we need valid
46+
// addresses
47+
return simulation::compute_contract_address(instance);
48+
}
49+
50+
// Creates a default transaction that the single app logic enqueued call can be inserted into
51+
Tx create_default_tx(const AztecAddress& contract_address,
52+
const AztecAddress& sender_address,
53+
const std::vector<FF>& calldata,
54+
[[maybe_unused]] const FF& transaction_fee,
55+
bool is_static_call,
56+
const Gas& gas_limit)
57+
{
58+
return Tx{
59+
.hash = TRANSACTION_HASH,
60+
.gas_settings = GasSettings{
61+
.gas_limits = gas_limit,
62+
.max_fees_per_gas = GasFees{ .fee_per_da_gas = FEE_PER_DA_GAS, .fee_per_l2_gas = FEE_PER_L2_GAS },
63+
},
64+
.effective_gas_fees = EFFECTIVE_GAS_FEES,
65+
.non_revertible_accumulated_data = AccumulatedData{
66+
.note_hashes = NON_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES,
67+
// This nullifier is needed to make the nonces for note hashes and expected by simulation_helper
68+
.nullifiers = NON_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS,
69+
.l2_to_l1_messages = NON_REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MESSAGES,
70+
},
71+
.revertible_accumulated_data = AccumulatedData{
72+
.note_hashes = REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES,
73+
.nullifiers = REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS,
74+
.l2_to_l1_messages = REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MESSAGES,
75+
},
76+
.setup_enqueued_calls = SETUP_ENQUEUED_CALLS,
77+
.app_logic_enqueued_calls = {
78+
PublicCallRequestWithCalldata{
79+
.request = PublicCallRequest{
80+
.msg_sender = MSG_SENDER,
81+
.contract_address = contract_address,
82+
.is_static_call = is_static_call,
83+
.calldata_hash = 0,
84+
},
85+
.calldata = calldata,
86+
},
87+
},
88+
.teardown_enqueued_call = TEARDOWN_ENQUEUED_CALLS,
89+
.gas_used_by_private = GAS_USED_BY_PRIVATE,
90+
.fee_payer = sender_address,
91+
};
92+
}
93+
94+
namespace bb::avm2::fuzzer {
95+
96+
ContractDBProxy* ContractDBProxy::instance = nullptr;
97+
98+
ContractDBProxy::ContractDBProxy()
99+
{
100+
contract_db = new FuzzerContractDB();
101+
}
102+
103+
ContractDBProxy* ContractDBProxy::get_instance()
104+
{
105+
if (instance == nullptr) {
106+
instance = new ContractDBProxy();
107+
}
108+
return instance;
109+
}
110+
111+
FF ContractDBProxy::register_contract_from_bytecode(const std::vector<uint8_t>& bytecode)
112+
{
113+
if (instance == nullptr) {
114+
instance = new ContractDBProxy();
115+
}
116+
auto default_class = create_default_class(bytecode);
117+
auto default_instance = create_default_instance(default_class.id);
118+
auto contract_address = simulation::compute_contract_address(default_instance);
119+
instance->contract_db->add_contract_class(default_class.id, default_class);
120+
instance->contract_db->add_contract_instance(contract_address, default_instance);
121+
instance->registered_contract_addresses.push_back(contract_address);
122+
123+
FuzzerWorldStateManager::getInstance()->register_contract_address(contract_address);
124+
return contract_address;
125+
}
126+
127+
FF ContractDBProxy::get_function_address(size_t index)
128+
{
129+
if (instance == nullptr) {
130+
instance = new ContractDBProxy();
131+
}
132+
if (instance->registered_contract_addresses.size() < 1) {
133+
return FF::zero();
134+
}
135+
return instance->registered_contract_addresses[index % (instance->registered_contract_addresses.size())];
136+
}
137+
138+
void ContractDBProxy::reset_instance()
139+
{
140+
if (instance != nullptr) {
141+
delete instance;
142+
instance = new ContractDBProxy();
143+
}
144+
}
145+
} // namespace bb::avm2::fuzzer

0 commit comments

Comments
 (0)