foundry-rs / starknet-foundry

Blazing fast toolkit for developing Starknet contracts.
https://foundry-rs.github.io/starknet-foundry/
MIT License
328 stars 179 forks source link

`map_entry_address` Produces Incorrect Address for Serialized Const Array #2593

Open Th0rgal opened 1 month ago

Th0rgal commented 1 month ago

Which component is your bug related to?

snforge

Foundry Version

snforge 0.31.0

What operating system are you using?

MacOS

What system architecture are you using?

arm

What happened

The map_entry_address function is not outputting the correct address when used on a serialized const array for a storage Map. Specifically, when using a custom Digest type (which is a [u32; 8]) with a .into() trait that outputs its content as a span of felts, the computed address is incorrect.

When running the following code:

let found_address = map_entry_address(selector!("blocks"), block1_digest.into());
let spann: Span<felt252> = block1_digest.into();
println!("serialized: {:?}", spann);
println!("selector: {}", selector!("blocks"));
println!("found_address: {:?}", found_address);

The output is:

serialized: [16777216, 0, 0, 0, 0, 0, 0, 0]
selector: 1185783998090047139479923081391258119726215163852195987944736116288677385718
found_address: 2615699797321488741109702562325062279495142019795495137834641940075987537936

However, when printing the actual storage address in the contract:

fn get_status(self: @ContractState, block_hash: Digest) -> BlockStatus {
    println!("base_address: {:?}", self.blocks.base_address);
    println!("address: {:?}", self.blocks.entry(block_hash).storage_pointer_address);
    self.blocks.read(block_hash)
}

The output is:

base_address: 1185783998090047139479923081391258119726215163852195987944736116288677385718
address: 2189951415783994990461367959466671320294598733793400746396676636287532258831

The found_address computed by map_entry_address should match the address printed by the contract's storage pointer but it doesn't.

Trait to serialize it:

pub impl DigestIntoSpan of Into<Digest, Span<felt252>> {
    fn into(self: Digest) -> Span<felt252> {
        let mut serialized_struct: Array<felt252> = array![];
        self.serialize(ref serialized_struct);
        serialized_struct.span()
    }
}

Trace

No response

Is there an existing issue for this?

ArielElp commented 1 day ago

Both LegacyMap and Map agree with the documented address computation. The issue here is that Serde (used in your into implementation) adds a length prefix which messes up the hash.