Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
call_stack_metadata_collector.cpp
Go to the documentation of this file.
2
7
8namespace bb::avm2::simulation {
9
14
16{
17 // Check call stack depth limit (size - 1 because we have a dummy root).
19 return true;
20 }
21 // Check total call stack items limit.
23 return true;
24 }
25 return false;
26}
27
29 uint32_t caller_pc,
30 const CalldataProvider& calldata_provider,
31 bool is_static_call,
32 const Gas& gas_limit)
33{
34 assert(!call_stack_metadata.empty());
35
36 // Check if we should stop collecting due to limits.
38 return;
39 }
40
41 call_stack_metadata.top().num_nested_calls++;
43
44 // Use configured limit or default.
45 uint32_t max_calldata_size = limits.max_calldata_size_in_fields > 0 ? limits.max_calldata_size_in_fields : 1024;
46 std::vector<FF> calldata = calldata_provider(max_calldata_size);
47
49 .timestamp = timestamp++,
50 .phase = current_phase,
51 .contract_address = contract_address,
52 .caller_pc = caller_pc,
53 .calldata = calldata,
54 .is_static_call = is_static_call,
55 .gas_limit = gas_limit,
56 // To be filled in by the exit call or further nested calls.
57 .reverted = false,
58 .nested = {},
59 .internal_call_stack_at_exit = {},
60 .num_nested_calls = 0,
61 });
62}
63
65 uint32_t pc,
66 const std::optional<std::string>& halting_message,
67 const ReturnDataProvider& return_data_provider,
68 const InternalCallStackProvider& internal_call_stack_provider)
69{
70 // If we only have the dummy root, we skipped collection for this call.
71 if (call_stack_metadata.size() <= 1) {
72 return;
73 }
74
75 // Use configured limit or default.
76 uint32_t max_return_data_size =
78 std::vector<FF> return_data = return_data_provider(max_return_data_size);
79 std::vector<PC> internal_call_stack = internal_call_stack_provider();
80 internal_call_stack.push_back(pc);
81
82 CallStackMetadata top_call_stack_metadata = call_stack_metadata.top();
83 top_call_stack_metadata.reverted = !success;
84 top_call_stack_metadata.halting_message = std::move(halting_message);
85 top_call_stack_metadata.output = std::move(return_data);
87
88 // While exiting, we will move the top call of the stack to the nested vector of the parent call.
89 assert(call_stack_metadata.size() > 1);
91 call_stack_metadata.top().nested.push_back(std::move(top_call_stack_metadata));
92}
93
94void CallStackMetadataCollector::notify_tx_revert(const std::string& revert_message)
95{
96 // Create a synthetic CallStackMetadata entry to capture the revert reason.
97 // This is used when a tx-level revert happens outside of an enqueued call
98 // (e.g., during revertible insertions from private).
99 assert(call_stack_metadata.size() == 1);
100 call_stack_metadata.top().nested.push_back({
101 .timestamp = timestamp++,
102 .phase = current_phase,
103 .contract_address = 0, // No specific contract
104 .caller_pc = 0,
105 .calldata = {},
106 .is_static_call = false,
107 .gas_limit = {},
108 .output = {},
109 .reverted = true,
110 .nested = {},
111 .internal_call_stack_at_exit = {},
112 .halting_message = revert_message,
113 .num_nested_calls = 0,
114 });
115}
116
122
124{
125 auto cd_offset = context.get_parent_cd_addr();
126 auto cd_size = context.get_parent_cd_size();
127 return [&context, cd_offset, cd_size](uint32_t max_size) -> std::vector<FF> {
128 try {
129 // TODO: check if this will pad to size. We don't want that.
130 auto data = context.get_calldata(cd_offset, std::min(max_size, cd_size));
131 return std::vector<FF>(data.begin(), data.end());
132 } catch (...) {
133 vinfo("Failed to collect calldata (to:",
134 context.get_address(),
135 " pc:",
136 context.get_pc(),
137 " cd_offset:",
138 cd_offset,
139 " cd_size:",
140 cd_size,
141 " max_size:",
142 max_size,
143 ")");
144 return {};
145 }
146 };
147}
148
149ReturnDataProvider make_return_data_provider(const ContextInterface& context, uint32_t rd_offset, uint32_t rd_size)
150{
151 return [&context, rd_offset, rd_size](uint32_t max_size) -> std::vector<FF> {
152 try {
153 const auto& memory = context.get_memory();
154 std::vector<FF> data;
155 data.reserve(std::min(max_size, rd_size));
156 for (uint32_t i = 0; i < std::min(max_size, rd_size); i++) {
157 data.push_back(memory.get(rd_offset + i).as_ff());
158 }
159 return data;
160 } catch (...) {
161 vinfo("Failed to collect returndata (to:",
162 context.get_address(),
163 " pc:",
164 context.get_pc(),
165 " rd_offset:",
166 rd_offset,
167 " rd_size:",
168 rd_size,
169 " max_size:",
170 max_size,
171 ")");
172 return {};
173 }
174 };
175}
176
178 const InternalCallStackManagerInterface& internal_call_stack_manager)
179{
180 return [&internal_call_stack_manager]() -> std::vector<PC> {
181 return internal_call_stack_manager.get_current_call_stack();
182 };
183}
184
185} // namespace bb::avm2::simulation
void notify_exit_call(bool success, uint32_t pc, const std::optional< std::string > &halting_message, const ReturnDataProvider &return_data_provider, const InternalCallStackProvider &internal_call_stack_provider) override
void set_phase(CoarseTransactionPhase phase) override
std::vector< CallStackMetadata > dump_call_stack_metadata() override
void notify_enter_call(const AztecAddress &contract_address, uint32_t caller_pc, const CalldataProvider &calldata_provider, bool is_static_call, const Gas &gas_limit) override
void notify_tx_revert(const std::string &revert_message) override
virtual std::vector< PC > get_current_call_stack() const =0
#define vinfo(...)
Definition log.hpp:80
const std::vector< MemoryValue > data
std::function< std::vector< PC >()> InternalCallStackProvider
InternalCallStackProvider make_internal_call_stack_provider(const InternalCallStackManagerInterface &internal_call_stack_manager)
ReturnDataProvider make_return_data_provider(const ContextInterface &context, uint32_t rd_offset, uint32_t rd_size)
std::function< std::vector< FF >(uint32_t max_size)> CalldataProvider
std::function< std::vector< FF >(uint32_t max_size)> ReturnDataProvider
CalldataProvider make_calldata_provider(const ContextInterface &context)
CoarseTransactionPhase
Definition avm_io.hpp:482
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
uint32_t cd_offset
std::vector< PC > internal_call_stack_at_exit
Definition avm_io.hpp:515
std::optional< std::string > halting_message
Definition avm_io.hpp:516
std::vector< FF > output
Definition avm_io.hpp:511