Skip to content

Commit

Permalink
piecrust: distinguish 32 and 64-bit memories
Browse files Browse the repository at this point in the history
  • Loading branch information
Eduardo Leegwater Simões committed Oct 31, 2023
1 parent 9020fbe commit 8020e66
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 157 deletions.
34 changes: 0 additions & 34 deletions piecrust/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use std::sync::Arc;

use bytecheck::CheckBytes;
use dusk_wasmtime::{Engine, Module};
use piecrust_uplink::ContractId;
use rkyv::{Archive, Deserialize, Serialize};

use crate::error::Error;

pub struct ContractData<'a, A, const N: usize> {
pub(crate) contract_id: Option<ContractId>,
pub(crate) constructor_arg: Option<&'a A>,
Expand Down Expand Up @@ -80,32 +75,3 @@ pub struct ContractMetadata {
pub contract_id: ContractId,
pub owner: Vec<u8>,
}

#[derive(Clone)]
pub struct WrappedContract {
serialized: Arc<Vec<u8>>,
}

impl WrappedContract {
pub fn new<B: AsRef<[u8]>, C: AsRef<[u8]>>(
engine: &Engine,
bytecode: B,
objectcode: Option<C>,
) -> Result<Self, Error> {
let serialized = match objectcode {
Some(obj) => obj.as_ref().to_vec(),
_ => {
let contract = Module::new(engine, bytecode.as_ref())?;
contract.serialize()?.to_vec()
}
};

Ok(WrappedContract {
serialized: Arc::new(serialized),
})
}

pub fn as_bytes(&self) -> &[u8] {
&self.serialized
}
}
11 changes: 3 additions & 8 deletions piecrust/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ use std::ops::{Deref, DerefMut};
use dusk_wasmtime::{Instance, Module, Mutability, Store, ValType};
use piecrust_uplink::{ContractId, Event, ARGBUF_LEN};

use crate::contract::WrappedContract;
use crate::imports::Imports;
use crate::session::Session;
use crate::store::{Memory, MAX_MEM_SIZE};
use crate::store::Memory;
use crate::Error;

