Skip to main content

revive_strategy/executor/
runner.rs

1use alloy_primitives::{Address, U256};
2use foundry_cheatcodes::CheatcodeInspectorStrategy;
3use foundry_compilers::{
4    ProjectCompileOutput, compilers::resolc::dual_compiled_contracts::DualCompiledContracts,
5};
6use foundry_evm::{
7    Env,
8    backend::BackendStrategy,
9    executors::{
10        EvmExecutorStrategyRunner, ExecutorStrategyContext, ExecutorStrategyRunner,
11        strategy::ExecutorStrategyExt,
12    },
13};
14use polkadot_sdk::sp_externalities::Externalities;
15use revm::context::result::ResultAndState;
16
17use crate::{
18    backend::ReviveBackendStrategyBuilder, cheatcodes::PvmCheatcodeInspectorStrategyBuilder,
19    executor::context::ReviveExecutorStrategyContext,
20};
21
22/// Defines the [ExecutorStrategyRunner] strategy for Revive.
23#[derive(Debug, Default, Clone)]
24pub struct ReviveExecutorStrategyRunner;
25
26impl ReviveExecutorStrategyRunner {
27    pub fn new() -> Self {
28        Self
29    }
30}
31
32impl ExecutorStrategyRunner for ReviveExecutorStrategyRunner {
33    fn new_backend_strategy(&self, _ctx: &dyn ExecutorStrategyContext) -> BackendStrategy {
34        BackendStrategy::new_revive()
35    }
36
37    fn new_cheatcodes_strategy(
38        &self,
39        ctx: &dyn ExecutorStrategyContext,
40    ) -> foundry_cheatcodes::CheatcodesStrategy {
41        let ctx = get_context_ref(ctx);
42        CheatcodeInspectorStrategy::new_pvm(
43            ctx.dual_compiled_contracts.clone(),
44            ctx.runtime_mode,
45            ctx.externalties.shallow_clone(),
46        )
47    }
48
49    /// Sets the balance of an account.
50    ///
51    /// Amount should be in the range of [0, u128::MAX] despite the type
52    /// because Ethereum balances are u256 while Polkadot balances are u128.
53    fn set_balance(
54        &self,
55        executor: &mut foundry_evm::executors::Executor,
56        address: Address,
57        amount: U256,
58    ) -> foundry_evm::backend::BackendResult<()> {
59        EvmExecutorStrategyRunner.set_balance(executor, address, amount)?;
60
61        let ctx = get_context_ref_mut(executor.strategy.context.as_mut());
62
63        ctx.externalties.set_balance(address, amount);
64        Ok(())
65    }
66
67    fn get_balance(
68        &self,
69        executor: &mut foundry_evm::executors::Executor,
70        address: Address,
71    ) -> foundry_evm::backend::BackendResult<U256> {
72        let evm_balance = EvmExecutorStrategyRunner.get_balance(executor, address)?;
73        let ctx = get_context_ref_mut(executor.strategy.context.as_mut());
74
75        let revive_balance = ctx.externalties.get_balance(address);
76        assert_eq!(evm_balance, revive_balance);
77        Ok(evm_balance)
78    }
79
80    fn set_nonce(
81        &self,
82        executor: &mut foundry_evm::executors::Executor,
83        address: Address,
84        nonce: u64,
85    ) -> foundry_evm::backend::BackendResult<()> {
86        EvmExecutorStrategyRunner.set_nonce(executor, address, nonce)?;
87        let ctx = get_context_ref_mut(executor.strategy.context.as_mut());
88        ctx.externalties.set_nonce(address, nonce);
89        Ok(())
90    }
91
92    fn get_nonce(
93        &self,
94        executor: &mut foundry_evm::executors::Executor,
95        address: Address,
96    ) -> foundry_evm::backend::BackendResult<u64> {
97        let evm_nonce = EvmExecutorStrategyRunner.get_nonce(executor, address)?;
98        let ctx = get_context_ref_mut(executor.strategy.context.as_mut());
99
100        let revive_nonce = ctx.externalties.get_nonce(address);
101
102        assert_eq!(evm_nonce, revive_nonce as u64);
103        Ok(evm_nonce)
104    }
105
106    fn call(
107        &self,
108        ctx: &dyn ExecutorStrategyContext,
109        backend: &mut foundry_evm::backend::CowBackend<'_>,
110        env: &mut Env,
111        executor_env: &Env,
112        inspector: &mut foundry_evm::inspectors::InspectorStack,
113    ) -> eyre::Result<ResultAndState> {
114        EvmExecutorStrategyRunner.call(ctx, backend, env, executor_env, inspector)
115    }
116
117    fn transact(
118        &self,
119        ctx: &mut dyn ExecutorStrategyContext,
120        backend: &mut foundry_evm::backend::Backend,
121        env: &mut Env,
122        executor_env: &Env,
123        inspector: &mut foundry_evm::inspectors::InspectorStack,
124    ) -> eyre::Result<ResultAndState> {
125        EvmExecutorStrategyRunner.transact(ctx, backend, env, executor_env, inspector)
126    }
127}
128
129fn get_context_ref(ctx: &dyn ExecutorStrategyContext) -> &ReviveExecutorStrategyContext {
130    ctx.as_any_ref().downcast_ref().expect("expected ReviveExecutorStrategyContext")
131}
132
133fn get_context_ref_mut(
134    ctx: &mut dyn ExecutorStrategyContext,
135) -> &mut ReviveExecutorStrategyContext {
136    ctx.as_any_mut().downcast_mut().expect("expected ReviveExecutorStrategyContext")
137}
138
139impl ExecutorStrategyExt for ReviveExecutorStrategyRunner {
140    fn revive_set_dual_compiled_contracts(
141        &self,
142        ctx: &mut dyn ExecutorStrategyContext,
143        dual_compiled_contracts: DualCompiledContracts,
144    ) {
145        let ctx = get_context_ref_mut(ctx);
146        ctx.dual_compiled_contracts = dual_compiled_contracts;
147    }
148
149    fn revive_set_compilation_output(
150        &self,
151        ctx: &mut dyn ExecutorStrategyContext,
152        output: ProjectCompileOutput,
153    ) {
154        let ctx = get_context_ref_mut(ctx);
155        ctx.compilation_output.replace(output);
156    }
157    fn start_transaction(&self, ctx: &dyn ExecutorStrategyContext) {
158        let ctx = get_context_ref(ctx);
159        let mut externalities = ctx.externalties.0.lock().unwrap();
160        externalities.externalities.ext().storage_start_transaction();
161    }
162
163    fn rollback_transaction(&self, ctx: &dyn ExecutorStrategyContext) {
164        let ctx = get_context_ref(ctx);
165        let mut state = ctx.externalties.0.lock().unwrap();
166        let _ = state.externalities.ext().storage_rollback_transaction();
167    }
168}