@@ -21,24 +21,20 @@ use wasmi::Module as WasmModule;
2121use runtime_version:: RuntimeVersion ;
2222use std:: collections:: HashMap ;
2323use codec:: Decode ;
24- use twox_hash:: XxHash ;
25- use std:: hash:: Hasher ;
24+ use primitives:: hashing:: blake2_256;
2625use parking_lot:: { Mutex , MutexGuard } ;
2726use RuntimeInfo ;
2827use primitives:: KeccakHasher ;
2928
3029// For the internal Runtime Cache:
3130// Is it compatible enough to run this natively or do we need to fall back on the WasmModule
3231
33- enum Compatibility {
34- InvalidVersion ( WasmModule ) ,
35- IsCompatible ( RuntimeVersion , WasmModule ) ,
36- NotCompatible ( RuntimeVersion , WasmModule )
32+ enum RuntimePreproc {
33+ InvalidCode ,
34+ ValidCode ( WasmModule , Option < RuntimeVersion > ) ,
3735}
3836
39- unsafe impl Send for Compatibility { }
40-
41- type CacheType = HashMap < u64 , Compatibility > ;
37+ type CacheType = HashMap < [ u8 ; 32 ] , RuntimePreproc > ;
4238
4339lazy_static ! {
4440 static ref RUNTIMES_CACHE : Mutex <CacheType > = Mutex :: new( HashMap :: new( ) ) ;
@@ -48,10 +44,8 @@ lazy_static! {
4844// it is asserted that part of the audit process that any potential on-chain code change
4945// will have done is to ensure that the two-x hash is different to that of any other
5046// :code value from the same chain
51- fn gen_cache_key ( code : & [ u8 ] ) -> u64 {
52- let mut h = XxHash :: with_seed ( 0 ) ;
53- h. write ( code) ;
54- h. finish ( )
47+ fn gen_cache_key ( code : & [ u8 ] ) -> [ u8 ; 32 ] {
48+ blake2_256 ( code)
5549}
5650
5751/// fetch a runtime version from the cache or if there is no cached version yet, create
@@ -61,25 +55,22 @@ fn fetch_cached_runtime_version<'a, E: Externalities<KeccakHasher>>(
6155 wasm_executor : & WasmExecutor ,
6256 cache : & ' a mut MutexGuard < CacheType > ,
6357 ext : & mut E ,
64- code : & [ u8 ] ,
65- ref_version : RuntimeVersion
66- ) -> & ' a Compatibility {
67- cache. entry ( gen_cache_key ( code) )
68- . or_insert_with ( || {
69- let module = WasmModule :: from_buffer ( code) . expect ( "all modules compiled with rustc are valid wasm code; qed" ) ;
70- let version = wasm_executor. call_in_wasm_module ( ext, & module, "version" , & [ ] ) . ok ( )
71- . and_then ( |v| RuntimeVersion :: decode ( & mut v. as_slice ( ) ) ) ;
72-
73- if let Some ( v) = version {
74- if ref_version. can_call_with ( & v) {
75- Compatibility :: IsCompatible ( v, module)
76- } else {
77- Compatibility :: NotCompatible ( v, module)
78- }
79- } else {
80- Compatibility :: InvalidVersion ( module)
58+ code : & [ u8 ]
59+ ) -> Result < ( & ' a WasmModule , & ' a Option < RuntimeVersion > ) > {
60+ let maybe_runtime_preproc = cache. entry ( gen_cache_key ( code) )
61+ . or_insert_with ( || match WasmModule :: from_buffer ( code) {
62+ Ok ( module) => {
63+ let version = wasm_executor. call_in_wasm_module ( ext, & module, "version" , & [ ] )
64+ . ok ( )
65+ . and_then ( |v| RuntimeVersion :: decode ( & mut v. as_slice ( ) ) ) ;
66+ RuntimePreproc :: ValidCode ( module, version)
8167 }
82- } )
68+ Err ( _) => RuntimePreproc :: InvalidCode ,
69+ } ) ;
70+ match maybe_runtime_preproc {
71+ RuntimePreproc :: InvalidCode => Err ( ErrorKind :: InvalidCode ( code. into ( ) ) . into ( ) ) ,
72+ RuntimePreproc :: ValidCode ( m, v) => Ok ( ( m, v) ) ,
73+ }
8374}
8475
8576fn safe_call < F , U > ( f : F ) -> Result < U >
@@ -157,11 +148,7 @@ impl<D: NativeExecutionDispatch> RuntimeInfo for NativeExecutor<D> {
157148 ext : & mut E ,
158149 code : & [ u8 ] ,
159150 ) -> Option < RuntimeVersion > {
160- let mut c = RUNTIMES_CACHE . lock ( ) ;
161- match fetch_cached_runtime_version ( & self . fallback , & mut c, ext, code, D :: VERSION ) {
162- Compatibility :: IsCompatible ( v, _) | Compatibility :: NotCompatible ( v, _) => Some ( v. clone ( ) ) ,
163- Compatibility :: InvalidVersion ( _m) => None
164- }
151+ fetch_cached_runtime_version ( & self . fallback , & mut RUNTIMES_CACHE . lock ( ) , ext, code) . ok ( ) ?. 1 . clone ( )
165152 }
166153}
167154
@@ -177,10 +164,22 @@ impl<D: NativeExecutionDispatch> CodeExecutor<KeccakHasher> for NativeExecutor<D
177164 use_native : bool ,
178165 ) -> ( Result < Vec < u8 > > , bool ) {
179166 let mut c = RUNTIMES_CACHE . lock ( ) ;
180- match ( use_native, fetch_cached_runtime_version ( & self . fallback , & mut c, ext, code, D :: VERSION ) ) {
181- ( _, Compatibility :: NotCompatible ( _, m) ) | ( _, Compatibility :: InvalidVersion ( m) ) | ( false , Compatibility :: IsCompatible ( _, m) ) =>
182- ( self . fallback . call_in_wasm_module ( ext, m, method, data) , false ) ,
183- _ => ( D :: dispatch ( ext, method, data) , true ) ,
167+ let ( module, onchain_version) = match fetch_cached_runtime_version ( & self . fallback , & mut c, ext, code) {
168+ Ok ( ( module, onchain_version) ) => ( module, onchain_version) ,
169+ Err ( _) => return ( Err ( ErrorKind :: InvalidCode ( code. into ( ) ) . into ( ) ) , false ) ,
170+ } ;
171+ match ( use_native, onchain_version. as_ref ( ) . map_or ( false , |v| v. can_call_with ( & D :: VERSION ) ) ) {
172+ ( _, false ) => {
173+ trace ! ( target: "executor" , "Request for native execution failed (native: {}, chain: {})" , D :: VERSION , onchain_version. as_ref( ) . map_or_else( ||"<None>" . into( ) , |v| format!( "{}" , v) ) ) ;
174+ ( self . fallback . call_in_wasm_module ( ext, module, method, data) , false )
175+ }
176+ ( false , _) => {
177+ ( self . fallback . call_in_wasm_module ( ext, module, method, data) , false )
178+ }
179+ _ => {
180+ trace ! ( target: "executor" , "Request for native execution succeeded (native: {}, chain: {})" , D :: VERSION , onchain_version. as_ref( ) . map_or_else( ||"<None>" . into( ) , |v| format!( "{}" , v) ) ) ;
181+ ( D :: dispatch ( ext, method, data) , true )
182+ }
184183 }
185184 }
186185}
0 commit comments