Skip to content

Commit

Permalink
Merge pull request #377 from dusk-network/rm-contract-id-uninit
Browse files Browse the repository at this point in the history
Remove the concept of an "uninitialized" `ContractId`
  • Loading branch information
Eduardo Leegwater Simões authored Jul 30, 2024
2 parents d464f36 + 133b378 commit e7787fb
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 69 deletions.
10 changes: 4 additions & 6 deletions contracts/callcenter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,17 @@ impl Callcenter {
}

/// Return the caller of this contract
pub fn return_caller(&self) -> ContractId {
pub fn return_caller(&self) -> Option<ContractId> {
uplink::caller()
}

/// Make sure that the caller of this contract is the contract itself
pub fn call_self(&self) -> Result<bool, ContractError> {
let self_id = uplink::self_id();
let caller = uplink::caller();

match caller.is_uninitialized() {
true => uplink::call(self_id, "call_self", &())
match uplink::caller() {
None => uplink::call(self_id, "call_self", &())
.expect("querying self should succeed"),
false => Ok(caller == self_id),
Some(caller) => Ok(caller == self_id),
}
}

Expand Down
3 changes: 2 additions & 1 deletion contracts/crossover/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ impl Crossover {
) {
self.set_crossover(value_to_set);

let caller = uplink::caller();
let caller =
uplink::caller().expect("Should be called by another contract");
uplink::debug!("calling back {caller:?}");

uplink::call::<_, ()>(caller, "set_crossover", &value_to_set_back)
Expand Down
2 changes: 1 addition & 1 deletion contracts/spender/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl Spender {
let limit = uplink::limit();
let spent_before = uplink::spent();

match uplink::caller().is_uninitialized() {
match uplink::caller().is_none() {
// if this contract has not been called by another contract,
// i.e. has been called directly from the outside, call the function
// via the host and return the limit and spent values before and
Expand Down
5 changes: 5 additions & 0 deletions piecrust-uplink/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Add `impl PartialEq<[u8; 32]> for ContractId` [#375]

### Changed

- Change `callee` function to return `Option<ContractId>`
- Change `callee` ABI to return an integer

## [0.15.0] - 2024-07-03

### Fixed
Expand Down
39 changes: 18 additions & 21 deletions piecrust-uplink/src/abi/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rkyv::{
archived_root,
ser::serializers::{BufferScratch, BufferSerializer, CompositeSerializer},
ser::Serializer,
Archive, Archived, Deserialize, Infallible, Serialize,
Archive, Deserialize, Infallible, Serialize,
};

use crate::{
Expand Down Expand Up @@ -57,7 +57,7 @@ mod ext {
pub fn emit(topic: *const u8, topic_len: u32, arg_len: u32);
pub fn feed(arg_len: u32);

pub fn caller();
pub fn caller() -> i32;
pub fn limit() -> u64;
pub fn spent() -> u64;
pub fn owner(contract_id: *const u8) -> i32;
Expand Down Expand Up @@ -269,29 +269,26 @@ pub fn self_owner<const N: usize>() -> [u8; N] {
/// Return the current contract's id.
pub fn self_id() -> ContractId {
unsafe { ext::self_id() };
let id: ContractId = with_arg_buf(|buf| {
let ret =
unsafe { archived_root::<ContractId>(&buf[..CONTRACT_ID_BYTES]) };
ret.deserialize(&mut Infallible).expect("Infallible")
});
id
}

/// Return the ID of the calling contract. The returned id will be
/// uninitialized if there is no caller - meaning this is the first contract
/// to be called.
pub fn caller() -> ContractId {
unsafe { ext::caller() };
with_arg_buf(|buf| {
let ret = unsafe {
archived_root::<ContractId>(
&buf[..core::mem::size_of::<Archived<ContractId>>()],
)
};
ret.deserialize(&mut Infallible).expect("Infallible")
let mut bytes = [0; CONTRACT_ID_BYTES];
bytes.copy_from_slice(&buf[..32]);
ContractId::from_bytes(bytes)
})
}

/// Returns the ID of the calling contract, or `None` if this is the first
/// contract to be called.
pub fn caller() -> Option<ContractId> {
match unsafe { ext::caller() } {
0 => None,
_ => with_arg_buf(|buf| {
let mut bytes = [0; CONTRACT_ID_BYTES];
bytes.copy_from_slice(&buf[..32]);
Some(ContractId::from_bytes(bytes))
}),
}
}

/// Returns the gas limit with which the contact was called.
pub fn limit() -> u64 {
unsafe { ext::limit() }
Expand Down
13 changes: 0 additions & 13 deletions piecrust-uplink/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,6 @@ pub const CONTRACT_ID_BYTES: usize = 32;
pub struct ContractId([u8; CONTRACT_ID_BYTES]);

impl ContractId {
/// Creates a placeholder [`ContractId`] until the host deploys the contract
/// and sets a real [`ContractId`]. This can also be used to determine if a
/// contract is the first to be called.
pub const fn uninitialized() -> Self {
ContractId([0u8; CONTRACT_ID_BYTES])
}

/// Creates a new [`ContractId`] from an array of bytes
pub const fn from_bytes(bytes: [u8; CONTRACT_ID_BYTES]) -> Self {
Self(bytes)
Expand All @@ -91,12 +84,6 @@ impl ContractId {
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut self.0
}

/// Determines whether the [`ContractId`] is uninitialized, which can be
/// used to check if this contract is the first to be called.
pub fn is_uninitialized(&self) -> bool {
self == &Self::uninitialized()
}
}

impl From<[u8; CONTRACT_ID_BYTES]> for ContractId {
Expand Down
4 changes: 4 additions & 0 deletions piecrust/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Change `callee` import to return an integer

## [0.22.0] - 2024-07-03

### Added
Expand Down
53 changes: 30 additions & 23 deletions piecrust/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ pub(crate) fn hd(

pub(crate) fn c(
mut fenv: Caller<Env>,
mod_id_ofs: usize,
callee_ofs: usize,
name_ofs: usize,
name_len: u32,
arg_len: u32,
Expand All @@ -229,7 +229,7 @@ pub(crate) fn c(

let name_len = name_len as usize;

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

Expand All @@ -248,13 +248,14 @@ pub(crate) fn c(
let with_memory = |memory: &mut [u8]| -> Result<_, Error> {
let arg_buf = &memory[argbuf_ofs..][..ARGBUF_LEN];

let mut mod_id = ContractId::uninitialized();
mod_id.as_bytes_mut().copy_from_slice(
&memory[mod_id_ofs..][..std::mem::size_of::<ContractId>()],
let mut callee_bytes = [0; CONTRACT_ID_BYTES];
callee_bytes.copy_from_slice(
&memory[callee_ofs..callee_ofs + CONTRACT_ID_BYTES],
);
let callee_id = ContractId::from_bytes(callee_bytes);

let callee_stack_element = env
.push_callstack(mod_id, callee_limit)
.push_callstack(callee_id, callee_limit)
.expect("pushing to the callstack should succeed");
let callee = env
.instance(&callee_stack_element.contract_id)
Expand Down Expand Up @@ -351,17 +352,20 @@ pub(crate) fn emit(
Ok(())
}

fn caller(env: Caller<Env>) {
fn caller(env: Caller<Env>) -> i32 {
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())
})
match env.nth_from_top(1) {
Some(call_tree_elem) => {
let instance = env.self_instance();
instance.with_arg_buf_mut(|buf| {
let caller = call_tree_elem.contract_id;
buf[..CONTRACT_ID_BYTES].copy_from_slice(caller.as_bytes());
});
1
}
None => 0,
}
}

fn feed(mut fenv: Caller<Env>, arg_len: u32) -> WasmtimeResult<()> {
Expand Down Expand Up @@ -432,10 +436,13 @@ fn panic(fenv: Caller<Env>, arg_len: u32) -> WasmtimeResult<()> {
})?)
}

fn get_metadata(env: &mut Env, mod_id_ofs: usize) -> Option<&ContractMetadata> {
fn get_metadata(
env: &mut Env,
contract_id_ofs: usize,
) -> Option<&ContractMetadata> {
// The null pointer is always zero, so we can use this to check if the
// caller wants their own ID.
if mod_id_ofs == 0 {
if contract_id_ofs == 0 {
let self_id = env.self_contract_id().to_owned();

let contract_metadata = env
Expand All @@ -446,15 +453,15 @@ fn get_metadata(env: &mut Env, mod_id_ofs: usize) -> Option<&ContractMetadata> {
} else {
let instance = env.self_instance();

let mod_id = instance.with_memory(|memory| {
let mut mod_id = ContractId::uninitialized();
mod_id.as_bytes_mut().copy_from_slice(
&memory[mod_id_ofs..][..std::mem::size_of::<ContractId>()],
let contract_id = instance.with_memory(|memory| {
let mut contract_id_bytes = [0u8; CONTRACT_ID_BYTES];
contract_id_bytes.copy_from_slice(
&memory[contract_id_ofs..][..CONTRACT_ID_BYTES],
);
mod_id
ContractId::from_bytes(contract_id_bytes)
});

env.contract_metadata(&mod_id)
env.contract_metadata(&contract_id)
}
}

Expand Down
6 changes: 4 additions & 2 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, Event, ARGBUF_LEN, CONTRACT_ID_BYTES, SCRATCH_BUF_BYTES,
};
use rkyv::ser::serializers::{
BufferScratch, BufferSerializer, CompositeSerializer,
};
Expand Down Expand Up @@ -138,7 +140,7 @@ impl Session {
data: SessionData,
) -> Self {
let inner = SessionInner {
current: ContractId::uninitialized(),
current: ContractId::from_bytes([0; CONTRACT_ID_BYTES]),
call_tree: CallTree::new(),
instances: BTreeMap::new(),
debug: vec![],
Expand Down
4 changes: 2 additions & 2 deletions piecrust/tests/callcenter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,9 @@ pub fn cc_caller_uninit() -> Result<(), Error> {
LIMIT,
)?;

let caller: ContractId =
let caller: Option<ContractId> =
session.call(center_id, "return_caller", &(), LIMIT)?.data;
assert_eq!(caller, ContractId::uninitialized());
assert_eq!(caller, None);

Ok(())
}
Expand Down

0 comments on commit e7787fb

Please sign in to comment.