Skip to content

feat: panicking on direct calls to external funcs#18126

Merged
benesjan merged 1 commit intonextfrom
10-31-feat_panicking_on_direct_calls_to_external_funcs
Nov 9, 2025
Merged

feat: panicking on direct calls to external funcs#18126
benesjan merged 1 commit intonextfrom
10-31-feat_panicking_on_direct_calls_to_external_funcs

Conversation

@benesjan
Copy link
Contributor

@benesjan benesjan commented Oct 31, 2025

Fixes F-27

Given #[private] fn foo() we want for foo() to issue a compilation error. To achieve that we need to replace the function's body with a static_assert(false).

Given that the #[external(...)] macro is being processed before the #[aztec] macro we can do the following:

  1. In the #[external(...)] macro invocation I register the function into 3 global variables based on the external type (private, public or utility),
  2. then in the #[aztec] macros for each of these functions I generate a new function with __aztecnr_internals__ prefix by taking the original function's args and body, doing the same transformation on it as we do now for external funcs and then I inject these new functions into the contract,
  3. then I replace the body of the original function's static_assert(false, "yo, go check the docs how to actually call a function");
  4. for the functions that are currently injected by the #[aztec] macro (e.g. sync_private_state) I would not apply the #[external(...)] macro attribute as is currently done but instead I would just directly call the "transformation function" on it that is also used in step 3 and then inject the function.

Note that this PR is currently not mergeable as I needed to disable caching in BB to get a fresh AVM transpiler + there is a broken test. Both of these are (most likely) unrelated to this PR so I think this can be already reviewed.

@benesjan benesjan force-pushed the 10-31-feat_panicking_on_direct_calls_to_external_funcs branch 3 times, most recently from b4943a1 to b4a5454 Compare November 4, 2025 14:55
@benesjan benesjan changed the base branch from next to graphite-base/18126 November 4, 2025 20:05
@benesjan benesjan force-pushed the 10-31-feat_panicking_on_direct_calls_to_external_funcs branch from 728ea91 to 9c49f01 Compare November 4, 2025 20:05
@benesjan benesjan changed the base branch from graphite-base/18126 to 10-17-refactor_moving_atec-nargo_init_to_aztec November 4, 2025 20:05
@benesjan benesjan marked this pull request as ready for review November 4, 2025 23:15
@benesjan benesjan marked this pull request as draft November 5, 2025 00:33
@benesjan benesjan force-pushed the 10-17-refactor_moving_atec-nargo_init_to_aztec branch from b0bd5bd to 7ff9178 Compare November 5, 2025 16:10
@benesjan benesjan force-pushed the 10-31-feat_panicking_on_direct_calls_to_external_funcs branch from 201dd56 to 4b8cc14 Compare November 5, 2025 16:10

