@@ -88,28 +88,33 @@ where
88
88
}
89
89
90
90
/// get instance returns a wasmer Instance tied to a previously saved wasm
91
- pub fn get_instance ( & mut self , id : & [ u8 ] , deps : Extern < S , A > ) -> Result < Instance < S , A > , Error > {
91
+ pub fn get_instance (
92
+ & mut self ,
93
+ id : & [ u8 ] ,
94
+ deps : Extern < S , A > ,
95
+ gas_limit : u64 ,
96
+ ) -> Result < Instance < S , A > , Error > {
92
97
let hash = WasmHash :: generate ( & id) ;
93
98
94
99
// pop from lru cache if present
95
100
if let Some ( cache) = & mut self . instances {
96
101
if let Some ( cached_instance) = cache. pop ( & hash) {
97
102
self . stats . hits_instance += 1 ;
98
- return Ok ( Instance :: from_wasmer ( cached_instance, deps) ) ;
103
+ return Ok ( Instance :: from_wasmer ( cached_instance, deps, gas_limit ) ) ;
99
104
}
100
105
}
101
106
102
107
// try from the module cache
103
108
let res = self . modules . load_with_backend ( hash, backend ( ) ) ;
104
109
if let Ok ( module) = res {
105
110
self . stats . hits_module += 1 ;
106
- return Instance :: from_module ( & module, deps) ;
111
+ return Instance :: from_module ( & module, deps, gas_limit ) ;
107
112
}
108
113
109
114
// fall back to wasm cache (and re-compiling) - this is for backends that don't support serialization
110
115
let wasm = self . load_wasm ( id) ?;
111
116
self . stats . misses += 1 ;
112
- Instance :: from_code ( & wasm, deps)
117
+ Instance :: from_code ( & wasm, deps, gas_limit )
113
118
}
114
119
115
120
pub fn store_instance ( & mut self , id : & [ u8 ] , instance : Instance < S , A > ) -> Option < Extern < S , A > > {
@@ -135,6 +140,7 @@ mod test {
135
140
use cosmwasm:: mock:: { dependencies, mock_env, MockApi , MockStorage } ;
136
141
use cosmwasm:: types:: coin;
137
142
143
+ static TESTING_GAS_LIMIT : u64 = 400_000 ;
138
144
static CONTRACT_0_7 : & [ u8 ] = include_bytes ! ( "../testdata/contract_0.7.wasm" ) ;
139
145
140
146
#[ test]
@@ -170,7 +176,7 @@ mod test {
170
176
let mut cache = unsafe { CosmCache :: new ( tmp_dir. path ( ) , 10 ) . unwrap ( ) } ;
171
177
let id = cache. save_wasm ( CONTRACT_0_7 ) . unwrap ( ) ;
172
178
let deps = dependencies ( 20 ) ;
173
- let _instance = cache. get_instance ( & id, deps) . unwrap ( ) ;
179
+ let _instance = cache. get_instance ( & id, deps, TESTING_GAS_LIMIT ) . unwrap ( ) ;
174
180
assert_eq ! ( cache. stats. hits_instance, 0 ) ;
175
181
assert_eq ! ( cache. stats. hits_module, 1 ) ;
176
182
assert_eq ! ( cache. stats. misses, 0 ) ;
@@ -184,11 +190,11 @@ mod test {
184
190
let deps1 = dependencies ( 20 ) ;
185
191
let deps2 = dependencies ( 20 ) ;
186
192
let deps3 = dependencies ( 20 ) ;
187
- let instance1 = cache. get_instance ( & id, deps1) . unwrap ( ) ;
193
+ let instance1 = cache. get_instance ( & id, deps1, TESTING_GAS_LIMIT ) . unwrap ( ) ;
188
194
cache. store_instance ( & id, instance1) ;
189
- let instance2 = cache. get_instance ( & id, deps2) . unwrap ( ) ;
195
+ let instance2 = cache. get_instance ( & id, deps2, TESTING_GAS_LIMIT ) . unwrap ( ) ;
190
196
cache. store_instance ( & id, instance2) ;
191
- let instance3 = cache. get_instance ( & id, deps3) . unwrap ( ) ;
197
+ let instance3 = cache. get_instance ( & id, deps3, TESTING_GAS_LIMIT ) . unwrap ( ) ;
192
198
cache. store_instance ( & id, instance3) ;
193
199
assert_eq ! ( cache. stats. hits_instance, 2 ) ;
194
200
assert_eq ! ( cache. stats. hits_module, 1 ) ;
@@ -201,7 +207,7 @@ mod test {
201
207
let mut cache = unsafe { CosmCache :: new ( tmp_dir. path ( ) , 10 ) . unwrap ( ) } ;
202
208
let id = cache. save_wasm ( CONTRACT_0_7 ) . unwrap ( ) ;
203
209
let deps = dependencies ( 20 ) ;
204
- let mut instance = cache. get_instance ( & id, deps) . unwrap ( ) ;
210
+ let mut instance = cache. get_instance ( & id, deps, TESTING_GAS_LIMIT ) . unwrap ( ) ;
205
211
206
212
// run contract
207
213
let env = mock_env ( & instance. api , "creator" , & coin ( "1000" , "earth" ) , & [ ] ) ;
@@ -219,7 +225,7 @@ mod test {
219
225
let mut cache = unsafe { CosmCache :: new ( tmp_dir. path ( ) , 10 ) . unwrap ( ) } ;
220
226
let id = cache. save_wasm ( CONTRACT_0_7 ) . unwrap ( ) ;
221
227
let deps = dependencies ( 20 ) ;
222
- let mut instance = cache. get_instance ( & id, deps) . unwrap ( ) ;
228
+ let mut instance = cache. get_instance ( & id, deps, TESTING_GAS_LIMIT ) . unwrap ( ) ;
223
229
224
230
// init contract
225
231
let env = mock_env ( & instance. api , "creator" , & coin ( "1000" , "earth" ) , & [ ] ) ;
@@ -252,7 +258,7 @@ mod test {
252
258
let deps2 = dependencies ( 20 ) ;
253
259
254
260
// init instance 1
255
- let mut instance = cache. get_instance ( & id, deps1) . unwrap ( ) ;
261
+ let mut instance = cache. get_instance ( & id, deps1, TESTING_GAS_LIMIT ) . unwrap ( ) ;
256
262
let env = mock_env ( & instance. api , "owner1" , & coin ( "1000" , "earth" ) , & [ ] ) ;
257
263
let msg = r#"{"verifier": "sue", "beneficiary": "mary"}"# . as_bytes ( ) ;
258
264
let res = call_init ( & mut instance, & env, msg) . unwrap ( ) ;
@@ -261,7 +267,7 @@ mod test {
261
267
let deps1 = cache. store_instance ( & id, instance) . unwrap ( ) ;
262
268
263
269
// init instance 2
264
- let mut instance = cache. get_instance ( & id, deps2) . unwrap ( ) ;
270
+ let mut instance = cache. get_instance ( & id, deps2, TESTING_GAS_LIMIT ) . unwrap ( ) ;
265
271
let env = mock_env ( & instance. api , "owner2" , & coin ( "500" , "earth" ) , & [ ] ) ;
266
272
let msg = r#"{"verifier": "bob", "beneficiary": "john"}"# . as_bytes ( ) ;
267
273
let res = call_init ( & mut instance, & env, msg) . unwrap ( ) ;
@@ -270,7 +276,7 @@ mod test {
270
276
let deps2 = cache. store_instance ( & id, instance) . unwrap ( ) ;
271
277
272
278
// run contract 2 - just sanity check - results validate in contract unit tests
273
- let mut instance = cache. get_instance ( & id, deps2) . unwrap ( ) ;
279
+ let mut instance = cache. get_instance ( & id, deps2, TESTING_GAS_LIMIT ) . unwrap ( ) ;
274
280
let env = mock_env (
275
281
& instance. api ,
276
282
"bob" ,
@@ -284,7 +290,7 @@ mod test {
284
290
let _ = cache. store_instance ( & id, instance) . unwrap ( ) ;
285
291
286
292
// run contract 1 - just sanity check - results validate in contract unit tests
287
- let mut instance = cache. get_instance ( & id, deps1) . unwrap ( ) ;
293
+ let mut instance = cache. get_instance ( & id, deps1, TESTING_GAS_LIMIT ) . unwrap ( ) ;
288
294
let env = mock_env (
289
295
& instance. api ,
290
296
"sue" ,
@@ -297,4 +303,76 @@ mod test {
297
303
assert_eq ! ( 1 , msgs. len( ) ) ;
298
304
let _ = cache. store_instance ( & id, instance) ;
299
305
}
306
+
307
+ #[ test]
308
+ #[ cfg( feature = "default-singlepass" ) ]
309
+ fn resets_gas_when_reusing_instance ( ) {
310
+ let tmp_dir = TempDir :: new ( ) . unwrap ( ) ;
311
+ let mut cache = unsafe { CosmCache :: new ( tmp_dir. path ( ) , 10 ) . unwrap ( ) } ;
312
+ let id = cache. save_wasm ( CONTRACT_0_7 ) . unwrap ( ) ;
313
+
314
+ let deps1 = dependencies ( 20 ) ;
315
+ let deps2 = dependencies ( 20 ) ;
316
+
317
+ // Init from module cache
318
+ let mut instance1 = cache. get_instance ( & id, deps1, TESTING_GAS_LIMIT ) . unwrap ( ) ;
319
+ assert_eq ! ( cache. stats. hits_module, 1 ) ;
320
+ assert_eq ! ( cache. stats. hits_instance, 0 ) ;
321
+ assert_eq ! ( cache. stats. misses, 0 ) ;
322
+ let original_gas = instance1. get_gas ( ) ;
323
+
324
+ // Consume some gas
325
+ let env = mock_env ( & instance1. api , "owner1" , & coin ( "1000" , "earth" ) , & [ ] ) ;
326
+ let msg = r#"{"verifier": "sue", "beneficiary": "mary"}"# . as_bytes ( ) ;
327
+ call_init ( & mut instance1, & env, msg) . unwrap ( ) ;
328
+ assert ! ( instance1. get_gas( ) < original_gas) ;
329
+ cache. store_instance ( & id, instance1) . unwrap ( ) ;
330
+
331
+ // Init from instance cache
332
+ let instance2 = cache. get_instance ( & id, deps2, TESTING_GAS_LIMIT ) . unwrap ( ) ;
333
+ assert_eq ! ( cache. stats. hits_module, 1 ) ;
334
+ assert_eq ! ( cache. stats. hits_instance, 1 ) ;
335
+ assert_eq ! ( cache. stats. misses, 0 ) ;
336
+ assert_eq ! ( instance2. get_gas( ) , TESTING_GAS_LIMIT ) ;
337
+ }
338
+
339
+ #[ test]
340
+ #[ cfg( feature = "default-singlepass" ) ]
341
+ fn recovers_from_out_of_gas ( ) {
342
+ let tmp_dir = TempDir :: new ( ) . unwrap ( ) ;
343
+ let mut cache = unsafe { CosmCache :: new ( tmp_dir. path ( ) , 10 ) . unwrap ( ) } ;
344
+ let id = cache. save_wasm ( CONTRACT_0_7 ) . unwrap ( ) ;
345
+
346
+ let deps1 = dependencies ( 20 ) ;
347
+ let deps2 = dependencies ( 20 ) ;
348
+
349
+ // Init from module cache
350
+ let mut instance1 = cache. get_instance ( & id, deps1, 10 ) . unwrap ( ) ;
351
+ assert_eq ! ( cache. stats. hits_module, 1 ) ;
352
+ assert_eq ! ( cache. stats. hits_instance, 0 ) ;
353
+ assert_eq ! ( cache. stats. misses, 0 ) ;
354
+
355
+ // Consume some gas. This fails
356
+ let env1 = mock_env ( & instance1. api , "owner1" , & coin ( "1000" , "earth" ) , & [ ] ) ;
357
+ let msg1 = r#"{"verifier": "sue", "beneficiary": "mary"}"# . as_bytes ( ) ;
358
+ match call_init ( & mut instance1, & env1, msg1) {
359
+ Err ( Error :: RuntimeErr { .. } ) => ( ) , // all good, continue
360
+ Err ( e) => panic ! ( "unexpected error, {:?}" , e) ,
361
+ Ok ( _) => panic ! ( "call_init must run out of gas" ) ,
362
+ }
363
+ assert_eq ! ( instance1. get_gas( ) , 0 ) ;
364
+ cache. store_instance ( & id, instance1) . unwrap ( ) ;
365
+
366
+ // Init from instance cache
367
+ let mut instance2 = cache. get_instance ( & id, deps2, TESTING_GAS_LIMIT ) . unwrap ( ) ;
368
+ assert_eq ! ( cache. stats. hits_module, 1 ) ;
369
+ assert_eq ! ( cache. stats. hits_instance, 1 ) ;
370
+ assert_eq ! ( cache. stats. misses, 0 ) ;
371
+ assert_eq ! ( instance2. get_gas( ) , TESTING_GAS_LIMIT ) ;
372
+
373
+ // Now it works
374
+ let env2 = mock_env ( & instance2. api , "owner2" , & coin ( "500" , "earth" ) , & [ ] ) ;
375
+ let msg2 = r#"{"verifier": "bob", "beneficiary": "john"}"# . as_bytes ( ) ;
376
+ call_init ( & mut instance2, & env2, msg2) . unwrap ( ) ;
377
+ }
300
378
}
0 commit comments