Skip to content

Commit 4b11623

Browse files
authored
Merge pull request #580 from CosmWasm/co/add-store-code
Add SimulateStoreCode function on main
2 parents ee9d20c + 4f4b1ad commit 4b11623

File tree

8 files changed

+106
-44
lines changed

8 files changed

+106
-44
lines changed

internal/api/api_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestValidateAddressFailure(t *testing.T) {
1717
// create contract
1818
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
1919
require.NoError(t, err)
20-
checksum, err := StoreCode(cache, wasm)
20+
checksum, err := StoreCode(cache, wasm, true)
2121
require.NoError(t, err)
2222

2323
gasMeter := NewMockGasMeter(TESTING_GAS_LIMIT)

internal/api/bindings.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -414,10 +414,11 @@ typedef struct GasReport {
414414

415415
struct cache_t *init_cache(struct ByteSliceView config, struct UnmanagedVector *error_msg);
416416

417-
struct UnmanagedVector save_wasm(struct cache_t *cache,
418-
struct ByteSliceView wasm,
419-
bool unchecked,
420-
struct UnmanagedVector *error_msg);
417+
struct UnmanagedVector store_code(struct cache_t *cache,
418+
struct ByteSliceView wasm,
419+
bool checked,
420+
bool persist,
421+
struct UnmanagedVector *error_msg);
421422

422423
void remove_wasm(struct cache_t *cache,
423424
struct ByteSliceView checksum,

internal/api/lib.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ func ReleaseCache(cache Cache) {
8686
cache.lockfile.Close() // Also releases the file lock
8787
}
8888

89-
func StoreCode(cache Cache, wasm []byte) ([]byte, error) {
89+
func StoreCode(cache Cache, wasm []byte, persist bool) ([]byte, error) {
9090
w := makeView(wasm)
9191
defer runtime.KeepAlive(wasm)
9292
errmsg := uninitializedUnmanagedVector()
93-
checksum, err := C.save_wasm(cache.ptr, w, cbool(false), &errmsg)
93+
checksum, err := C.store_code(cache.ptr, w, cbool(true), cbool(persist), &errmsg)
9494
if err != nil {
9595
return nil, errorWithMessage(err, errmsg)
9696
}
@@ -101,7 +101,7 @@ func StoreCodeUnchecked(cache Cache, wasm []byte) ([]byte, error) {
101101
w := makeView(wasm)
102102
defer runtime.KeepAlive(wasm)
103103
errmsg := uninitializedUnmanagedVector()
104-
checksum, err := C.save_wasm(cache.ptr, w, cbool(true), &errmsg)
104+
checksum, err := C.store_code(cache.ptr, w, cbool(true), cbool(true), &errmsg)
105105
if err != nil {
106106
return nil, errorWithMessage(err, errmsg)
107107
}

internal/api/lib_test.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ func TestStoreCodeAndGetCode(t *testing.T) {
219219
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
220220
require.NoError(t, err)
221221

222-
checksum, err := StoreCode(cache, wasm)
222+
checksum, err := StoreCode(cache, wasm, true)
223223
require.NoError(t, err)
224224
expectedChecksum := sha256.Sum256(wasm)
225225
require.Equal(t, expectedChecksum[:], checksum)
@@ -236,7 +236,7 @@ func TestRemoveCode(t *testing.T) {
236236
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
237237
require.NoError(t, err)
238238

239-
checksum, err := StoreCode(cache, wasm)
239+
checksum, err := StoreCode(cache, wasm, true)
240240
require.NoError(t, err)
241241

242242
// First removal works
@@ -253,7 +253,7 @@ func TestStoreCodeFailsWithBadData(t *testing.T) {
253253
defer cleanup()
254254

255255
wasm := []byte("some invalid data")
256-
_, err := StoreCode(cache, wasm)
256+
_, err := StoreCode(cache, wasm, true)
257257
require.Error(t, err)
258258
}
259259

@@ -281,7 +281,7 @@ func TestPin(t *testing.T) {
281281
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
282282
require.NoError(t, err)
283283

284-
checksum, err := StoreCode(cache, wasm)
284+
checksum, err := StoreCode(cache, wasm, true)
285285
require.NoError(t, err)
286286

287287
err = Pin(cache, checksum)
@@ -324,7 +324,7 @@ func TestUnpin(t *testing.T) {
324324
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
325325
require.NoError(t, err)
326326

327-
checksum, err := StoreCode(cache, wasm)
327+
checksum, err := StoreCode(cache, wasm, true)
328328
require.NoError(t, err)
329329

330330
err = Pin(cache, checksum)
@@ -368,7 +368,7 @@ func TestGetMetrics(t *testing.T) {
368368
// Store contract
369369
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
370370
require.NoError(t, err)
371-
checksum, err := StoreCode(cache, wasm)
371+
checksum, err := StoreCode(cache, wasm, true)
372372
require.NoError(t, err)
373373

374374
// GetMetrics 2
@@ -483,7 +483,7 @@ func TestGetPinnedMetrics(t *testing.T) {
483483
// Store contract 1
484484
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
485485
require.NoError(t, err)
486-
checksum, err := StoreCode(cache, wasm)
486+
checksum, err := StoreCode(cache, wasm, true)
487487
require.NoError(t, err)
488488

489489
err = Pin(cache, checksum)
@@ -492,7 +492,7 @@ func TestGetPinnedMetrics(t *testing.T) {
492492
// Store contract 2
493493
cyberpunkWasm, err := os.ReadFile("../../testdata/cyberpunk.wasm")
494494
require.NoError(t, err)
495-
cyberpunkChecksum, err := StoreCode(cache, cyberpunkWasm)
495+
cyberpunkChecksum, err := StoreCode(cache, cyberpunkWasm, true)
496496
require.NoError(t, err)
497497

498498
err = Pin(cache, cyberpunkChecksum)
@@ -557,7 +557,7 @@ func TestInstantiate(t *testing.T) {
557557
// create contract
558558
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
559559
require.NoError(t, err)
560-
checksum, err := StoreCode(cache, wasm)
560+
checksum, err := StoreCode(cache, wasm, true)
561561
require.NoError(t, err)
562562

563563
gasMeter := NewMockGasMeter(TESTING_GAS_LIMIT)
@@ -1204,7 +1204,7 @@ func createFloaty2(t testing.TB, cache Cache) []byte {
12041204
func createContract(t testing.TB, cache Cache, wasmFile string) []byte {
12051205
wasm, err := os.ReadFile(wasmFile)
12061206
require.NoError(t, err)
1207-
checksum, err := StoreCode(cache, wasm)
1207+
checksum, err := StoreCode(cache, wasm, true)
12081208
require.NoError(t, err)
12091209
return checksum
12101210
}

lib_libwasmvm.go

+17-4
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,20 @@ func (vm *VM) StoreCode(code WasmCode, gasLimit uint64) (Checksum, uint64, error
7373
return nil, gasCost, types.OutOfGasError{}
7474
}
7575

76-
checksum, err := api.StoreCode(vm.cache, code)
76+
checksum, err := api.StoreCode(vm.cache, code, true)
77+
return checksum, gasCost, err
78+
}
79+
80+
// SimulateStoreCode is the same as StoreCode but does not actually store the code.
81+
// This is useful for simulating all the validations happening in StoreCode without actually
82+
// writing anything to disk.
83+
func (vm *VM) SimulateStoreCode(code WasmCode, gasLimit uint64) (Checksum, uint64, error) {
84+
gasCost := compileCost(code)
85+
if gasLimit < gasCost {
86+
return nil, gasCost, types.OutOfGasError{}
87+
}
88+
89+
checksum, err := api.StoreCode(vm.cache, code, false)
7790
return checksum, gasCost, err
7891
}
7992

@@ -320,11 +333,11 @@ func (vm *VM) MigrateWithInfo(
320333
return &result, gasReport.UsedInternally, nil
321334
}
322335

323-
// Sudo allows native Go modules to make priviledged (sudo) calls on the contract.
336+
// Sudo allows native Go modules to make privileged (sudo) calls on the contract.
324337
// The contract can expose entry points that cannot be triggered by any transaction, but only via
325338
// native Go modules, and delegate the access control to the system.
326339
//
327-
// These work much like Migrate (same scenario) but allows custom apps to extend the priviledged entry points
340+
// These work much like Migrate (same scenario) but allows custom apps to extend the privileged entry points
328341
// without forking cosmwasm-vm.
329342
func (vm *VM) Sudo(
330343
checksum Checksum,
@@ -354,7 +367,7 @@ func (vm *VM) Sudo(
354367
return &result, gasReport.UsedInternally, nil
355368
}
356369

357-
// Reply allows the native Go wasm modules to make a priviledged call to return the result
370+
// Reply allows the native Go wasm modules to make a privileged call to return the result
358371
// of executing a SubMsg.
359372
//
360373
// These work much like Sudo (same scenario) but focuses on one specific case (and one message type)

lib_libwasmvm_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,41 @@ func TestStoreCode(t *testing.T) {
102102
}
103103
}
104104

105+
func TestSimulateStoreCode(t *testing.T) {
106+
vm := withVM(t)
107+
108+
hackatom, err := os.ReadFile(HACKATOM_TEST_CONTRACT)
109+
require.NoError(t, err)
110+
111+
specs := map[string]struct {
112+
wasm []byte
113+
err string
114+
}{
115+
"valid hackatom contract": {
116+
wasm: hackatom,
117+
},
118+
"no wasm": {
119+
wasm: []byte("foobar"),
120+
err: "Wasm bytecode could not be deserialized",
121+
},
122+
}
123+
124+
for name, spec := range specs {
125+
t.Run(name, func(t *testing.T) {
126+
checksum, _, err := vm.SimulateStoreCode(spec.wasm, TESTING_GAS_LIMIT)
127+
128+
if spec.err != "" {
129+
assert.ErrorContains(t, err, spec.err)
130+
} else {
131+
assert.NoError(t, err)
132+
133+
_, err = vm.GetCode(checksum)
134+
assert.ErrorContains(t, err, "Error opening Wasm file for reading")
135+
}
136+
})
137+
}
138+
}
139+
105140
func TestStoreCodeAndGet(t *testing.T) {
106141
vm := withVM(t)
107142

libwasmvm/bindings.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -414,10 +414,11 @@ typedef struct GasReport {
414414

415415
struct cache_t *init_cache(struct ByteSliceView config, struct UnmanagedVector *error_msg);
416416

417-
struct UnmanagedVector save_wasm(struct cache_t *cache,
418-
struct ByteSliceView wasm,
419-
bool unchecked,
420-
struct UnmanagedVector *error_msg);
417+
struct UnmanagedVector store_code(struct cache_t *cache,
418+
struct ByteSliceView wasm,
419+
bool checked,
420+
bool persist,
421+
struct UnmanagedVector *error_msg);
421422

422423
void remove_wasm(struct cache_t *cache,
423424
struct ByteSliceView checksum,

libwasmvm/src/cache.rs

+30-18
Original file line numberDiff line numberDiff line change
@@ -48,31 +48,35 @@ fn do_init_cache(config: ByteSliceView) -> Result<*mut Cache<GoApi, GoStorage, G
4848
}
4949

5050
#[no_mangle]
51-
pub extern "C" fn save_wasm(
51+
pub extern "C" fn store_code(
5252
cache: *mut cache_t,
5353
wasm: ByteSliceView,
54-
unchecked: bool,
54+
checked: bool,
55+
persist: bool,
5556
error_msg: Option<&mut UnmanagedVector>,
5657
) -> UnmanagedVector {
5758
let r = match to_cache(cache) {
58-
Some(c) => catch_unwind(AssertUnwindSafe(move || do_save_wasm(c, wasm, unchecked)))
59-
.unwrap_or_else(|err| {
60-
handle_vm_panic("do_save_wasm", err);
61-
Err(Error::panic())
62-
}),
59+
Some(c) => catch_unwind(AssertUnwindSafe(move || {
60+
do_store_code(c, wasm, checked, persist)
61+
}))
62+
.unwrap_or_else(|err| {
63+
handle_vm_panic("do_store_code", err);
64+
Err(Error::panic())
65+
}),
6366
None => Err(Error::unset_arg(CACHE_ARG)),
6467
};
6568
let checksum = handle_c_error_binary(r, error_msg);
6669
UnmanagedVector::new(Some(checksum))
6770
}
6871

69-
fn do_save_wasm(
72+
fn do_store_code(
7073
cache: &mut Cache<GoApi, GoStorage, GoQuerier>,
7174
wasm: ByteSliceView,
72-
unchecked: bool,
75+
checked: bool,
76+
persist: bool,
7377
) -> Result<Checksum, Error> {
7478
let wasm = wasm.read().ok_or_else(|| Error::unset_arg(WASM_ARG))?;
75-
Ok(cache.store_code(wasm, !unchecked, true)?)
79+
Ok(cache.store_code(wasm, checked, persist)?)
7680
}
7781

7882
#[no_mangle]
@@ -518,10 +522,11 @@ mod tests {
518522
let _ = error_msg.consume();
519523

520524
let mut error_msg = UnmanagedVector::default();
521-
save_wasm(
525+
store_code(
522526
cache_ptr,
523527
ByteSliceView::new(HACKATOM),
524528
false,
529+
true,
525530
Some(&mut error_msg),
526531
);
527532
assert!(error_msg.is_none());
@@ -548,10 +553,11 @@ mod tests {
548553
let _ = error_msg.consume();
549554

550555
let mut error_msg = UnmanagedVector::default();
551-
let checksum = save_wasm(
556+
let checksum = store_code(
552557
cache_ptr,
553558
ByteSliceView::new(HACKATOM),
554559
false,
560+
true,
555561
Some(&mut error_msg),
556562
);
557563
assert!(error_msg.is_none());
@@ -604,10 +610,11 @@ mod tests {
604610
let _ = error_msg.consume();
605611

606612
let mut error_msg = UnmanagedVector::default();
607-
let checksum = save_wasm(
613+
let checksum = store_code(
608614
cache_ptr,
609615
ByteSliceView::new(HACKATOM),
610616
false,
617+
true,
611618
Some(&mut error_msg),
612619
);
613620
assert!(error_msg.is_none());
@@ -646,10 +653,11 @@ mod tests {
646653
let _ = error_msg.consume();
647654

648655
let mut error_msg = UnmanagedVector::default();
649-
let checksum = save_wasm(
656+
let checksum = store_code(
650657
cache_ptr,
651658
ByteSliceView::new(HACKATOM),
652659
false,
660+
true,
653661
Some(&mut error_msg),
654662
);
655663
assert!(error_msg.is_none());
@@ -696,10 +704,11 @@ mod tests {
696704
let _ = error_msg.consume();
697705

698706
let mut error_msg = UnmanagedVector::default();
699-
let checksum = save_wasm(
707+
let checksum = store_code(
700708
cache_ptr,
701709
ByteSliceView::new(HACKATOM),
702710
false,
711+
true,
703712
Some(&mut error_msg),
704713
);
705714
assert!(error_msg.is_none());
@@ -755,21 +764,23 @@ mod tests {
755764
let _ = error_msg.consume();
756765

757766
let mut error_msg = UnmanagedVector::default();
758-
let checksum_hackatom = save_wasm(
767+
let checksum_hackatom = store_code(
759768
cache_ptr,
760769
ByteSliceView::new(HACKATOM),
761770
false,
771+
true,
762772
Some(&mut error_msg),
763773
);
764774
assert!(error_msg.is_none());
765775
let _ = error_msg.consume();
766776
let checksum_hackatom = checksum_hackatom.consume().unwrap_or_default();
767777

768778
let mut error_msg = UnmanagedVector::default();
769-
let checksum_ibc_reflect = save_wasm(
779+
let checksum_ibc_reflect = store_code(
770780
cache_ptr,
771781
ByteSliceView::new(IBC_REFLECT),
772782
false,
783+
true,
773784
Some(&mut error_msg),
774785
);
775786
assert!(error_msg.is_none());
@@ -955,10 +966,11 @@ mod tests {
955966

956967
// Save wasm
957968
let mut error_msg = UnmanagedVector::default();
958-
let checksum_hackatom = save_wasm(
969+
let checksum_hackatom = store_code(
959970
cache_ptr,
960971
ByteSliceView::new(HACKATOM),
961972
false,
973+
true,
962974
Some(&mut error_msg),
963975
);
964976
assert!(error_msg.is_none());

0 commit comments

Comments
 (0)