Skip to content

Commit

Permalink
Merge pull request #284 from dusk-network/memory64
Browse files Browse the repository at this point in the history
Support for `memory64`
  • Loading branch information
Eduardo Leegwater Simões authored Oct 25, 2023
2 parents c787212 + a8b9c21 commit 13dc56f
Show file tree
Hide file tree
Showing 14 changed files with 277 additions and 136 deletions.
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ contracts: setup-compiler ## Build example contracts
--manifest-path=contracts/Cargo.toml \
--color=always \
-Z build-std=core,alloc \
--target wasm32-unknown-unknown
@contracts/c-example/build.sh
--target wasm64-unknown-unknown
@mkdir -p target/stripped
@find target/wasm32-unknown-unknown/release -maxdepth 1 -name "*.wasm" \
@contracts/c-example/build.sh
@find target/wasm64-unknown-unknown/release -maxdepth 1 -name "*.wasm" \
| xargs -I % basename % \
| xargs -I % wasm-tools strip -a \
target/wasm32-unknown-unknown/release/% \
target/wasm64-unknown-unknown/release/% \
-o target/stripped/%

test: contracts cold-reboot assert-counter-contract-small ## Run all tests
Expand Down
4 changes: 2 additions & 2 deletions contracts/c-example/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
BASEDIR=$(dirname "$0")

