Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
bytecode_manager.cpp
Go to the documentation of this file.
2
3#include <cassert>
4
14
15namespace bb::avm2::simulation {
16
18{
19 BB_BENCH_NAME("TxBytecodeManager::get_bytecode");
20 // Use shared ContractInstanceManager for contract instance retrieval and validation
21 // This handles nullifier checks, address derivation, and update validation
22 auto tree_states = merkle_db.get_tree_state();
23 AppendOnlyTreeSnapshot before_snapshot = retrieved_bytecodes_tree_check.get_snapshot();
24
25 BytecodeRetrievalEvent retrieval_event = {
26 .bytecode_id = FF(0), // Use default ID for error cases
27 .address = address,
28 .nullifier_root = tree_states.nullifierTree.tree.root,
29 .public_data_tree_root = tree_states.publicDataTree.tree.root,
30 .retrieved_bytecodes_snapshot_before = before_snapshot,
31 .retrieved_bytecodes_snapshot_after = before_snapshot,
32 };
33
34 auto maybe_instance = contract_instance_manager.get_contract_instance(address);
35
36 if (!maybe_instance.has_value()) {
37 retrieval_event.instance_not_found_error = true;
38 // Contract instance not found - emit error event and throw
39 retrieval_events.emit(std::move(retrieval_event));
40 vinfo("Contract ", field_to_string(address), " is not deployed!");
41 throw BytecodeRetrievalError("Contract " + field_to_string(address) + " is not deployed");
42 }
43
44 ContractInstance instance = maybe_instance.value();
46 retrieval_event.current_class_id = current_class_id;
47
48 bool is_new_class = !retrieved_bytecodes_tree_check.contains(current_class_id);
49 retrieval_event.is_new_class = is_new_class;
50
51 uint32_t retrieved_bytecodes_count = retrieved_bytecodes_tree_check.size();
52
53 if (is_new_class && retrieved_bytecodes_count >= MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS) {
54 retrieval_event.limit_error = true;
55 retrieval_events.emit(std::move(retrieval_event));
56 throw BytecodeRetrievalError("Can't retrieve more than " +
58 " bytecodes per tx");
59 }
60
62 AppendOnlyTreeSnapshot snapshot_after = retrieved_bytecodes_tree_check.get_snapshot();
63 retrieval_event.retrieved_bytecodes_snapshot_after = snapshot_after;
64
65 // Contract class retrieval and class ID validation
67 // Note: we don't need to silo and check the class id because the deployer contract guarantees
68 // that if a contract instance exists, the class has been registered.
69 assert(maybe_klass.has_value());
70 auto& klass = maybe_klass.value();
71 retrieval_event.contract_class = klass; // WARNING: this class has the whole bytecode.
72 debug("Bytecode for ", address, " successfully retrieved!");
73
74 // Bytecode hashing and decomposition, deduplicated by bytecode_id (commitment)
75 BytecodeId bytecode_id = klass.public_bytecode_commitment;
76 retrieval_event.bytecode_id = bytecode_id;
77
78 // Check if we've already processed this bytecode. If so, don't do hashing and decomposition again!
79 if (bytecodes.contains(bytecode_id)) {
80 // Already processed this bytecode - just emit retrieval event and return
81 retrieval_events.emit(std::move(retrieval_event));
82 return bytecode_id;
83 }
84
85 // First time seeing this bytecode - check hashing and decomposition
87 bytecode_id, klass.packed_bytecode, klass.public_bytecode_commitment);
88
89 // We convert the bytecode to a shared_ptr because it will be shared by some events.
90 auto shared_bytecode = std::make_shared<std::vector<uint8_t>>(std::move(klass.packed_bytecode));
91 decomposition_events.emit({ .bytecode_id = bytecode_id, .bytecode = shared_bytecode });
92
93 // We now save the bytecode so that we don't repeat this process.
94 bytecodes.emplace(bytecode_id, std::move(shared_bytecode));
95
96 retrieval_events.emit(std::move(retrieval_event));
97
98 return bytecode_id;
99}
100
102{
103 return read_instruction(bytecode_id, get_bytecode_data(bytecode_id), pc);
104}
105
107 std::shared_ptr<std::vector<uint8_t>> bytecode_ptr,
108 uint32_t pc)
109{
110 BB_BENCH_NAME("TxBytecodeManager::read_instruction");
111
112 // We'll be filling in the event as we progress.
113 InstructionFetchingEvent instr_fetching_event;
114
115 instr_fetching_event.bytecode_id = bytecode_id;
116 instr_fetching_event.pc = pc;
117
118 const auto& bytecode = *bytecode_ptr;
119 instr_fetching_event.bytecode = std::move(bytecode_ptr);
120
121 try {
122 instr_fetching_event.instruction = deserialize_instruction(bytecode, pc);
123
124 // If the following code is executed, no error was thrown in deserialize_instruction().
125 if (!check_tag(instr_fetching_event.instruction)) {
127 };
128 } catch (const InstrDeserializationError& error) {
129 instr_fetching_event.error = error;
130 }
131
132 // We are showing whether bytecode_size > pc or not. If there is no fetching error,
133 // we always have bytecode_size > pc.
134 const auto bytecode_size = bytecode.size();
135 const uint128_t pc_diff = bytecode_size > pc ? bytecode_size - pc - 1 : pc - bytecode_size;
136 range_check.assert_range(pc_diff, AVM_PC_SIZE_IN_BITS);
137
138 // The event will be deduplicated internally.
139 fetching_events.emit(InstructionFetchingEvent(instr_fetching_event));
140
141 // Communicate error to the caller.
142 if (instr_fetching_event.error.has_value()) {
143 throw InstructionFetchingError("Instruction fetching error: " +
144 std::to_string(static_cast<int>(instr_fetching_event.error.value())));
145 }
146
147 return instr_fetching_event.instruction;
148}
149
154
155} // namespace bb::avm2::simulation
#define MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS
#define AVM_PC_SIZE_IN_BITS
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:218
virtual void assert_public_bytecode_commitment(const BytecodeId &bytecode_id, const std::vector< uint8_t > &bytecode, const FF &public_bytecode_commitment)=0
virtual std::optional< ContractClass > get_contract_class(const ContractClassId &class_id) const =0
virtual std::optional< ContractInstance > get_contract_instance(const FF &contract_address)=0
Retrieve and validate a contract instance.
virtual TreeStates get_tree_state() const =0
HighLevelMerkleDBInterface & merkle_db
EventEmitterInterface< BytecodeDecompositionEvent > & decomposition_events
EventEmitterInterface< BytecodeRetrievalEvent > & retrieval_events
EventEmitterInterface< InstructionFetchingEvent > & fetching_events
unordered_flat_map< BytecodeId, std::shared_ptr< std::vector< uint8_t > > > bytecodes
std::shared_ptr< std::vector< uint8_t > > get_bytecode_data(const BytecodeId &bytecode_id) override
BytecodeHashingInterface & bytecode_hasher
ContractInstanceManagerInterface & contract_instance_manager
BytecodeId get_bytecode(const AztecAddress &address) override
Instruction read_instruction(const BytecodeId &bytecode_id, uint32_t pc) override
#define vinfo(...)
Definition log.hpp:79
#define debug(...)
Definition log.hpp:61
bool check_tag(const Instruction &instruction)
Check whether the instruction must have a tag operand and whether the operand value is in the value t...
Instruction deserialize_instruction(std::span< const uint8_t > bytecode, size_t pos)
Parsing of an instruction in the supplied bytecode at byte position pos. This checks that the WireOpC...
FF ContractClassId
std::string field_to_string(const FF &ff)
Definition stringify.cpp:5
AvmFlavorSettings::FF FF
Definition field.hpp:10
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
std::string to_string(bb::avm2::ValueTag tag)
unsigned __int128 uint128_t
Definition serialize.hpp:44
FF current_class_id
ContractClassId current_class_id
AppendOnlyTreeSnapshot retrieved_bytecodes_snapshot_after
std::optional< InstrDeserializationError > error
std::shared_ptr< std::vector< uint8_t > > bytecode