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