Skip to content

Identifiers for aliases are not built properly #2041

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

Closed
enitrat opened this issue Apr 1, 2025 · 5 comments
Closed

Identifiers for aliases are not built properly #2041

enitrat opened this issue Apr 1, 2025 · 5 comments
Labels
bug Something isn't working

Comments

@enitrat
Copy link
Contributor

enitrat commented Apr 1, 2025

TLDR: I think the Identifiers for aliases are missing some useful data; example: in this test I would expect the identifier to have the full_path set to to the "destination" value - or something similar

Identifier {
pc: None,
type_: Some(String::from("alias")),
value: None,
full_name: None,
members: None,
cairo_type: None,
size: None,
},


I'm working on making all python hints compatible to use with the RustVM, and for that, i'm currently working on making the constant of the programs resolvable and accessible through an ids object.

For that I need to properly retrieve the values associated to constants.
Here are my tests (done in https://github.com/kkrt-labs/keth repo & hard to repro as i'm still fiddling around):

from ethereum.exceptions import ValueError
const MY_CONST = 100;
func test__access_local_const() {
    %{ assert ids.MY_CONST == 100 %}
    ret;
}

func test__access_non_imported_const_should_fail() {
    %{ ids.HALF_SHIFT %}
    ret;
}

func test__access_imported_const() {
    %{ assert ids.ValueError == int.from_bytes('ValueError'.encode("ascii"), "big") %}
    ret;
}

Test 1: test with a locally defined constant. This works. If I log some information, I can see that at some point, I'm doing:

Checking identifier for if __main__.MY_CONST - result: Some(Identifier { pc: None, type_: Some("const"), value: Some(0x64), full_name: None, members: None, cairo_type: None, size: None })

Test 2: verifying that non-important program constants are not accssible. works fine

Test 3: verifying if imported program constants are accessible. This however is problematic: here's what searching the Identifiers yields:

Checking identifier for __main__.ValueError - result: Some(Identifier { pc: None, type_: Some("alias"), value: None, full_name: None, members: None, cairo_type: None, size: None })

As you can see this is correctly being retrieved as an Identifier of type alias which is expected. However there's no associated value, nor any other type information.

I don't know if this is intended or not? I would expect there to be more info, perhaps, full_name resolving to the path of the constant in the program? This way I could easily use the constants argument passed in all hints execution to get the proper value.

This is happening during the execute_hint step, relevant code that I wrote:

    pub fn execute_hint(
        &mut self,
        hint_code: &str,
        vm: &mut VirtualMachine,
        exec_scopes: &mut ExecutionScopes,
        ids_data: &HashMap<String, HintReference>,
        ap_tracking: &ApTracking,
        constants: &HashMap<String, Felt252>,
        hint_accessible_scopes: &Vec<String>,
    ) -> Result<(), HintError> {
...
    for (name, value) in constants {
        // A constant is accessible if any of the hint accessible scopes is a prefix of the constant
        // name
        let name_parts = name.split('.').collect::<Vec<_>>();
        let name_parts_without_last = name_parts[..name_parts.len() - 1].join(".");
        let name_last_part = name_parts[name_parts.len() - 1].to_string();
        if hint_accessible_scopes.iter().any(|scope| name_parts_without_last == *scope) {
            println!("{} is accessible", name);
            py_ids_dict
                .borrow_mut(py)
                .items
                .insert(name_last_part.clone(), value.to_biguint().into_bound_py_any(py)?.into());
        }

        //TODO: this works fine if the constant is not an alias(==imported in current module), but if it is, we need to resolve the
        //alias to the actual name!
        // Start by checking for each accessible scope if scope + name_last_part is an alias
        // If it is, resolve the alias to the actual name and use that instead.
        for scope in hint_accessible_scopes {
            let alias = format!("{}.{}", scope, name_last_part);
            let identifier = identifiers.get(&alias);
            println!("Checking if {} is an alias - result: {:?}", alias, identifier);
        }

Second note: I made of fork of the CairoVM to have hint_accessible_scopes available during hint executions. Which I believe should be there. I will submit a PR isolated for this.

For reference, in the python VM, I can get the original path from the alias.

Resolving alias __main__.ValueError
Resolved __main__.ValueError to IdentifierSearchResult(identifier_definition=ConstDefinition(value=407920666966016633499506), canonical_name=ScopedName(path=('ethereum', 'exceptions', 'ValueError')), non_parsed=ScopedName(path=()))
@enitrat enitrat added the bug Something isn't working label Apr 1, 2025
@FrancoGiachetta
Copy link
Contributor

FrancoGiachetta commented Apr 1, 2025

Hi @enitrat!
Looking at the code in cairo-vm/vm/src/serde/deserialize_program.rs. It seems like this should be the expected behaviour, right? This is the compiled program of the test mentioned:

{
    "prime": "0x800000000000011000000000000000000000000000000000000000000000001",
    "attributes": [],
    "debug_info": {
        "instruction_locations": {}
    },
    "data": [
    ],
    "builtins": [],
    "hints": {},
    "reference_manager": {
        "references": []
    },
    "identifiers": {
        "__main__.main": {
            "decorators": [],
            "pc": 0,
            "type": "function"
        },
        "__main__.compare_abs_arrays.SIZEOF_LOCALS": {
            "type": "const",
            "value": -3618502788666131213697322783095070105623107215331596699973092056135872020481
        },
        "starkware.cairo.common.cairo_keccak.keccak.unsigned_div_rem": {
            "destination": "starkware.cairo.common.math.unsigned_div_rem",
            "type": "alias"
        },
        "starkware.cairo.common.cairo_keccak.packed_keccak.ALL_ONES": {
            "type": "const",
            "value": -106710729501573572985208420194530329073740042555888586719234
        },
        "starkware.cairo.common.cairo_keccak.packed_keccak.BLOCK_SIZE": {
            "type": "const",
            "value": 3
        },
        "starkware.cairo.common.alloc.alloc.SIZEOF_LOCALS": {
            "type": "const",
            "value": 0
        },
        "starkware.cairo.common.uint256.SHIFT": {
            "type": "const",
            "value": 340282366920938463463374607431768211456
        }
    }
}

As you can see, starkware.cairo.common.cairo_keccak.keccak.unsigned_div_rem has no value associated. I can't compile your test. Could you do it to check if it has the same result?

@enitrat
Copy link
Contributor Author

enitrat commented Apr 1, 2025

Hey @FrancoGiachetta, please TAL at #2042 which partially solves the issue by making it possible to resolve the original path for aliases. I'll get back to you tomorrow for more in-depth discussions! Thanks

As you can see, starkware.cairo.common.cairo_keccak.keccak.unsigned_div_rem has no value associated. I can't compile your test. Could you do it to check if it has the same result?

Indeed, it looks like the compiled program doesn't have information about this. I was a bit disturbed because even though the program doesn't have this info, we should have a way to resolve the aliases anyway: hence my idea of adding the "destination" field in the Identifier model, which can trivially be done by Serde.

@FrancoGiachetta
Copy link
Contributor

I see, I'll it then!

@JulianGCalderon
Copy link
Contributor

Hey @enitrat, I believe this issue has been resolved, right?

I'll write a summary on this issue:

Summary

There was not enough information to resolve aliases from within a hint:

Now, If we have the following import

from a import CONST_VAR

And the following hint:

%{
    ids.foo = ids.CONST_VAR
%}

Then as long as we have access to the identifiers from within the hint processor, we can:

  • Find the alias CONST_VAR by searching for the identifiers accessible in the current scope.
  • Find the aliased CONST_VAR by using the destination field of the alias identifier.

@enitrat
Copy link
Contributor Author

enitrat commented Apr 23, 2025

Yes perfect!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants