cfx_executor/internal_contract/components/
contract.rs1use std::{collections::HashMap, sync::Arc};
6
7use cfx_bytes::Bytes;
8use cfx_types::{Address, H256};
9use cfx_vm_types::{self as vm, ActionParams, GasLeft, Spec};
10use keccak_hash::keccak;
11use primitives::BlockNumber;
12use solidity_abi::ABIDecodeError;
13
14use crate::spec::CommonParams;
15
16use super::{
17 InternalRefContext, InternalTrapResult, IsActive, SolidityFunctionTrait,
18};
19
20lazy_static! {
21 static ref INTERNAL_CONTRACT_CODE: Arc<Bytes> =
22 Arc::new(vec![0u8, 0u8, 0u8, 0u8]);
23 static ref INTERNAL_CONTRACT_CODE_HASH: H256 = keccak([0u8, 0u8, 0u8, 0u8]);
24}
25
26pub trait InternalContractTrait: Send + Sync + IsActive {
28 fn address(&self) -> &Address;
30
31 fn initialize_block(&self, params: &CommonParams) -> BlockNumber;
33
34 fn get_func_table(&self) -> &SolFnTable;
36
37 fn execute(
39 &self, params: &ActionParams, context: &mut InternalRefContext,
40 ) -> InternalTrapResult<GasLeft> {
41 let func_table = self.get_func_table();
42
43 let (solidity_fn, call_params) =
44 match load_solidity_fn(¶ms.data, func_table, context.spec) {
45 Ok(res) => res,
46 Err(err) => {
47 return InternalTrapResult::Return(Err(err));
48 }
49 };
50
51 solidity_fn.execute(call_params, params, context)
52 }
53
54 fn code(&self) -> Arc<Bytes> { INTERNAL_CONTRACT_CODE.clone() }
55
56 fn code_hash(&self) -> H256 { *INTERNAL_CONTRACT_CODE_HASH }
57
58 fn code_size(&self) -> usize { INTERNAL_CONTRACT_CODE.len() }
59}
60
61pub type SolFnTable = HashMap<[u8; 4], Box<dyn SolidityFunctionTrait>>;
62
63fn load_solidity_fn<'a>(
64 data: &'a Option<Bytes>, func_table: &'a SolFnTable, spec: &'a Spec,
65) -> vm::Result<(&'a Box<dyn SolidityFunctionTrait>, &'a [u8])> {
66 let call_data = data.as_ref().ok_or(ABIDecodeError("None call data"))?;
67 let (fn_sig_slice, call_params) = if call_data.len() < 4 {
68 return Err(ABIDecodeError("Incomplete function signature").into());
69 } else {
70 call_data.split_at(4)
71 };
72
73 let mut fn_sig = [0u8; 4];
74 fn_sig.clone_from_slice(fn_sig_slice);
75
76 let solidity_fn = func_table
77 .get(&fn_sig)
78 .filter(|&func| func.is_active(spec))
79 .ok_or(vm::Error::InternalContract("unsupported function".into()))?;
80 Ok((solidity_fn, call_params))
81}
82
83#[macro_export]
85macro_rules! make_solidity_contract {
86 ( $(#[$attr:meta])* $visibility:vis struct $name:ident ($addr:expr, "placeholder"); ) => {
87 $crate::make_solidity_contract! {
88 $(#[$attr])* $visibility struct $name ($addr, || Default::default(), initialize: |_: &CommonParams| u64::MAX, is_active: |_: &Spec| false);
89 }
90 };
91 ( $(#[$attr:meta])* $visibility:vis struct $name:ident ($addr:expr, $gen_table:expr, "active_at_genesis"); ) => {
92 $crate::make_solidity_contract! {
93 $(#[$attr])* $visibility struct $name ($addr, $gen_table, initialize: |_: &CommonParams| 0u64, is_active: |_: &Spec| true);
94 }
95 };
96 ( $(#[$attr:meta])* $visibility:vis struct $name:ident ($addr:expr, $gen_table:expr, initialize: $init:expr, is_active: $is_active:expr); ) => {
97 $(#[$attr])*
98 $visibility struct $name {
99 function_table: SolFnTable
100 }
101
102 impl $name {
103 pub fn instance() -> Self {
104 Self {
105 function_table: $gen_table()
106 }
107 }
108 }
109
110 impl InternalContractTrait for $name {
111 fn address(&self) -> &Address { &$addr }
112 fn get_func_table(&self) -> &SolFnTable { &self.function_table }
113 fn initialize_block(&self, param: &CommonParams) -> BlockNumber{ $init(param) }
114 }
115
116 impl IsActive for $name {
117 fn is_active(&self, spec: &Spec) -> bool {$is_active(spec)}
118 }
119 };
120}
121
122#[macro_export]
125macro_rules! make_function_table {
126 ($($func:ty), *) => { {
127 let mut table = SolFnTable::new();
128 $({ let f = <$func>::instance(); table.insert(f.function_sig(), Box::new(f)); }) *
129 table
130 } }
131}