Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDK: RoleIdentifier additions #1738

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ debug/
target/
target-tarpaulin/
target-custom/
venv/

# These are backup files generated by rustfmt
**/*.rs.bk
Expand Down
129 changes: 81 additions & 48 deletions sdk/src/common/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@ use rkyv::Deserialize;
use {
crate::common::merkle::merkleize,
crate::common::types::{CanonicalOrderedTemporalHints, CrossProgramCall, Poseidon2Hash},
crate::core::constants::DIGEST_BYTES,
// crate::core::constants::DIGEST_BYTES,
crate::core::ecall::{
call_tape_read, event_tape_read, ioread_private, ioread_public, self_prog_id_tape_read,
call_tape_read,
event_tape_read,
// ioread_private, ioread_public, self_prog_id_tape_read,
},
core::ptr::slice_from_raw_parts,
std::collections::BTreeSet,
// std::collections::BTreeSet,
};
#[cfg(not(target_os = "mozakvm"))]
use {core::cell::RefCell, std::rc::Rc};

use crate::common::traits::{Call, CallArgument, CallReturn, EventEmit};
use crate::common::traits::{Call, EventEmit};
use crate::common::types::{
CallTapeType, Event, EventTapeType, PrivateInputTapeType, ProgramIdentifier,
PublicInputTapeType, SystemTape,
CallTapeType, Event, EventTapeType, PrivateInputTapeType, PublicInputTapeType, RoleIdentifier,
SystemTape,
};

/// `SYSTEM_TAPE` is a global singleton for interacting with
Expand Down Expand Up @@ -63,39 +65,47 @@ pub(crate) static mut SYSTEM_TAPE: Lazy<SystemTape> = Lazy::new(|| {
// pre-populated data elements
#[cfg(target_os = "mozakvm")]
{
let mut self_prog_id_bytes = [0; DIGEST_BYTES];
self_prog_id_tape_read(self_prog_id_bytes.as_mut_ptr());
let self_prog_id = ProgramIdentifier(Poseidon2Hash::from(self_prog_id_bytes));
type _x = PrivateInputTapeType;
type _y = PublicInputTapeType;
// TODO: Fix
// let mut self_prog_id_bytes = [0; DIGEST_BYTES];
// self_prog_id_tape_read(self_prog_id_bytes.as_mut_ptr()); // Implement
// self_role_id_tape_read let self_prog_id =
// ProgramIdentifier(Poseidon2Hash::from(self_prog_id_bytes));

let call_tape = populate_call_tape(self_prog_id);
let event_tape = populate_event_tape(self_prog_id);
// let call_tape = populate_call_tape(self_prog_id);
// let event_tape = populate_event_tape(self_prog_id);

let mut size_hint_bytes = [0; 4];
// let mut size_hint_bytes = [0; 4];

ioread_public(size_hint_bytes.as_mut_ptr(), 4);
let size_hint: usize = u32::from_le_bytes(size_hint_bytes).try_into().unwrap();
let public_input_tape = PublicInputTapeType::with_size_hint(size_hint);
// ioread_public(size_hint_bytes.as_mut_ptr(), 4);
// let size_hint: usize =
// u32::from_le_bytes(size_hint_bytes).try_into().unwrap();
// let public_input_tape = PublicInputTapeType::with_size_hint(size_hint);

ioread_private(size_hint_bytes.as_mut_ptr(), 4);
let size_hint: usize = u32::from_le_bytes(size_hint_bytes).try_into().unwrap();
let private_input_tape = PrivateInputTapeType::with_size_hint(size_hint);
// ioread_private(size_hint_bytes.as_mut_ptr(), 4);
// let size_hint: usize =
// u32::from_le_bytes(size_hint_bytes).try_into().unwrap();
// let private_input_tape = PrivateInputTapeType::with_size_hint(size_hint);

SystemTape {
private_input_tape,
public_input_tape,
call_tape,
event_tape,
}
// SystemTape {
// private_input_tape,
// public_input_tape,
// call_tape,
// event_tape,
// }
SystemTape::default()
}
});

#[cfg(target_os = "mozakvm")]
#[allow(warnings)]
/// Populates a `MozakVM` [`CallTapeType`] via ECALLs.
///
/// At this point, the [`CrossProgramCall`] messages are still rkyv-serialized,
/// and must be deserialized at the point of consumption. Only the `callee`s are
/// deserialized for persistence of the `cast_list`.
fn populate_call_tape(self_prog_id: ProgramIdentifier) -> CallTapeType {
fn populate_call_tape(self_role_id: RoleIdentifier) -> CallTapeType {
let mut len_bytes = [0; 4];
call_tape_read(len_bytes.as_mut_ptr(), 4);
let len: usize = u32::from_le_bytes(len_bytes).try_into().unwrap();
Expand All @@ -106,31 +116,32 @@ fn populate_call_tape(self_prog_id: ProgramIdentifier) -> CallTapeType {
rkyv::access_unchecked::<Vec<CrossProgramCall>>(&*slice_from_raw_parts(buf.as_ptr(), len))
};

let cast_list: Vec<ProgramIdentifier> = archived_cpc_messages
.iter()
.map(|m| {
m.callee
.deserialize(Strategy::<_, Panic>::wrap(&mut ()))
.unwrap()
})
.collect::<BTreeSet<_>>()
.into_iter()
.collect();
// let cast_list: Vec<RoleIdentifier> = archived_cpc_messages
// .iter()
// .map(|m| {
// m.callee
// .deserialize(Strategy::<_, Panic>::wrap(&mut ()))
// .unwrap()
// })
// .collect::<BTreeSet<_>>()
// .into_iter()
// .collect();

CallTapeType {
cast_list,
self_prog_id,
cast_list: Vec::default(),
self_role_id,
reader: Some(archived_cpc_messages),
index: 0,
}
}

#[cfg(target_os = "mozakvm")]
#[allow(warnings)]
/// Populates a `MozakVM` [`EventTapeType`] via ECALLs.
///
/// At this point, the vector of [`CanonicalOrderedTemporalHints`] are still
/// rkyv-serialized, and must be deserialized at the point of consumption.
fn populate_event_tape(self_prog_id: ProgramIdentifier) -> EventTapeType {
fn populate_event_tape(self_role_id: RoleIdentifier) -> EventTapeType {
let mut len_bytes = [0; 4];
event_tape_read(len_bytes.as_mut_ptr(), 4);
let len: usize = u32::from_le_bytes(len_bytes).try_into().unwrap();
Expand All @@ -145,7 +156,7 @@ fn populate_event_tape(self_prog_id: ProgramIdentifier) -> EventTapeType {
};

EventTapeType {
self_prog_id,
self_role_id,
reader: Some(canonical_ordered_temporal_hints),
seen: vec![false; canonical_ordered_temporal_hints.len()],
index: 0,
Expand All @@ -161,37 +172,59 @@ pub fn event_emit(event: Event) {
}
}

/// Gets a roleID determined fully by `(Prog, instance)` tuple. It is
/// guaranteed that any call wih same `(Prog, instance)` tuple during one
/// native context will always return the same `RoleIdentifier` within that
/// context. Useful when different programs need to call the same role.
#[cfg(not(target_os = "mozakvm"))]
pub fn get_deterministic_role_id(
prog: crate::common::types::ProgramIdentifier,
instance: String,
) -> RoleIdentifier {
unsafe {
SYSTEM_TAPE
.call_tape
.get_deterministic_role_id(prog, instance)
}
}

/// Gets a fresh & unique roleID referencible only by the `RoleIdentifier`
#[cfg(not(target_os = "mozakvm"))]
pub fn get_unique_role_id(prog: crate::common::types::ProgramIdentifier) -> RoleIdentifier {
unsafe { SYSTEM_TAPE.call_tape.get_unique_role_id(prog) }
}

/// Receive one message from mailbox targetted to us and its index
/// "consume" such message. Subsequent reads will never
/// return the same message. Panics on call-tape non-abidance.
#[must_use]
pub fn call_receive<A, R>() -> Option<(ProgramIdentifier, A, R)>
pub fn call_receive<A, R>() -> Option<(crate::common::types::RoleIdentifier, A, R)>
where
A: CallArgument + PartialEq,
R: CallReturn,
A: crate::common::traits::CallArgument + PartialEq,
R: crate::common::traits::CallReturn,
<A as rkyv::Archive>::Archived: Deserialize<A, Strategy<(), Panic>>,
<R as rkyv::Archive>::Archived: Deserialize<R, Strategy<(), Panic>>, {
unsafe { SYSTEM_TAPE.call_tape.receive() }
unsafe { crate::common::system::SYSTEM_TAPE.call_tape.receive() }
}

/// Send one message from mailbox targetted to some third-party
/// resulting in such messages finding itself in their mailbox
/// Panics on call-tape non-abidance.
#[allow(clippy::similar_names)]
pub fn call_send<A, R>(
recipient_program: ProgramIdentifier,
recipient: crate::common::types::RoleIdentifier,
argument: A,
resolver: impl Fn(A) -> R,
) -> R
where
A: CallArgument + PartialEq,
R: CallReturn,
A: crate::common::traits::CallArgument + PartialEq,
R: crate::common::traits::CallReturn,
<A as rkyv::Archive>::Archived: Deserialize<A, Strategy<(), Panic>>,
<R as rkyv::Archive>::Archived: Deserialize<R, Strategy<(), Panic>>, {
unsafe {
SYSTEM_TAPE
crate::common::system::SYSTEM_TAPE
.call_tape
.send(recipient_program, argument, resolver)
.send(recipient, argument, resolver)
}
}

Expand Down
10 changes: 5 additions & 5 deletions sdk/src/common/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rkyv::ser::{AllocSerializer, Composite};
use rkyv::util::AlignedVec;
use rkyv::{Archive, Deserialize, Serialize};

use crate::common::types::{Event, ProgramIdentifier};
use crate::common::types::{Event, RoleIdentifier};

pub trait RkyvSerializable = rkyv::Serialize<
Strategy<Composite<AlignedVec, AllocationTracker<GlobalAllocator>, Panic>, Panic>,
Expand All @@ -14,9 +14,9 @@ pub trait CallReturn = ?Sized + Clone + Default + RkyvSerializable + Archive;

/// A data struct that is aware of it's own ID
pub trait SelfIdentify {
fn get_self_identity(&self) -> ProgramIdentifier;
fn get_self_identity(&self) -> RoleIdentifier;
#[allow(dead_code)]
fn set_self_identity(&mut self, id: ProgramIdentifier);
fn set_self_identity(&mut self, id: RoleIdentifier);
}

/// `Call` trait provides methods `send` & `receive` to use an
Expand All @@ -28,7 +28,7 @@ pub trait Call: SelfIdentify {
/// deserialization. This func never serializes in `mozakvm`.
fn send<A, R>(
&mut self,
recipient_program: ProgramIdentifier,
recipient: RoleIdentifier,
argument: A,
resolver: impl Fn(A) -> R,
) -> R
Expand All @@ -45,7 +45,7 @@ pub trait Call: SelfIdentify {
/// the result that they want us to ensure is correct.
/// Under the hood, wherever required, it uses `rkyv` for
/// deserialization. This func never serializes in `mozakvm`.
fn receive<A, R>(&mut self) -> Option<(ProgramIdentifier, A, R)>
fn receive<A, R>(&mut self) -> Option<(RoleIdentifier, A, R)>
where
A: CallArgument + PartialEq,
R: CallReturn,
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/common/types/cross_program_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
)]
#[allow(clippy::pub_underscore_fields)]
pub struct CrossProgramCall {
pub caller: super::ProgramIdentifier,
pub callee: super::ProgramIdentifier,
pub caller: super::RoleIdentifier,
pub callee: super::RoleIdentifier,
pub argument: super::RawMessage,
pub return_: super::RawMessage,
}
2 changes: 2 additions & 0 deletions sdk/src/common/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub(crate) mod event;
pub(crate) mod poseidon2hash;
pub(crate) mod program_identifier;
pub(crate) mod raw_message;
pub(crate) mod role;
pub(crate) mod state_address;
pub(crate) mod state_object;
pub(crate) mod system_tape;
Expand All @@ -12,6 +13,7 @@ pub use event::{CanonicalEvent, CanonicalOrderedTemporalHints, Event, EventType}
pub use poseidon2hash::Poseidon2Hash;
pub use program_identifier::ProgramIdentifier;
pub use raw_message::RawMessage;
pub use role::RoleIdentifier;
pub use state_address::StateAddress;
pub use state_object::StateObject;
pub use system_tape::{
Expand Down
4 changes: 4 additions & 0 deletions sdk/src/common/types/role.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/// A monotonically increasing identifier of different program executions
/// based on the order of discover
#[allow(clippy::module_name_repetitions)]
pub type RoleIdentifier = u32;
2 changes: 2 additions & 0 deletions sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub mod common;

#[cfg(feature = "std")]
pub use crate::common::system::{call_receive, call_send, event_emit};
#[cfg(all(feature = "std", not(target_os = "mozakvm")))]
pub use crate::common::system::{get_deterministic_role_id, get_unique_role_id};

#[cfg(all(feature = "std", target_os = "mozakvm"))]
pub mod mozakvm;
Expand Down
33 changes: 11 additions & 22 deletions sdk/src/mozakvm/calltape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,27 @@ use rkyv::rancor::{Panic, Strategy};
use rkyv::{Archive, Deserialize};

use crate::common::traits::{Call, CallArgument, CallReturn, SelfIdentify};
use crate::common::types::{CrossProgramCall, ProgramIdentifier};
use crate::common::types::{CrossProgramCall, ProgramIdentifier, RoleIdentifier};

/// Represents the `CallTape` under `mozak-vm`
#[derive(Default, Clone)]
pub struct CallTape {
pub(crate) cast_list: Vec<ProgramIdentifier>,
pub(crate) self_prog_id: ProgramIdentifier,
pub(crate) self_role_id: RoleIdentifier,
pub(crate) reader: Option<&'static <Vec<CrossProgramCall> as Archive>::Archived>,
pub(crate) index: usize,
}

impl CallTape {
/// Checks if actor seen is casted actor
fn is_casted_actor(&self, actor: &ProgramIdentifier) -> bool {
&ProgramIdentifier::default() == actor || self.cast_list.contains(actor)
}
}

impl SelfIdentify for CallTape {
fn set_self_identity(&mut self, id: ProgramIdentifier) { self.self_prog_id = id; }
fn set_self_identity(&mut self, id: RoleIdentifier) { self.self_role_id = id; }

fn get_self_identity(&self) -> ProgramIdentifier { self.self_prog_id }
fn get_self_identity(&self) -> RoleIdentifier { self.self_role_id }
}

impl Call for CallTape {
fn send<A, R>(
&mut self,
recipient_program: ProgramIdentifier,
recipient: RoleIdentifier,
argument: A,
_resolver: impl Fn(A) -> R,
) -> R
Expand All @@ -48,8 +41,7 @@ impl Call for CallTape {

// Ensure fields are correctly populated for caller and callee
assert!(cpcmsg.caller == self.get_self_identity());
assert!(cpcmsg.callee == recipient_program);
assert!(self.is_casted_actor(&recipient_program));
assert!(cpcmsg.callee == recipient);

// Deserialize the `arguments` seen on the tape, and assert
let zcd_args = unsafe { rkyv::access_unchecked::<A>(&cpcmsg.argument.0[..]) };
Expand All @@ -76,7 +68,7 @@ impl Call for CallTape {
}

#[allow(clippy::similar_names)]
fn receive<A, R>(&mut self) -> Option<(ProgramIdentifier, A, R)>
fn receive<A, R>(&mut self) -> Option<(RoleIdentifier, A, R)>
where
A: CallArgument + PartialEq,
R: CallReturn,
Expand All @@ -96,23 +88,20 @@ impl Call for CallTape {
// Well, once we are sure that we were not the caller, we can
// either be a callee in which case we process and send information
// back or we continue searching.
let callee: ProgramIdentifier = zcd_cpcmsg
let callee: RoleIdentifier = zcd_cpcmsg
.callee
.deserialize(Strategy::<_, Panic>::wrap(&mut ()))
.unwrap();

if self.self_prog_id == callee {
if self.self_role_id == callee {
// First, ensure that we are not the caller, no-one can call
// themselves. (Even if they can w.r.t. self-calling extension,
// the `caller` field would remain distinct)
let caller: ProgramIdentifier = zcd_cpcmsg
let caller: RoleIdentifier = zcd_cpcmsg
.caller
.deserialize(Strategy::<_, Panic>::wrap(&mut ()))
.unwrap();
assert!(caller != self.self_prog_id);

// Before accepting, make sure that caller was a part of castlist
assert!(self.is_casted_actor(&caller));
assert!(caller != self.self_role_id);

let archived_args =
unsafe { rkyv::access_unchecked::<A>(zcd_cpcmsg.argument.0.as_slice()) };
Expand Down
Loading
Loading