diff --git a/x/programs/cmd/simulator/cmd/plan.go b/x/programs/cmd/simulator/cmd/plan.go index 9e61d7aaa0..ad40ac92ac 100644 --- a/x/programs/cmd/simulator/cmd/plan.go +++ b/x/programs/cmd/simulator/cmd/plan.go @@ -240,7 +240,15 @@ func runStepFunc( return nil } - id, _, balance, err := programExecuteFunc(ctx, log, db, params, method, maxUnits) + id, response, balance, err := programExecuteFunc(ctx, log, db, params, method, maxUnits) + if err != nil { + return err + } + resp.setResponse(response) + ok, err := validateAssertion(response[0], require) + if !ok { + return fmt.Errorf("%w", ErrResultAssertionFailed) + } if err != nil { return err } diff --git a/x/programs/examples/imports/pstate/pstate.go b/x/programs/examples/imports/pstate/pstate.go index efca9cbeb5..64c60e7663 100644 --- a/x/programs/examples/imports/pstate/pstate.go +++ b/x/programs/examples/imports/pstate/pstate.go @@ -217,9 +217,45 @@ func (i *Import) deleteFn(caller *program.Caller, memOffset int32, size int32) ( } k := storage.ProgramPrefixKey(args.ProgramID[:], args.Key) + bytes, err = i.mu.GetValue(context.Background(), k) + if err != nil { + if errors.Is(err, database.ErrNotFound) { + val, err := program.WriteBytes(memory, []byte{0}) + if err != nil { + i.log.Error("failed to write to memory", + zap.Error(err), + ) + return nil, err + } + + return types.ValI32(int32(val)), nil + } + + i.log.Error("failed to get value from storage", + zap.Error(err), + ) + return nil, err + } + + // prepend 1 to val + bytes = append([]byte{1}, bytes...) + + ptr, err := program.WriteBytes(memory, bytes) + if err != nil { + { + i.log.Error("failed to write to memory", + zap.Error(err), + ) + } + return nil, err + } + if err := i.mu.Remove(context.Background(), k); err != nil { - i.log.Error("failed to remove from storage", zap.Error(err)) - return types.ValI32(-1), nil + i.log.Error("failed to delete value from storage", + zap.Error(err), + ) + return nil, err } - return types.ValI32(0), nil + + return types.ValI32(int32(ptr)), nil } diff --git a/x/programs/rust/examples/token/src/lib.rs b/x/programs/rust/examples/token/src/lib.rs index e523308554..0e8259145b 100644 --- a/x/programs/rust/examples/token/src/lib.rs +++ b/x/programs/rust/examples/token/src/lib.rs @@ -72,13 +72,13 @@ pub fn mint_to(context: Context, recipient: Address, amount: i64) -> bool { /// Burn the token from the recipient. #[public] -pub fn burn_from(context: Context, recipient: Address) -> bool { +pub fn burn_from(context: Context, recipient: Address) -> i64 { let Context { program } = context; program .state() - .delete(StateKey::Balance(recipient)) - .expect("failed to burn recipient tokens"); - true + .delete::(StateKey::Balance(recipient)) + .expect("failed to burn recipient tokens") + .expect("recipient balance not found") } /// Transfers balance from the sender to the the recipient. @@ -184,6 +184,7 @@ mod tests { .map(Param::Key); let alice_initial_balance = 1000; let transfer_amount = 100; + let post_transfer_balance = alice_initial_balance - transfer_amount; let mut plan = Plan::new(owner_key_id.clone()); @@ -262,7 +263,7 @@ mod tests { max_units: 0, params: vec![program_id.into(), alice_key.clone()], require: Some(Require { - result: ResultAssertion::NumericEq(alice_initial_balance - transfer_amount), + result: ResultAssertion::NumericEq(post_transfer_balance), }), }); @@ -281,7 +282,9 @@ mod tests { method: "burn_from".into(), params: vec![program_id.into(), alice_key.clone()], max_units: 1000000, - require: None, + require: Some(Require { + result: ResultAssertion::NumericEq(post_transfer_balance), + }), }); plan.add_step(Step { diff --git a/x/programs/rust/wasmlanche-sdk/src/lib.rs b/x/programs/rust/wasmlanche-sdk/src/lib.rs index 68b176bd63..544c271ca8 100644 --- a/x/programs/rust/wasmlanche-sdk/src/lib.rs +++ b/x/programs/rust/wasmlanche-sdk/src/lib.rs @@ -8,7 +8,7 @@ mod memory; mod program; pub use self::{ - memory::{from_host_ptr, CPointer}, + memory::from_host_ptr, params::{serialize_param, Params}, program::Program, }; diff --git a/x/programs/rust/wasmlanche-sdk/src/memory.rs b/x/programs/rust/wasmlanche-sdk/src/memory.rs index 1f230eb1e0..244598d52b 100644 --- a/x/programs/rust/wasmlanche-sdk/src/memory.rs +++ b/x/programs/rust/wasmlanche-sdk/src/memory.rs @@ -8,9 +8,6 @@ use crate::state::Error as StateError; use borsh::{from_slice, BorshDeserialize}; use std::{alloc::Layout, cell::RefCell, collections::HashMap}; -#[repr(C)] -pub struct CPointer(pub *const u8, pub usize); - thread_local! { /// Map of pointer to the length of its content on the heap static GLOBAL_STORE: RefCell> = RefCell::new(HashMap::new()); diff --git a/x/programs/rust/wasmlanche-sdk/src/state.rs b/x/programs/rust/wasmlanche-sdk/src/state.rs index 78bea4bc87..e54acafca6 100644 --- a/x/programs/rust/wasmlanche-sdk/src/state.rs +++ b/x/programs/rust/wasmlanche-sdk/src/state.rs @@ -131,7 +131,7 @@ where /// # Errors /// Returns an [Error] if the key cannot be serialized /// or if the host fails to delete the key and the associated value - pub fn delete(&mut self, key: K) -> Result<(), Error> { + pub fn delete(&mut self, key: K) -> Result, Error> { self.cache.remove(&key); let args = GetAndDeleteArgs { @@ -199,7 +199,10 @@ struct GetAndDeleteArgs { } mod host { - use crate::state::Error; + use super::Error; + use crate::memory::from_host_ptr; + use borsh::BorshDeserialize; + use std::ptr::NonNull; /// Persists the bytes at key on the host storage. pub(super) fn put_bytes(bytes: &[u8]) -> Result<(), Error> { @@ -235,17 +238,15 @@ mod host { } /// Deletes the bytes at key ptr from the host storage - pub(super) fn delete_bytes(bytes: &[u8]) -> Result<(), Error> { + pub(super) fn delete_bytes(bytes: &[u8]) -> Result, Error> { #[link(wasm_import_module = "state")] extern "C" { #[link_name = "delete"] - fn ffi(ptr: *const u8, len: usize) -> i32; + fn ffi(ptr: *const u8, len: usize) -> NonNull; } - let result = unsafe { ffi(bytes.as_ptr(), bytes.len()) }; - match result { - 0 => Ok(()), - _ => Err(Error::Delete), - } + let ptr = unsafe { ffi(bytes.as_ptr(), bytes.len()) }; + + from_host_ptr(ptr.as_ptr()) } }