1pub use evm::{
19 executor::stack::{PrecompileFailure, PrecompileOutput, PrecompileSet},
20 Context, ExitError, ExitRevert, ExitSucceed,
21};
22
23pub type PrecompileResult = Result<PrecompileOutput, PrecompileFailure>;
24
25pub trait Precompile {
27 fn execute(
31 input: &[u8],
32 target_gas: Option<u64>,
33 context: &Context,
34 is_static: bool,
35 ) -> PrecompileResult;
36}
37
38pub trait LinearCostPrecompile {
39 const BASE: u64;
40 const WORD: u64;
41
42 fn execute(
43 input: &[u8],
44 cost: u64,
45 ) -> core::result::Result<(ExitSucceed, Vec<u8>), PrecompileFailure>;
46}
47
48impl<T: LinearCostPrecompile> Precompile for T {
49 fn execute(input: &[u8], target_gas: Option<u64>, _: &Context, _: bool) -> PrecompileResult {
50 let cost = ensure_linear_cost(target_gas, input.len() as u64, T::BASE, T::WORD)?;
51
52 let (exit_status, output) = T::execute(input, cost)?;
53 Ok(PrecompileOutput {
54 exit_status,
55 cost,
56 output,
57 logs: Default::default(),
58 })
59 }
60}
61
62fn ensure_linear_cost(
64 target_gas: Option<u64>,
65 len: u64,
66 base: u64,
67 word: u64,
68) -> Result<u64, PrecompileFailure> {
69 let cost = base
70 .checked_add(word.checked_mul(len.saturating_add(31) / 32).ok_or(
71 PrecompileFailure::Error {
72 exit_status: ExitError::OutOfGas,
73 },
74 )?)
75 .ok_or(PrecompileFailure::Error {
76 exit_status: ExitError::OutOfGas,
77 })?;
78
79 if let Some(target_gas) = target_gas {
80 if cost > target_gas {
81 return Err(PrecompileFailure::Error {
82 exit_status: ExitError::OutOfGas,
83 });
84 }
85 }
86
87 Ok(cost)
88}