Skip to content

Commit

Permalink
piecrust: implemented economic mode buffer scheme
Browse files Browse the repository at this point in the history
  • Loading branch information
miloszm committed May 8, 2024
1 parent cfc15b2 commit 1a96723
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 62 deletions.
2 changes: 1 addition & 1 deletion contracts/c-example/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub static mut A: [u8; 65536] = [0; 65536];

// Define second argument buffer for the Economic Protocol
#[no_mangle]
pub static mut B: [u8; 16] = [0; 16];
pub static mut ECO_MODE: [u8; 16] = [0; 16];

// ==== Host functions ====
//
Expand Down
4 changes: 2 additions & 2 deletions contracts/callcenter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl Callcenter {
fn_arg: Vec<u8>,
) -> Result<Vec<u8>, ContractError> {
uplink::debug!("raw query {fn_name} at {contract_id:?}");
uplink::call_raw(contract_id, &fn_name, &fn_arg)
uplink::call_raw(contract_id, &fn_name, &fn_arg).map(|r|r.data)
}

/// Pass the current query
Expand All @@ -62,7 +62,7 @@ impl Callcenter {
fn_name: String,
fn_arg: Vec<u8>,
) -> Vec<u8> {
uplink::call_raw(contract_id, &fn_name, &fn_arg).unwrap()
uplink::call_raw(contract_id, &fn_name, &fn_arg).unwrap().data
}

