@@ -29,7 +29,7 @@ use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec};
29
29
use core:: { cell:: RefCell , marker:: PhantomData , ops:: RangeInclusive } ;
30
30
use fp_evm:: {
31
31
ExitError , IsPrecompileResult , Precompile , PrecompileFailure , PrecompileHandle ,
32
- PrecompileResult , PrecompileSet ,
32
+ PrecompileResult , PrecompileSet , ACCOUNT_CODES_METADATA_PROOF_SIZE ,
33
33
} ;
34
34
use frame_support:: pallet_prelude:: Get ;
35
35
use impl_trait_for_tuples:: impl_for_tuples;
@@ -304,13 +304,11 @@ impl<T: SelectorFilter> PrecompileChecks for CallableByPrecompile<T> {
304
304
#[ derive( PartialEq ) ]
305
305
#[ cfg_attr( feature = "std" , derive( Debug ) ) ]
306
306
pub enum AddressType {
307
- /// The code stored at the address is less than 5 bytes, but not well known.
308
- Unknown ,
309
307
/// No code is stored at the address, therefore is EOA.
310
308
EOA ,
311
309
/// The 5-byte magic constant for a precompile is stored at the address.
312
310
Precompile ,
313
- /// The code is greater than 5-bytes, potentially a Smart Contract.
311
+ /// Every address that is not a EOA or a Precompile is potentially a Smart Contract.
314
312
Contract ,
315
313
}
316
314
@@ -319,39 +317,27 @@ pub fn get_address_type<R: pallet_evm::Config>(
319
317
handle : & mut impl PrecompileHandle ,
320
318
address : H160 ,
321
319
) -> Result < AddressType , ExitError > {
320
+ // Check if address is a precompile
321
+ if let Ok ( true ) = is_precompile_or_fail :: < R > ( address, handle. remaining_gas ( ) ) {
322
+ return Ok ( AddressType :: Precompile ) ;
323
+ }
324
+
325
+ // Contracts under-construction don't have code yet
326
+ if handle. is_contract_being_constructed ( address) {
327
+ return Ok ( AddressType :: Contract ) ;
328
+ }
329
+
322
330
// AccountCodesMetadata:
323
331
// Blake2128(16) + H160(20) + CodeMetadata(40)
324
- handle. record_db_read :: < R > ( 76 ) ?;
332
+ handle. record_db_read :: < R > ( ACCOUNT_CODES_METADATA_PROOF_SIZE as usize ) ?;
325
333
let code_len = pallet_evm:: Pallet :: < R > :: account_code_metadata ( address) . size ;
326
334
327
- // 0 => either EOA or precompile without dummy code
335
+ // Having no code at this point means that the address is an EOA
328
336
if code_len == 0 {
329
337
return Ok ( AddressType :: EOA ) ;
330
338
}
331
339
332
- // dummy code is 5 bytes long, so any other len means it is a contract.
333
- if code_len != 5 {
334
- return Ok ( AddressType :: Contract ) ;
335
- }
336
-
337
- // check code matches dummy code
338
- handle. record_db_read :: < R > ( code_len as usize ) ?;
339
- let code = pallet_evm:: AccountCodes :: < R > :: get ( address) ;
340
- if code == [ 0x60 , 0x00 , 0x60 , 0x00 , 0xfd ] {
341
- return Ok ( AddressType :: Precompile ) ;
342
- }
343
-
344
- Ok ( AddressType :: Unknown )
345
- }
346
-
347
- fn is_address_eoa_or_precompile < R : pallet_evm:: Config > (
348
- handle : & mut impl PrecompileHandle ,
349
- address : H160 ,
350
- ) -> Result < bool , ExitError > {
351
- match get_address_type :: < R > ( handle, address) ? {
352
- AddressType :: EOA | AddressType :: Precompile => Ok ( true ) ,
353
- _ => Ok ( false ) ,
354
- }
340
+ Ok ( AddressType :: Contract )
355
341
}
356
342
357
343
/// Common checks for precompile and precompile sets.
@@ -375,17 +361,27 @@ fn common_checks<R: pallet_evm::Config, C: PrecompileChecks>(
375
361
u32:: from_be_bytes ( buffer)
376
362
} ) ;
377
363
378
- // Is this selector callable from a smart contract?
379
- let callable_by_smart_contract =
380
- C :: callable_by_smart_contract ( caller, selector) . unwrap_or ( false ) ;
381
- if !callable_by_smart_contract && !is_address_eoa_or_precompile :: < R > ( handle, caller) ? {
382
- return Err ( revert ( "Function not callable by smart contracts" ) ) ;
383
- }
384
-
385
- // Is this selector callable from a precompile?
386
- let callable_by_precompile = C :: callable_by_precompile ( caller, selector) . unwrap_or ( false ) ;
387
- if !callable_by_precompile && is_precompile_or_fail :: < R > ( caller, handle. remaining_gas ( ) ) ? {
388
- return Err ( revert ( "Function not callable by precompiles" ) ) ;
364
+ let caller_address_type = get_address_type :: < R > ( handle, caller) ?;
365
+ match caller_address_type {
366
+ AddressType :: Precompile => {
367
+ // Is this selector callable from a precompile?
368
+ 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
+ // Is this selector callable from a smart contract?
376
+ 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
+ // No check required for EOA
384
+ }
389
385
}
390
386
391
387
Ok ( ( ) )
@@ -463,6 +459,10 @@ impl<'a, H: PrecompileHandle> PrecompileHandle for RestrictiveHandle<'a, H> {
463
459
self . handle . context ( )
464
460
}
465
461
462
+ fn origin ( & self ) -> H160 {
463
+ self . handle . origin ( )
464
+ }
465
+
466
466
fn is_static ( & self ) -> bool {
467
467
self . handle . is_static ( )
468
468
}
@@ -484,6 +484,10 @@ impl<'a, H: PrecompileHandle> PrecompileHandle for RestrictiveHandle<'a, H> {
484
484
fn refund_external_cost ( & mut self , ref_time : Option < u64 > , proof_size : Option < u64 > ) {
485
485
self . handle . refund_external_cost ( ref_time, proof_size)
486
486
}
487
+
488
+ fn is_contract_being_constructed ( & self , address : H160 ) -> bool {
489
+ self . handle . is_contract_being_constructed ( address)
490
+ }
487
491
}
488
492
489
493
/// Allows to know if a precompile is active or not.
0 commit comments