@@ -1046,6 +1046,7 @@ pub mod pallet {
10461046 #[ pallet:: compact] storage_deposit_limit : BalanceOf < T > ,
10471047 data : Vec < u8 > ,
10481048 ) -> DispatchResultWithPostInfo {
1049+ Self :: ensure_non_contract_if_signed ( & origin) ?;
10491050 let mut output = Self :: bare_call (
10501051 origin,
10511052 dest,
@@ -1082,6 +1083,7 @@ pub mod pallet {
10821083 data : Vec < u8 > ,
10831084 salt : Option < [ u8 ; 32 ] > ,
10841085 ) -> DispatchResultWithPostInfo {
1086+ Self :: ensure_non_contract_if_signed ( & origin) ?;
10851087 let data_len = data. len ( ) as u32 ;
10861088 let mut output = Self :: bare_instantiate (
10871089 origin,
@@ -1146,6 +1148,7 @@ pub mod pallet {
11461148 data : Vec < u8 > ,
11471149 salt : Option < [ u8 ; 32 ] > ,
11481150 ) -> DispatchResultWithPostInfo {
1151+ Self :: ensure_non_contract_if_signed ( & origin) ?;
11491152 let code_len = code. len ( ) as u32 ;
11501153 let data_len = data. len ( ) as u32 ;
11511154 let mut output = Self :: bare_instantiate (
@@ -1207,6 +1210,7 @@ pub mod pallet {
12071210 encoded_len : u32 ,
12081211 ) -> DispatchResultWithPostInfo {
12091212 let origin = Self :: ensure_eth_origin ( origin) ?;
1213+ Self :: ensure_non_contract_if_signed ( & origin) ?;
12101214 let mut call = Call :: < T > :: eth_instantiate_with_code {
12111215 value,
12121216 gas_limit,
@@ -1277,6 +1281,7 @@ pub mod pallet {
12771281 encoded_len : u32 ,
12781282 ) -> DispatchResultWithPostInfo {
12791283 let origin = Self :: ensure_eth_origin ( origin) ?;
1284+ Self :: ensure_non_contract_if_signed ( & origin) ?;
12801285 let mut call = Call :: < T > :: eth_call {
12811286 dest,
12821287 value,
@@ -1352,6 +1357,7 @@ pub mod pallet {
13521357 code : Vec < u8 > ,
13531358 #[ pallet:: compact] storage_deposit_limit : BalanceOf < T > ,
13541359 ) -> DispatchResult {
1360+ Self :: ensure_non_contract_if_signed ( & origin) ?;
13551361 Self :: bare_upload_code ( origin, code, storage_deposit_limit) . map ( |_| ( ) )
13561362 }
13571363
@@ -1413,6 +1419,7 @@ pub mod pallet {
14131419 #[ pallet:: call_index( 7 ) ]
14141420 #[ pallet:: weight( <T as Config >:: WeightInfo :: map_account( ) ) ]
14151421 pub fn map_account ( origin : OriginFor < T > ) -> DispatchResult {
1422+ Self :: ensure_non_contract_if_signed ( & origin) ?;
14161423 let origin = ensure_signed ( origin) ?;
14171424 T :: AddressMapper :: map ( & origin)
14181425 }
@@ -1445,6 +1452,7 @@ pub mod pallet {
14451452 origin : OriginFor < T > ,
14461453 call : Box < <T as Config >:: RuntimeCall > ,
14471454 ) -> DispatchResultWithPostInfo {
1455+ Self :: ensure_non_contract_if_signed ( & origin) ?;
14481456 let origin = ensure_signed ( origin) ?;
14491457 let unmapped_account =
14501458 T :: AddressMapper :: to_fallback_account_id ( & T :: AddressMapper :: to_address ( & origin) ) ;
@@ -1485,9 +1493,6 @@ impl<T: Config> Pallet<T> {
14851493 data : Vec < u8 > ,
14861494 exec_config : ExecConfig ,
14871495 ) -> ContractResult < ExecReturnValue , BalanceOf < T > > {
1488- if let Err ( contract_result) = Self :: ensure_non_contract_if_signed ( & origin) {
1489- return contract_result;
1490- }
14911496 let mut gas_meter = GasMeter :: new ( gas_limit) ;
14921497 let mut storage_deposit = Default :: default ( ) ;
14931498
@@ -1544,10 +1549,6 @@ impl<T: Config> Pallet<T> {
15441549 salt : Option < [ u8 ; 32 ] > ,
15451550 exec_config : ExecConfig ,
15461551 ) -> ContractResult < InstantiateReturnValue , BalanceOf < T > > {
1547- // Enforce EIP-3607 for top-level signed origins: deny signed contract addresses.
1548- if let Err ( contract_result) = Self :: ensure_non_contract_if_signed ( & origin) {
1549- return contract_result;
1550- }
15511552 let mut gas_meter = GasMeter :: new ( gas_limit) ;
15521553 let mut storage_deposit = Default :: default ( ) ;
15531554 let try_instantiate = || {
@@ -2094,6 +2095,39 @@ impl<T: Config> Pallet<T> {
20942095 . map_err ( ContractAccessError :: StorageWriteFailed )
20952096 }
20962097
2098+ /// Pallet account, used to hold funds for contracts upload deposit.
2099+ pub fn account_id ( ) -> T :: AccountId {
2100+ use frame_support:: PalletId ;
2101+ use sp_runtime:: traits:: AccountIdConversion ;
2102+ PalletId ( * b"py/reviv" ) . into_account_truncating ( )
2103+ }
2104+
2105+ /// The address of the validator that produced the current block.
2106+ pub fn block_author ( ) -> H160 {
2107+ use frame_support:: traits:: FindAuthor ;
2108+
2109+ let digest = <frame_system:: Pallet < T > >:: digest ( ) ;
2110+ let pre_runtime_digests = digest. logs . iter ( ) . filter_map ( |d| d. as_pre_runtime ( ) ) ;
2111+
2112+ T :: FindAuthor :: find_author ( pre_runtime_digests)
2113+ . map ( |account_id| T :: AddressMapper :: to_address ( & account_id) )
2114+ . unwrap_or_default ( )
2115+ }
2116+
2117+ /// Returns the code at `address`.
2118+ ///
2119+ /// This takes pre-compiles into account.
2120+ pub fn code ( address : & H160 ) -> Vec < u8 > {
2121+ use precompiles:: { All , Precompiles } ;
2122+ if let Some ( code) = <All < T > >:: code ( address. as_fixed_bytes ( ) ) {
2123+ return code. into ( )
2124+ }
2125+ AccountInfo :: < T > :: load_contract ( & address)
2126+ . and_then ( |contract| <PristineCode < T > >:: get ( contract. code_hash ) )
2127+ . map ( |code| code. into ( ) )
2128+ . unwrap_or_default ( )
2129+ }
2130+
20972131 /// Uploads new code and returns the Vm binary contract blob and deposit amount collected.
20982132 fn try_upload_pvm_code (
20992133 origin : T :: AccountId ,
@@ -2131,80 +2165,6 @@ impl<T: Config> Pallet<T> {
21312165 T :: FeeInfo :: weight_to_fee ( & weight, Combinator :: Max ) . into ( )
21322166 }
21332167
2134- /// Ensure the origin has no code deplyoyed if it is a signed origin.
2135- fn ensure_non_contract_if_signed < ReturnValue > (
2136- origin : & OriginFor < T > ,
2137- ) -> Result < ( ) , ContractResult < ReturnValue , BalanceOf < T > > > {
2138- use crate :: exec:: is_precompile;
2139- let Ok ( who) = ensure_signed ( origin. clone ( ) ) else { return Ok ( ( ) ) } ;
2140- let address = <T :: AddressMapper as AddressMapper < T > >:: to_address ( & who) ;
2141-
2142- // EIP_1052: precompile can never be used as EOA.
2143- if is_precompile :: < T , ContractBlob < T > > ( & address) {
2144- log:: debug!(
2145- target: crate :: LOG_TARGET ,
2146- "EIP-3607: reject externally-signed tx from precompile account {:?}" ,
2147- address
2148- ) ;
2149- return Err ( ContractResult {
2150- result : Err ( DispatchError :: BadOrigin ) ,
2151- gas_consumed : Weight :: default ( ) ,
2152- gas_required : Weight :: default ( ) ,
2153- storage_deposit : Default :: default ( ) ,
2154- } ) ;
2155- }
2156-
2157- // Deployed code exists when hash is neither zero (no account) nor EMPTY_CODE_HASH
2158- // (account exists but no code).
2159- if <AccountInfo < T > >:: is_contract ( & address) {
2160- log:: debug!(
2161- target: crate :: LOG_TARGET ,
2162- "EIP-3607: reject externally-signed tx from contract account {:?}" ,
2163- address
2164- ) ;
2165- return Err ( ContractResult {
2166- result : Err ( DispatchError :: BadOrigin ) ,
2167- gas_consumed : Weight :: default ( ) ,
2168- gas_required : Weight :: default ( ) ,
2169- storage_deposit : Default :: default ( ) ,
2170- } ) ;
2171- }
2172- Ok ( ( ) )
2173- }
2174-
2175- /// Pallet account, used to hold funds for contracts upload deposit.
2176- pub fn account_id ( ) -> T :: AccountId {
2177- use frame_support:: PalletId ;
2178- use sp_runtime:: traits:: AccountIdConversion ;
2179- PalletId ( * b"py/reviv" ) . into_account_truncating ( )
2180- }
2181-
2182- /// The address of the validator that produced the current block.
2183- pub fn block_author ( ) -> H160 {
2184- use frame_support:: traits:: FindAuthor ;
2185-
2186- let digest = <frame_system:: Pallet < T > >:: digest ( ) ;
2187- let pre_runtime_digests = digest. logs . iter ( ) . filter_map ( |d| d. as_pre_runtime ( ) ) ;
2188-
2189- T :: FindAuthor :: find_author ( pre_runtime_digests)
2190- . map ( |account_id| T :: AddressMapper :: to_address ( & account_id) )
2191- . unwrap_or_default ( )
2192- }
2193-
2194- /// Returns the code at `address`.
2195- ///
2196- /// This takes pre-compiles into account.
2197- pub fn code ( address : & H160 ) -> Vec < u8 > {
2198- use precompiles:: { All , Precompiles } ;
2199- if let Some ( code) = <All < T > >:: code ( address. as_fixed_bytes ( ) ) {
2200- return code. into ( )
2201- }
2202- AccountInfo :: < T > :: load_contract ( & address)
2203- . and_then ( |contract| <PristineCode < T > >:: get ( contract. code_hash ) )
2204- . map ( |code| code. into ( ) )
2205- . unwrap_or_default ( )
2206- }
2207-
22082168 /// Transfer a deposit from some account to another.
22092169 ///
22102170 /// `from` is usually the transaction origin and `to` a contract or
@@ -2331,6 +2291,30 @@ impl<T: Config> Pallet<T> {
23312291 _ => Err ( BadOrigin . into ( ) ) ,
23322292 }
23332293 }
2294+
2295+ /// Ensure that the origin is neither a pre-compile nor a contract.
2296+ ///
2297+ /// This enforces EIP-3607.
2298+ fn ensure_non_contract_if_signed ( origin : & OriginFor < T > ) -> DispatchResult {
2299+ let Some ( address) = origin
2300+ . as_system_ref ( )
2301+ . and_then ( |o| o. as_signed ( ) )
2302+ . map ( <T :: AddressMapper as AddressMapper < T > >:: to_address)
2303+ else {
2304+ return Ok ( ( ) )
2305+ } ;
2306+ if exec:: is_precompile :: < T , ContractBlob < T > > ( & address) ||
2307+ <AccountInfo < T > >:: is_contract ( & address)
2308+ {
2309+ log:: debug!(
2310+ target: crate :: LOG_TARGET ,
2311+ "EIP-3607: reject tx as pre-compile or account exist at {address:?}" ,
2312+ ) ;
2313+ Err ( DispatchError :: BadOrigin )
2314+ } else {
2315+ Ok ( ( ) )
2316+ }
2317+ }
23342318}
23352319
23362320/// The address used to call the runtime's pallets dispatchables
0 commit comments