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 PC caller_pc,
30 const CalldataProvider& calldata_provider,
31 bool is_static_call,
32 const Gas& gas_limit)
33{
34 BB_ASSERT(!call_stack_metadata.empty(), "Call stack metadata is 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 std::vector<FF> calldata = calldata_provider(limits.max_calldata_size_in_fields);
45
47 .timestamp = timestamp++,
48 .phase = current_phase,
49 .contract_address = contract_address,
50 .caller_pc = caller_pc,
51 .calldata = std::move(calldata),
52 .is_static_call = is_static_call,
53 .gas_limit = gas_limit,
54 // To be filled in by the exit call or further nested calls.
55 .reverted = false,
56 .nested = {},
57 .internal_call_stack_at_exit = {},
58 .num_nested_calls = 0,
59 });
60}
61
63 PC pc,
64 const std::optional<std::string>& halting_message,
65 const ReturnDataProvider& return_data_provider,
66 const InternalCallStackProvider& internal_call_stack_provider)
67{
68 // If we only have the dummy root, we skipped collection for this call.
69 if (call_stack_metadata.size() <= 1) {
70 return;
71 }
72
73 std::vector<FF> return_data = return_data_provider(limits.max_returndata_size_in_fields);
74 std::vector<PC> internal_call_stack = internal_call_stack_provider();
75 internal_call_stack.push_back(pc);
76
77 CallStackMetadata top_call_stack_metadata = call_stack_metadata.top();
78 top_call_stack_metadata.reverted = !success;
79 top_call_stack_metadata.halting_message = std::move(halting_message);
80 top_call_stack_metadata.output = std::move(return_data);
82
83 // While exiting, we will move the top call of the stack to the nested vector of the parent call.
84 BB_ASSERT_GT(call_stack_metadata.size(), static_cast<size_t>(1), "Call stack metadata size is not greater than 1");
86 call_stack_metadata.top().nested.push_back(std::move(top_call_stack_metadata));
87}
88
89void CallStackMetadataCollector::notify_tx_revert(const std::string& revert_message)
90{
91 // Create a synthetic CallStackMetadata entry to capture the revert reason.
92 // This is used when a tx-level revert happens outside of an enqueued call
93 // (e.g., during revertible insertions from private).
94 BB_ASSERT_EQ(call_stack_metadata.size(), static_cast<size_t>(1), "Call stack metadata size is not equal to 1");
95 call_stack_metadata.top().nested.push_back({
96 .timestamp = timestamp++,
97 .phase = current_phase,
98 .contract_address = 0, // No specific contract
99 .caller_pc = 0,
100 .calldata = {},
101 .is_static_call = false,
102 .gas_limit = {},
103 .output = {},
104 .reverted = true,
105 .nested = {},
106 .internal_call_stack_at_exit = {},
107 .halting_message = revert_message,
108 .num_nested_calls = 0,
109 });
110}
111
113{
114 BB_ASSERT_EQ(call_stack_metadata.size(), static_cast<size_t>(1), "Call stack metadata size is not equal to 1");
115 return std::move(call_stack_metadata.top().nested);
116}
117
119{
120 auto cd_size = context.get_parent_cd_size();
121 return [&context, cd_size](uint32_t max_size) -> std::vector<FF> {
122 // NOTE: get_calldata will handle offsetting into parent memory for nested contexts
123 // In principle, get_calldata would pad, but this shouldn't happen since we always ask for less than cd_size.
124 auto data = context.get_calldata(0, std::min(max_size, cd_size));
125 // Convert MemoryValue to FF.
126 return std::vector<FF>(data.begin(), data.end());
127 };
128}
129
131 uint32_t rd_mem_offset_in_child,
132 uint32_t rd_size)
133{
134 return [&context, rd_mem_offset_in_child, rd_size](uint32_t max_size) -> std::vector<FF> {
135 // NOTE: We can't use get_returndata here because that needs the parent and not the child context.
136 // Passing the parent context to this method gives other problems like handling top-level returns.
137 const auto& memory = context.get_memory();
138 std::vector<FF> data;
139 uint32_t effective_rd_size = std::min(max_size, rd_size);
140 data.reserve(effective_rd_size);
141 // This will copy effective_rd_size elements from returndata and will not pad.
142 for (uint32_t i = 0; i < effective_rd_size; i++) {
143 data.push_back(memory.get(rd_mem_offset_in_child + i).as_ff());
144 }
145 return data;
146 };
147}
148
150 const InternalCallStackManagerInterface& internal_call_stack_manager)
151{
152 return [&internal_call_stack_manager]() -> std::vector<PC> {
153 return internal_call_stack_manager.get_current_call_stack();
154 };
155}
156
157} // namespace bb::avm2::simulation
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
#define BB_ASSERT_GT(left, right,...)
Definition assert.hpp:113
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
void notify_exit_call(bool success, PC 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, PC 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
const std::vector< MemoryValue > data
std::function< std::vector< PC >()> InternalCallStackProvider
InternalCallStackProvider make_internal_call_stack_provider(const InternalCallStackManagerInterface &internal_call_stack_manager)
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)
ReturnDataProvider make_return_data_provider(const ContextInterface &context, uint32_t rd_mem_offset_in_child, uint32_t rd_size)
uint32_t PC
CoarseTransactionPhase
Definition avm_io.hpp:482
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
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