Skip to content

Conversation

@greenhat
Copy link
Contributor

@greenhat greenhat commented Dec 5, 2025

Ref #698

This PR introduces crates for on-chain and off-chain serialization. The reason for two crates instead of one is different Felt types. For off-chain, it wraps u64 and for on-chain, it wraps float.

The on-chain deserialization trait is at

/// A reader that wraps a slice of `Felt` elements and tracks the current position.
pub struct FeltReader<'a> {
data: &'a [Felt],
pos: usize,
}
impl<'a> FeltReader<'a> {
/// Creates a new `FeltReader` from a slice of `Felt` elements.
#[inline(always)]
pub fn new(data: &'a [Felt]) -> Self {
Self { data, pos: 0 }
}
/// Reads the next `Felt` element, advancing the position.
#[inline(always)]
pub fn read(&mut self) -> Felt {
let felt = self.data[self.pos];
self.pos += 1;
felt
}
}
/// A writer that wraps a `Vec<Felt>` and appends elements to it.
pub struct FeltWriter<'a> {
data: &'a mut Vec<Felt>,
}
impl<'a> FeltWriter<'a> {
/// Creates a new `FeltWriter` from a mutable reference to a `Vec<Felt>`.
#[inline(always)]
pub fn new(data: &'a mut Vec<Felt>) -> Self {
Self { data }
}
/// Writes a `Felt` element to the output.
#[inline(always)]
pub fn write(&mut self, felt: Felt) {
self.data.push(felt);
}
}
/// Trait for deserialization from felt memory representation.
pub trait FromFeltRepr: Sized {
/// Deserializes from a `FeltReader`, consuming the required elements.
fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self;
}

The off-chain deserialization trait is at
/// A reader that wraps a slice of `Felt` elements and tracks the current position.
pub struct FeltReader<'a> {
data: &'a [Felt],
pos: usize,
}
impl<'a> FeltReader<'a> {
/// Creates a new `FeltReader` from a slice of `Felt` elements.
pub fn new(data: &'a [Felt]) -> Self {
Self { data, pos: 0 }
}
/// Reads the next `Felt` element, advancing the position.
pub fn read(&mut self) -> Felt {
let felt = self.data[self.pos];
self.pos += 1;
felt
}
}
/// A writer that wraps a `Vec<Felt>` and appends elements to it.
pub struct FeltWriter<'a> {
data: &'a mut Vec<Felt>,
}
impl<'a> FeltWriter<'a> {
/// Creates a new `FeltWriter` from a mutable reference to a `Vec<Felt>`.
pub fn new(data: &'a mut Vec<Felt>) -> Self {
Self { data }
}
/// Writes a `Felt` element to the output.
pub fn write(&mut self, felt: Felt) {
self.data.push(felt);
}
}
/// Trait for deserialization from felt memory representation.
pub trait FromFeltRepr: Sized {
/// Deserializes from a `FeltReader`, consuming the required elements.
fn from_felt_repr(reader: &mut FeltReader<'_>) -> Self;
}

Although they look identical the only reason for them to be in separate crates is different underlying Felt type in off-chain and on-chain code (see above). To have it defined only once the schema for user-defined types is discussed at #814.

The usage in the P2ID is at

#[note_script]
fn run(_arg: Word, account: &mut Account) {
let inputs = active_note::get_inputs();
let target_account_id: AccountId = inputs.as_slice().into();
let current_account = account.get_id();
assert_eq!(current_account, target_account_id);
with the AccountId implementation derived at
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromFeltRepr)]
pub struct AccountId {

The off-chain code is at

inputs: AccountIdFeltRepr(&alice_account.id()).to_felt_repr(),
with the implementation derived temporarily through proxy (AccountIdFeltRepr) later the miden-base::AccountId will have it derived as well.

This PR implements serialization and deserialization parts only to keep the PR size reasonable. The rest of #698 (DX, macros) will be addressed in the subsequent PR.

TODO:

  • super roundtrip test suite;
  • test various struct shapes;
  • file a u64-related memory corruption bug;
  • instead expect files make a test.dump_codes(artifact_name) that will write wat/ir/masm files somewhere (target folder?) ignored by git but not hidden from the editor;
  • remove basic-wallet from miden example? Otherwise, release the SDK before updating the basic-wallet example.

@greenhat
Copy link
Contributor Author

@bitwalker @bobbinth Following our discussion I put the current(temporary) approach with two type definitions in the PR description and made #814 for defining types only once.

add the test for u64-related bug reproduction.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants