-
Notifications
You must be signed in to change notification settings - Fork 224
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example of an unexpectedly-huge contract artifact. #6786
Comments
@aakoshh Do you have bandwidth to take a look at this? |
The first jump I found in the size was AztecProtocol/aztec-packages@3304046 where the Commands to check: PROGRAM_DIR=$PWD/noir-projects/noir-contracts
git checkout 3304046704e257902e32b86baf1aafc8b23bcaf6
cd noir/noir-repo
cargo run --release -p nargo_cli -- --program-dir $PROGRAM_DIR compile --package stateful_test_contract
jq '.functions | sort_by(.name) | .[] | {name: .name, size: .bytecode | length }' $PROGRAM_DIR/target/stateful_test_contract-StatefulTest.json |
Within the syncing PR AztecProtocol/aztec-packages#10307 that backs the above squashed commit, the two commits where there are significant bytecode size increases for
|
The following is the printout of the number of lines in the SSA in AztecProtocol/aztec-packages@369ea54
We can see that there is a dramatic increase in the Compare it with the same in its parent commit AztecProtocol/aztec-packages@0577c1a
In this version Further digging revealed that Printing the number of arrays reveals where they get introduced. This is in 0577c1a
And this is in 369ea54:
The numbers show the count of of arrays that would be merged in the entry block of the functions, the only block IfElse counter let mut count = 0;
let block = function.entry_block();
for instruction in function.dfg[block].instructions() {
if let Instruction::IfElse { then_condition: _, then_value, else_value: _ } =
function.dfg[*instruction]
{
let then_value = function.dfg.resolve(then_value);
if let Type::Array(..) = function.dfg.type_of_value(then_value) {
count += 1;
}
}
} So the question is why has One further thing to look at would be whether there were more stores to arrays in this commit then before.
whereas after there are more if-then-else and less stores, but the if-then-else's don't get eliminated, which then plays a magnified role during
|
Looking at what is causing the following:
Printing SSA sizes does not reveal any smoking gun, the numbers are similar to above.
Whereas in 70cf870f we have a smaller SSA, but the final ACIR opcode count is 5x larger:
The following are the statistics of how many ACIR opcodes were generated from how many encountered In feef655:
In 70cf870f:
The biggest visible change is in the ratio of opcodes generated from Just looking at binary instructions originally:
and then after the new commit:
Further digging revealed that the difference in the number of instructions generated comes from check_unsigned_overflow: previously we only generated 434 constraints, but with the new commit the number is 471,411. The following show the number of times
And in the new commit:
It shows that we switched from doing mostly signed to mostly unsigned binary operations, which is what induced the creation of the new range constraints. The cause of this change is how the rules in the ValueMerger::merge_numeric_valuespub(crate) fn merge_numeric_values(
dfg: &mut DataFlowGraph,
block: BasicBlockId,
then_condition: ValueId,
else_condition: ValueId,
then_value: ValueId,
else_value: ValueId,
) -> ValueId {
let then_type = dfg.type_of_value(then_value);
let else_type = dfg.type_of_value(else_value);
assert_eq!(
then_type, else_type,
"Expected values merged to be of the same type but found {then_type} and {else_type}"
);
if then_value == else_value {
return then_value;
}
let then_call_stack = dfg.get_value_call_stack(then_value);
let else_call_stack = dfg.get_value_call_stack(else_value);
let call_stack = if then_call_stack.is_empty() { else_call_stack } else { then_call_stack };
let then_field = Instruction::Cast(then_value, Type::field());
let then_field_value =
dfg.insert_instruction_and_results(then_field, block, None, call_stack.clone()).first();
let else_field = Instruction::Cast(else_value, Type::field());
let else_field_value =
dfg.insert_instruction_and_results(else_field, block, None, call_stack.clone()).first();
// We must cast the bool conditions to the actual numeric type used by each value.
let then_condition = dfg
.insert_instruction_and_results(
Instruction::Cast(then_condition, Type::field()),
block,
None,
call_stack.clone(),
)
.first();
let else_condition = dfg
.insert_instruction_and_results(
Instruction::Cast(else_condition, Type::field()),
block,
None,
call_stack.clone(),
)
.first();
let mul = Instruction::binary(BinaryOp::Mul, then_condition, then_field_value);
let then_value =
dfg.insert_instruction_and_results(mul, block, None, call_stack.clone()).first();
let mul = Instruction::binary(BinaryOp::Mul, else_condition, else_field_value);
let else_value =
dfg.insert_instruction_and_results(mul, block, None, call_stack.clone()).first();
let add = Instruction::binary(BinaryOp::Add, then_value, else_value);
let add_field_value =
dfg.insert_instruction_and_results(add, block, None, call_stack.clone()).first();
let merged = Instruction::Cast(add_field_value, then_type);
dfg.insert_instruction_and_results(merged, block, None, call_stack).first()
} With this modification, the results would be:
The problem, of course, is that this would be potentially unsafe as it would not detect overflows, which is probably why it was reverted. OTOH we're only using it in combination with a boolean conditional variable, so it should be Most probably the effect of this range check is exacerbated by the previous change, which causes Note that even with the change above to use |
The next larger change to the overall size shown by (I'll keep updating the comment if I find anything). Within the PR it is the transition from AztecProtocol/aztec-packages@7a66f06 to AztecProtocol/aztec-packages@9c79a87 that sees the size go from 42MB to 64MB Unfortunately this 9c79a87 is a merge from None of these files are under the |
@aakoshh I don't know if you've seen my comment but there the cause of blowup is pretty clear. Might make sense to investigate that first as the cause of the blowup of the stateful contract seems hard to point down (might be the same issue). |
AztecProtocol/aztec-packages#10546
In particular,
create_note
andcreate_note_no_init_check
https://github.com/AztecProtocol/aztec-packages/blob/6f209fb69fcce868c6e0fe9b79b5ac3f3a1e5c48/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr#L45
The text was updated successfully, but these errors were encountered: