NethermindEth / blockifier

Blockifier is a Rust implementation for the transaction-executing component in the StarkNet sequencer, in charge of creating state diffs and blocks.
Apache License 2.0
1 stars 4 forks source link

[DO NOT MERGE] Minimal bug reproduction for fallback mechanism #105

Closed varex83 closed 2 months ago

varex83 commented 3 months ago

Description

The current solution for fallback mechanism is implemented wrong, since we pass the same State from failed native execution to the VM, which could be corrupted (e.g the same value could be written twice).

image

But it should use the same state as input gets, like in the following diagram:

image

Reproduction

To reproduce it locally I've created mock contract that has two methods: set_value and get_value, but we invoke only set_value method, which checks if contract storage value set to 0 and if not - throw an error. Then it changes it to any value passed to the function arguments and calls send_message_to_l1 syscall (to throw an error on native side). The cairo code will be as follows:

        fn set_value(ref self: ContractState, value: u32) {
            assert!(self.value.read() == 0, "value must be 0");

            self.value.write(value);

            let caller = get_caller_address();

            syscalls::send_message_to_l1_syscall(caller.into(), array![].span()).unwrap();
        }

And on the blockifier side, there are some hard-coded things, that will force native executor to throw an error.

To test it out, use the following command:

FALLBACK_ENABLED=1 cargo test --test fallback_tests --features testing   

Proposed solution

Proposed solution to fix this problem would be using something similar to TransactionalState (if fallback enabled) to pass it to the native and then either commit it if everything is OK or abort changes and fallback to the VM with initial state.