pub struct WrappedInstance {
Expand Down Expand Up @@ -85,18 +84,14 @@ impl WrappedInstance {
pub fn new(
session: Session,
contract_id: ContractId,
contract: &WrappedContract,
module: &Module,
memory: Memory,
) -> Result<Self, Error> {
let engine = session.engine().clone();

let env = Env {
self_id: contract_id,
session,
};

let module =
unsafe { Module::deserialize(&engine, contract.as_bytes())? };
let mut store = Store::new(&engine, env);

// Ensure there is at most one memory exported, and that it is called
Expand Down Expand Up @@ -169,7 +164,7 @@ impl WrappedInstance {
_ => return Err(Error::InvalidArgumentBuffer),
};

if arg_buf_ofs + ARGBUF_LEN >= MAX_MEM_SIZE {
if arg_buf_ofs + ARGBUF_LEN >= memory.len() {
return Err(Error::InvalidArgumentBuffer);
}

Expand Down
17 changes: 5 additions & 12 deletions piecrust/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ use rkyv::{
};

use crate::call_tree::{CallTree, CallTreeElem};
use crate::contract::{ContractData, ContractMetadata, WrappedContract};
use crate::contract::{ContractData, ContractMetadata};
use crate::error::Error::{self, InitalizationError, PersistenceError};
use crate::instance::WrappedInstance;
use crate::store::{ContractSession, Objectcode, PAGE_SIZE};
use crate::store::{ContractSession, Module, PAGE_SIZE};
use crate::types::StandardBufSerializer;
use crate::vm::HostQueries;

Expand Down Expand Up @@ -274,8 +274,7 @@ impl Session {
));
}

let wrapped_contract =
WrappedContract::new(&self.engine, bytecode, None::<Objectcode>)?;
let objectcode = self.engine.precompile_module(bytecode)?;
let contract_metadata = ContractMetadata { contract_id, owner };
let metadata_bytes = Self::serialize_data(&contract_metadata)?;

Expand All @@ -284,7 +283,7 @@ impl Session {
.deploy(
contract_id,
bytecode,
wrapped_contract.as_bytes(),
objectcode,
contract_metadata,
metadata_bytes.as_slice(),
)
Expand Down Expand Up @@ -528,18 +527,12 @@ impl Session {
.map_err(|err| PersistenceError(Arc::new(err)))?
.ok_or(Error::ContractDoesNotExist(contract_id))?;

let contract = WrappedContract::new(
&self.engine,
store_data.bytecode,
Some(store_data.objectcode),
)?;

self.inner.current = contract_id;

let instance = WrappedInstance::new(
self.clone(),
contract_id,
&contract,
&store_data.module,
store_data.memory,
)?;

Expand Down
46 changes: 28 additions & 18 deletions piecrust/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,22 @@
mod bytecode;
mod memory;
mod metadata;
mod objectcode;
mod module;
mod session;
mod tree;

use std::collections::btree_map::Entry::*;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt::{Debug, Formatter};
use std::path::{Path, PathBuf};
use std::sync::mpsc;
use std::{fs, io, thread};

pub use bytecode::Bytecode;
use dusk_wasmtime::{Engine, Module};
pub use memory::{Memory, MAX_MEM_SIZE, PAGE_SIZE};
use dusk_wasmtime::Engine;
pub use memory::{Memory, PAGE_SIZE};
pub use metadata::Metadata;
pub use objectcode::Objectcode;
pub use module::Module;
use piecrust_uplink::ContractId;
use session::ContractDataEntry;
pub use session::ContractSession;
Expand All @@ -36,13 +37,23 @@ const OBJECTCODE_EXTENSION: &str = "a";
const METADATA_EXTENSION: &str = "m";

/// A store for all contract commits.
#[derive(Debug)]
pub struct ContractStore {
engine: Engine,
sync_loop: thread::JoinHandle<()>,
call: mpsc::Sender<Call>,
root_dir: PathBuf,
}

impl Debug for ContractStore {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ContractStore")
.field("syn_loop", &self.sync_loop)
.field("call", &self.call)
.field("root_dir", &self.root_dir)
.finish()
}
}

impl ContractStore {
/// Loads a new contract store from the given `dir`ectory.
///
Expand All @@ -53,13 +64,13 @@ impl ContractStore {
/// [`commit`]: ContractSession::commit
/// [`delete`]: ContractStore::delete_commit
/// [`session spawning`]: ContractStore::session
pub fn new<P: AsRef<Path>>(engine: &Engine, dir: P) -> io::Result<Self> {
pub fn new<P: AsRef<Path>>(engine: Engine, dir: P) -> io::Result<Self> {
let root_dir = dir.as_ref();

fs::create_dir_all(root_dir)?;

let (call, calls) = mpsc::channel();
let commits = read_all_commits(engine, root_dir)?;
let commits = read_all_commits(&engine, root_dir)?;

let loop_root_dir = root_dir.to_path_buf();

Expand All @@ -70,6 +81,7 @@ impl ContractStore {
.spawn(|| sync_loop(loop_root_dir, commits, calls))?;

Ok(Self {
engine,
sync_loop,
call,
root_dir: root_dir.into(),
Expand Down Expand Up @@ -144,7 +156,12 @@ impl ContractStore {
}

fn session_with_base(&self, base: Option<Commit>) -> ContractSession {
ContractSession::new(&self.root_dir, base, self.call.clone())
ContractSession::new(
&self.root_dir,
self.engine.clone(),
base,
self.call.clone(),
)
}
}

Expand Down Expand Up @@ -217,20 +234,13 @@ fn commit_from_dir<P: AsRef<Path>>(

// SAFETY it is safe to deserialize the file here, since we don't use
// the module here. We just want to check if the file is valid.
if unsafe {
Module::deserialize_file(engine, &objectcode_path).is_err()
} {
if Module::from_file(engine, &objectcode_path).is_err() {
let bytecode = Bytecode::from_file(bytecode_path)?;
let module =
Module::new(engine, bytecode.as_ref()).map_err(|err| {
io::Error::new(io::ErrorKind::InvalidData, err)
})?;
fs::write(
objectcode_path,
module.serialize().map_err(|err| {
io::Error::new(io::ErrorKind::InvalidData, err)
})?,
)?;
fs::write(objectcode_path, module.serialize())?;
}

let memory_dir = memory_dir.join(&contract_hex);
Expand Down Expand Up @@ -537,7 +547,7 @@ fn write_commit_inner<P: AsRef<Path>>(
}
} else {
fs::write(bytecode_path, &contract_data.bytecode)?;
fs::write(objectcode_path, &contract_data.objectcode)?;
fs::write(objectcode_path, contract_data.module.serialize())?;
fs::write(metadata_path, &contract_data.metadata)?;
}
}
Expand Down
44 changes: 31 additions & 13 deletions piecrust/src/store/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,23 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use std::sync::atomic::Ordering;
use std::{
fmt::{Debug, Formatter},
io,
ops::{Deref, DerefMut, Range},
sync::atomic::AtomicUsize,
sync::atomic::{AtomicUsize, Ordering},
};

use crumbles::{LocateFile, Mmap};
use dusk_wasmtime::LinearMemory;

pub const PAGE_SIZE: usize = 0x10000;
const WASM_MAX_PAGES: u32 = 0x4000000;

const MIN_PAGES: usize = 4;
const MIN_MEM_SIZE: usize = MIN_PAGES * PAGE_SIZE;
const MAX_PAGES: usize = WASM_MAX_PAGES as usize;
const WASM32_MAX_PAGES: usize = 0x10000;
const WASM64_MAX_PAGES: usize = 0x4000000;

pub const MAX_MEM_SIZE: usize = MAX_PAGES * PAGE_SIZE;
pub const MAX32_MEM_SIZE: usize = WASM32_MAX_PAGES * PAGE_SIZE;
pub const MAX64_MEM_SIZE: usize = WASM64_MAX_PAGES * PAGE_SIZE;

pub struct MemoryInner {
pub mmap: Mmap,
Expand Down Expand Up @@ -63,32 +61,52 @@ pub struct Memory {
}

impl Memory {
pub fn new() -> io::Result<Self> {
pub fn new(is_64: bool) -> io::Result<Self> {
let max_pages = if is_64 {
WASM64_MAX_PAGES
} else {
WASM32_MAX_PAGES
};

Ok(Self {
inner: Box::leak(Box::new(MemoryInner {
mmap: Mmap::new(MAX_PAGES, PAGE_SIZE)?,
current_len: MIN_MEM_SIZE,
mmap: Mmap::new(max_pages, PAGE_SIZE)?,
current_len: 0,
is_new: true,
ref_count: AtomicUsize::new(1),
})),
})
}

pub fn from_files<FL>(file_locator: FL, len: usize) -> io::Result<Self>
pub fn from_files<FL>(
is_64: bool,
file_locator: FL,
len: usize,
) -> io::Result<Self>
where
FL: 'static + LocateFile,
{
let max_pages = if is_64 {
WASM64_MAX_PAGES
} else {
WASM32_MAX_PAGES
};

Ok(Self {
inner: Box::leak(Box::new(MemoryInner {
mmap: unsafe {
Mmap::with_files(MAX_PAGES, PAGE_SIZE, file_locator)?
Mmap::with_files(max_pages, PAGE_SIZE, file_locator)?
},
current_len: len,
is_new: false,
ref_count: AtomicUsize::new(1),
})),
})
}

pub fn is_64(&self) -> bool {
self.inner.len() == MAX64_MEM_SIZE
}
}

/// This implementation of clone is dangerous, and must be accompanied by the
Expand Down Expand Up @@ -143,7 +161,7 @@ unsafe impl LinearMemory for Memory {
}

fn maximum_byte_size(&self) -> Option<usize> {
Some(MAX_MEM_SIZE)
Some(self.inner.len())
}

fn grow_to(&mut self, new_size: usize) -> Result<(), dusk_wasmtime::Error> {
Expand Down
Loading

0 comments on commit 8020e66

Please sign in to comment.