clang -nostdlib -Os \
--target=wasm32 \
--target=wasm64 \
-Wl,--allow-undefined \
-Wl,--no-entry \
-Wl,--export=A \
-Wl,--export=increment_and_read \
-Wl,--export=out_of_bounds \
"$BASEDIR/contract.c" \
-o "$BASEDIR/../../target/wasm32-unknown-unknown/release/c-example.wasm"
-o "$BASEDIR/../../target/wasm64-unknown-unknown/release/c-example.wasm"
2 changes: 1 addition & 1 deletion contracts/c-example/contract.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,6 @@ int32_t increment_and_read(int32_t _arg_len) {
// Calls the "hd" extern with an (almost) certainly out of bounds pointer, in an
// effort to trigger an error.
int32_t out_of_bounds(int32_t _arg_len) {
hd((uint8_t*)4294967295, 2);
hd((uint8_t*)4398046511103, 2);
return 0;
}
5 changes: 5 additions & 0 deletions piecrust/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Added

- Support `memory64` smart contracts [#281]
- Add some `Error` variants:
* `InvalidFunction`
* `InvalidMemory`
- Add `once_cell` dependency

## Changed

- Change contract tree to be arity 4 and height 17 [#159]
- Maximum contract size is now 4TiB [#159]
- Change `Error::RuntimeError` variant to contain `dusk_wasmtime::Error`,
and changed `From` implementation
- Switch runtime from `wasmer` to `wasmtime`
Expand Down Expand Up @@ -281,6 +284,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 -->
[#281]: https://github.com/dusk-network/piecrust/issues/281
[#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
Expand All @@ -301,6 +305,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#167]: https://github.com/dusk-network/piecrust/issues/167
[#166]: https://github.com/dusk-network/piecrust/issues/166
[#162]: https://github.com/dusk-network/piecrust/issues/162
[#159]: https://github.com/dusk-network/piecrust/issues/159
[#158]: https://github.com/dusk-network/piecrust/issues/158
[#136]: https://github.com/dusk-network/piecrust/issues/136
[#93]: https://github.com/dusk-network/piecrust/issues/93
Expand Down
197 changes: 105 additions & 92 deletions piecrust/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

mod wasm32;
mod wasm64;

use std::sync::Arc;

use dusk_wasmtime::{
Expand All @@ -16,7 +19,7 @@ use piecrust_uplink::{
use crate::instance::{Env, WrappedInstance};
use crate::Error;

const POINT_PASS_PCT: u64 = 93;
pub const POINT_PASS_PCT: u64 = 93;

pub(crate) struct Imports;

Expand All @@ -25,14 +28,15 @@ impl Imports {
pub fn for_module(
store: &mut Store<Env>,
module: &Module,
is_64: bool,
) -> Result<Vec<Extern>, Error> {
let max_imports = 12;
let mut imports = Vec::with_capacity(max_imports);

for import in module.imports() {
let import_name = import.name();

match Self::import(store, import_name) {
match Self::import(store, import_name, is_64) {
None => {
return Err(Error::InvalidFunction(import_name.to_string()))
}
Expand All @@ -45,13 +49,25 @@ impl Imports {
Ok(imports)
}

fn import(store: &mut Store<Env>, name: &str) -> Option<Func> {
fn import(store: &mut Store<Env>, name: &str, is_64: bool) -> Option<Func> {
Some(match name {
"caller" => Func::wrap(store, caller),
"c" => Func::wrap(store, c),
"hq" => Func::wrap(store, hq),
"hd" => Func::wrap(store, hd),
"emit" => Func::wrap(store, emit),
"c" => match is_64 {
false => Func::wrap(store, wasm32::c),
true => Func::wrap(store, wasm64::c),
},
"hq" => match is_64 {
false => Func::wrap(store, wasm32::hq),
true => Func::wrap(store, wasm64::hq),
},
"hd" => match is_64 {
false => Func::wrap(store, wasm32::hd),
true => Func::wrap(store, wasm64::hd),
},
"emit" => match is_64 {
false => Func::wrap(store, wasm32::emit),
true => Func::wrap(store, wasm64::emit),
},
"feed" => Func::wrap(store, feed),
"limit" => Func::wrap(store, limit),
"spent" => Func::wrap(store, spent),
Expand All @@ -65,16 +81,13 @@ impl Imports {
}
}

fn check_ptr(
pub fn check_ptr(
instance: &WrappedInstance,
offset: u32,
len: u32,
offset: usize,
len: usize,
) -> Result<(), Error> {
let mem_len = instance.with_memory(|mem| mem.len());

let offset = offset as usize;
let len = len as usize;

if offset + len >= mem_len {
return Err(Error::MemoryAccessOutOfBounds {
offset,
Expand All @@ -86,7 +99,10 @@ fn check_ptr(
Ok(())
}

fn check_arg(instance: &WrappedInstance, arg_len: u32) -> Result<(), Error> {
pub fn check_arg(
instance: &WrappedInstance,
arg_len: u32,
) -> Result<(), Error> {
let mem_len = instance.with_memory(|mem| mem.len());

let arg_ofs = instance.arg_buffer_offset();
Expand All @@ -111,23 +127,64 @@ fn check_arg(instance: &WrappedInstance, arg_len: u32) -> Result<(), Error> {
Ok(())
}

fn caller(env: Caller<Env>) {
let env = env.data();
pub(crate) fn hq(
mut fenv: Caller<Env>,
name_ofs: usize,
name_len: u32,
arg_len: u32,
) -> WasmtimeResult<u32> {
let env = fenv.data_mut();

let mod_id = env
.nth_from_top(1)
.map_or(ContractId::uninitialized(), |elem| elem.contract_id);
let instance = env.self_instance();

env.self_instance().with_arg_buf_mut(|arg| {
arg[..std::mem::size_of::<ContractId>()]
.copy_from_slice(mod_id.as_bytes())
})
let name_len = name_len as usize;

check_ptr(instance, name_ofs, name_len)?;
check_arg(instance, arg_len)?;

let name = instance.with_memory(|buf| {
// performance: use a dedicated buffer here?
core::str::from_utf8(&buf[name_ofs..][..name_len])
.map(ToOwned::to_owned)
})?;

Ok(instance
.with_arg_buf_mut(|buf| env.host_query(&name, buf, arg_len))
.ok_or(Error::MissingHostQuery(name))?)
}

pub(crate) fn hd(
mut fenv: Caller<Env>,
name_ofs: usize,
name_len: u32,
) -> WasmtimeResult<u32> {
let env = fenv.data_mut();

let instance = env.self_instance();

let name_len = name_len as usize;

check_ptr(instance, name_ofs, name_len)?;

let name = instance.with_memory(|buf| {
// performance: use a dedicated buffer here?
core::str::from_utf8(&buf[name_ofs..][..name_len])
.map(ToOwned::to_owned)
})?;

let data = env.meta(&name).unwrap_or_default();

instance.with_arg_buf_mut(|buf| {
buf[..data.len()].copy_from_slice(&data);
});

Ok(data.len() as u32)
}

fn c(
pub(crate) fn c(
mut fenv: Caller<Env>,
mod_id_ofs: u32,
name_ofs: u32,
mod_id_ofs: usize,
name_ofs: usize,
name_len: u32,
arg_len: u32,
points_limit: u64,
Expand All @@ -136,7 +193,9 @@ fn c(

let instance = env.self_instance();

check_ptr(instance, mod_id_ofs, CONTRACT_ID_BYTES as u32)?;
let name_len = name_len as usize;

check_ptr(instance, mod_id_ofs, CONTRACT_ID_BYTES)?;
check_ptr(instance, name_ofs, name_len)?;
check_arg(instance, arg_len)?;

Expand All @@ -155,7 +214,7 @@ fn c(

let mut mod_id = ContractId::uninitialized();
mod_id.as_bytes_mut().copy_from_slice(
&memory[mod_id_ofs as usize..][..std::mem::size_of::<ContractId>()],
&memory[mod_id_ofs..][..std::mem::size_of::<ContractId>()],
);

let callee_stack_element = env
Expand All @@ -170,9 +229,7 @@ fn c(
io: Arc::new(err),
})?;

let name = core::str::from_utf8(
&memory[name_ofs as usize..][..name_len as usize],
)?;
let name = core::str::from_utf8(&memory[name_ofs..][..name_len])?;

let arg = &arg_buf[..arg_len as usize];

Expand Down Expand Up @@ -214,71 +271,17 @@ fn c(
Ok(ret)
}

fn hq(
mut fenv: Caller<Env>,
name_ofs: u32,
name_len: u32,
arg_len: u32,
) -> WasmtimeResult<u32> {
let env = fenv.data_mut();

let instance = env.self_instance();

check_ptr(instance, name_ofs, arg_len)?;
check_arg(instance, arg_len)?;

let name_ofs = name_ofs as usize;
let name_len = name_len as usize;

let name = instance.with_memory(|buf| {
// performance: use a dedicated buffer here?
core::str::from_utf8(&buf[name_ofs..][..name_len])
.map(ToOwned::to_owned)
})?;

Ok(instance
.with_arg_buf_mut(|buf| env.host_query(&name, buf, arg_len))
.ok_or(Error::MissingHostQuery(name))?)
}

fn hd(
mut fenv: Caller<Env>,
name_ofs: u32,
name_len: u32,
) -> WasmtimeResult<u32> {
let env = fenv.data_mut();

let instance = env.self_instance();

check_ptr(instance, name_ofs, name_len)?;

let name_ofs = name_ofs as usize;
let name_len = name_len as usize;

let name = instance.with_memory(|buf| {
// performance: use a dedicated buffer here?
core::str::from_utf8(&buf[name_ofs..][..name_len])
.map(ToOwned::to_owned)
})?;

let data = env.meta(&name).unwrap_or_default();

instance.with_arg_buf_mut(|buf| {
buf[..data.len()].copy_from_slice(&data);
});

Ok(data.len() as u32)
}

fn emit(
pub(crate) fn emit(
mut fenv: Caller<Env>,
topic_ofs: u32,
topic_ofs: usize,
topic_len: u32,
arg_len: u32,
) -> WasmtimeResult<()> {
let env = fenv.data_mut();
let instance = env.self_instance();

let topic_len = topic_len as usize;

check_ptr(instance, topic_ofs, topic_len)?;
check_arg(instance, arg_len)?;

Expand All @@ -287,9 +290,6 @@ fn emit(
Vec::from(&buf[..arg_len])
});

let topic_ofs = topic_ofs as usize;
let topic_len = topic_len as usize;

let topic = instance.with_memory(|buf| {
// performance: use a dedicated buffer here?
core::str::from_utf8(&buf[topic_ofs..][..topic_len])
Expand All @@ -301,6 +301,19 @@ fn emit(
Ok(())
}

fn caller(env: Caller<Env>) {
let env = env.data();

let mod_id = env
.nth_from_top(1)
.map_or(ContractId::uninitialized(), |elem| elem.contract_id);

env.self_instance().with_arg_buf_mut(|arg| {
arg[..std::mem::size_of::<ContractId>()]
.copy_from_slice(mod_id.as_bytes())
})
}

fn feed(mut fenv: Caller<Env>, arg_len: u32) -> WasmtimeResult<()> {
let env = fenv.data_mut();
let instance = env.self_instance();
Expand Down
Loading

0 comments on commit 13dc56f

Please sign in to comment.