pallet_revive/precompiles/builtin/
system.rs1use crate::{
19 precompiles::{BuiltinAddressMatcher, BuiltinPrecompile, Error, Ext},
20 vm::RuntimeCosts,
21 Config,
22};
23use alloc::vec::Vec;
24use alloy_core::sol;
25use core::{marker::PhantomData, num::NonZero};
26use sp_core::hexdisplay::AsBytesRef;
27
28pub struct System<T>(PhantomData<T>);
29
30sol! {
31 interface ISystem {
32 function hashBlake256(bytes memory input) external pure returns (bytes32 digest);
34 function hashBlake128(bytes memory input) external pure returns (bytes32 digest);
36 function toAccountId(address input) external view returns (bytes memory account_id);
46 }
47}
48
49impl<T: Config> BuiltinPrecompile for System<T> {
50 type T = T;
51 type Interface = ISystem::ISystemCalls;
52 const MATCHER: BuiltinAddressMatcher =
53 BuiltinAddressMatcher::Fixed(NonZero::new(0x900).unwrap());
54 const HAS_CONTRACT_INFO: bool = false;
55
56 fn call(
57 _address: &[u8; 20],
58 input: &Self::Interface,
59 env: &mut impl Ext<T = Self::T>,
60 ) -> Result<Vec<u8>, Error> {
61 use ISystem::ISystemCalls;
62 match input {
63 ISystemCalls::hashBlake256(ISystem::hashBlake256Call { input }) => {
64 env.gas_meter_mut().charge(RuntimeCosts::HashBlake256(input.len() as u32))?;
65 let output = sp_io::hashing::blake2_256(input.as_bytes_ref());
66 Ok(output.to_vec())
67 },
68 ISystemCalls::hashBlake128(ISystem::hashBlake128Call { input }) => {
69 env.gas_meter_mut().charge(RuntimeCosts::HashBlake128(input.len() as u32))?;
70 let output = sp_io::hashing::blake2_128(input.as_bytes_ref());
71 Ok(output.to_vec())
72 },
73 ISystemCalls::toAccountId(ISystem::toAccountIdCall { input }) => {
74 use crate::address::AddressMapper;
75 use codec::Encode;
76 env.gas_meter_mut().charge(RuntimeCosts::ToAccountId)?;
77 let account_id =
78 T::AddressMapper::to_account_id(&crate::H160::from_slice(input.as_slice()));
79 Ok(account_id.encode())
80 },
81 }
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::{ISystem, *};
88 use crate::{
89 address::AddressMapper,
90 call_builder::{caller_funding, CallSetup},
91 pallet,
92 precompiles::{tests::run_test_vectors, BuiltinPrecompile},
93 tests::{ExtBuilder, Test},
94 H160,
95 };
96 use codec::Decode;
97 use frame_support::traits::fungible::Mutate;
98
99 #[test]
100 fn test_system_precompile() {
101 run_test_vectors::<System<Test>>(include_str!("testdata/900-blake2_256.json"));
102 run_test_vectors::<System<Test>>(include_str!("testdata/900-blake2_128.json"));
103 run_test_vectors::<System<Test>>(include_str!("testdata/900-to_account_id.json"));
104 }
105
106 #[test]
107 fn test_system_precompile_unmapped_account() {
108 ExtBuilder::default().build().execute_with(|| {
109 let mut call_setup = CallSetup::<Test>::default();
111 let (mut ext, _) = call_setup.ext();
112 let unmapped_address = H160::zero();
113
114 let input = ISystem::ISystemCalls::toAccountId(ISystem::toAccountIdCall {
116 input: unmapped_address.0.into(),
117 });
118 let expected_fallback_account_id =
119 <System<Test>>::call(&<System<Test>>::MATCHER.base_address(), &input, &mut ext)
120 .unwrap();
121
122 assert_eq!(
124 expected_fallback_account_id[20..32],
125 [0xEE; 12],
126 "no fallback suffix found where one should be"
127 );
128 })
129 }
130
131 #[test]
132 fn test_system_precompile_mapped_account() {
133 use crate::test_utils::EVE;
134 ExtBuilder::default().build().execute_with(|| {
135 let mapped_address = {
137 <Test as pallet::Config>::Currency::set_balance(&EVE, caller_funding::<Test>());
138 let _ = <Test as pallet::Config>::AddressMapper::map(&EVE);
139 <Test as pallet::Config>::AddressMapper::to_address(&EVE)
140 };
141
142 let mut call_setup = CallSetup::<Test>::default();
143 let (mut ext, _) = call_setup.ext();
144
145 let input = ISystem::ISystemCalls::toAccountId(ISystem::toAccountIdCall {
147 input: mapped_address.0.into(),
148 });
149 let data =
150 <System<Test>>::call(&<System<Test>>::MATCHER.base_address(), &input, &mut ext)
151 .unwrap();
152
153 assert_ne!(
155 data.as_slice()[20..32],
156 [0xEE; 12],
157 "fallback suffix found where none should be"
158 );
159 assert_eq!(
160 <Test as frame_system::Config>::AccountId::decode(&mut data.as_slice()),
161 Ok(EVE),
162 );
163 })
164 }
165}