Skip to content

Commit

Permalink
feat: increase the id bytes size and use context_id as root (#912)
Browse files Browse the repository at this point in the history
Co-authored-by: Miraculous Owonubi <[email protected]>
  • Loading branch information
chefsale and miraclx authored Oct 31, 2024
1 parent 0cc8b3d commit 25697e0
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 190 deletions.
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

0 comments on commit 25697e0

Please sign in to comment.