revm_handler/
precompile_provider.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use context_interface::{Cfg, CfgGetter};
use handler_interface::PrecompileProvider;
use interpreter::{Gas, InstructionResult, InterpreterResult};
use precompile::PrecompileErrors;
use precompile::{PrecompileSpecId, Precompiles};
use primitives::{Address, Bytes};

pub struct EthPrecompileProvider<CTX, ERROR> {
    pub precompiles: &'static Precompiles,
    pub _phantom: core::marker::PhantomData<(CTX, ERROR)>,
}

impl<CTX, ERROR> Clone for EthPrecompileProvider<CTX, ERROR> {
    fn clone(&self) -> Self {
        Self {
            precompiles: self.precompiles,
            _phantom: core::marker::PhantomData,
        }
    }
}

impl<CTX, ERROR> PrecompileProvider for EthPrecompileProvider<CTX, ERROR>
where
    CTX: CfgGetter,
    ERROR: From<PrecompileErrors>,
{
    type Context = CTX;
    type Error = ERROR;

    fn new(context: &mut Self::Context) -> Self {
        let spec = context.cfg().spec().into();
        Self {
            precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)),
            _phantom: core::marker::PhantomData,
        }
    }

    fn run(
        &mut self,
        _context: &mut Self::Context,
        address: &Address,
        bytes: &Bytes,
        gas_limit: u64,
    ) -> Result<Option<InterpreterResult>, Self::Error> {
        let Some(precompile) = self.precompiles.get(address) else {
            return Ok(None);
        };

        let mut result = InterpreterResult {
            result: InstructionResult::Return,
            gas: Gas::new(gas_limit),
            output: Bytes::new(),
        };

        match (*precompile)(bytes, gas_limit) {
            Ok(output) => {
                let underflow = result.gas.record_cost(output.gas_used);
                assert!(underflow, "Gas underflow is not possible");
                result.result = InstructionResult::Return;
                result.output = output.bytes;
            }
            Err(PrecompileErrors::Error(e)) => {
                result.result = if e.is_oog() {
                    InstructionResult::PrecompileOOG
                } else {
                    InstructionResult::PrecompileError
                };
            }
            Err(err @ PrecompileErrors::Fatal { .. }) => return Err(err.into()),
        }
        Ok(Some(result))
    }

    fn warm_addresses(&self) -> impl Iterator<Item = Address> {
        self.precompiles.addresses().cloned()
    }

    fn contains(&self, address: &Address) -> bool {
        self.precompiles.contains(address)
    }
}