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

feat: increase the id bytes size and use context_id as root #912

Merged
merged 3 commits into from
Oct 31, 2024
Merged
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
125 changes: 59 additions & 66 deletions crates/storage/src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ use borsh::{BorshDeserialize, BorshSerialize};
use calimero_sdk::serde::{Deserialize, Serialize};
use fixedstr::Flexstr;
use thiserror::Error as ThisError;
use uuid::{Bytes, Uuid};

use crate::env::random_bytes;
use crate::env::{context_id, random_bytes};

/// Globally-unique identifier for an [`Element`](crate::entities::Element).
///
Expand All @@ -35,101 +34,95 @@ use crate::env::random_bytes;
/// system operation. Abstracting the true type away provides a level of
/// insulation that is useful for any future changes.
///
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(
BorshSerialize,
BorshDeserialize,
Copy,
Clone,
Debug,
Deserialize,
Eq,
PartialEq,
Hash,
Ord,
PartialOrd,
Serialize,
)]
#[serde(crate = "calimero_sdk::serde")]
pub struct Id(Uuid);
pub struct Id {
/// The byte array representation of the ID.
bytes: [u8; 32],
}

impl Id {
/// Creates a new globally-unique identifier.
///
/// Returns the byte array representation of the ID.
///
/// # Examples
///
/// ```rust
/// use calimero_storage::address::Id;
/// let id = Id::new();
/// let id = Id::new([0; 32]);
/// assert_eq!(id.as_bytes(), &[0; 32]);
/// ```
///
#[must_use]
pub fn new() -> Self {
let mut bytes = [0; 16];
random_bytes(&mut bytes);
Self(uuid::Builder::from_random_bytes(bytes).into_uuid())
}

/// Returns a slice of 16 octets containing the value.
#[must_use]
pub const fn as_bytes(&self) -> &Bytes {
self.0.as_bytes()
pub fn new(bytes: [u8; 32]) -> Self {
// random_bytes(&mut bytes);
Self { bytes }
}

/// Root ID which is set to all zeroes by default.
#[must_use]
pub const fn root() -> Self {
Self(Uuid::nil())
}
}

impl BorshDeserialize for Id {
fn deserialize(buf: &mut &[u8]) -> Result<Self, IoError> {
if buf.len() < 16 {
return Err(IoError::new(
IoErrorKind::UnexpectedEof,
"Not enough bytes to deserialize Id",
));
}
let (bytes, rest) = buf.split_at(16);
*buf = rest;
Ok(Self(Uuid::from_slice(bytes).map_err(|err| {
IoError::new(IoErrorKind::InvalidData, err)
})?))
pub fn root() -> Self {
Id::new(context_id())
}

fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self, IoError> {
let mut bytes = [0_u8; 16];
reader.read_exact(&mut bytes)?;
Ok(Self(Uuid::from_bytes(bytes)))
}
}

impl BorshSerialize for Id {
fn serialize<W: Write>(&self, writer: &mut W) -> Result<(), IoError> {
writer.write_all(self.0.as_bytes())
/// Creates a new random globally-unique identifier.
///
/// # Examples
///
/// ```rust
/// use calimero_storage::address::Id;
/// let id = Id::random();
/// ```
#[must_use]
pub fn random() -> Id {
let mut bytes = [0_u8; 32];
random_bytes(&mut bytes);
Id::new(bytes)
}
}

impl Default for Id {
fn default() -> Self {
Self::new()
/// Returns the byte array representation of the ID.
///
/// # Examples
///
/// ```rust
/// use calimero_storage::address::Id;
/// let id = Id::new([0; 32]);
/// assert_eq!(id.as_bytes(), &[0; 32]);
/// ```
#[must_use]
pub fn as_bytes(&self) -> &[u8; 32] {
&self.bytes
}
}

impl Display for Id {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}

impl From<[u8; 16]> for Id {
fn from(bytes: [u8; 16]) -> Self {
Self(Uuid::from_bytes(bytes))
write!(f, "{:?}", self)
}
}

impl From<&[u8; 16]> for Id {
fn from(bytes: &[u8; 16]) -> Self {
Self(Uuid::from_bytes(*bytes))
}
}

impl From<Id> for [u8; 16] {
fn from(id: Id) -> Self {
*id.0.as_bytes()
impl From<[u8; 32]> for Id {
fn from(bytes: [u8; 32]) -> Self {
Self::new(bytes)
}
}

impl From<Id> for Uuid {
impl From<Id> for [u8; 32] {
fn from(id: Id) -> Self {
id.0
id.bytes
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/storage/src/entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ impl Element {
pub fn new(path: &Path) -> Self {
let timestamp = time_now();
Self {
id: Id::new(),
id: Id::random(),
is_dirty: true,
metadata: Metadata {
created_at: timestamp,
Expand Down
4 changes: 2 additions & 2 deletions crates/storage/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -944,8 +944,8 @@ impl<S: StorageAdaptor> MainInterface<S> {
/// If an error occurs when interacting with the storage system, an error
/// will be returned.
///
pub fn root<D: Data>(context_id: &[u8; 16]) -> Result<Option<D>, StorageError> {
Self::find_by_id(context_id.into())
pub fn root<D: Data>() -> Result<Option<D>, StorageError> {
Self::find_by_id(Id::root())
}

/// Saves an [`Element`](crate::entities::Element) to the storage system.
Expand Down
8 changes: 4 additions & 4 deletions crates/storage/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ pub enum Key {
impl Key {
/// Converts the key to a byte array.
#[must_use]
pub fn to_bytes(&self) -> [u8; 17] {
let mut bytes = [0; 17];
pub fn to_bytes(&self) -> [u8; 33] {
let mut bytes = [0; 33];
match *self {
Self::Index(id) => {
bytes[0] = 0;
bytes[1..17].copy_from_slice(id.as_bytes());
bytes[1..33].copy_from_slice(id.as_bytes());
}
Self::Entry(id) => {
bytes[0] = 1;
bytes[1..17].copy_from_slice(id.as_bytes());
bytes[1..33].copy_from_slice(id.as_bytes());
}
}
bytes
Expand Down
51 changes: 0 additions & 51 deletions crates/storage/src/tests/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,6 @@ use borsh::to_vec;
use claims::assert_err;

use super::*;
use crate::tests::common::TEST_UUID;

#[cfg(test)]
mod id__public_methods {
use super::*;

#[test]
fn as_bytes() {
assert_eq!(Id(Uuid::from_bytes(TEST_UUID[0])).as_bytes(), &TEST_UUID[0]);
}
}

#[cfg(test)]
mod id__traits {
use super::*;

#[test]
fn borsh_deserialization__valid() {
assert_eq!(
Id::try_from_slice(&TEST_UUID[0]).unwrap(),
Id(Uuid::from_bytes(TEST_UUID[0]))
);
}

#[test]
fn borsh_deserialization__too_short() {
assert_err!(Id::try_from_slice(&[1, 2, 3]));
}

#[test]
fn borsh_serialization__valid() {
let serialized = to_vec(&Id(Uuid::from_bytes(TEST_UUID[0]))).unwrap();
assert_eq!(serialized.len(), 16);
assert_eq!(serialized, TEST_UUID[0]);
}

#[test]
fn borsh_serialization__roundtrip() {
let id1 = Id::new();
let id2 = Id::try_from_slice(&to_vec(&id1).unwrap()).unwrap();
assert_eq!(id1, id2);
}

#[test]
fn from__for_uuid() {
assert_eq!(
Uuid::from(Id(Uuid::from_bytes(TEST_UUID[0]))).as_bytes(),
&TEST_UUID[0]
);
}
}

#[cfg(test)]
mod path__constructor {
Expand Down
22 changes: 0 additions & 22 deletions crates/storage/src/tests/common.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,12 @@
use std::collections::BTreeMap;
use std::sync::LazyLock;

use borsh::{to_vec, BorshDeserialize, BorshSerialize};
use sha2::{Digest, Sha256};
use velcro::btree_map;

use crate::address::Id;
use crate::entities::{AtomicUnit, ChildInfo, Collection, Data, Element};
use crate::interface::{Interface, StorageError};

/// A set of non-empty test UUIDs.
pub const TEST_UUID: [[u8; 16]; 5] = [
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
[2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
[3, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
[4, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
[5, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
];

/// A set of non-empty test IDs.
pub static TEST_ID: LazyLock<[Id; 5]> = LazyLock::new(|| {
[
Id::from(TEST_UUID[0]),
Id::from(TEST_UUID[1]),
Id::from(TEST_UUID[2]),
Id::from(TEST_UUID[3]),
Id::from(TEST_UUID[4]),
]
});

/// For tests against empty data structs.
#[derive(BorshDeserialize, BorshSerialize, Clone, Debug, Eq, PartialEq, PartialOrd)]
pub struct EmptyData {
Expand Down
8 changes: 4 additions & 4 deletions crates/storage/src/tests/entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ mod child_info__constructor {

#[test]
fn new() {
let id = Id::new();
let id = Id::random();
let hash = Sha256::digest(b"1").into();
let info = ChildInfo::new(id, hash);
assert_eq!(info.id, id);
Expand All @@ -191,13 +191,13 @@ mod child_info__public_methods {

#[test]
fn id() {
let info = ChildInfo::new(Id::new(), Sha256::digest(b"1").into());
let info = ChildInfo::new(Id::random(), Sha256::digest(b"1").into());
assert_eq!(info.id(), info.id);
}

#[test]
fn merkle_hash() {
let info = ChildInfo::new(Id::new(), Sha256::digest(b"1").into());
let info = ChildInfo::new(Id::random(), Sha256::digest(b"1").into());
assert_eq!(info.merkle_hash(), info.merkle_hash);
}
}
Expand All @@ -208,7 +208,7 @@ mod child_info__traits {

#[test]
fn display() {
let info = ChildInfo::new(Id::new(), Sha256::digest(b"1").into());
let info = ChildInfo::new(Id::random(), Sha256::digest(b"1").into());
assert_eq!(
format!("{info}"),
format!(
Expand Down
Loading
Loading