1use crate::{
24 evm::handle::PrecompileHandleExt,
25 solidity::{codec::String, revert::revert},
26 EvmResult,
27};
28use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec};
29use core::{cell::RefCell, marker::PhantomData, ops::RangeInclusive};
30use fp_evm::{
31 ExitError, IsPrecompileResult, Precompile, PrecompileFailure, PrecompileHandle,
32 PrecompileResult, PrecompileSet, ACCOUNT_CODES_METADATA_PROOF_SIZE,
33};
34use frame_support::pallet_prelude::Get;
35use impl_trait_for_tuples::impl_for_tuples;
36use pallet_evm::AddressMapping;
37use sp_core::{H160, H256};
38
39pub trait PrecompileChecks {
50 #[inline(always)]
51 fn recursion_limit() -> Option<Option<u16>> {
58 None
59 }
60
61 #[inline(always)]
62 fn accept_delegate_call() -> Option<bool> {
66 None
67 }
68
69 #[inline(always)]
70 fn callable_by_smart_contract(_caller: H160, _called_selector: Option<u32>) -> Option<bool> {
74 None
75 }
76
77 #[inline(always)]
78 fn callable_by_precompile(_caller: H160, _called_selector: Option<u32>) -> Option<bool> {
82 None
83 }
84
85 #[inline(always)]
86 fn allow_subcalls() -> Option<bool> {
90 None
91 }
92
93 fn callable_by_smart_contract_summary() -> Option<String> {
95 None
96 }
97
98 fn callable_by_precompile_summary() -> Option<String> {
100 None
101 }
102}
103
104#[derive(Debug, Clone)]
105pub enum DiscriminantResult<T> {
106 Some(T, u64),
107 None(u64),
108 OutOfGas,
109}
110
111impl<T> From<DiscriminantResult<T>> for IsPrecompileResult {
112 fn from(val: DiscriminantResult<T>) -> Self {
113 match val {
114 DiscriminantResult::<T>::Some(_, extra_cost) => IsPrecompileResult::Answer {
115 is_precompile: true,
116 extra_cost,
117 },
118 DiscriminantResult::<T>::None(extra_cost) => IsPrecompileResult::Answer {
119 is_precompile: false,
120 extra_cost,
121 },
122 DiscriminantResult::<T>::OutOfGas => IsPrecompileResult::OutOfGas,
123 }
124 }
125}
126
127#[derive(Debug, Clone)]
128#[cfg_attr(feature = "testing", derive(serde::Serialize, serde::Deserialize))]
129pub enum PrecompileKind {
130 Single(H160),
131 Prefixed(Vec<u8>),
132 Multiple(Vec<H160>),
133}
134
135#[derive(Debug, Clone)]
136#[cfg_attr(feature = "testing", derive(serde::Serialize, serde::Deserialize))]
137pub struct PrecompileCheckSummary {
138 pub name: Option<String>,
139 pub precompile_kind: PrecompileKind,
140 pub recursion_limit: Option<u16>,
141 pub accept_delegate_call: bool,
142 pub callable_by_smart_contract: String,
143 pub callable_by_precompile: String,
144}
145
146#[impl_for_tuples(0, 20)]
147impl PrecompileChecks for Tuple {
148 #[inline(always)]
149 fn recursion_limit() -> Option<Option<u16>> {
150 for_tuples!(#(
151 if let Some(check) = Tuple::recursion_limit() {
152 return Some(check);
153 }
154 )*);
155
156 None
157 }
158
159 #[inline(always)]
160 fn accept_delegate_call() -> Option<bool> {
161 for_tuples!(#(
162 if let Some(check) = Tuple::accept_delegate_call() {
163 return Some(check);
164 }
165 )*);
166
167 None
168 }
169
170 #[inline(always)]
171 fn callable_by_smart_contract(caller: H160, called_selector: Option<u32>) -> Option<bool> {
172 for_tuples!(#(
173 if let Some(check) = Tuple::callable_by_smart_contract(caller, called_selector) {
174 return Some(check);
175 }
176 )*);
177
178 None
179 }
180
181 #[inline(always)]
182 fn callable_by_precompile(caller: H160, called_selector: Option<u32>) -> Option<bool> {
183 for_tuples!(#(
184 if let Some(check) = Tuple::callable_by_precompile(caller, called_selector) {
185 return Some(check);
186 }
187 )*);
188
189 None
190 }
191
192 #[inline(always)]
193 fn allow_subcalls() -> Option<bool> {
194 for_tuples!(#(
195 if let Some(check) = Tuple::allow_subcalls() {
196 return Some(check);
197 }
198 )*);
199
200 None
201 }
202
203 fn callable_by_smart_contract_summary() -> Option<String> {
204 for_tuples!(#(
205 if let Some(check) = Tuple::callable_by_smart_contract_summary() {
206 return Some(check);
207 }
208 )*);
209
210 None
211 }
212
213 fn callable_by_precompile_summary() -> Option<String> {
214 for_tuples!(#(
215 if let Some(check) = Tuple::callable_by_precompile_summary() {
216 return Some(check);
217 }
218 )*);
219
220 None
221 }
222}
223
224pub struct AcceptDelegateCall;
226
227impl PrecompileChecks for AcceptDelegateCall {
228 #[inline(always)]
229 fn accept_delegate_call() -> Option<bool> {
230 Some(true)
231 }
232}
233
234pub struct SubcallWithMaxNesting<const R: u16>;
236
237impl<const R: u16> PrecompileChecks for SubcallWithMaxNesting<R> {
238 #[inline(always)]
239 fn recursion_limit() -> Option<Option<u16>> {
240 Some(Some(R))
241 }
242
243 #[inline(always)]
244 fn allow_subcalls() -> Option<bool> {
245 Some(true)
246 }
247}
248
249pub trait SelectorFilter {
250 fn is_allowed(_caller: H160, _selector: Option<u32>) -> bool;
251
252 fn description() -> String;
253}
254pub struct ForAllSelectors;
255impl SelectorFilter for ForAllSelectors {
256 fn is_allowed(_caller: H160, _selector: Option<u32>) -> bool {
257 true
258 }
259
260 fn description() -> String {
261 "Allowed for all selectors and callers".into()
262 }
263}
264
265pub struct OnlyFrom<T>(PhantomData<T>);
266impl<T: Get<H160>> SelectorFilter for OnlyFrom<T> {
267 fn is_allowed(caller: H160, _selector: Option<u32>) -> bool {
268 caller == T::get()
269 }
270
271 fn description() -> String {
272 alloc::format!("Allowed for all selectors only if called from {}", T::get())
273 }
274}
275
276pub struct CallableByContract<T = ForAllSelectors>(PhantomData<T>);
277
278impl<T: SelectorFilter> PrecompileChecks for CallableByContract<T> {
279 #[inline(always)]
280 fn callable_by_smart_contract(caller: H160, called_selector: Option<u32>) -> Option<bool> {
281 Some(T::is_allowed(caller, called_selector))
282 }
283
284 fn callable_by_smart_contract_summary() -> Option<String> {
285 Some(T::description())
286 }
287}
288
289pub struct CallableByPrecompile<T = ForAllSelectors>(PhantomData<T>);
291
292impl<T: SelectorFilter> PrecompileChecks for CallableByPrecompile<T> {
293 #[inline(always)]
294 fn callable_by_precompile(caller: H160, called_selector: Option<u32>) -> Option<bool> {
295 Some(T::is_allowed(caller, called_selector))
296 }
297
298 fn callable_by_precompile_summary() -> Option<String> {
299 Some(T::description())
300 }
301}
302
303#[derive(PartialEq)]
305#[cfg_attr(feature = "std", derive(Debug))]
306pub enum AddressType {
307 EOA,
309 Precompile,
311 Contract,
313}
314
315pub fn get_address_type<R: pallet_evm::Config>(
317 handle: &mut impl PrecompileHandle,
318 address: H160,
319) -> Result<AddressType, ExitError> {
320 if let Ok(true) = is_precompile_or_fail::<R>(address, handle.remaining_gas()) {
322 return Ok(AddressType::Precompile);
323 }
324
325 if handle.is_contract_being_constructed(address) {
327 return Ok(AddressType::Contract);
328 }
329
330 handle.record_db_read::<R>(ACCOUNT_CODES_METADATA_PROOF_SIZE as usize)?;
333 let code_len = pallet_evm::Pallet::<R>::account_code_metadata(address).size;
334
335 if code_len == 0 {
337 return Ok(AddressType::EOA);
338 }
339
340 Ok(AddressType::Contract)
341}
342
343fn common_checks<R: pallet_evm::Config, C: PrecompileChecks>(
346 handle: &mut impl PrecompileHandle,
347) -> EvmResult<()> {
348 let code_address = handle.code_address();
349 let caller = handle.context().caller;
350
351 let accept_delegate_call = C::accept_delegate_call().unwrap_or(false);
353 if !accept_delegate_call && code_address != handle.context().address {
354 return Err(revert("Cannot be called with DELEGATECALL or CALLCODE"));
355 }
356
357 let selector = handle.input().get(0..4).map(|bytes| {
359 let mut buffer = [0u8; 4];
360 buffer.copy_from_slice(bytes);
361 u32::from_be_bytes(buffer)
362 });
363
364 let caller_address_type = get_address_type::<R>(handle, caller)?;
365 match caller_address_type {
366 AddressType::Precompile => {
367 let callable_by_precompile =
369 C::callable_by_precompile(caller, selector).unwrap_or(false);
370 if !callable_by_precompile {
371 return Err(revert("Function not callable by precompiles"));
372 }
373 }
374 AddressType::Contract => {
375 let callable_by_smart_contract =
377 C::callable_by_smart_contract(caller, selector).unwrap_or(false);
378 if !callable_by_smart_contract {
379 return Err(revert("Function not callable by smart contracts"));
380 }
381 }
382 AddressType::EOA => {
383 }
385 }
386
387 Ok(())
388}
389
390pub fn is_precompile_or_fail<R: pallet_evm::Config>(address: H160, gas: u64) -> EvmResult<bool> {
391 match <R as pallet_evm::Config>::PrecompilesValue::get().is_precompile(address, gas) {
392 IsPrecompileResult::Answer { is_precompile, .. } => Ok(is_precompile),
393 IsPrecompileResult::OutOfGas => Err(PrecompileFailure::Error {
394 exit_status: ExitError::OutOfGas,
395 }),
396 }
397}
398
399pub struct AddressU64<const N: u64>;
400impl<const N: u64> Get<H160> for AddressU64<N> {
401 #[inline(always)]
402 fn get() -> H160 {
403 H160::from_low_u64_be(N)
404 }
405}
406
407pub struct RestrictiveHandle<'a, H> {
408 handle: &'a mut H,
409 allow_subcalls: bool,
410}
411
412impl<H: PrecompileHandle> PrecompileHandle for RestrictiveHandle<'_, H> {
413 fn call(
414 &mut self,
415 address: H160,
416 transfer: Option<evm::Transfer>,
417 input: Vec<u8>,
418 target_gas: Option<u64>,
419 is_static: bool,
420 context: &evm::Context,
421 ) -> (evm::ExitReason, Vec<u8>) {
422 if !self.allow_subcalls {
423 return (
424 evm::ExitReason::Revert(evm::ExitRevert::Reverted),
425 crate::solidity::revert::revert_as_bytes("subcalls disabled for this precompile"),
426 );
427 }
428
429 self.handle
430 .call(address, transfer, input, target_gas, is_static, context)
431 }
432
433 fn record_cost(&mut self, cost: u64) -> Result<(), evm::ExitError> {
434 self.handle.record_cost(cost)
435 }
436
437 fn remaining_gas(&self) -> u64 {
438 self.handle.remaining_gas()
439 }
440
441 fn log(
442 &mut self,
443 address: H160,
444 topics: Vec<H256>,
445 data: Vec<u8>,
446 ) -> Result<(), evm::ExitError> {
447 self.handle.log(address, topics, data)
448 }
449
450 fn code_address(&self) -> H160 {
451 self.handle.code_address()
452 }
453
454 fn input(&self) -> &[u8] {
455 self.handle.input()
456 }
457
458 fn context(&self) -> &evm::Context {
459 self.handle.context()
460 }
461
462 fn origin(&self) -> H160 {
463 self.handle.origin()
464 }
465
466 fn is_static(&self) -> bool {
467 self.handle.is_static()
468 }
469
470 fn gas_limit(&self) -> Option<u64> {
471 self.handle.gas_limit()
472 }
473
474 fn record_external_cost(
475 &mut self,
476 ref_time: Option<u64>,
477 proof_size: Option<u64>,
478 storage_growth: Option<u64>,
479 ) -> Result<(), ExitError> {
480 self.handle
481 .record_external_cost(ref_time, proof_size, storage_growth)
482 }
483
484 fn refund_external_cost(&mut self, ref_time: Option<u64>, proof_size: Option<u64>) {
485 self.handle.refund_external_cost(ref_time, proof_size)
486 }
487
488 fn is_contract_being_constructed(&self, address: H160) -> bool {
489 self.handle.is_contract_being_constructed(address)
490 }
491}
492
493pub trait IsActivePrecompile {
497 fn is_active_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult;
501}
502
503pub trait PrecompileSetFragment {
509 fn new() -> Self;
511
512 fn execute<R: pallet_evm::Config>(
514 &self,
515 handle: &mut impl PrecompileHandle,
516 ) -> Option<PrecompileResult>;
517
518 fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult;
520
521 fn used_addresses(&self) -> Vec<H160>;
523
524 fn summarize_checks(&self) -> Vec<PrecompileCheckSummary>;
526}
527
528pub struct PrecompileAt<A, P, C = ()> {
534 current_recursion_level: RefCell<u16>,
535 _phantom: PhantomData<(A, P, C)>,
536}
537
538impl<A, P, C> PrecompileSetFragment for PrecompileAt<A, P, C>
539where
540 A: Get<H160>,
541 P: Precompile,
542 C: PrecompileChecks,
543{
544 #[inline(always)]
545 fn new() -> Self {
546 Self {
547 current_recursion_level: RefCell::new(0),
548 _phantom: PhantomData,
549 }
550 }
551
552 #[inline(always)]
553 fn execute<R: pallet_evm::Config>(
554 &self,
555 handle: &mut impl PrecompileHandle,
556 ) -> Option<PrecompileResult> {
557 let code_address = handle.code_address();
558
559 if A::get() != code_address {
561 return None;
562 }
563
564 if let Err(err) = common_checks::<R, C>(handle) {
566 return Some(Err(err));
567 }
568
569 let recursion_limit = C::recursion_limit().unwrap_or(Some(0));
571 if let Some(max_recursion_level) = recursion_limit {
572 match self.current_recursion_level.try_borrow_mut() {
573 Ok(mut recursion_level) => {
574 if *recursion_level > max_recursion_level {
575 return Some(Err(revert("Precompile is called with too high nesting")));
576 }
577
578 *recursion_level += 1;
579 }
580 Err(_) => return Some(Err(revert("Couldn't check precompile nesting"))),
583 }
584 }
585
586 let allow_subcalls = C::allow_subcalls().unwrap_or(false);
588 let mut handle = RestrictiveHandle {
589 handle,
590 allow_subcalls,
591 };
592
593 let res = P::execute(&mut handle);
594
595 if recursion_limit.is_some() {
597 match self.current_recursion_level.try_borrow_mut() {
598 Ok(mut recursion_level) => {
599 *recursion_level -= 1;
600 }
601 Err(_) => return Some(Err(revert("Couldn't check precompile nesting"))),
604 }
605 }
606
607 Some(res)
608 }
609
610 #[inline(always)]
611 fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult {
612 IsPrecompileResult::Answer {
613 is_precompile: address == A::get(),
614 extra_cost: 0,
615 }
616 }
617
618 #[inline(always)]
619 fn used_addresses(&self) -> Vec<H160> {
620 vec![A::get()]
621 }
622
623 fn summarize_checks(&self) -> Vec<PrecompileCheckSummary> {
624 vec![PrecompileCheckSummary {
625 name: None,
626 precompile_kind: PrecompileKind::Single(A::get()),
627 recursion_limit: C::recursion_limit().unwrap_or(Some(0)),
628 accept_delegate_call: C::accept_delegate_call().unwrap_or(false),
629 callable_by_smart_contract: C::callable_by_smart_contract_summary()
630 .unwrap_or_else(|| "Not callable".into()),
631 callable_by_precompile: C::callable_by_precompile_summary()
632 .unwrap_or_else(|| "Not callable".into()),
633 }]
634 }
635}
636
637impl<A, P, C> IsActivePrecompile for PrecompileAt<A, P, C>
638where
639 A: Get<H160>,
640{
641 #[inline(always)]
642 fn is_active_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult {
643 IsPrecompileResult::Answer {
644 is_precompile: address == A::get(),
645 extra_cost: 0,
646 }
647 }
648}
649
650pub struct PrecompileSetStartingWith<A, P, C = ()> {
656 precompile_set: P,
657 current_recursion_level: RefCell<BTreeMap<H160, u16>>,
658 _phantom: PhantomData<(A, C)>,
659}
660
661impl<A, P, C> PrecompileSetFragment for PrecompileSetStartingWith<A, P, C>
662where
663 A: Get<&'static [u8]>,
664 P: PrecompileSet + Default,
665 C: PrecompileChecks,
666{
667 #[inline(always)]
668 fn new() -> Self {
669 Self {
670 precompile_set: P::default(),
671 current_recursion_level: RefCell::new(BTreeMap::new()),
672 _phantom: PhantomData,
673 }
674 }
675
676 #[inline(always)]
677 fn execute<R: pallet_evm::Config>(
678 &self,
679 handle: &mut impl PrecompileHandle,
680 ) -> Option<PrecompileResult> {
681 let code_address = handle.code_address();
682 if !is_precompile_or_fail::<R>(code_address, handle.remaining_gas()).ok()? {
683 return None;
684 }
685 if let Err(err) = common_checks::<R, C>(handle) {
687 return Some(Err(err));
688 }
689
690 let recursion_limit = C::recursion_limit().unwrap_or(Some(0));
692 if let Some(max_recursion_level) = recursion_limit {
693 match self.current_recursion_level.try_borrow_mut() {
694 Ok(mut recursion_level_map) => {
695 let recursion_level = recursion_level_map.entry(code_address).or_insert(0);
696
697 if *recursion_level > max_recursion_level {
698 return Some(Err(revert("Precompile is called with too high nesting")));
699 }
700
701 *recursion_level += 1;
702 }
703 Err(_) => return Some(Err(revert("Couldn't check precompile nesting"))),
706 }
707 }
708
709 let allow_subcalls = C::allow_subcalls().unwrap_or(false);
711 let mut handle = RestrictiveHandle {
712 handle,
713 allow_subcalls,
714 };
715
716 let res = self.precompile_set.execute(&mut handle);
717
718 if recursion_limit.is_some() {
720 match self.current_recursion_level.try_borrow_mut() {
721 Ok(mut recursion_level_map) => {
722 let recursion_level = match recursion_level_map.get_mut(&code_address) {
723 Some(recursion_level) => recursion_level,
724 None => return Some(Err(revert("Couldn't retrieve precompile nesting"))),
725 };
726
727 *recursion_level -= 1;
728 }
729 Err(_) => return Some(Err(revert("Couldn't check precompile nesting"))),
732 }
733 }
734
735 res
736 }
737
738 #[inline(always)]
739 fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult {
740 if address.as_bytes().starts_with(A::get()) {
741 return self.precompile_set.is_precompile(address, gas);
742 }
743 IsPrecompileResult::Answer {
744 is_precompile: false,
745 extra_cost: 0,
746 }
747 }
748
749 #[inline(always)]
750 fn used_addresses(&self) -> Vec<H160> {
751 vec![]
753 }
754
755 fn summarize_checks(&self) -> Vec<PrecompileCheckSummary> {
756 let prefix = A::get();
757
758 vec![PrecompileCheckSummary {
759 name: None,
760 precompile_kind: PrecompileKind::Prefixed(prefix.to_vec()),
761 recursion_limit: C::recursion_limit().unwrap_or(Some(0)),
762 accept_delegate_call: C::accept_delegate_call().unwrap_or(false),
763 callable_by_smart_contract: C::callable_by_smart_contract_summary()
764 .unwrap_or_else(|| "Not callable".into()),
765 callable_by_precompile: C::callable_by_precompile_summary()
766 .unwrap_or_else(|| "Not callable".into()),
767 }]
768 }
769}
770
771impl<A, P, C> IsActivePrecompile for PrecompileSetStartingWith<A, P, C>
772where
773 Self: PrecompileSetFragment,
774{
775 #[inline(always)]
776 fn is_active_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult {
777 self.is_precompile(address, gas)
778 }
779}
780
781pub struct RevertPrecompile<A>(PhantomData<A>);
784
785impl<A> PrecompileSetFragment for RevertPrecompile<A>
786where
787 A: Get<H160>,
788{
789 #[inline(always)]
790 fn new() -> Self {
791 Self(PhantomData)
792 }
793
794 #[inline(always)]
795 fn execute<R: pallet_evm::Config>(
796 &self,
797 handle: &mut impl PrecompileHandle,
798 ) -> Option<PrecompileResult> {
799 if A::get() == handle.code_address() {
800 Some(Err(revert("revert")))
801 } else {
802 None
803 }
804 }
805
806 #[inline(always)]
807 fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult {
808 IsPrecompileResult::Answer {
809 is_precompile: address == A::get(),
810 extra_cost: 0,
811 }
812 }
813
814 #[inline(always)]
815 fn used_addresses(&self) -> Vec<H160> {
816 vec![A::get()]
817 }
818
819 fn summarize_checks(&self) -> Vec<PrecompileCheckSummary> {
820 vec![PrecompileCheckSummary {
821 name: None,
822 precompile_kind: PrecompileKind::Single(A::get()),
823 recursion_limit: Some(0),
824 accept_delegate_call: true,
825 callable_by_smart_contract: "Reverts in all cases".into(),
826 callable_by_precompile: "Reverts in all cases".into(),
827 }]
828 }
829}
830
831impl<A> IsActivePrecompile for RevertPrecompile<A> {
832 #[inline(always)]
833 fn is_active_precompile(&self, _address: H160, _gas: u64) -> IsPrecompileResult {
834 IsPrecompileResult::Answer {
835 is_precompile: true,
836 extra_cost: 0,
837 }
838 }
839}
840
841pub struct RemovedPrecompilesAt<A>(PhantomData<A>);
844impl<A> PrecompileSetFragment for RemovedPrecompilesAt<A>
845where
846 A: Get<Vec<H160>>,
847{
848 #[inline(always)]
849 fn new() -> Self {
850 Self(PhantomData)
851 }
852
853 #[inline(always)]
854 fn execute<R: pallet_evm::Config>(
855 &self,
856 handle: &mut impl PrecompileHandle,
857 ) -> Option<PrecompileResult> {
858 if A::get().contains(&handle.code_address()) {
859 Some(Err(revert("Removed precompile")))
860 } else {
861 None
862 }
863 }
864
865 #[inline(always)]
866 fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult {
867 IsPrecompileResult::Answer {
868 is_precompile: A::get().contains(&address),
869 extra_cost: 0,
870 }
871 }
872
873 #[inline(always)]
874 fn used_addresses(&self) -> Vec<H160> {
875 A::get()
876 }
877
878 fn summarize_checks(&self) -> Vec<PrecompileCheckSummary> {
879 vec![PrecompileCheckSummary {
880 name: None,
881 precompile_kind: PrecompileKind::Multiple(A::get()),
882 recursion_limit: Some(0),
883 accept_delegate_call: true,
884 callable_by_smart_contract: "Reverts in all cases".into(),
885 callable_by_precompile: "Reverts in all cases".into(),
886 }]
887 }
888}
889
890impl<A> IsActivePrecompile for RemovedPrecompilesAt<A>
891where
892 Self: PrecompileSetFragment,
893{
894 #[inline(always)]
895 fn is_active_precompile(&self, _address: H160, _gas: u64) -> IsPrecompileResult {
896 IsPrecompileResult::Answer {
897 is_precompile: false,
898 extra_cost: 0,
899 }
900 }
901}
902
903pub struct RemovedPrecompileAt<A>(PhantomData<A>);
906impl<A> PrecompileSetFragment for RemovedPrecompileAt<A>
907where
908 A: Get<H160>,
909{
910 #[inline(always)]
911 fn new() -> Self {
912 Self(PhantomData)
913 }
914
915 #[inline(always)]
916 fn execute<R: pallet_evm::Config>(
917 &self,
918 handle: &mut impl PrecompileHandle,
919 ) -> Option<PrecompileResult> {
920 if A::get() == handle.code_address() {
921 Some(Err(revert("Removed precompile")))
922 } else {
923 None
924 }
925 }
926
927 #[inline(always)]
928 fn is_precompile(&self, address: H160, _gas: u64) -> IsPrecompileResult {
929 IsPrecompileResult::Answer {
930 is_precompile: address == A::get(),
931 extra_cost: 0,
932 }
933 }
934
935 #[inline(always)]
936 fn used_addresses(&self) -> Vec<H160> {
937 vec![A::get()]
938 }
939
940 fn summarize_checks(&self) -> Vec<PrecompileCheckSummary> {
941 vec![PrecompileCheckSummary {
942 name: None,
943 precompile_kind: PrecompileKind::Single(A::get()),
944 recursion_limit: Some(0),
945 accept_delegate_call: true,
946 callable_by_smart_contract: "Reverts in all cases".into(),
947 callable_by_precompile: "Reverts in all cases".into(),
948 }]
949 }
950}
951
952impl<A> IsActivePrecompile for RemovedPrecompileAt<A> {
953 #[inline(always)]
954 fn is_active_precompile(&self, _address: H160, _gas: u64) -> IsPrecompileResult {
955 IsPrecompileResult::Answer {
956 is_precompile: false,
957 extra_cost: 0,
958 }
959 }
960}
961
962#[impl_for_tuples(1, 100)]
964impl PrecompileSetFragment for Tuple {
965 #[inline(always)]
966 fn new() -> Self {
967 (for_tuples!(#(
968 Tuple::new()
969 ),*))
970 }
971
972 #[inline(always)]
973 fn execute<R: pallet_evm::Config>(
974 &self,
975 handle: &mut impl PrecompileHandle,
976 ) -> Option<PrecompileResult> {
977 for_tuples!(#(
978 if let Some(res) = self.Tuple.execute::<R>(handle) {
979 return Some(res);
980 }
981 )*);
982
983 None
984 }
985
986 #[inline(always)]
987 fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult {
988 for_tuples!(#(
989 if let IsPrecompileResult::Answer {
990 is_precompile: true,
991 ..
992 } = self.Tuple.is_precompile(address, gas) { return IsPrecompileResult::Answer {
993 is_precompile: true,
994 extra_cost: 0,
995 }
996 };
997 )*);
998 IsPrecompileResult::Answer {
999 is_precompile: false,
1000 extra_cost: 0,
1001 }
1002 }
1003
1004 #[inline(always)]
1005 fn used_addresses(&self) -> Vec<H160> {
1006 let mut used_addresses = vec![];
1007
1008 for_tuples!(#(
1009 let mut inner = self.Tuple.used_addresses();
1010 used_addresses.append(&mut inner);
1011 )*);
1012
1013 used_addresses
1014 }
1015
1016 fn summarize_checks(&self) -> Vec<PrecompileCheckSummary> {
1017 let mut checks = Vec::new();
1018
1019 for_tuples!(#(
1020 let mut inner = self.Tuple.summarize_checks();
1021 checks.append(&mut inner);
1022 )*);
1023
1024 checks
1025 }
1026}
1027
1028#[impl_for_tuples(1, 100)]
1029impl IsActivePrecompile for Tuple {
1030 #[inline(always)]
1031 fn is_active_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult {
1032 for_tuples!(#(
1033 if let IsPrecompileResult::Answer {
1034 is_precompile: true,
1035 ..
1036 } = self.Tuple.is_active_precompile(address, gas) { return IsPrecompileResult::Answer {
1037 is_precompile: true,
1038 extra_cost: 0,
1039 } };
1040 )*);
1041 IsPrecompileResult::Answer {
1042 is_precompile: false,
1043 extra_cost: 0,
1044 }
1045 }
1046}
1047
1048pub struct PrecompilesInRangeInclusive<R, P> {
1051 inner: P,
1052 range: RangeInclusive<H160>,
1053 _phantom: PhantomData<R>,
1054}
1055
1056impl<S, E, P> PrecompileSetFragment for PrecompilesInRangeInclusive<(S, E), P>
1057where
1058 S: Get<H160>,
1059 E: Get<H160>,
1060 P: PrecompileSetFragment,
1061{
1062 fn new() -> Self {
1063 Self {
1064 inner: P::new(),
1065 range: RangeInclusive::new(S::get(), E::get()),
1066 _phantom: PhantomData,
1067 }
1068 }
1069
1070 fn execute<R: pallet_evm::Config>(
1071 &self,
1072 handle: &mut impl PrecompileHandle,
1073 ) -> Option<PrecompileResult> {
1074 if self.range.contains(&handle.code_address()) {
1075 self.inner.execute::<R>(handle)
1076 } else {
1077 None
1078 }
1079 }
1080
1081 fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult {
1082 if self.range.contains(&address) {
1083 self.inner.is_precompile(address, gas)
1084 } else {
1085 IsPrecompileResult::Answer {
1086 is_precompile: false,
1087 extra_cost: 0,
1088 }
1089 }
1090 }
1091
1092 fn used_addresses(&self) -> Vec<H160> {
1093 self.inner.used_addresses()
1094 }
1095
1096 fn summarize_checks(&self) -> Vec<PrecompileCheckSummary> {
1097 self.inner.summarize_checks()
1098 }
1099}
1100
1101impl<S, E, P> IsActivePrecompile for PrecompilesInRangeInclusive<(S, E), P>
1102where
1103 P: IsActivePrecompile,
1104{
1105 fn is_active_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult {
1106 if self.range.contains(&address) {
1107 self.inner.is_active_precompile(address, gas)
1108 } else {
1109 IsPrecompileResult::Answer {
1110 is_precompile: false,
1111 extra_cost: 0,
1112 }
1113 }
1114 }
1115}
1116
1117pub struct PrecompileSetBuilder<R, P> {
1119 inner: P,
1120 _phantom: PhantomData<R>,
1121}
1122
1123impl<R: pallet_evm::Config, P: PrecompileSetFragment> PrecompileSet for PrecompileSetBuilder<R, P> {
1124 fn execute(&self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult> {
1125 self.inner.execute::<R>(handle)
1126 }
1127
1128 fn is_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult {
1129 self.inner.is_precompile(address, gas)
1130 }
1131}
1132
1133impl<R, P: IsActivePrecompile> IsActivePrecompile for PrecompileSetBuilder<R, P> {
1134 fn is_active_precompile(&self, address: H160, gas: u64) -> IsPrecompileResult {
1135 self.inner.is_active_precompile(address, gas)
1136 }
1137}
1138
1139impl<R: pallet_evm::Config, P: PrecompileSetFragment> Default for PrecompileSetBuilder<R, P> {
1140 fn default() -> Self {
1141 Self::new()
1142 }
1143}
1144
1145impl<R: pallet_evm::Config, P: PrecompileSetFragment> PrecompileSetBuilder<R, P> {
1146 pub fn new() -> Self {
1148 Self {
1149 inner: P::new(),
1150 _phantom: PhantomData,
1151 }
1152 }
1153
1154 pub fn used_addresses() -> impl Iterator<Item = pallet_evm::AccountIdOf<R>> {
1156 Self::used_addresses_h160().map(R::AddressMapping::into_account_id)
1157 }
1158
1159 pub fn used_addresses_h160() -> impl Iterator<Item = H160> {
1161 Self::new().inner.used_addresses().into_iter()
1162 }
1163
1164 pub fn summarize_checks(&self) -> Vec<PrecompileCheckSummary> {
1165 self.inner.summarize_checks()
1166 }
1167}