Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
simulator.cpp
Go to the documentation of this file.
2
3#include <cstdint>
4#include <iomanip>
5#include <iostream>
6#include <sys/wait.h>
7#include <unistd.h>
8#include <vector>
9
27
29using namespace bb::avm2;
30using namespace bb::avm2::simulation;
31using namespace bb::avm2::fuzzer;
32using namespace bb::world_state;
33
34constexpr auto MAX_RETURN_DATA_SIZE_IN_FIELDS = 1024;
35
36// Helper function to serialize simulation request via msgpack
38 const Tx& tx,
39 const GlobalVariables& globals,
41 const std::vector<bb::crypto::merkle_tree::PublicDataLeafValue>& public_data_writes,
42 const std::vector<FF>& note_hashes,
43 const ProtocolContracts& protocol_contracts)
44{
45 // Build vectors from contract_db
46 std::vector<ContractClass> classes_vec = contract_db.get_contract_classes();
47 std::vector<std::pair<AztecAddress, ContractInstance>> instances_vec = contract_db.get_contract_instances();
48
52 .tx = tx,
53 .globals = globals,
54 .contract_classes = std::move(classes_vec),
55 .contract_instances = std::move(instances_vec),
56 .public_data_writes = public_data_writes,
57 .note_hashes = note_hashes,
58 .protocol_contracts = protocol_contracts,
59 };
60
61 auto [buffer, size] = msgpack_encode_buffer(request);
62 std::string result = base64_encode(buffer, size);
63 delete[] buffer;
64 return result;
65}
66
67// Helper function to create default global variables for testing
69{
70 return GlobalVariables{
72 .version = VERSION,
73 .block_number = BLOCK_NUMBER,
74 .slot_number = SLOT_NUMBER,
75 .timestamp = TIMESTAMP,
76 .coinbase = COINBASE,
77 .fee_recipient = FEE_RECIPIENT,
78 .gas_fees = GasFees{ .fee_per_da_gas = FEE_PER_DA_GAS, .fee_per_l2_gas = FEE_PER_L2_GAS },
79 };
80}
81
85 const Tx& tx,
86 const GlobalVariables& globals,
87 [[maybe_unused]] const std::vector<bb::crypto::merkle_tree::PublicDataLeafValue>& public_data_writes,
88 [[maybe_unused]] const std::vector<FF>& note_hashes,
89 const ProtocolContracts& protocol_contracts)
90{
91 // Note: public_data_writes and note_hashes are already applied to C++ world state in setup_fuzzer_state
92
93 const PublicSimulatorConfig config{
94 .skip_fee_enforcement = false,
95 .collect_call_metadata = true,
96 .collect_public_inputs = true,
97 .collection_limits = {
98 .max_returndata_size_in_fields = MAX_RETURN_DATA_SIZE_IN_FIELDS,
99 },
100 };
101
104
105 AvmSimulationHelper helper;
106 TxSimulationResult result =
107 helper.simulate_fast_with_existing_ws(contract_db, ws_rev, ws, config, tx, globals, protocol_contracts);
108 bool reverted = result.revert_code != RevertCode::OK;
109 // Just process the top level call's output
110 vinfo(
111 "C++ Simulator result - reverted: ", reverted, ", output size: ", result.call_stack_metadata[0].output.size());
112 std::vector<FF> values = {};
113 if (result.call_stack_metadata.size() != 0) {
114 for (const auto& metadata : result.call_stack_metadata) {
115 // Only collect outputs from APP_LOGIC phase (matches TypeScript getAppLogicReturnValues())
116 if (metadata.phase == CoarseTransactionPhase::APP_LOGIC) {
117 for (const auto& output : metadata.output) {
118 values.push_back(output);
119 }
120 }
121 }
122 }
123 if (result.public_inputs.has_value()) {
124 return { .reverted = reverted,
125 .output = values,
126 .end_tree_snapshots = result.public_inputs->end_tree_snapshots,
127 .public_tx_effect = result.public_tx_effect };
128 }
129 return { .reverted = reverted, .output = values, .public_tx_effect = result.public_tx_effect };
130}
131
133JsSimulator::JsSimulator(std::string& simulator_path)
134 : simulator_path(simulator_path)
135 , process("LOG_LEVEL=silent node " + simulator_path + " 2>/dev/null")
136{}
137
139{
140 if (instance == nullptr) {
141 throw std::runtime_error("JsSimulator should be initializing in FUZZ INIT");
142 }
143 return instance;
144}
145
148void JsSimulator::initialize(std::string& simulator_path)
149{
150 if (instance != nullptr) {
151 throw std::runtime_error("JsSimulator already initialized");
152 }
154}
155
157 [[maybe_unused]] fuzzer::FuzzerWorldStateManager& ws_mgr,
159 const Tx& tx,
160 const GlobalVariables& globals,
161 const std::vector<bb::crypto::merkle_tree::PublicDataLeafValue>& public_data_writes,
162 const std::vector<FF>& note_hashes,
163 const ProtocolContracts& protocol_contracts)
164{
165 std::string serialized =
166 serialize_simulation_request(tx, globals, contract_db, public_data_writes, note_hashes, protocol_contracts);
167
168 // Send the request
169 process.write_line(serialized);
170 std::string response = process.read_line();
171 while (response.empty()) {
172 std::cout << "Empty response, reading again" << std::endl;
173 std::this_thread::sleep_for(std::chrono::milliseconds(10));
174 response = process.read_line();
175 }
176 // Remove the newline character
177 response.erase(response.find_last_not_of('\n') + 1);
178
179 // Parse with msg_pack
180 auto res_buffer = base64_decode(response);
181 SimulatorResult result;
182 result = msgpack::unpack(res_buffer.data(), res_buffer.size()).get().convert(result);
183 return result;
184}
185
187{
188 // Since the simulator results are interchangeable between TS and C++, we limit the return data size for comparison
189 // todo(ilyas): we ideally specify one param as the TS result and truncate only that one
190 if (result1.output.size() > MAX_RETURN_DATA_SIZE_IN_FIELDS) {
192 }
193 if (result2.output.size() > MAX_RETURN_DATA_SIZE_IN_FIELDS) {
195 }
196
197 // TODO(avm):
198 // https://linear.app/aztec-labs/issue/AVM-209/l2l1msgs-possible-completeness-issue-with-recipient-20-bytes
199 for (auto& l2_to_l1_msg : result1.public_tx_effect.l2_to_l1_msgs) {
200 l2_to_l1_msg.message.recipient = FF(static_cast<uint256_t>(l2_to_l1_msg.message.recipient).slice(0, 20));
201 }
202
203 for (auto& l2_to_l1_msg : result2.public_tx_effect.l2_to_l1_msgs) {
204 l2_to_l1_msg.message.recipient = FF(static_cast<uint256_t>(l2_to_l1_msg.message.recipient).slice(0, 20));
205 }
206
207 return result1.reverted == result2.reverted && result1.output == result2.output &&
208 result1.end_tree_snapshots == result2.end_tree_snapshots &&
209 result1.public_tx_effect == result2.public_tx_effect;
210}
211
212// Creates a default transaction that the single app logic enqueued call can be inserted into
214 const AztecAddress& sender_address,
215 const std::vector<FF>& calldata,
216 [[maybe_unused]] const FF& transaction_fee,
217 bool is_static_call,
218 const Gas& gas_limit)
219{
220 return Tx{
222 .gas_settings = GasSettings{
223 .gas_limits = gas_limit,
224 .max_fees_per_gas = GasFees{ .fee_per_da_gas = FEE_PER_DA_GAS, .fee_per_l2_gas = FEE_PER_L2_GAS },
225 },
226 .effective_gas_fees = EFFECTIVE_GAS_FEES,
227 .non_revertible_accumulated_data = AccumulatedData{
229 // This nullifier is needed to make the nonces for note hashes and expected by simulation_helper
232 },
233 .revertible_accumulated_data = AccumulatedData{
237 },
238 .setup_enqueued_calls = SETUP_ENQUEUED_CALLS,
239 .app_logic_enqueued_calls = {
243 .contract_address = contract_address,
244 .is_static_call = is_static_call,
245 .calldata_hash = compute_calldata_hash(calldata),
246 },
247 .calldata = calldata,
248 },
249 },
250 .teardown_enqueued_call = TEARDOWN_ENQUEUED_CALLS,
251 .gas_used_by_private = GAS_USED_BY_PRIVATE,
252 .fee_payer = sender_address,
253 };
254}
const std::optional< PublicCallRequestWithCalldata > TEARDOWN_ENQUEUED_CALLS
Definition constants.hpp:34
const std::vector< ScopedL2ToL1Message > NON_REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MESSAGES
Definition constants.hpp:28
const uint32_t BLOCK_NUMBER
Definition constants.hpp:16
const std::vector< FF > NON_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS
Definition constants.hpp:26
const AztecAddress FEE_RECIPIENT
Definition constants.hpp:20
const std::vector< FF > NON_REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES
Definition constants.hpp:27
constexpr GasFees EFFECTIVE_GAS_FEES
Definition constants.hpp:24
const std::vector< PublicCallRequestWithCalldata > SETUP_ENQUEUED_CALLS
Definition constants.hpp:32
const EthAddress COINBASE
Definition constants.hpp:19
const FF MSG_SENDER
Definition constants.hpp:33
const FF SLOT_NUMBER
Definition constants.hpp:17
const std::string TRANSACTION_HASH
Definition constants.hpp:23
const FF CHAIN_ID
Definition constants.hpp:14
constexpr uint128_t FEE_PER_DA_GAS
Definition constants.hpp:21
const std::vector< ScopedL2ToL1Message > REVERTIBLE_ACCUMULATED_DATA_L2_TO_L1_MESSAGES
Definition constants.hpp:31
const Gas GAS_USED_BY_PRIVATE
Definition constants.hpp:35
const std::vector< FF > REVERTIBLE_ACCUMULATED_DATA_NOTE_HASHES
Definition constants.hpp:30
const std::vector< FF > REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS
Definition constants.hpp:29
constexpr uint128_t FEE_PER_L2_GAS
Definition constants.hpp:22
std::string base64_decode(std::string const &s, bool remove_linebreaks)
Definition base64.cpp:249
std::string base64_encode(unsigned char const *bytes_to_encode, size_t in_len, bool url)
Definition base64.cpp:117
StrictMock< MockContractDB > contract_db
SimulatorResult simulate(fuzzer::FuzzerWorldStateManager &ws_mgr, fuzzer::FuzzerContractDB &contract_db, const Tx &tx, const GlobalVariables &globals, const std::vector< bb::crypto::merkle_tree::PublicDataLeafValue > &public_data_writes, const std::vector< FF > &note_hashes, const ProtocolContracts &protocol_contracts) override
Definition simulator.cpp:82
uses the yarn-project/simulator to simulate the bytecode Singleton, because initializing the simulato...
Definition simulator.hpp:88
SimulatorResult simulate(fuzzer::FuzzerWorldStateManager &ws_mgr, fuzzer::FuzzerContractDB &contract_db, const Tx &tx, const GlobalVariables &globals, const std::vector< bb::crypto::merkle_tree::PublicDataLeafValue > &public_data_writes, const std::vector< FF > &note_hashes, const ProtocolContracts &protocol_contracts) override
static JsSimulator * getInstance()
static JsSimulator * instance
Definition simulator.hpp:90
std::string simulator_path
Definition simulator.hpp:91
static void initialize(std::string &simulator_path)
JsSimulator(std::string &simulator_path)
Process process
Definition simulator.hpp:93
std::string read_line() const
Reads a line from the process.
Definition process.cpp:70
void write_line(const std::string &line) const
Ends line with a newline character, sends to the process.
Definition process.cpp:49
TxSimulationResult simulate_fast_with_existing_ws(simulation::ContractDBInterface &raw_contract_db, const world_state::WorldStateRevision &world_state_revision, world_state::WorldState &ws, const PublicSimulatorConfig &config, const Tx &tx, const GlobalVariables &global_variables, const ProtocolContracts &protocol_contracts, simulation::CancellationTokenPtr cancellation_token=nullptr)
world_state::WorldState & get_world_state()
Definition dbs.hpp:96
static const char * get_data_dir()
Definition dbs.hpp:104
world_state::WorldStateRevision get_current_revision() const
Definition dbs.cpp:206
constexpr uint256_t slice(uint64_t start, uint64_t end) const
Holds the Merkle trees responsible for storing the state of the Aztec protocol.
#define vinfo(...)
Definition log.hpp:94
uint8_t buffer[RANDOM_BUFFER_SIZE]
Definition engine.cpp:34
FuzzerWorldStateManager * ws_mgr
Definition fuzz.test.cpp:16
std::pair< uint8_t *, size_t > msgpack_encode_buffer(auto &&obj, uint8_t *scratch_buf=nullptr, size_t scratch_size=0)
FF compute_calldata_hash(std::span< const FF > calldata)
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
bool compare_simulator_results(SimulatorResult &result1, SimulatorResult &result2)
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, const std::vector< FF > &note_hashes, const ProtocolContracts &protocol_contracts)
Definition simulator.cpp:37
Tx create_default_tx(const AztecAddress &contract_address, const AztecAddress &sender_address, const std::vector< FF > &calldata, const FF &transaction_fee, bool is_static_call, const Gas &gas_limit)
GlobalVariables create_default_globals()
Definition simulator.cpp:68
constexpr auto MAX_RETURN_DATA_SIZE_IN_FIELDS
Definition simulator.cpp:34
TreeSnapshots end_tree_snapshots
Definition simulator.hpp:49
PublicTxEffect public_tx_effect
Definition simulator.hpp:51
std::vector< FF > output
Definition simulator.hpp:48
std::vector< FF > note_hashes
Definition avm_io.hpp:318
uint128_t fee_per_da_gas
std::vector< ScopedL2ToL1Message > l2_to_l1_msgs
Definition avm_io.hpp:539
std::string hash
Definition avm_io.hpp:330
PublicTxEffect public_tx_effect
Definition avm_io.hpp:552
std::vector< CallStackMetadata > call_stack_metadata
Definition avm_io.hpp:554
std::optional< PublicInputs > public_inputs
Definition avm_io.hpp:557