Skip to content

Commit

Permalink
piecrust: add support for panic import
Browse files Browse the repository at this point in the history
  • Loading branch information
Eduardo Leegwater Simões committed Sep 22, 2023
1 parent 4f7e662 commit 6546d70
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 69 deletions.
11 changes: 11 additions & 0 deletions piecrust/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add `panic` import implementation [#271]
- Add `Error::ContractPanic` variant [#271]

### Changed

- Allow for multiple initializations on a new memory [#271]
- Downcast `Error::RuntimeError` on each call boundary [#271]

## [0.10.0] - 2023-09-13

### Added
Expand Down Expand Up @@ -229,6 +239,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#234]: https://github.com/dusk-network/piecrust/pull/234

<!-- ISSUES -->
[#271]: https://github.com/dusk-network/piecrust/issues/271
[#268]: https://github.com/dusk-network/piecrust/issues/268
[#254]: https://github.com/dusk-network/piecrust/issues/254
[#253]: https://github.com/dusk-network/piecrust/issues/253
Expand Down
16 changes: 15 additions & 1 deletion piecrust/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ pub enum Error {
MissingHostQuery(String),
#[error("OutOfPoints")]
OutOfPoints,
#[error("Contract panic: {0}")]
ContractPanic(String),
#[error(transparent)]
ParsingError(wasmer::wasmparser::BinaryReaderError),
#[error(transparent)]
Expand All @@ -92,6 +94,18 @@ pub enum Error {
ValidationError,
}

impl Error {
pub fn normalize(self) -> Self {
match self {
Self::RuntimeError(rerr) => match rerr.downcast() {
Ok(err) => err,
Err(rerr) => Self::RuntimeError(rerr),
},
err => err,
}
}
}

impl From<std::convert::Infallible> for Error {
fn from(err: Infallible) -> Self {
Self::Infallible(err)
Expand Down Expand Up @@ -162,9 +176,9 @@ const OTHER_STATUS_CODE: i32 = i32::MIN;

impl From<Error> for ContractError {
fn from(err: Error) -> Self {
// TODO implement this fully
match err {
Error::OutOfPoints => Self::OUTOFGAS,
Error::ContractPanic(_) => Self::PANIC,
_ => Self::OTHER(OTHER_STATUS_CODE),
}
}
Expand Down
23 changes: 22 additions & 1 deletion piecrust/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl DefaultImports {
"feed" => Function::new_typed_with_env(store, &fenv, feed),
"limit" => Function::new_typed_with_env(store, &fenv, limit),
"spent" => Function::new_typed_with_env(store, &fenv, spent),
"panic" => Function::new_typed_with_env(store, &fenv, panic),
"owner" => Function::new_typed_with_env(store, &fenv, owner),
"self_id" => Function::new_typed_with_env(store, &fenv, self_id),
}
Expand Down Expand Up @@ -163,7 +164,9 @@ fn c(
let arg = &arg_buf[..arg_len as usize];

callee.write_argument(arg);
let ret_len = callee.call(name, arg.len() as u32, callee_limit)?;
let ret_len = callee
.call(name, arg.len() as u32, callee_limit)
.map_err(Error::normalize)?;
check_arg(callee, ret_len as u32)?;

// copy back result
Expand Down Expand Up @@ -339,6 +342,24 @@ fn spent(fenv: FunctionEnvMut<Env>) -> u64 {
limit - remaining
}

fn panic(fenv: FunctionEnvMut<Env>, arg_len: u32) -> Result<(), Error> {
let env = fenv.data();
let instance = env.self_instance();

check_arg(instance, arg_len)?;

instance.with_arg_buffer(|buf| {
let slice = &buf[..arg_len as usize];

let msg = match std::str::from_utf8(slice) {
Ok(msg) => msg,
Err(err) => return Err(Error::Utf8(err)),
};

Err(Error::ContractPanic(msg.to_owned()))
})
}

fn owner(fenv: FunctionEnvMut<Env>) -> u32 {
let env = fenv.data();
let self_id = env.self_contract_id();
Expand Down
23 changes: 13 additions & 10 deletions piecrust/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,16 +635,19 @@ impl Session {
})?;

let arg_len = instance.write_bytes_to_arg_buffer(&fdata);
let ret_len = instance.call(fname, arg_len, limit).map_err(|err| {
if let Err(io_err) = self.revert_callstack() {
return Error::MemorySnapshotFailure {
reason: Some(Arc::new(err)),
io: Arc::new(io_err),
};
}
self.pop_callstack_prune();
err
})?;
let ret_len = instance
.call(fname, arg_len, limit)
.map_err(|err| {
if let Err(io_err) = self.revert_callstack() {
return Error::MemorySnapshotFailure {
reason: Some(Arc::new(err)),
io: Arc::new(io_err),
};
}
self.pop_callstack_prune();
err
})
.map_err(Error::normalize)?;
let ret = instance.read_bytes_from_arg_buffer(ret_len as u32);

let spent = limit
Expand Down
21 changes: 9 additions & 12 deletions piecrust/src/store/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub const MAX_MEM_SIZE: usize = MAX_PAGES * PAGE_SIZE;
pub(crate) struct MemoryInner {
pub(crate) mmap: Mmap,
pub(crate) def: VMMemoryDefinition,
init: bool,
is_new: bool,
}

/// WASM memory belonging to a given contract during a given session.
Expand All @@ -50,7 +50,7 @@ impl Memory {
inner: Arc::new(RwLock::new(MemoryInner {
mmap,
def,
init: false,
is_new: true,
})),
})
}
Expand Down Expand Up @@ -79,7 +79,7 @@ impl Memory {
inner: Arc::new(RwLock::new(MemoryInner {
mmap,
def,
init: true,
is_new: false,
})),
})
}
Expand Down Expand Up @@ -201,16 +201,13 @@ impl LinearMemory for Memory {
data: &[u8],
) -> Result<(), Trap> {
let this = self.write();
let mut inner = this.inner;

match inner.init {
true => Ok(()),
false => {
initialize_memory_with_data(&inner.def, start, data).map(|_| {
inner.init = true;
})
}
let inner = this.inner;

if inner.is_new {
initialize_memory_with_data(&inner.def, start, data)?;
}

Ok(())
}
}

Expand Down
22 changes: 22 additions & 0 deletions piecrust/tests/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,25 @@ fn call_through_c() -> Result<(), Error> {

Ok(())
}

#[test]
fn increment_panic() -> Result<(), Error> {
let vm = VM::ephemeral()?;

let mut session = vm.session(SessionData::builder())?;

let counter_id = session.deploy(
contract_bytecode!("fallible_counter"),
ContractData::builder(OWNER),
LIMIT,
)?;

match session.call::<_, ()>(counter_id, "increment", &true, LIMIT) {
Err(Error::ContractPanic(panic_msg)) => {
assert_eq!(panic_msg, String::from("Incremental panic"));
}
_ => panic!("Expected a panic error"),
}

Ok(())
}
45 changes: 0 additions & 45 deletions piecrust/tests/fallible_counter.rs

This file was deleted.

0 comments on commit 6546d70

Please sign in to comment.