/// Check whether the current caller is the contract itself
Expand Down
6 changes: 3 additions & 3 deletions contracts/grower/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ static mut STATE: Grower = Grower(Vec::new());
impl Grower {
/// Appends the bytes sent in the argument buffer to the state vector.
fn append(&mut self, len: usize) {
with_arg_buf(|buf| {
with_arg_buf(|buf, _| {
self.0.extend_from_slice(&buf[..len]);
});
}

/// Parses offset and length from the argument buffer, and copies the bytes
/// at said offset and length on the state vector to the argument buffer.
fn view(&self, arg_len: usize) -> usize {
with_arg_buf(|buf| {
with_arg_buf(|buf, _| {
if arg_len != 8 {
panic!("Bad arguments");
}
Expand All @@ -62,7 +62,7 @@ impl Grower {

/// Emplace the length of the state vector into the argument buffer.
fn len(&self) -> usize {
with_arg_buf(|buf| {
with_arg_buf(|buf, _| {
let len = self.0.len() as u32;
let len_bytes = len.to_le_bytes();
buf[..4].copy_from_slice(&len_bytes);
Expand Down
13 changes: 7 additions & 6 deletions piecrust/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ use dusk_wasmtime::{
Caller, Extern, Func, Module, Result as WasmtimeResult, Store,
};
use piecrust_uplink::{
ContractError, ContractId, ARGBUF_B_LEN, ARGBUF_LEN, CONTRACT_ID_BYTES,
ContractError, ContractId, ARGBUF_LEN, CONTRACT_ID_BYTES, ECO_MODE_BUF_LEN,
ECO_MODE_LEN,
};

use crate::instance::{Env, WrappedInstance};
Expand Down Expand Up @@ -212,7 +213,7 @@ pub(crate) fn c(
check_arg(instance, arg_len)?;

let argbuf_ofs = instance.arg_buffer_offset();
let argbuf_b_ofs = instance.arg_buffer_b_offset();
let eco_mode_ofs = instance.eco_mode_offset();

let caller_remaining = instance.get_remaining_gas();

Expand All @@ -226,7 +227,6 @@ pub(crate) fn c(

let with_memory = |memory: &mut [u8]| -> Result<_, Error> {
let arg_buf = &memory[argbuf_ofs..][..ARGBUF_LEN];
let arg_buf_b = &memory[argbuf_b_ofs..][..ARGBUF_B_LEN];

let mut mod_id = ContractId::uninitialized();
mod_id.as_bytes_mut().copy_from_slice(
Expand All @@ -248,18 +248,19 @@ pub(crate) fn c(
let name = core::str::from_utf8(&memory[name_ofs..][..name_len])?;

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

callee.write_argument(arg);
callee.write_argument_b(arg_b);
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
callee.read_argument(&mut memory[argbuf_ofs..][..ret_len as usize]);
callee.read_argument_b(&mut memory[argbuf_b_ofs..][..ARGBUF_B_LEN]);
callee.read_eco_mode_buf(
&mut memory[eco_mode_ofs..][ECO_MODE_LEN..ECO_MODE_BUF_LEN],
);
callee.clear_eco_mode();

let callee_remaining = callee.get_remaining_gas();
let callee_spent = callee_limit - callee_remaining;
Expand Down
58 changes: 27 additions & 31 deletions piecrust/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use std::ops::{Deref, DerefMut};
use std::ptr;

use dusk_wasmtime::{Instance, Module, Mutability, Store, ValType};
use piecrust_uplink::{ContractId, Event, ARGBUF_B_LEN, ARGBUF_LEN};
use piecrust_uplink::{
ContractId, EconomicMode, Event, ARGBUF_LEN, ECO_MODE_LEN,
};

use crate::contract::WrappedContract;
use crate::imports::Imports;
Expand All @@ -20,7 +22,7 @@ use crate::Error;
pub struct WrappedInstance {
instance: Instance,
arg_buf_ofs: usize,
arg_buf_b_ofs: usize,
eco_mode_ofs: usize,
store: Store<Env>,
memory: Memory,
}
Expand Down Expand Up @@ -176,17 +178,17 @@ impl WrappedInstance {
return Err(Error::InvalidArgumentBuffer);
}

let arg_buf_b_ofs = if is_64 {
let eco_mode_ofs = if is_64 {
instance
.get_global(&mut store, "B")
.expect("B should be exported")
.get_global(&mut store, "ECO_MODE")
.expect("ECO_MODE should be exported")
.get(&mut store)
.i64()
.ok_or(Error::InvalidArgumentBuffer)? as usize
} else {
instance
.get_global(&mut store, "B")
.expect("B should be exported")
.get_global(&mut store, "ECO_MODE")
.expect("ECO_MODE should be exported")
.get(&mut store)
.i32()
.ok_or(Error::InvalidArgumentBuffer)? as usize
Expand All @@ -198,7 +200,7 @@ impl WrappedInstance {
store,
instance,
arg_buf_ofs,
arg_buf_b_ofs,
eco_mode_ofs,
memory,
};

Expand All @@ -225,17 +227,13 @@ impl WrappedInstance {
self.with_arg_buf_mut(|buf| buf[..arg.len()].copy_from_slice(arg))
}

pub(crate) fn write_argument_b(&mut self, arg: &[u8]) {
self.with_arg_buf_b_mut(|buf| buf[..arg.len()].copy_from_slice(arg))
}

// Read argument from instance
pub(crate) fn read_argument(&mut self, arg: &mut [u8]) {
self.with_arg_buf(|buf| arg.copy_from_slice(&buf[..arg.len()]))
}

pub(crate) fn read_argument_b(&mut self, arg: &mut [u8]) {
self.with_arg_buf_b(|buf| arg.copy_from_slice(&buf[..arg.len()]))
pub(crate) fn read_eco_mode_buf(&mut self, arg: &mut [u8]) {
self.with_eco_mode_buf(|buf| arg.copy_from_slice(&buf[..arg.len()]))
}

pub(crate) fn read_bytes_from_arg_buffer(&self, arg_len: u32) -> Vec<u8> {
Expand All @@ -245,17 +243,15 @@ impl WrappedInstance {
})
}

pub(crate) fn read_from_arg_buffer_b(&self) -> Vec<u64> {
self.with_arg_buf_b(|bbuf| {
bbuf.chunks_exact(std::mem::size_of::<u64>())
.map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap()))
.collect()
})
pub(crate) fn read_eco_mode(&self) -> EconomicMode {
self.with_eco_mode_buf(EconomicMode::read)
}

pub(crate) fn clear_arg_buffer_b(&mut self) {
self.with_arg_buf_b_mut(|bbuf| {
unsafe { ptr::write_bytes(bbuf.as_mut_ptr(), 0u8, ARGBUF_B_LEN) };
pub(crate) fn clear_eco_mode(&mut self) {
self.with_eco_mode_buf_mut(|eco_mode_buf| {
unsafe {
ptr::write_bytes(eco_mode_buf.as_mut_ptr(), 0u8, ECO_MODE_LEN)
};
});
}

Expand Down Expand Up @@ -293,13 +289,13 @@ impl WrappedInstance {
)
}

pub(crate) fn with_arg_buf_b<F, R>(&self, f: F) -> R
pub(crate) fn with_eco_mode_buf<F, R>(&self, f: F) -> R
where
F: FnOnce(&[u8]) -> R,
{
let offset = self.arg_buf_b_ofs;
let offset = self.eco_mode_ofs;
self.with_memory(|memory_bytes| {
f(&memory_bytes[offset..][..ARGBUF_B_LEN])
f(&memory_bytes[offset..][..ECO_MODE_LEN])
})
}

Expand All @@ -313,13 +309,13 @@ impl WrappedInstance {
})
}

pub(crate) fn with_arg_buf_b_mut<F, R>(&mut self, f: F) -> R
pub(crate) fn with_eco_mode_buf_mut<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let offset = self.arg_buf_b_ofs;
let offset = self.eco_mode_ofs;
self.with_memory_mut(|memory_bytes| {
f(&mut memory_bytes[offset..][..ARGBUF_B_LEN])
f(&mut memory_bytes[offset..][..ECO_MODE_LEN])
})
}

Expand Down Expand Up @@ -413,8 +409,8 @@ impl WrappedInstance {
self.arg_buf_ofs
}

pub fn arg_buffer_b_offset(&self) -> usize {
self.arg_buf_b_ofs
pub fn eco_mode_offset(&self) -> usize {
self.eco_mode_ofs
}
}

Expand Down
34 changes: 15 additions & 19 deletions piecrust/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use std::sync::{mpsc, Arc};

use bytecheck::CheckBytes;
use dusk_wasmtime::{Engine, LinearMemory, MemoryCreator, MemoryType};
use piecrust_uplink::{ContractId, Event, ARGBUF_LEN, SCRATCH_BUF_BYTES};
use piecrust_uplink::{
ContractId, EconomicMode, Event, ARGBUF_LEN, SCRATCH_BUF_BYTES,
};
use rkyv::ser::serializers::{
BufferScratch, BufferSerializer, CompositeSerializer,
};
Expand Down Expand Up @@ -381,7 +383,7 @@ impl Session {
return Err(InitalizationError("init call not allowed".into()));
}

let (data, gas_spent, call_tree) =
let (data, gas_spent, call_tree, economic_mode) =
self.call_inner(contract, fn_name, fn_arg.into(), gas_limit)?;
let events = mem::take(&mut self.inner.events);

Expand All @@ -391,6 +393,7 @@ impl Session {
events,
call_tree,
data,
economic_mode,
})
}

Expand Down Expand Up @@ -748,7 +751,7 @@ impl Session {
fname: &str,
fdata: Vec<u8>,
limit: u64,
) -> Result<(Vec<u8>, u64, CallTree), Error> {
) -> Result<(Vec<u8>, u64, CallTree, EconomicMode), Error> {
let stack_element = self.push_callstack(contract, limit)?;
let instance = self
.instance(&stack_element.contract_id)
Expand All @@ -762,7 +765,7 @@ impl Session {
})?;

let arg_len = instance.write_bytes_to_arg_buffer(&fdata)?;
instance.clear_arg_buffer_b();
instance.clear_eco_mode();
let ret_len = instance
.call(fname, arg_len, limit)
.map_err(|err| {
Expand All @@ -778,20 +781,9 @@ impl Session {
})
.map_err(Error::normalize)?;
let ret = instance.read_bytes_from_arg_buffer(ret_len as u32);
let ret_b = instance.read_from_arg_buffer_b();
let allowance = *ret_b.first().unwrap_or(&0u64);
let charge = *ret_b.get(1).unwrap_or(&0u64);

let mut spent = limit - instance.get_remaining_gas();

if allowance > 0 {
// the call has been paid for by the contract so we can set
// the spent amount to zero,
spent = 0;
} else {
// add possible contract's charge
spent += charge;
}
let economic_mode = instance.read_eco_mode();

let spent = limit - instance.get_remaining_gas();

for elem in self.inner.call_tree.iter() {
let instance = self
Expand All @@ -810,7 +802,7 @@ impl Session {
mem::swap(&mut self.inner.call_tree, &mut call_tree);
call_tree.update_spent(spent);

Ok((ret, spent, call_tree))
Ok((ret, spent, call_tree, economic_mode))
}

pub fn contract_metadata(
Expand Down Expand Up @@ -840,6 +832,9 @@ pub struct CallReceipt<T> {

/// The data returned by the called contract.
pub data: T,

/// Economic mode applied during the execution of the call.
pub economic_mode: EconomicMode,
}

impl CallReceipt<Vec<u8>> {
Expand All @@ -860,6 +855,7 @@ impl CallReceipt<Vec<u8>> {
events: self.events,
call_tree: self.call_tree,
data,
economic_mode: self.economic_mode,
})
}
}
Expand Down

0 comments on commit 1a96723

Please sign in to comment.