Skip to content

Commit

Permalink
Merge pull request #580 from CosmWasm/co/add-store-code
Browse files Browse the repository at this point in the history
Add SimulateStoreCode function on main
  • Loading branch information
chipshort authored Dec 19, 2024
2 parents ee9d20c + 4f4b1ad commit 4b11623
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 44 deletions.
2 changes: 1 addition & 1 deletion internal/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestValidateAddressFailure(t *testing.T) {
// create contract
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
require.NoError(t, err)
checksum, err := StoreCode(cache, wasm)
checksum, err := StoreCode(cache, wasm, true)
require.NoError(t, err)

gasMeter := NewMockGasMeter(TESTING_GAS_LIMIT)
Expand Down
9 changes: 5 additions & 4 deletions internal/api/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,10 +414,11 @@ typedef struct GasReport {

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

struct UnmanagedVector save_wasm(struct cache_t *cache,
struct ByteSliceView wasm,
bool unchecked,
struct UnmanagedVector *error_msg);
struct UnmanagedVector store_code(struct cache_t *cache,
struct ByteSliceView wasm,
bool checked,
bool persist,
struct UnmanagedVector *error_msg);

void remove_wasm(struct cache_t *cache,
struct ByteSliceView checksum,
Expand Down
6 changes: 3 additions & 3 deletions internal/api/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ func ReleaseCache(cache Cache) {
cache.lockfile.Close() // Also releases the file lock
}

func StoreCode(cache Cache, wasm []byte) ([]byte, error) {
func StoreCode(cache Cache, wasm []byte, persist bool) ([]byte, error) {
w := makeView(wasm)
defer runtime.KeepAlive(wasm)
errmsg := uninitializedUnmanagedVector()
checksum, err := C.save_wasm(cache.ptr, w, cbool(false), &errmsg)
checksum, err := C.store_code(cache.ptr, w, cbool(true), cbool(persist), &errmsg)
if err != nil {
return nil, errorWithMessage(err, errmsg)
}
Expand All @@ -101,7 +101,7 @@ func StoreCodeUnchecked(cache Cache, wasm []byte) ([]byte, error) {
w := makeView(wasm)
defer runtime.KeepAlive(wasm)
errmsg := uninitializedUnmanagedVector()
checksum, err := C.save_wasm(cache.ptr, w, cbool(true), &errmsg)
checksum, err := C.store_code(cache.ptr, w, cbool(true), cbool(true), &errmsg)
if err != nil {
return nil, errorWithMessage(err, errmsg)
}
Expand Down
20 changes: 10 additions & 10 deletions internal/api/lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ func TestStoreCodeAndGetCode(t *testing.T) {
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
require.NoError(t, err)

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

checksum, err := StoreCode(cache, wasm)
checksum, err := StoreCode(cache, wasm, true)
require.NoError(t, err)

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

wasm := []byte("some invalid data")
_, err := StoreCode(cache, wasm)
_, err := StoreCode(cache, wasm, true)
require.Error(t, err)
}

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

checksum, err := StoreCode(cache, wasm)
checksum, err := StoreCode(cache, wasm, true)
require.NoError(t, err)

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

checksum, err := StoreCode(cache, wasm)
checksum, err := StoreCode(cache, wasm, true)
require.NoError(t, err)

err = Pin(cache, checksum)
Expand Down Expand Up @@ -368,7 +368,7 @@ func TestGetMetrics(t *testing.T) {
// Store contract
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
require.NoError(t, err)
checksum, err := StoreCode(cache, wasm)
checksum, err := StoreCode(cache, wasm, true)
require.NoError(t, err)

// GetMetrics 2
Expand Down Expand Up @@ -483,7 +483,7 @@ func TestGetPinnedMetrics(t *testing.T) {
// Store contract 1
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
require.NoError(t, err)
checksum, err := StoreCode(cache, wasm)
checksum, err := StoreCode(cache, wasm, true)
require.NoError(t, err)

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

err = Pin(cache, cyberpunkChecksum)
Expand Down Expand Up @@ -557,7 +557,7 @@ func TestInstantiate(t *testing.T) {
// create contract
wasm, err := os.ReadFile("../../testdata/hackatom.wasm")
require.NoError(t, err)
checksum, err := StoreCode(cache, wasm)
checksum, err := StoreCode(cache, wasm, true)
require.NoError(t, err)

gasMeter := NewMockGasMeter(TESTING_GAS_LIMIT)
Expand Down Expand Up @@ -1204,7 +1204,7 @@ func createFloaty2(t testing.TB, cache Cache) []byte {
func createContract(t testing.TB, cache Cache, wasmFile string) []byte {
wasm, err := os.ReadFile(wasmFile)
require.NoError(t, err)
checksum, err := StoreCode(cache, wasm)
checksum, err := StoreCode(cache, wasm, true)
require.NoError(t, err)
return checksum
}
Expand Down
21 changes: 17 additions & 4 deletions lib_libwasmvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,20 @@ func (vm *VM) StoreCode(code WasmCode, gasLimit uint64) (Checksum, uint64, error
return nil, gasCost, types.OutOfGasError{}
}

checksum, err := api.StoreCode(vm.cache, code)
checksum, err := api.StoreCode(vm.cache, code, true)
return checksum, gasCost, err
}

// SimulateStoreCode is the same as StoreCode but does not actually store the code.
// This is useful for simulating all the validations happening in StoreCode without actually
// writing anything to disk.
func (vm *VM) SimulateStoreCode(code WasmCode, gasLimit uint64) (Checksum, uint64, error) {
gasCost := compileCost(code)
if gasLimit < gasCost {
return nil, gasCost, types.OutOfGasError{}
}

checksum, err := api.StoreCode(vm.cache, code, false)
return checksum, gasCost, err
}

Expand Down Expand Up @@ -320,11 +333,11 @@ func (vm *VM) MigrateWithInfo(
return &result, gasReport.UsedInternally, nil
}

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

// Reply allows the native Go wasm modules to make a priviledged call to return the result
// Reply allows the native Go wasm modules to make a privileged call to return the result
// of executing a SubMsg.
//
// These work much like Sudo (same scenario) but focuses on one specific case (and one message type)
Expand Down
35 changes: 35 additions & 0 deletions lib_libwasmvm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,41 @@ func TestStoreCode(t *testing.T) {
}
}

func TestSimulateStoreCode(t *testing.T) {
vm := withVM(t)

hackatom, err := os.ReadFile(HACKATOM_TEST_CONTRACT)
require.NoError(t, err)

specs := map[string]struct {
wasm []byte
err string
}{
"valid hackatom contract": {
wasm: hackatom,
},
"no wasm": {
wasm: []byte("foobar"),
err: "Wasm bytecode could not be deserialized",
},
}

for name, spec := range specs {
t.Run(name, func(t *testing.T) {
checksum, _, err := vm.SimulateStoreCode(spec.wasm, TESTING_GAS_LIMIT)

if spec.err != "" {
assert.ErrorContains(t, err, spec.err)
} else {
assert.NoError(t, err)

_, err = vm.GetCode(checksum)
assert.ErrorContains(t, err, "Error opening Wasm file for reading")
}
})
}
}

func TestStoreCodeAndGet(t *testing.T) {
vm := withVM(t)

Expand Down
9 changes: 5 additions & 4 deletions libwasmvm/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,10 +414,11 @@ typedef struct GasReport {

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

struct UnmanagedVector save_wasm(struct cache_t *cache,
struct ByteSliceView wasm,
bool unchecked,
struct UnmanagedVector *error_msg);
struct UnmanagedVector store_code(struct cache_t *cache,
struct ByteSliceView wasm,
bool checked,
bool persist,
struct UnmanagedVector *error_msg);

void remove_wasm(struct cache_t *cache,
struct ByteSliceView checksum,
Expand Down
48 changes: 30 additions & 18 deletions libwasmvm/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,31 +48,35 @@ fn do_init_cache(config: ByteSliceView) -> Result<*mut Cache<GoApi, GoStorage, G
}

#[no_mangle]
pub extern "C" fn save_wasm(
pub extern "C" fn store_code(
cache: *mut cache_t,
wasm: ByteSliceView,
unchecked: bool,
checked: bool,
persist: bool,
error_msg: Option<&mut UnmanagedVector>,
) -> UnmanagedVector {
let r = match to_cache(cache) {
Some(c) => catch_unwind(AssertUnwindSafe(move || do_save_wasm(c, wasm, unchecked)))
.unwrap_or_else(|err| {
handle_vm_panic("do_save_wasm", err);
Err(Error::panic())
}),
Some(c) => catch_unwind(AssertUnwindSafe(move || {
do_store_code(c, wasm, checked, persist)
}))
.unwrap_or_else(|err| {
handle_vm_panic("do_store_code", err);
Err(Error::panic())
}),
None => Err(Error::unset_arg(CACHE_ARG)),
};
let checksum = handle_c_error_binary(r, error_msg);
UnmanagedVector::new(Some(checksum))
}

fn do_save_wasm(
fn do_store_code(
cache: &mut Cache<GoApi, GoStorage, GoQuerier>,
wasm: ByteSliceView,
unchecked: bool,
checked: bool,
persist: bool,
) -> Result<Checksum, Error> {
let wasm = wasm.read().ok_or_else(|| Error::unset_arg(WASM_ARG))?;
Ok(cache.store_code(wasm, !unchecked, true)?)
Ok(cache.store_code(wasm, checked, persist)?)
}

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

let mut error_msg = UnmanagedVector::default();
save_wasm(
store_code(
cache_ptr,
ByteSliceView::new(HACKATOM),
false,
true,
Some(&mut error_msg),
);
assert!(error_msg.is_none());
Expand All @@ -548,10 +553,11 @@ mod tests {
let _ = error_msg.consume();

let mut error_msg = UnmanagedVector::default();
let checksum = save_wasm(
let checksum = store_code(
cache_ptr,
ByteSliceView::new(HACKATOM),
false,
true,
Some(&mut error_msg),
);
assert!(error_msg.is_none());
Expand Down Expand Up @@ -604,10 +610,11 @@ mod tests {
let _ = error_msg.consume();

let mut error_msg = UnmanagedVector::default();
let checksum = save_wasm(
let checksum = store_code(
cache_ptr,
ByteSliceView::new(HACKATOM),
false,
true,
Some(&mut error_msg),
);
assert!(error_msg.is_none());
Expand Down Expand Up @@ -646,10 +653,11 @@ mod tests {
let _ = error_msg.consume();

let mut error_msg = UnmanagedVector::default();
let checksum = save_wasm(
let checksum = store_code(
cache_ptr,
ByteSliceView::new(HACKATOM),
false,
true,
Some(&mut error_msg),
);
assert!(error_msg.is_none());
Expand Down Expand Up @@ -696,10 +704,11 @@ mod tests {
let _ = error_msg.consume();

let mut error_msg = UnmanagedVector::default();
let checksum = save_wasm(
let checksum = store_code(
cache_ptr,
ByteSliceView::new(HACKATOM),
false,
true,
Some(&mut error_msg),
);
assert!(error_msg.is_none());
Expand Down Expand Up @@ -755,21 +764,23 @@ mod tests {
let _ = error_msg.consume();

let mut error_msg = UnmanagedVector::default();
let checksum_hackatom = save_wasm(
let checksum_hackatom = store_code(
cache_ptr,
ByteSliceView::new(HACKATOM),
false,
true,
Some(&mut error_msg),
);
assert!(error_msg.is_none());
let _ = error_msg.consume();
let checksum_hackatom = checksum_hackatom.consume().unwrap_or_default();

let mut error_msg = UnmanagedVector::default();
let checksum_ibc_reflect = save_wasm(
let checksum_ibc_reflect = store_code(
cache_ptr,
ByteSliceView::new(IBC_REFLECT),
false,
true,
Some(&mut error_msg),
);
assert!(error_msg.is_none());
Expand Down Expand Up @@ -955,10 +966,11 @@ mod tests {

// Save wasm
let mut error_msg = UnmanagedVector::default();
let checksum_hackatom = save_wasm(
let checksum_hackatom = store_code(
cache_ptr,
ByteSliceView::new(HACKATOM),
false,
true,
Some(&mut error_msg),
);
assert!(error_msg.is_none());
Expand Down

0 comments on commit 4b11623

Please sign in to comment.