for function in contract.functions {
if function.custom_attributes.contains(&"public".to_string()) {
if function.custom_attributes.contains(&"abi_public".to_string()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed the attribute from public to abi_public because now the dev never sees it and abi_public is used only to inform the artifact generation regarding what type of function it is.

abi_public is a much better name as it's way more searchable and it makes it clearer that now it's just a low-level thing.


pub(crate) comptime fn transform_private(f: FunctionDefinition) -> Quoted {
// TODO(benesjan): This function should only generate the new function's quote. Move the following to a different
// place.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a followup PR I would rename these functions and make them solely new function quote-generation focused.

///
/// # Important
/// This function needs to be run before transformations modifying the signature of the target function `f` are applied
/// (e.g. transform_private).
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer relevant as the original is now not getting transformed.

@@ -249,36 +264,45 @@ comptime fn generate_contract_library_method_compute_note_hash_and_nullifier() -
}

comptime fn generate_sync_private_state() -> Quoted {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is quite a big change as now I could not apply the external utility macro to the functions because the transformation functionality would not get triggered as that is handled in the aztec macro which is currently being processed here.

So I needed to do the transformation manually. The ugliest here is the manual creation of the funciton abi exports but I would say it's ok.

@benesjan benesjan marked this pull request as ready for review November 5, 2025 18:18
@benesjan benesjan added the ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure label Nov 5, 2025
@benesjan benesjan requested a review from nventuro November 5, 2025 20:29
@benesjan benesjan force-pushed the 10-17-refactor_moving_atec-nargo_init_to_aztec branch from 80e26bf to 2102b17 Compare November 6, 2025 22:00
@benesjan benesjan force-pushed the 10-17-refactor_moving_atec-nargo_init_to_aztec branch from 2102b17 to 69a40c3 Compare November 7, 2025 20:21
@benesjan benesjan force-pushed the 10-31-feat_panicking_on_direct_calls_to_external_funcs branch from 346fe6e to 78376ff Compare November 7, 2025 20:21
Copy link
Contributor

@nventuro nventuro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for swimming through the macro mud!

export BB=${BB:-"$REPO_ROOT/barretenberg/cpp/build/bin/bb"}
export NARGO=${NARGO:-"$REPO_ROOT/noir/noir-repo/target/release/nargo"}
export TRANSPILER=${TRANSPILER:-"$REPO_ROOT/avm-transpiler/target/release/avm-transpiler"}
export STRIP_INTERNAL_PREFIX=${STRIP_INTERNAL_PREFIX:-"$REPO_ROOT/noir-projects/noir-contracts/scripts/strip_internal_prefix.sh"}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'internal' is maybe a complicated term given that #[internal] is a thing no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a point. Renamed it to strip_aztec_nr_prefix.sh.

Comment on lines +213 to +214
// #[initializer], and #[noinitcheck]. Since we cannot enforce a specific ordering between these modifiers and
// #[external(...)], and we cannot access the #[external(...)] argument from within these modifiers' implementations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could check this in the #[aztec] macro no? Go through all utility fns and check they're correct etc. Essentially first collect all atrtributes, put them in the registry, and then do all the work in one pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right that now we could. Now it's possible because we have the external macro add the function definitions to the corresponding to the corresponding external function registry by type. So we can move these checks there.

That will be cleaner.

Will take a note to do it.

Comment on lines +229 to +230
// TODO(benesjan): This function should only generate the new function's quote. Move the following to a different
// place.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following what?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meant the following line where is the call to register_public_fn_stubs. I've already did the change in a PR up the stack so will not clarify this here to avoid unnecessary conflicts.

Comment on lines +1 to +4
//! The functionality in this module is triggered by the `#[aztec]` macro. It generates new functions, prefixed with
//! `__aztec_nr_internals___`, from the ones marked with `#[external(...)]` attributes. The original functions are then
//! modified to be uncallable. This prevents developers from inadvertently calling a function directly, instead of
//! performing a proper contract call.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When did you start doing these module comments?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I learnt from you that they exist. Do you like it?

Comment on lines +70 to +74
// We call a function whose name is prefixed with `__aztec_nr_internals__`. This is necessary because the
// original function is intentionally made uncallable, preventing direct invocation within the contract.
// Instead, a new function with the same name, but prefixed by `__aztec_nr_internals__`, has been generated to
// be called here. For more details see the `process_functions` function.
let name = f"__aztec_nr_internals__{fn_name}".quoted_contents();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this right? Don't we want to keep the original name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point we've made the original external functions uncallable by injecting the static assert and hence here in the public dispatch we need to use the modified naming that invokes the modified generated functions.

@benesjan benesjan marked this pull request as draft November 8, 2025 22:17
@benesjan benesjan force-pushed the 10-17-refactor_moving_atec-nargo_init_to_aztec branch from 69a40c3 to c263145 Compare November 8, 2025 22:18
@benesjan benesjan force-pushed the 10-31-feat_panicking_on_direct_calls_to_external_funcs branch from 78376ff to 69667c0 Compare November 8, 2025 22:18
@AztecBot AztecBot force-pushed the 10-17-refactor_moving_atec-nargo_init_to_aztec branch from c263145 to 1e6a6a6 Compare November 8, 2025 22:38
Base automatically changed from 10-17-refactor_moving_atec-nargo_init_to_aztec to next November 8, 2025 23:11
@benesjan benesjan force-pushed the 10-31-feat_panicking_on_direct_calls_to_external_funcs branch from 5ef6d41 to d5d1f0d Compare November 8, 2025 23:16
@benesjan benesjan marked this pull request as ready for review November 8, 2025 23:18
@benesjan benesjan enabled auto-merge November 8, 2025 23:18
@AztecBot
Copy link
Collaborator

AztecBot commented Nov 8, 2025

Flakey Tests

🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry.

\033[38;2;188;109;208mFLAKED\033[0m (\033[38;2;250;217;121m8;;http://ci.aztec-labs.com/75fa720da8e80ab0�75fa720da8e80ab08;;�\033[0m): BOX=react BROWSER=firefox run_compose_test react-firefox box boxes (76s) (code: 1) (\033[38;2;188;109;208mJan Beneš\033[0m: feat: panicking on direct calls to external funcs (#18126))

@benesjan benesjan added this pull request to the merge queue Nov 8, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Nov 9, 2025
@benesjan benesjan added this pull request to the merge queue Nov 9, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Nov 9, 2025
@benesjan benesjan added this pull request to the merge queue Nov 9, 2025
Merged via the queue into next with commit 9b3b5ff Nov 9, 2025
17 checks passed
@benesjan benesjan deleted the 10-31-feat_panicking_on_direct_calls_to_external_funcs branch November 9, 2025 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants