From 9a7ce8ce1b9e9bd9eeed04335beead76c8bcc14f Mon Sep 17 00:00:00 2001 From: grumbach Date: Fri, 18 Oct 2024 16:00:13 +0900 Subject: [PATCH 1/4] feat: user data stored in vault --- autonomi/Cargo.toml | 4 +- autonomi/src/client/archive.rs | 23 ++--- autonomi/src/client/data.rs | 4 +- autonomi/src/client/mod.rs | 2 + autonomi/src/client/vault.rs | 38 ++++++-- autonomi/src/client/vault_user_data.rs | 118 +++++++++++++++++++++++++ autonomi/src/client/wasm.rs | 24 ++--- autonomi/tests/fs.rs | 21 +++-- sn_networking/src/record_store.rs | 5 +- sn_protocol/src/error.rs | 3 + sn_protocol/src/lib.rs | 5 +- sn_protocol/src/storage/scratchpad.rs | 26 ++++-- 12 files changed, 215 insertions(+), 58 deletions(-) create mode 100644 autonomi/src/client/vault_user_data.rs diff --git a/autonomi/Cargo.toml b/autonomi/Cargo.toml index c7ecf07338..12dbf13cf9 100644 --- a/autonomi/Cargo.toml +++ b/autonomi/Cargo.toml @@ -13,10 +13,10 @@ repository = "https://github.com/maidsafe/safe_network" crate-type = ["cdylib", "rlib"] [features] -default = ["data"] +default = ["data", "vault"] full = ["data", "registers", "vault"] data = [] -vault = ["data"] +vault = ["data", "registers"] fs = ["tokio/fs", "data"] local = ["sn_networking/local", "test_utils/local", "sn_evm/local"] registers = ["data"] diff --git a/autonomi/src/client/archive.rs b/autonomi/src/client/archive.rs index 2e4b1b7e4a..17055e0682 100644 --- a/autonomi/src/client/archive.rs +++ b/autonomi/src/client/archive.rs @@ -14,13 +14,12 @@ use std::{ use sn_networking::target_arch::{Duration, SystemTime, UNIX_EPOCH}; use super::{ - data::DataAddr, - data::{GetError, PutError}, + data::{CostError, DataAddr, GetError, PutError}, Client, }; use bytes::Bytes; use serde::{Deserialize, Serialize}; -use sn_evm::EvmWallet; +use sn_evm::{AttoTokens, EvmWallet}; use xor_name::XorName; /// The address of an archive on the network. Points to an [`Archive`]. @@ -36,13 +35,13 @@ pub enum RenameError { /// An archive of files that containing file paths, their metadata and the files data addresses /// Using archives is useful for uploading entire directories to the network, only needing to keep track of a single address. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] pub struct Archive { map: HashMap, } /// Metadata for a file in an archive -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct Metadata { pub created: u64, pub modified: u64, @@ -147,12 +146,6 @@ impl Archive { } } -impl Default for Archive { - fn default() -> Self { - Self::new() - } -} - impl Client { /// Fetch an archive from the network pub async fn archive_get(&self, addr: ArchiveAddr) -> Result { @@ -171,4 +164,12 @@ impl Client { .map_err(|e| PutError::Serialization(format!("Failed to serialize archive: {e:?}")))?; self.data_put(bytes, wallet).await } + + /// Get the cost to upload an archive + pub async fn archive_cost(&self, archive: Archive) -> Result { + let bytes = archive + .into_bytes() + .map_err(|e| CostError::Serialization(format!("Failed to serialize archive: {e:?}")))?; + self.data_cost(bytes).await + } } diff --git a/autonomi/src/client/data.rs b/autonomi/src/client/data.rs index 366ad643be..d417978b81 100644 --- a/autonomi/src/client/data.rs +++ b/autonomi/src/client/data.rs @@ -39,7 +39,7 @@ pub enum PutError { Network(#[from] NetworkError), #[error("Error occurred during payment.")] PayError(#[from] PayError), - #[error("Failed to serialize {0}")] + #[error("Serialization error: {0}")] Serialization(String), #[error("A wallet error occurred.")] Wallet(#[from] sn_evm::EvmError), @@ -82,6 +82,8 @@ pub enum CostError { CouldNotGetStoreQuote(XorName), #[error("Could not get store costs: {0:?}")] CouldNotGetStoreCosts(NetworkError), + #[error("Failed to serialize {0}")] + Serialization(String), } impl Client { diff --git a/autonomi/src/client/mod.rs b/autonomi/src/client/mod.rs index df5dab4ec0..2205d51cd5 100644 --- a/autonomi/src/client/mod.rs +++ b/autonomi/src/client/mod.rs @@ -18,6 +18,8 @@ pub mod fs; pub mod registers; #[cfg(feature = "vault")] pub mod vault; +#[cfg(feature = "vault")] +pub mod vault_user_data; #[cfg(target_arch = "wasm32")] pub mod wasm; diff --git a/autonomi/src/client/vault.rs b/autonomi/src/client/vault.rs index 02eda1f4a6..bbcfd18bbd 100644 --- a/autonomi/src/client/vault.rs +++ b/autonomi/src/client/vault.rs @@ -7,17 +7,18 @@ // permissions and limitations relating to use of the SAFE Network Software. use std::collections::HashSet; +use std::hash::{DefaultHasher, Hash, Hasher}; use crate::client::data::PutError; use crate::client::Client; use bls::SecretKey; -use bytes::Bytes; use libp2p::kad::{Quorum, Record}; use sn_evm::EvmWallet; use sn_networking::{GetRecordCfg, NetworkError, PutRecordCfg, VerificationKind}; use sn_protocol::storage::{ try_serialize_record, RecordKind, RetryStrategy, Scratchpad, ScratchpadAddress, }; +use sn_protocol::Bytes; use sn_protocol::{storage::try_deserialize_record, NetworkAddress}; use tracing::info; @@ -33,16 +34,32 @@ pub enum VaultError { Network(#[from] NetworkError), } +/// The version of the vault content +/// The version is used to determine the type of the contents of the bytes contained in a vault +/// Custom apps can use this to store their own custom types of data in vaults +/// The value 0 is reserved for tests +pub type VaultContentVersion = u64; + +/// For custom apps using Scratchpad, this function converts an app identifier or name to a VaultContentVersion +pub fn app_name_to_version(s: T) -> VaultContentVersion { + let mut hasher = DefaultHasher::new(); + s.hash(&mut hasher); + hasher.finish() +} + impl Client { /// Retrieves and returns a decrypted vault if one exists. + /// Returns the version of the vault content + /// The version is used to determine the type of the contents of the bytes pub async fn fetch_and_decrypt_vault( &self, secret_key: &SecretKey, - ) -> Result, VaultError> { + ) -> Result<(Bytes, VaultContentVersion), VaultError> { info!("Fetching and decrypting vault"); let pad = self.get_vault_from_network(secret_key).await?; - Ok(pad.decrypt_data(secret_key)?) + let data = pad.decrypt_data(secret_key)?; + Ok((data, pad.version())) } /// Gets the vault Scratchpad from a provided client public key @@ -81,14 +98,17 @@ impl Client { /// Put data into the client's VaultPacket /// - /// Pays for a new VaultPacket if none yet created for the client. Returns the current version - /// of the data on success. + /// Pays for a new VaultPacket if none yet created for the client. + /// Provide the bytes to be written to the vault and the version of the vault content. + /// The Version of the vault content is used to determine the type of the contents of the bytes. + /// It is recommended to use the hash of the app name or unique identifier as the version. pub async fn write_bytes_to_vault( &self, data: Bytes, wallet: &EvmWallet, secret_key: &SecretKey, - ) -> Result { + version: VaultContentVersion, + ) -> Result<(), PutError> { let client_pk = secret_key.public_key(); let pad_res = self.get_vault_from_network(secret_key).await; @@ -106,10 +126,10 @@ impl Client { existing_data } else { trace!("new scratchpad creation"); - Scratchpad::new(client_pk) + Scratchpad::new(client_pk, version) }; - let next_count = scratch.update_and_sign(data, secret_key); + let _next_count = scratch.update_and_sign(data, secret_key); let scratch_address = scratch.network_address(); let scratch_key = scratch_address.to_record_key(); @@ -181,6 +201,6 @@ impl Client { ) })?; - Ok(next_count) + Ok(()) } } diff --git a/autonomi/src/client/vault_user_data.rs b/autonomi/src/client/vault_user_data.rs new file mode 100644 index 0000000000..2dbe941430 --- /dev/null +++ b/autonomi/src/client/vault_user_data.rs @@ -0,0 +1,118 @@ +// Copyright 2024 MaidSafe.net limited. +// +// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3. +// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed +// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. Please review the Licences for the specific language governing +// permissions and limitations relating to use of the SAFE Network Software. + +use std::collections::HashMap; +use std::collections::HashSet; + +use super::archive::ArchiveAddr; +use super::data::GetError; +use super::data::PutError; +use super::registers::RegisterAddress; +use super::vault::VaultError; +use super::Client; +use crate::client::vault::{app_name_to_version, VaultContentVersion}; +use bls::SecretKey; +use serde::{Deserialize, Serialize}; +use sn_evm::EvmWallet; +use sn_protocol::Bytes; + +use std::sync::LazyLock; + +/// Vault content version for UserDataVault +pub static USER_DATA_VAULT_CONTENT_VERSION: LazyLock = + LazyLock::new(|| app_name_to_version("UserData")); + +/// UserData is stored in Vaults and contains most of a user's private data: +/// It allows users to keep track of only the key to their User Data Vault +/// while having the rest kept on the Network encrypted in a Vault for them +/// Using User Data Vault is optional, one can decide to keep all their data locally instead. +#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)] +pub struct UserData { + /// The register secret key hex encoded + pub register_sk: Option, + /// Owned register addresses + pub registers: HashSet, + /// Owned file archive addresses + pub file_archives: HashSet, + + /// Owner register names, providing it is optional + pub register_names: HashMap, + /// Owned file archive addresses along with a name for that archive providing it is optional + pub file_archive_names: HashMap, +} + +/// Errors that can occur during the get operation. +#[derive(Debug, thiserror::Error)] +pub enum UserDataVaultGetError { + #[error("Vault error: {0}")] + Vault(#[from] VaultError), + #[error("Unsupported vault content version: {0}")] + UnsupportedVaultContentVersion(VaultContentVersion), + #[error("Serialization error: {0}")] + Serialization(String), + #[error("Get error: {0}")] + GetError(#[from] GetError), +} + +impl UserData { + /// Create a new empty UserData + pub fn new() -> Self { + Self::default() + } + + /// To bytes + pub fn to_bytes(&self) -> Result { + let bytes = rmp_serde::to_vec(&self)?; + Ok(Bytes::from(bytes)) + } + + /// From bytes + pub fn from_bytes(bytes: Bytes) -> Result { + let vault_content = rmp_serde::from_slice(&bytes)?; + Ok(vault_content) + } +} + +impl Client { + /// Get the user data from the vault + pub async fn get_user_data_from_vault( + &self, + secret_key: &SecretKey, + ) -> Result { + let (bytes, version) = self.fetch_and_decrypt_vault(secret_key).await?; + + if version != *USER_DATA_VAULT_CONTENT_VERSION { + return Err(UserDataVaultGetError::UnsupportedVaultContentVersion( + version, + )); + } + + let vault = UserData::from_bytes(bytes).map_err(|e| { + UserDataVaultGetError::Serialization(format!( + "Failed to deserialize vault content: {e}" + )) + })?; + + Ok(vault) + } + + /// Put the user data to the vault + pub async fn put_user_data_to_vault( + &self, + secret_key: &SecretKey, + wallet: &EvmWallet, + user_data: UserData, + ) -> Result<(), PutError> { + let bytes = user_data + .to_bytes() + .map_err(|e| PutError::Serialization(format!("Failed to serialize user data: {e}")))?; + self.write_bytes_to_vault(bytes, wallet, secret_key, *USER_DATA_VAULT_CONTENT_VERSION) + .await?; + Ok(()) + } +} diff --git a/autonomi/src/client/wasm.rs b/autonomi/src/client/wasm.rs index 34400356f2..3bc2504636 100644 --- a/autonomi/src/client/wasm.rs +++ b/autonomi/src/client/wasm.rs @@ -2,6 +2,10 @@ use libp2p::Multiaddr; use wasm_bindgen::prelude::*; use super::address::{addr_to_str, str_to_addr}; +use super::vault_user_data::UserData; + +#[wasm_bindgen(js_name = UserData)] +pub struct JsUserData(UserData); #[wasm_bindgen(js_name = Client)] pub struct JsClient(super::Client); @@ -115,33 +119,31 @@ mod vault { #[wasm_bindgen(js_class = Client)] impl JsClient { - #[wasm_bindgen(js_name = fetchAndDecryptVault)] - pub async fn fetch_and_decrypt_vault( + #[wasm_bindgen(js_name = getUserDataFromVault)] + pub async fn get_user_data_from_vault( &self, secret_key: Vec, - ) -> Result>, JsError> { + ) -> Result { let secret_key: [u8; 32] = secret_key[..].try_into()?; let secret_key = SecretKey::from_bytes(secret_key)?; - let vault = self.0.fetch_and_decrypt_vault(&secret_key).await?; - let vault = vault.map(|v| v.to_vec()); + let user_data = self.0.get_user_data_from_vault(&secret_key).await?; - Ok(vault) + Ok(JsUserData(user_data)) } - #[wasm_bindgen(js_name = writeBytesToVault)] - pub async fn write_bytes_to_vault( + #[wasm_bindgen(js_name = putUserDataToVault)] + pub async fn put_user_data_to_vault( &self, - vault: Vec, + user_data: JsUserData, wallet: &mut JsWallet, secret_key: Vec, ) -> Result<(), JsError> { let secret_key: [u8; 32] = secret_key[..].try_into()?; let secret_key = SecretKey::from_bytes(secret_key)?; - let vault = bytes::Bytes::from(vault); self.0 - .write_bytes_to_vault(vault, &mut wallet.0, &secret_key) + .put_user_data_to_vault(&secret_key, &wallet.0, user_data.0) .await?; Ok(()) diff --git a/autonomi/tests/fs.rs b/autonomi/tests/fs.rs index 9c53fd26b8..f59b7bf680 100644 --- a/autonomi/tests/fs.rs +++ b/autonomi/tests/fs.rs @@ -91,24 +91,23 @@ async fn file_into_vault() -> Result<()> { sleep(Duration::from_secs(2)).await; let archive = client.archive_get(addr).await?; + let set_version = 0; client - .write_bytes_to_vault(archive.into_bytes()?, &wallet, &client_sk) + .write_bytes_to_vault(archive.into_bytes()?, &wallet, &client_sk, set_version) .await?; // now assert over the stored account packet let new_client = Client::connect(&[]).await?; - if let Some(ap) = new_client.fetch_and_decrypt_vault(&client_sk).await? { - let ap_archive_fetched = autonomi::client::archive::Archive::from_bytes(ap)?; + let (ap, got_version) = new_client.fetch_and_decrypt_vault(&client_sk).await?; + assert_eq!(set_version, got_version); + let ap_archive_fetched = autonomi::client::archive::Archive::from_bytes(ap)?; - assert_eq!( - archive.iter().count(), - ap_archive_fetched.iter().count(), - "archive fetched should match archive put" - ); - } else { - eyre::bail!("No account packet found"); - } + assert_eq!( + archive.iter().count(), + ap_archive_fetched.iter().count(), + "archive fetched should match archive put" + ); Ok(()) } diff --git a/sn_networking/src/record_store.rs b/sn_networking/src/record_store.rs index 35b1cdec59..4ac9170e85 100644 --- a/sn_networking/src/record_store.rs +++ b/sn_networking/src/record_store.rs @@ -1238,7 +1238,7 @@ mod tests { let owner_sk = SecretKey::random(); let owner_pk = owner_sk.public_key(); - let mut scratchpad = Scratchpad::new(owner_pk); + let mut scratchpad = Scratchpad::new(owner_pk, 0); let _next_version = scratchpad.update_and_sign(unencrypted_scratchpad_data.clone(), &owner_sk); @@ -1283,8 +1283,7 @@ mod tests { let decrypted_data = scratchpad.decrypt_data(&owner_sk)?; assert_eq!( - decrypted_data, - Some(unencrypted_scratchpad_data), + decrypted_data, unencrypted_scratchpad_data, "Stored scratchpad data should match original" ); } diff --git a/sn_protocol/src/error.rs b/sn_protocol/src/error.rs index 8462ff85f3..2d24feb0d9 100644 --- a/sn_protocol/src/error.rs +++ b/sn_protocol/src/error.rs @@ -51,6 +51,9 @@ pub enum Error { /// The provided SecretyKey failed to decrypt the data #[error("Failed to derive CipherText from encrypted_data")] ScratchpadCipherTextFailed, + /// The provided cypher text is invalid + #[error("Provided cypher text is invalid")] + ScratchpadCipherTextInvalid, // ---------- payment errors #[error("There was an error getting the storecost from kademlia store")] diff --git a/sn_protocol/src/lib.rs b/sn_protocol/src/lib.rs index 4d3b92628d..f397173ca1 100644 --- a/sn_protocol/src/lib.rs +++ b/sn_protocol/src/lib.rs @@ -32,7 +32,10 @@ pub use error::Error; use storage::ScratchpadAddress; use self::storage::{ChunkAddress, RegisterAddress, SpendAddress}; -use bytes::Bytes; + +/// Re-export of Bytes used throughout the protocol +pub use bytes::Bytes; + use libp2p::{ kad::{KBucketDistance as Distance, KBucketKey as Key, RecordKey}, multiaddr::Protocol, diff --git a/sn_protocol/src/storage/scratchpad.rs b/sn_protocol/src/storage/scratchpad.rs index ea38d2e686..73c4aad3c1 100644 --- a/sn_protocol/src/storage/scratchpad.rs +++ b/sn_protocol/src/storage/scratchpad.rs @@ -8,9 +8,9 @@ use super::ScratchpadAddress; use crate::error::{Error, Result}; +use crate::Bytes; use crate::NetworkAddress; use bls::{Ciphertext, PublicKey, SecretKey, Signature}; -use bytes::Bytes; use serde::{Deserialize, Serialize}; use xor_name::XorName; @@ -23,6 +23,8 @@ pub struct Scratchpad { /// Network address. Omitted when serialising and /// calculated from the `encrypted_data` when deserialising. address: ScratchpadAddress, + /// Data version + version: u64, /// Contained data. This should be encrypted #[debug(skip)] encrypted_data: Bytes, @@ -35,10 +37,11 @@ pub struct Scratchpad { impl Scratchpad { /// Creates a new instance of `Scratchpad`. - pub fn new(owner: PublicKey) -> Self { + pub fn new(owner: PublicKey, version: u64) -> Self { Self { address: ScratchpadAddress::new(owner), encrypted_data: Bytes::new(), + version, counter: 0, signature: None, } @@ -49,6 +52,11 @@ impl Scratchpad { self.counter } + /// Return the current version + pub fn version(&self) -> u64 { + self.version + } + /// Increments the counter value. pub fn increment(&mut self) -> u64 { self.counter += 1; @@ -94,13 +102,13 @@ impl Scratchpad { } /// Returns the encrypted_data, decrypted via the passed SecretKey - pub fn decrypt_data(&self, sk: &SecretKey) -> Result> { - Ok(sk - .decrypt( - &Ciphertext::from_bytes(&self.encrypted_data) - .map_err(|_| Error::ScratchpadCipherTextFailed)?, - ) - .map(Bytes::from)) + pub fn decrypt_data(&self, sk: &SecretKey) -> Result { + let cipher = Ciphertext::from_bytes(&self.encrypted_data) + .map_err(|_| Error::ScratchpadCipherTextFailed)?; + let bytes = sk + .decrypt(&cipher) + .ok_or(Error::ScratchpadCipherTextInvalid)?; + Ok(Bytes::from(bytes)) } /// Returns the encrypted_data hash From 3c1dd9e16d4db4d689058fce9e1e1296bd6bfa92 Mon Sep 17 00:00:00 2001 From: grumbach Date: Fri, 18 Oct 2024 16:03:08 +0900 Subject: [PATCH 2/4] chore: fix test --- autonomi/tests/fs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/autonomi/tests/fs.rs b/autonomi/tests/fs.rs index f59b7bf680..b952852bc2 100644 --- a/autonomi/tests/fs.rs +++ b/autonomi/tests/fs.rs @@ -104,8 +104,7 @@ async fn file_into_vault() -> Result<()> { let ap_archive_fetched = autonomi::client::archive::Archive::from_bytes(ap)?; assert_eq!( - archive.iter().count(), - ap_archive_fetched.iter().count(), + archive, ap_archive_fetched, "archive fetched should match archive put" ); From 8bd5007c40f885e26fe22b535281532180632b83 Mon Sep 17 00:00:00 2001 From: grumbach Date: Fri, 18 Oct 2024 16:22:53 +0900 Subject: [PATCH 3/4] chore: improve naming to data encoding --- autonomi/src/client/vault.rs | 17 ++++++++-------- autonomi/src/client/vault_user_data.rs | 27 ++++++++++++++------------ sn_protocol/src/storage/scratchpad.rs | 14 ++++++------- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/autonomi/src/client/vault.rs b/autonomi/src/client/vault.rs index bbcfd18bbd..9417a8acf9 100644 --- a/autonomi/src/client/vault.rs +++ b/autonomi/src/client/vault.rs @@ -34,14 +34,15 @@ pub enum VaultError { Network(#[from] NetworkError), } -/// The version of the vault content -/// The version is used to determine the type of the contents of the bytes contained in a vault +/// The content type of the vault data +/// The number is used to determine the type of the contents of the bytes contained in a vault /// Custom apps can use this to store their own custom types of data in vaults +/// It is recommended to use the hash of the app name or unique identifier as the version /// The value 0 is reserved for tests -pub type VaultContentVersion = u64; +pub type VaultContentType = u64; -/// For custom apps using Scratchpad, this function converts an app identifier or name to a VaultContentVersion -pub fn app_name_to_version(s: T) -> VaultContentVersion { +/// For custom apps using Scratchpad, this function converts an app identifier or name to a VaultContentType +pub fn app_name_to_vault_content_type(s: T) -> VaultContentType { let mut hasher = DefaultHasher::new(); s.hash(&mut hasher); hasher.finish() @@ -54,12 +55,12 @@ impl Client { pub async fn fetch_and_decrypt_vault( &self, secret_key: &SecretKey, - ) -> Result<(Bytes, VaultContentVersion), VaultError> { + ) -> Result<(Bytes, VaultContentType), VaultError> { info!("Fetching and decrypting vault"); let pad = self.get_vault_from_network(secret_key).await?; let data = pad.decrypt_data(secret_key)?; - Ok((data, pad.version())) + Ok((data, pad.data_encoding())) } /// Gets the vault Scratchpad from a provided client public key @@ -107,7 +108,7 @@ impl Client { data: Bytes, wallet: &EvmWallet, secret_key: &SecretKey, - version: VaultContentVersion, + version: VaultContentType, ) -> Result<(), PutError> { let client_pk = secret_key.public_key(); diff --git a/autonomi/src/client/vault_user_data.rs b/autonomi/src/client/vault_user_data.rs index 2dbe941430..b0d88854cc 100644 --- a/autonomi/src/client/vault_user_data.rs +++ b/autonomi/src/client/vault_user_data.rs @@ -15,7 +15,7 @@ use super::data::PutError; use super::registers::RegisterAddress; use super::vault::VaultError; use super::Client; -use crate::client::vault::{app_name_to_version, VaultContentVersion}; +use crate::client::vault::{app_name_to_vault_content_type, VaultContentType}; use bls::SecretKey; use serde::{Deserialize, Serialize}; use sn_evm::EvmWallet; @@ -23,9 +23,9 @@ use sn_protocol::Bytes; use std::sync::LazyLock; -/// Vault content version for UserDataVault -pub static USER_DATA_VAULT_CONTENT_VERSION: LazyLock = - LazyLock::new(|| app_name_to_version("UserData")); +/// Vault content type for UserDataVault +pub static USER_DATA_VAULT_CONTENT_IDENTIFIER: LazyLock = + LazyLock::new(|| app_name_to_vault_content_type("UserData")); /// UserData is stored in Vaults and contains most of a user's private data: /// It allows users to keep track of only the key to their User Data Vault @@ -51,8 +51,8 @@ pub struct UserData { pub enum UserDataVaultGetError { #[error("Vault error: {0}")] Vault(#[from] VaultError), - #[error("Unsupported vault content version: {0}")] - UnsupportedVaultContentVersion(VaultContentVersion), + #[error("Unsupported vault content type: {0}")] + UnsupportedVaultContentType(VaultContentType), #[error("Serialization error: {0}")] Serialization(String), #[error("Get error: {0}")] @@ -86,10 +86,8 @@ impl Client { ) -> Result { let (bytes, version) = self.fetch_and_decrypt_vault(secret_key).await?; - if version != *USER_DATA_VAULT_CONTENT_VERSION { - return Err(UserDataVaultGetError::UnsupportedVaultContentVersion( - version, - )); + if version != *USER_DATA_VAULT_CONTENT_IDENTIFIER { + return Err(UserDataVaultGetError::UnsupportedVaultContentType(version)); } let vault = UserData::from_bytes(bytes).map_err(|e| { @@ -111,8 +109,13 @@ impl Client { let bytes = user_data .to_bytes() .map_err(|e| PutError::Serialization(format!("Failed to serialize user data: {e}")))?; - self.write_bytes_to_vault(bytes, wallet, secret_key, *USER_DATA_VAULT_CONTENT_VERSION) - .await?; + self.write_bytes_to_vault( + bytes, + wallet, + secret_key, + *USER_DATA_VAULT_CONTENT_IDENTIFIER, + ) + .await?; Ok(()) } } diff --git a/sn_protocol/src/storage/scratchpad.rs b/sn_protocol/src/storage/scratchpad.rs index 73c4aad3c1..5c99cbdcac 100644 --- a/sn_protocol/src/storage/scratchpad.rs +++ b/sn_protocol/src/storage/scratchpad.rs @@ -23,8 +23,8 @@ pub struct Scratchpad { /// Network address. Omitted when serialising and /// calculated from the `encrypted_data` when deserialising. address: ScratchpadAddress, - /// Data version - version: u64, + /// Data encoding: custom apps using scratchpad should use this so they can identify the type of data they are storing + data_encoding: u64, /// Contained data. This should be encrypted #[debug(skip)] encrypted_data: Bytes, @@ -37,11 +37,11 @@ pub struct Scratchpad { impl Scratchpad { /// Creates a new instance of `Scratchpad`. - pub fn new(owner: PublicKey, version: u64) -> Self { + pub fn new(owner: PublicKey, data_encoding: u64) -> Self { Self { address: ScratchpadAddress::new(owner), encrypted_data: Bytes::new(), - version, + data_encoding, counter: 0, signature: None, } @@ -52,9 +52,9 @@ impl Scratchpad { self.counter } - /// Return the current version - pub fn version(&self) -> u64 { - self.version + /// Return the current data encoding + pub fn data_encoding(&self) -> u64 { + self.data_encoding } /// Increments the counter value. From 88694f74ea397573ac43b33c8c5fc66864285b97 Mon Sep 17 00:00:00 2001 From: grumbach Date: Fri, 18 Oct 2024 16:28:40 +0900 Subject: [PATCH 4/4] chore: cleanup namings accordingly --- autonomi/src/client/vault.rs | 16 +++++++--------- autonomi/src/client/vault_user_data.rs | 8 +++++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/autonomi/src/client/vault.rs b/autonomi/src/client/vault.rs index 9417a8acf9..4004a3d530 100644 --- a/autonomi/src/client/vault.rs +++ b/autonomi/src/client/vault.rs @@ -37,11 +37,11 @@ pub enum VaultError { /// The content type of the vault data /// The number is used to determine the type of the contents of the bytes contained in a vault /// Custom apps can use this to store their own custom types of data in vaults -/// It is recommended to use the hash of the app name or unique identifier as the version +/// It is recommended to use the hash of the app name or an unique identifier as the content type using [`app_name_to_vault_content_type`] /// The value 0 is reserved for tests pub type VaultContentType = u64; -/// For custom apps using Scratchpad, this function converts an app identifier or name to a VaultContentType +/// For custom apps using Scratchpad, this function converts an app identifier or name to a [`VaultContentType`] pub fn app_name_to_vault_content_type(s: T) -> VaultContentType { let mut hasher = DefaultHasher::new(); s.hash(&mut hasher); @@ -50,8 +50,7 @@ pub fn app_name_to_vault_content_type(s: T) -> VaultContentType { impl Client { /// Retrieves and returns a decrypted vault if one exists. - /// Returns the version of the vault content - /// The version is used to determine the type of the contents of the bytes + /// Returns the content type of the bytes in the vault pub async fn fetch_and_decrypt_vault( &self, secret_key: &SecretKey, @@ -100,15 +99,14 @@ impl Client { /// Put data into the client's VaultPacket /// /// Pays for a new VaultPacket if none yet created for the client. - /// Provide the bytes to be written to the vault and the version of the vault content. - /// The Version of the vault content is used to determine the type of the contents of the bytes. - /// It is recommended to use the hash of the app name or unique identifier as the version. + /// Provide the bytes to be written to the vault and the content type of those bytes. + /// It is recommended to use the hash of the app name or unique identifier as the content type. pub async fn write_bytes_to_vault( &self, data: Bytes, wallet: &EvmWallet, secret_key: &SecretKey, - version: VaultContentType, + content_type: VaultContentType, ) -> Result<(), PutError> { let client_pk = secret_key.public_key(); @@ -127,7 +125,7 @@ impl Client { existing_data } else { trace!("new scratchpad creation"); - Scratchpad::new(client_pk, version) + Scratchpad::new(client_pk, content_type) }; let _next_count = scratch.update_and_sign(data, secret_key); diff --git a/autonomi/src/client/vault_user_data.rs b/autonomi/src/client/vault_user_data.rs index b0d88854cc..779cf023d9 100644 --- a/autonomi/src/client/vault_user_data.rs +++ b/autonomi/src/client/vault_user_data.rs @@ -84,10 +84,12 @@ impl Client { &self, secret_key: &SecretKey, ) -> Result { - let (bytes, version) = self.fetch_and_decrypt_vault(secret_key).await?; + let (bytes, content_type) = self.fetch_and_decrypt_vault(secret_key).await?; - if version != *USER_DATA_VAULT_CONTENT_IDENTIFIER { - return Err(UserDataVaultGetError::UnsupportedVaultContentType(version)); + if content_type != *USER_DATA_VAULT_CONTENT_IDENTIFIER { + return Err(UserDataVaultGetError::UnsupportedVaultContentType( + content_type, + )); } let vault = UserData::from_bytes(bytes).map_err(|e| {