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
82
83
84
85
86
87
88
pub use evm::{
executor::stack::{PrecompileFailure, PrecompileOutput, PrecompileSet},
Context, ExitError, ExitRevert, ExitSucceed,
};
pub type PrecompileResult = Result<PrecompileOutput, PrecompileFailure>;
pub trait Precompile {
fn execute(
input: &[u8],
target_gas: Option<u64>,
context: &Context,
is_static: bool,
) -> PrecompileResult;
}
pub trait LinearCostPrecompile {
const BASE: u64;
const WORD: u64;
fn execute(
input: &[u8],
cost: u64,
) -> core::result::Result<(ExitSucceed, Vec<u8>), PrecompileFailure>;
}
impl<T: LinearCostPrecompile> Precompile for T {
fn execute(input: &[u8], target_gas: Option<u64>, _: &Context, _: bool) -> PrecompileResult {
let cost = ensure_linear_cost(target_gas, input.len() as u64, T::BASE, T::WORD)?;
let (exit_status, output) = T::execute(input, cost)?;
Ok(PrecompileOutput {
exit_status,
cost,
output,
logs: Default::default(),
})
}
}
fn ensure_linear_cost(
target_gas: Option<u64>,
len: u64,
base: u64,
word: u64,
) -> Result<u64, PrecompileFailure> {
let cost = base
.checked_add(word.checked_mul(len.saturating_add(31) / 32).ok_or(
PrecompileFailure::Error {
exit_status: ExitError::OutOfGas,
},
)?)
.ok_or(PrecompileFailure::Error {
exit_status: ExitError::OutOfGas,
})?;
if let Some(target_gas) = target_gas {
if cost > target_gas {
return Err(PrecompileFailure::Error {
exit_status: ExitError::OutOfGas,
});
}
}
Ok(cost)
}