@@ -21,24 +21,20 @@ use wasmi::Module as WasmModule;
21
21
use runtime_version:: RuntimeVersion ;
22
22
use std:: collections:: HashMap ;
23
23
use codec:: Decode ;
24
- use twox_hash:: XxHash ;
25
- use std:: hash:: Hasher ;
24
+ use primitives:: hashing:: blake2_256;
26
25
use parking_lot:: { Mutex , MutexGuard } ;
27
26
use RuntimeInfo ;
28
27
use primitives:: KeccakHasher ;
29
28
30
29
// For the internal Runtime Cache:
31
30
// Is it compatible enough to run this natively or do we need to fall back on the WasmModule
32
31
33
- enum Compatibility {
34
- InvalidVersion ( WasmModule ) ,
35
- IsCompatible ( RuntimeVersion , WasmModule ) ,
36
- NotCompatible ( RuntimeVersion , WasmModule )
32
+ enum RuntimePreproc {
33
+ InvalidCode ,
34
+ ValidCode ( WasmModule , Option < RuntimeVersion > ) ,
37
35
}
38
36
39
- unsafe impl Send for Compatibility { }
40
-
41
- type CacheType = HashMap < u64 , Compatibility > ;
37
+ type CacheType = HashMap < [ u8 ; 32 ] , RuntimePreproc > ;
42
38
43
39
lazy_static ! {
44
40
static ref RUNTIMES_CACHE : Mutex <CacheType > = Mutex :: new( HashMap :: new( ) ) ;
@@ -48,10 +44,8 @@ lazy_static! {
48
44
// it is asserted that part of the audit process that any potential on-chain code change
49
45
// will have done is to ensure that the two-x hash is different to that of any other
50
46
// :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)
55
49
}
56
50
57
51
/// 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>>(
61
55
wasm_executor : & WasmExecutor ,
62
56
cache : & ' a mut MutexGuard < CacheType > ,
63
57
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)
81
67
}
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
+ }
83
74
}
84
75
85
76
fn safe_call < F , U > ( f : F ) -> Result < U >
@@ -157,11 +148,7 @@ impl<D: NativeExecutionDispatch> RuntimeInfo for NativeExecutor<D> {
157
148
ext : & mut E ,
158
149
code : & [ u8 ] ,
159
150
) -> 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 ( )
165
152
}
166
153
}
167
154
@@ -177,10 +164,22 @@ impl<D: NativeExecutionDispatch> CodeExecutor<KeccakHasher> for NativeExecutor<D
177
164
use_native : bool ,
178
165
) -> ( Result < Vec < u8 > > , bool ) {
179
166
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
+ }
184
183
}
185
184
}
186
185
}
0 commit comments