Aztec Compiler Bug Report
Bug Description
When duplicate #[external("public")] annotations are present on a function, the compiler reports "Public function selector collision detected". However, removing one of the duplicate annotations causes the entire contract's macro expansion to fail with 70+ additional errors about storage members not being found.
This creates a catch-22 situation where:
- Keeping the duplicates causes selector collision errors
- Removing the duplicates breaks the entire contract compilation
Environment
- Aztec version: v4.0.0-devnet.1-patch.0
- Component: aztec-nargo compile
- Noir contracts: Using aztec-nr dependency from tag v4.0.0-devnet.1-patch.0
- Platform: macOS (Darwin 24.6.0)
Steps to Reproduce
- Create a contract function with duplicate #[external("public")] annotations:
#[external("public")]
#[external("public")]
fn some_function(value: Field) {
let current = storage.some_field.read();
storage.some_field.write(current + value);
}
-
Run aztec-nargo compile
-
Observe error:
error: Public function selector collision detected between functions 'some_function' and 'some_function'
-
Remove one #[external("public")] annotation to fix the collision
-
Run aztec-nargo compile again
-
Observe ~70+ new errors like:
error: Type fn(TypeDefinition) -> Quoted has no member named some_field
error: Type fn(TypeDefinition) -> Quoted has no member named [other_storage_fields]
error: cannot find 'context' in this scope
Expected Behavior
Removing the duplicate #[external("public")] annotation should:
- Fix the selector collision error
- Allow the contract to compile successfully
- Not affect the #[aztec] macro expansion or storage access
Actual Behavior
Removing the duplicate annotation causes the #[aztec] macro to fail to properly expand, resulting in:
- Storage fields becoming inaccessible throughout the entire contract
- context variable not being available in function scope
- All storage operations failing with type errors
- The entire contract becoming uncompilable
Workaround
Currently, the only way to compile is to keep the duplicate annotations, which results in "selector collision" errors but allows the contract to otherwise compile successfully.
Additional Context
- Other functions in the same files with single #[external("public")] annotations work correctly
- This appears to be a bug in the macro system where the duplicate annotations somehow affect the macro expansion process
- The issue is reproducible across different functions and contracts
Attempted Fix Using Official Pattern
According to official Aztec examples (aztec-examples repository), internal helper functions should use the #[only_self] annotation pattern:
#[only_self]
#[external("public")]
fn _helper_function() {
// function body
}
This pattern is used consistently across official examples including:
- prediction-market contract (_process_buy function)
- recursive_verification contract (_increment_public function)
- account-contract (set_hashed_password function)
However, when this pattern is applied to v4.0.0-devnet.1-patch.0:
- Replacing duplicate annotations with #[only_self] + single #[external("public")]
- Results in 100+ compilation errors across the entire codebase
- Macro expansion fails for multiple unrelated functions
- Errors include storage member access failures and context scope issues
This suggests:
- The #[only_self] annotation may not be supported in v4.0.0-devnet.1-patch.0
- There may be a version incompatibility between the official examples and this devnet release
- The duplicate annotation workaround may be necessary for this specific version
Impact
- Severity: High - Blocks proper compilation
- Workaround: Available but produces compilation errors
- Scope: Affects contracts with duplicate external annotations
Minimal Reproducible Example
use ::aztec::macros::aztec;
#[aztec]
pub contract TestContract {
use ::aztec::{
macros::{functions::{external, initializer}, storage::storage},
};
use ::aztec::state_vars::{PublicMutable};
#[storage]
struct Storage<Context> {
counter: PublicMutable<Field, Context>,
}
#[external("public")]
#[initializer]
fn constructor() {
storage.counter.write(0);
}
// This function has the problematic duplicate annotation
#[external("public")]
#[external("public")]
fn increment() {
let current = storage.counter.read();
storage.counter.write(current + 1);
}
}
Result:
- With duplicate annotations: Selector collision error
- Without duplicate (correct code): 70+ macro expansion errors
Suggested Fix
The compiler should:
- Detect and reject duplicate #[external] annotations with a clear error message
- Not require duplicate annotations for proper macro expansion
- Ensure macro expansion is independent of annotation duplication
- Support the #[only_self] annotation pattern from official examples in devnet versions
- Provide clear migration guidance for version-specific annotation patterns
Related Issues
Aztec Compiler Bug Report
Bug Description
When duplicate #[external("public")] annotations are present on a function, the compiler reports "Public function selector collision detected". However, removing one of the duplicate annotations causes the entire contract's macro expansion to fail with 70+ additional errors about storage members not being found.
This creates a catch-22 situation where:
Environment
Steps to Reproduce
#[external("public")]
#[external("public")]
fn some_function(value: Field) {
let current = storage.some_field.read();
storage.some_field.write(current + value);
}
Run aztec-nargo compile
Observe error:
error: Public function selector collision detected between functions 'some_function' and 'some_function'
Remove one #[external("public")] annotation to fix the collision
Run aztec-nargo compile again
Observe ~70+ new errors like:
error: Type fn(TypeDefinition) -> Quoted has no member named some_field
error: Type fn(TypeDefinition) -> Quoted has no member named [other_storage_fields]
error: cannot find 'context' in this scope
Expected Behavior
Removing the duplicate #[external("public")] annotation should:
Actual Behavior
Removing the duplicate annotation causes the #[aztec] macro to fail to properly expand, resulting in:
Workaround
Currently, the only way to compile is to keep the duplicate annotations, which results in "selector collision" errors but allows the contract to otherwise compile successfully.
Additional Context
Attempted Fix Using Official Pattern
According to official Aztec examples (aztec-examples repository), internal helper functions should use the #[only_self] annotation pattern:
#[only_self]
#[external("public")]
fn _helper_function() {
// function body
}
This pattern is used consistently across official examples including:
However, when this pattern is applied to v4.0.0-devnet.1-patch.0:
This suggests:
Impact
Minimal Reproducible Example
use ::aztec::macros::aztec;
#[aztec]
pub contract TestContract {
use ::aztec::{
macros::{functions::{external, initializer}, storage::storage},
};
use ::aztec::state_vars::{PublicMutable};
}
Result:
Suggested Fix
The compiler should:
Related Issues