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
#![cfg_attr(not(feature = "std"), no_std)]
use core::marker::PhantomData;
use darwinia_evm::GasWeightMapping;
use darwinia_evm_precompile_utils::revert;
use darwinia_support::evm::DeriveSubstrateAddress;
use codec::Decode;
use fp_evm::{
Context, ExitError, ExitSucceed, Precompile, PrecompileFailure, PrecompileOutput,
PrecompileResult,
};
use frame_support::{
dispatch::{Dispatchable, GetDispatchInfo, PostDispatchInfo},
weights::{DispatchClass, Pays},
};
pub struct Dispatch<T> {
_marker: PhantomData<T>,
}
impl<T> Precompile for Dispatch<T>
where
T: darwinia_evm::Config,
T::Call: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo + Decode,
<T::Call as Dispatchable>::Origin: From<Option<T::AccountId>>,
{
fn execute(
input: &[u8],
target_gas: Option<u64>,
context: &Context,
_is_static: bool,
) -> PrecompileResult {
let call = T::Call::decode(&mut &input[..]).map_err(|_| revert("Decode call failed"))?;
let info = call.get_dispatch_info();
let valid_call = info.pays_fee == Pays::Yes && info.class == DispatchClass::Normal;
if !valid_call {
return Err(revert("Invalid call"));
}
if let Some(gas) = target_gas {
let valid_weight = info.weight <= T::GasWeightMapping::gas_to_weight(gas);
if !valid_weight {
return Err(PrecompileFailure::Error { exit_status: ExitError::OutOfGas });
}
}
let origin = T::IntoAccountId::derive_substrate_address(&context.caller);
match call.dispatch(Some(origin).into()) {
Ok(post_info) => {
let cost = T::GasWeightMapping::weight_to_gas(
post_info.actual_weight.unwrap_or(info.weight),
);
Ok(PrecompileOutput {
exit_status: ExitSucceed::Returned,
cost,
output: Default::default(),
logs: Default::default(),
})
},
Err(e) => {
let error_msg: &'static str = e.error.into();
Err(revert(error_msg))
},
}
}
}