Skip to content

Commit 08d4d25

Browse files
authored
fix: ensure empty BlockConstraints are handled gracefully in dsl (#18128)
Fixes reported assertion failure arising from processing empty `BlockConstraint`s. Observed in the wild with type `ReturnData` but issue was also present for `CallData`. Observed in `wormhole::publish_message_in_private` function [here](https://github.com/wormhole-foundation/wormhole/blob/7060126e9d2d70bcaa9488d2659e9708a8d1f230/aztec/contracts/src/main.nr#L137). Details: Empty ReturnData constraint generated from noir program bytecode would crash with: `Assertion failed: (context != nullptr)`, specifically in `bus_vector::set_values()` which couldn't extract a Builder context from an empty initialization vector, leaving `context` as nullptr. Solution: Explicitly set Builder context before calling `set_values()` in both ReturnData and CallData processing Note: New test `EmptyBlockConstraints` verifies all 4 block types (ROM, RAM, CallData, ReturnData) handle empty init gracefully. (Fix was required for only CallData and ReturnData).
2 parents ee83478 + 4e3500d commit 08d4d25

File tree

4 files changed

+44
-3
lines changed

4 files changed

+44
-3
lines changed

barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ void create_block_constraints(MegaCircuitBuilder& builder,
9393
process_call_data_operations(builder, constraint, has_valid_witness_assignments, init);
9494
} break;
9595
case BlockType::ReturnData: {
96-
process_return_data_operations(constraint, init);
96+
process_return_data_operations(builder, constraint, init);
9797
} break;
9898
default:
9999
throw_or_abort("Unexpected block constraint type.");
@@ -169,6 +169,7 @@ void process_call_data_operations(Builder& builder,
169169

170170
// Method for processing operations on a generic databus calldata array
171171
auto process_calldata = [&](auto& calldata_array) {
172+
calldata_array.set_context(&builder);
172173
calldata_array.set_values(init); // Initialize the data in the bus array
173174

174175
for (const auto& op : constraint.trace) {
@@ -195,11 +196,15 @@ void process_call_data_operations(Builder& builder,
195196
}
196197

197198
template <typename Builder>
198-
void process_return_data_operations(const BlockConstraint& constraint, std::vector<bb::stdlib::field_t<Builder>>& init)
199+
void process_return_data_operations(Builder& builder,
200+
const BlockConstraint& constraint,
201+
std::vector<bb::stdlib::field_t<Builder>>& init)
199202
{
200203
using databus_ct = stdlib::databus<Builder>;
201204

202205
databus_ct databus;
206+
207+
databus.return_data.set_context(&builder);
203208
// Populate the returndata in the databus
204209
databus.return_data.set_values(init);
205210
// For each entry of the return data, explicitly assert equality with the initialization value. This implicitly

barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ void process_call_data_operations(Builder& builder,
5252
bool has_valid_witness_assignments,
5353
std::vector<bb::stdlib::field_t<Builder>>& init);
5454
template <typename Builder>
55-
void process_return_data_operations(const BlockConstraint& constraint, std::vector<bb::stdlib::field_t<Builder>>& init);
55+
void process_return_data_operations(Builder& builder,
56+
const BlockConstraint& constraint,
57+
std::vector<bb::stdlib::field_t<Builder>>& init);
5658

5759
template <typename B> inline void read(B& buf, MemOp& mem_op)
5860
{

barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,36 @@ TEST_F(MegaHonk, DatabusReturn)
255255

256256
EXPECT_TRUE(CircuitChecker::check(circuit));
257257
}
258+
259+
// Test that all block constraint types handle empty initialization gracefully
260+
TEST_F(MegaHonk, EmptyBlockConstraints)
261+
{
262+
// Test each block constraint type
263+
std::vector<BlockType> types_to_test = {
264+
BlockType::ROM, BlockType::RAM, BlockType::CallData, BlockType::ReturnData
265+
};
266+
267+
// Create empty block constraint
268+
for (auto block_type : types_to_test) {
269+
BlockConstraint block{
270+
.init = {}, // Empty initialization data
271+
.trace = {}, // Empty trace
272+
.type = block_type,
273+
};
274+
275+
AcirProgram program;
276+
program.constraints = {
277+
.varnum = 0, // No variables needed for empty block constraints
278+
.num_acir_opcodes = 1,
279+
.public_inputs = {},
280+
.block_constraints = { block },
281+
.original_opcode_indices = create_empty_original_opcode_indices(),
282+
};
283+
284+
mock_opcode_indices(program.constraints);
285+
286+
// Circuit construction should succeed without errors
287+
auto circuit = create_circuit<Builder>(program);
288+
EXPECT_TRUE(CircuitChecker::check(circuit));
289+
}
290+
}

barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ template <typename Builder> class databus {
4848

4949
size_t size() const { return length; }
5050
Builder* get_context() const { return context; }
51+
void set_context(Builder* builder_context) { context = builder_context; }
5152

5253
private:
5354
mutable std::vector<field_pt> entries; // bus vector entries

0 commit comments

Comments
 (0)