From 3c9ecab11226b5179c7c41e1ebc6f52637b3dd24 Mon Sep 17 00:00:00 2001 From: Henrique Nogara Date: Wed, 20 Jul 2022 09:35:17 -0300 Subject: [PATCH 1/6] Add arbitrary bytes storage --- identity_account/Cargo.toml | 1 + identity_account/src/account/account.rs | 39 ++++++--- identity_account/src/error.rs | 6 ++ identity_account/src/tests/updates.rs | 16 ++-- identity_account/src/types/identity_state.rs | 79 +++++++++++++++++++ identity_account/src/types/mod.rs | 2 + identity_account_storage/Cargo.toml | 3 +- .../src/storage/memstore.rs | 44 +++-------- .../src/storage/stronghold.rs | 49 ++---------- .../src/storage/test_suite.rs | 64 ++++----------- .../src/storage/traits.rs | 16 +--- 11 files changed, 159 insertions(+), 160 deletions(-) create mode 100644 identity_account/src/types/identity_state.rs diff --git a/identity_account/Cargo.toml b/identity_account/Cargo.toml index 15cba9bb11..fc7f295c00 100644 --- a/identity_account/Cargo.toml +++ b/identity_account/Cargo.toml @@ -21,6 +21,7 @@ log = { version = "0.4", default-features = false } paste = { version = "1.0" } rand = { version = "0.8", default-features = false, features = ["std", "std_rng"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } +serde_json = { version = "1.0", default-features = false } strum = { version = "0.24.0", default-features = false, features = ["std", "derive"] } thiserror = { version = "1.0" } diff --git a/identity_account/src/account/account.rs b/identity_account/src/account/account.rs index 5f4a0f595b..d00884787a 100644 --- a/identity_account/src/account/account.rs +++ b/identity_account/src/account/account.rs @@ -32,6 +32,7 @@ use serde::Serialize; use crate::account::AccountBuilder; use crate::account::PublishOptions; use crate::types::IdentitySetup; +use crate::types::IdentityState; use crate::types::IdentityUpdater; use crate::updates::create_identity; use crate::updates::Update; @@ -126,12 +127,15 @@ where } // Ensure the identity exists in storage - let document: IotaDocument = setup.storage.document_get(&did).await?.ok_or(Error::IdentityNotFound)?; - let chain_state: ChainState = setup - .storage - .chain_state_get(&did) - .await? - .ok_or(Error::IdentityNotFound)?; + let identity_state_bytes: Vec = setup.storage.blob_get(&did).await?.ok_or(Error::IdentityNotFound)?; + let identity_state: IdentityState = serde_json::from_slice(&identity_state_bytes) + .map_err(|e| Error::SerializationError("unable to deserialize state".to_owned(), e))?; + let chain_state: ChainState = identity_state + .chain_state()? + .ok_or_else(|| Error::InvalidIdentityState("missing chain state".to_owned()))?; + let document: IotaDocument = identity_state + .document()? + .ok_or_else(|| Error::InvalidIdentityState("missing document".to_owned()))?; Self::with_setup(setup, chain_state, document).await } @@ -316,12 +320,18 @@ where // TODO: An account always holds a valid identity, // so if None is returned, that's a broken invariant. // This should be mapped to a fatal error in the future. - self + let identity_state_bytes: Vec = self .storage() .deref() - .document_get(self.did()) + .blob_get(self.did()) .await? - .ok_or(Error::IdentityNotFound) + .ok_or(Error::IdentityNotFound)?; + let identity_state: IdentityState = serde_json::from_slice(&identity_state_bytes) + .map_err(|e| Error::SerializationError("unable to deserialize state".to_owned(), e))?; + + identity_state + .document()? + .ok_or_else(|| Error::InvalidIdentityState("document not found".to_owned())) } pub(crate) async fn process_update(&mut self, update: Update) -> Result<()> { @@ -410,8 +420,15 @@ where } async fn store_state(&self) -> Result<()> { - self.storage.document_set(self.did(), &self.document).await?; - self.storage.chain_state_set(self.did(), self.chain_state()).await?; + let identity_state: IdentityState = IdentityState::new(Some(&self.document), Some(&self.chain_state))?; + self + .storage + .blob_set( + self.did(), + &serde_json::to_vec(&identity_state) + .map_err(|e| Error::SerializationError("unable to serialize state".to_owned(), e))?, + ) + .await?; self.save(false).await?; diff --git a/identity_account/src/error.rs b/identity_account/src/error.rs index 369f95411d..5bc41ec5e3 100644 --- a/identity_account/src/error.rs +++ b/identity_account/src/error.rs @@ -36,6 +36,12 @@ pub enum Error { /// Caused by verification methods without fragments. #[error("method missing fragment")] MethodMissingFragment, + /// Caused by reaching an invalid state for the identity. + #[error("invalid identity state: {0}")] + InvalidIdentityState(String), + /// Caused by an error when serialing or deserialing IdentityState. + #[error("serialization error: {0}")] + SerializationError(String, #[source] serde_json::Error), } impl From for Error { diff --git a/identity_account/src/tests/updates.rs b/identity_account/src/tests/updates.rs index 3ac3b0a893..673c009718 100644 --- a/identity_account/src/tests/updates.rs +++ b/identity_account/src/tests/updates.rs @@ -31,6 +31,7 @@ use crate::account::AccountSetup; use crate::error::Error; use crate::error::Result; use crate::types::IdentitySetup; +use crate::types::IdentityState; use crate::types::MethodContent; use crate::updates::Update; use crate::updates::UpdateError; @@ -131,12 +132,8 @@ async fn test_create_identity_already_exists() -> Result<()> { .await .unwrap(); - let initial_state = account_setup - .storage - .document_get(account.did()) - .await - .unwrap() - .unwrap(); + let initial_state: Vec = account_setup.storage.blob_get(account.did()).await?.unwrap(); + let initial_state: IdentityState = serde_json::from_slice(&initial_state).unwrap(); let output = Account::create_identity(account_setup.clone(), identity_create).await; @@ -146,10 +143,9 @@ async fn test_create_identity_already_exists() -> Result<()> { )); // Ensure nothing was overwritten in storage - assert_eq!( - initial_state, - account_setup.storage.document_get(account.did()).await?.unwrap() - ); + let account_state: Vec = account_setup.storage.blob_get(account.did()).await?.unwrap(); + let account_state: IdentityState = serde_json::from_slice(&account_state).unwrap(); + assert_eq!(initial_state.document()?, account_state.document()?); } Ok(()) } diff --git a/identity_account/src/types/identity_state.rs b/identity_account/src/types/identity_state.rs new file mode 100644 index 0000000000..20eed1c972 --- /dev/null +++ b/identity_account/src/types/identity_state.rs @@ -0,0 +1,79 @@ +// Copyright 2020-2022 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use identity_account_storage::identity::ChainState; +use identity_iota_core::document::IotaDocument; +use serde::Deserialize; +use serde::Serialize; + +use crate::error::Error; +use crate::error::Result; + +/// Holds the internal state for the identity. +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct IdentityState { + version: StateVersion, + document: Option>, + chain_state: Option>, +} + +impl IdentityState { + /// Creates a new [`IdentityState`]. + pub fn new(document: Option<&IotaDocument>, chain_state: Option<&ChainState>) -> Result { + let document: Option> = document + .map(|iota_doc| { + serde_json::to_vec(iota_doc) + .map_err(|e| Error::SerializationError("unable to serialize document".to_owned(), e)) + }) + .transpose()?; + let chain_state: Option> = chain_state + .map(|chain_state| { + serde_json::to_vec(chain_state) + .map_err(|e| Error::SerializationError("unable to serialize chain state".to_owned(), e)) + }) + .transpose()?; + Ok(IdentityState { + version: StateVersion::default(), + document, + chain_state, + }) + } + + /// Returns the deserialized [`IotaDocument`]. + pub fn document(&self) -> Result> { + match self.version { + StateVersion::V0 => Ok( + self + .document + .as_ref() + .map(|bytes| { + serde_json::from_slice(bytes) + .map_err(|e| Error::SerializationError("unable to deserialize document".to_owned(), e)) + }) + .transpose()?, + ), + } + } + + /// Returns the deserialized [`ChainState`]. + pub fn chain_state(&self) -> Result> { + match self.version { + StateVersion::V0 => Ok( + self + .chain_state + .as_ref() + .map(|bytes| { + serde_json::from_slice(bytes) + .map_err(|e| Error::SerializationError("unable to deserialize chain state".to_owned(), e)) + }) + .transpose()?, + ), + } + } +} + +#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +enum StateVersion { + #[default] + V0, +} diff --git a/identity_account/src/types/mod.rs b/identity_account/src/types/mod.rs index 79211b0f20..9c050bf776 100644 --- a/identity_account/src/types/mod.rs +++ b/identity_account/src/types/mod.rs @@ -2,9 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 pub use self::identity_setup::*; +pub use self::identity_state::*; pub use self::identity_updater::*; pub use self::method_content::*; mod identity_setup; +mod identity_state; mod identity_updater; mod method_content; diff --git a/identity_account_storage/Cargo.toml b/identity_account_storage/Cargo.toml index bb07c6d839..9a31951921 100644 --- a/identity_account_storage/Cargo.toml +++ b/identity_account_storage/Cargo.toml @@ -26,6 +26,7 @@ parking_lot = { version = "0.12" } rand = { version = "0.8", default-features = false, features = ["std", "std_rng"], optional = true } seahash = { version = "4.1.0", default-features = false } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } +serde_json = { version = "1.0", default-features = false, optional = true } strum = { version = "0.24.0", default-features = false, features = ["std", "derive"] } thiserror = { version = "1.0" } tokio = { version = "1.17.0", default-features = false, features = ["sync", "fs"], optional = true } @@ -47,6 +48,6 @@ stronghold = [ # Enables `Send` + `Sync` bounds for the Storage trait. send-sync-storage = [] # Exposes Storage `test_suite` module. -storage-test-suite = ["anyhow", "function_name", "rand"] +storage-test-suite = ["anyhow", "function_name", "rand", "serde_json"] # Enables encryption and decryption in the Storage trait. encryption = [] diff --git a/identity_account_storage/src/storage/memstore.rs b/identity_account_storage/src/storage/memstore.rs index 48303a220d..28842505c2 100644 --- a/identity_account_storage/src/storage/memstore.rs +++ b/identity_account_storage/src/storage/memstore.rs @@ -21,7 +21,6 @@ use identity_core::crypto::Sign; #[cfg(feature = "encryption")] use identity_core::crypto::X25519; use identity_iota_core::did::IotaDID; -use identity_iota_core::document::IotaDocument; use identity_iota_core::tangle::NetworkName; use std::sync::RwLockReadGuard; use std::sync::RwLockWriteGuard; @@ -29,7 +28,6 @@ use zeroize::Zeroize; use crate::error::Error; use crate::error::Result; -use crate::identity::ChainState; use crate::storage::Storage; #[cfg(feature = "encryption")] use crate::types::CekAlgorithm; @@ -41,10 +39,6 @@ use crate::types::KeyLocation; use crate::types::Signature; use crate::utils::Shared; -// The map from DIDs to chain states. -type ChainStates = HashMap; -// The map from DIDs to DID documents. -type Documents = HashMap; // The map from DIDs to vaults. type Vaults = HashMap; // The map from key locations to key pairs, that lives within a DID partition. @@ -54,9 +48,7 @@ type MemVault = HashMap; pub struct MemStore { // Controls whether to print the storages content when debugging. expand: bool, - // The `Shared` type is simply a light wrapper around `Rwlock`. - chain_states: Shared, - documents: Shared, + data: Shared>>, vaults: Shared, } @@ -65,8 +57,7 @@ impl MemStore { pub fn new() -> Self { Self { expand: false, - chain_states: Shared::new(HashMap::new()), - documents: Shared::new(HashMap::new()), + data: Shared::new(HashMap::new()), vaults: Shared::new(HashMap::new()), } } @@ -132,9 +123,7 @@ impl Storage for MemStore { // so we only need to do work if the DID still exists. // The return value signals whether the DID was actually removed during this operation. if self.vaults.write()?.remove(did).is_some() { - let _ = self.documents.write()?.remove(did); - let _ = self.chain_states.write()?.remove(did); - + let _ = self.data.write()?.remove(did); Ok(true) } else { Ok(false) @@ -381,28 +370,16 @@ impl Storage for MemStore { } } - async fn chain_state_get(&self, did: &IotaDID) -> Result> { - // Lookup the chain state of the given DID. - self.chain_states.read().map(|states| states.get(did).cloned()) - } - - async fn chain_state_set(&self, did: &IotaDID, chain_state: &ChainState) -> Result<()> { - // Set the chain state of the given DID. - self.chain_states.write()?.insert(did.clone(), chain_state.clone()); + async fn blob_set(&self, did: &IotaDID, value: &[u8]) -> Result<()> { + // Set the arbitrary value for the given DID. + self.data.write()?.insert(did.clone(), value.to_vec()); Ok(()) } - async fn document_get(&self, did: &IotaDID) -> Result> { - // Lookup the DID document of the given DID. - self.documents.read().map(|documents| documents.get(did).cloned()) - } - - async fn document_set(&self, did: &IotaDID, document: &IotaDocument) -> Result<()> { - // Set the DID document of the given DID. - self.documents.write()?.insert(did.clone(), document.clone()); - - Ok(()) + async fn blob_get(&self, did: &IotaDID) -> Result>> { + // Lookup the value stored of the given DID. + self.data.read().map(|data| data.get(did).cloned()) } async fn flush_changes(&self) -> Result<()> { @@ -532,8 +509,7 @@ impl Debug for MemStore { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { if self.expand { f.debug_struct("MemStore") - .field("chain_states", &self.chain_states) - .field("states", &self.documents) + .field("data", &self.data) .field("vaults", &self.vaults) .finish() } else { diff --git a/identity_account_storage/src/storage/stronghold.rs b/identity_account_storage/src/storage/stronghold.rs index 715c11d4f1..c45b8a9946 100644 --- a/identity_account_storage/src/storage/stronghold.rs +++ b/identity_account_storage/src/storage/stronghold.rs @@ -14,7 +14,6 @@ use identity_core::crypto::PrivateKey; use identity_core::crypto::PublicKey; use identity_core::crypto::X25519; use identity_iota_core::did::IotaDID; -use identity_iota_core::document::IotaDocument; use identity_iota_core::tangle::NetworkName; use iota_stronghold::procedures; use iota_stronghold::procedures::ProcedureError; @@ -32,7 +31,6 @@ use zeroize::Zeroize; use crate::error::Error; use crate::error::Result; -use crate::identity::ChainState; use crate::storage::Storage; use crate::stronghold::ClientOperation; use crate::stronghold::ClientPath; @@ -52,8 +50,7 @@ static INDEX_CLIENT_PATH: &str = "$index"; // The key in the index store that contains the serialized index. // This happens to be the same as the client path, but for explicitness we define them separately. static INDEX_STORE_KEY: &str = INDEX_CLIENT_PATH; -static CHAIN_STATE_STORE_KEY: &str = "$chain_state"; -static DOCUMENT_STORE_KEY: &str = "$document"; +static STORE_KEY: &str = "$store"; // The static identifier for vaults inside clients. static VAULT_PATH: &[u8; 6] = b"$vault"; @@ -377,58 +374,24 @@ impl Storage for Stronghold { } } - async fn chain_state_get(&self, did: &IotaDID) -> Result> { - let client: Client = self.client(&ClientPath::from(did))?; - let store: Store = client.store(); - - let data: Option> = store - .get(CHAIN_STATE_STORE_KEY.as_bytes()) - .map_err(|err| StrongholdError::Store(StoreOperation::Get, err))?; - - match data { - None => return Ok(None), - Some(data) => Ok(Some(ChainState::from_json_slice(&data)?)), - } - } - - async fn chain_state_set(&self, did: &IotaDID, chain_state: &ChainState) -> Result<()> { - let json: Vec = chain_state.to_json_vec()?; - + async fn blob_set(&self, did: &IotaDID, value: &[u8]) -> Result<()> { self.mutate_client(did, |client| { let store: Store = client.store(); store - .insert(CHAIN_STATE_STORE_KEY.as_bytes().to_vec(), json, None) + .insert(STORE_KEY.as_bytes().to_vec(), value.to_vec(), None) .map(|_| ()) .map_err(|err| StrongholdError::Store(StoreOperation::Insert, err).into()) }) } - async fn document_get(&self, did: &IotaDID) -> Result> { + async fn blob_get(&self, did: &IotaDID) -> Result>> { let client: Client = self.client(&ClientPath::from(did))?; let store: Store = client.store(); - let data: Option> = store - .get(DOCUMENT_STORE_KEY.as_bytes()) + .get(STORE_KEY.as_bytes()) .map_err(|err| StrongholdError::Store(StoreOperation::Get, err))?; - - match data { - None => return Ok(None), - Some(data) => Ok(Some(IotaDocument::from_json_slice(&data)?)), - } - } - - async fn document_set(&self, did: &IotaDID, document: &IotaDocument) -> Result<()> { - let json: Vec = document.to_json_vec()?; - - self.mutate_client(did, |client| { - let store: Store = client.store(); - - store - .insert(DOCUMENT_STORE_KEY.as_bytes().to_vec(), json, None) - .map(|_| ()) - .map_err(|err| StrongholdError::Store(StoreOperation::Insert, err).into()) - }) + Ok(data) } async fn flush_changes(&self) -> Result<()> { diff --git a/identity_account_storage/src/storage/test_suite.rs b/identity_account_storage/src/storage/test_suite.rs index 63046e310a..f5fbcb6547 100644 --- a/identity_account_storage/src/storage/test_suite.rs +++ b/identity_account_storage/src/storage/test_suite.rs @@ -382,25 +382,9 @@ impl StorageTestSuite { .await .context("did_create returned an error")?; - let chain_state: Option = storage - .chain_state_get(&did) - .await - .context("chain_state_get returned an error")?; - - ensure!( - chain_state.is_none(), - "expected chain_state_get to return `None` for a new DID" - ); - - let document: Option = storage - .document_get(&did) - .await - .context("document_get returned an error")?; + let value: Option> = storage.blob_get(&did).await.context("blob_get returned an error")?; - ensure!( - document.is_none(), - "expected document_get to return `None` for a new DID" - ); + ensure!(value.is_none(), "expected blob_get to return `None` for a new DID"); let public_key: PublicKey = storage .key_public(&did, &location) @@ -411,42 +395,30 @@ impl StorageTestSuite { IotaVerificationMethod::new(did.clone(), KeyType::Ed25519, &public_key, &fragment).unwrap(); let expected_document: IotaDocument = IotaDocument::from_verification_method(method).unwrap(); - storage - .document_set(&did, &expected_document) - .await - .context("document_set returned an error")?; - - let document: IotaDocument = storage - .document_get(&did) + .blob_set(&did, &serde_json::to_vec(&expected_document).unwrap()) .await - .context("document_get returned an error")? - .ok_or_else(|| anyhow::Error::msg("expected `Some(_)` to be returned, got `None`"))?; - + .context("blob_set returned an error")?; + let value: Option> = storage.blob_get(&did).await.context("blob_get returned an error")?; + let document: IotaDocument = serde_json::from_slice(&value.unwrap()).unwrap(); ensure_eq!( expected_document, document, - "expected document to be `{expected_document}`, got `{document}`" + "expected `{expected_document}`, got `{document}`" ); let mut expected_chain_state: ChainState = ChainState::new(); expected_chain_state.set_last_integration_message_id(MessageId::new([0xff; 32])); - storage - .chain_state_set(&did, &expected_chain_state) - .await - .context("chain_state_set returned an error")?; - - let chain_state: ChainState = storage - .chain_state_get(&did) + .blob_set(&did, &serde_json::to_vec(&expected_chain_state).unwrap()) .await - .context("chain_state_get returned an error")? - .ok_or_else(|| anyhow::Error::msg("expected `Some(_)` to be returned, got `None`"))?; - + .context("blob_set returned an error")?; + let value: Option> = storage.blob_get(&did).await.context("blob_get returned an error")?; + let chain_state: ChainState = serde_json::from_slice(&value.unwrap()).unwrap(); ensure_eq!( expected_chain_state, chain_state, - "expected chain state to be `{expected_chain_state:?}`, got `{chain_state:?}`" + "expected `{expected_chain_state:?}`, got `{chain_state:?}`" ); Ok(()) @@ -474,7 +446,7 @@ impl StorageTestSuite { expected_chain_state.set_last_integration_message_id(MessageId::new([0xff; 32])); storage - .chain_state_set(&did, &expected_chain_state) + .blob_set(&did, &serde_json::to_vec(&expected_chain_state).unwrap()) .await .context("chain_state_set returned an error")?; @@ -482,15 +454,9 @@ impl StorageTestSuite { ensure!(purged, "expected did `{did}` to have been purged"); - let chain_state: Option = storage - .chain_state_get(&did) - .await - .context("chain_state_get returned an error")?; + let value: Option> = storage.blob_get(&did).await.context("blob_get returned an error")?; - ensure!( - chain_state.is_none(), - "expected chain_state_get to return `None` after purging" - ); + ensure!(value.is_none(), "expected blob_get to return `None` after purging"); let exists: bool = storage .key_exists(&did, &location) diff --git a/identity_account_storage/src/storage/traits.rs b/identity_account_storage/src/storage/traits.rs index 7816ce1e3a..0bbbdc1bae 100644 --- a/identity_account_storage/src/storage/traits.rs +++ b/identity_account_storage/src/storage/traits.rs @@ -9,11 +9,9 @@ use identity_core::crypto::KeyType; use identity_core::crypto::PrivateKey; use identity_core::crypto::PublicKey; use identity_iota_core::did::IotaDID; -use identity_iota_core::document::IotaDocument; use identity_iota_core::tangle::NetworkName; use crate::error::Result; -use crate::identity::ChainState; #[cfg(feature = "encryption")] use crate::types::CekAlgorithm; #[cfg(feature = "encryption")] @@ -151,17 +149,11 @@ pub trait Storage: storage_sub_trait::StorageSendSyncMaybe + Debug { private_key: &KeyLocation, ) -> Result>; - /// Returns the chain state of the identity specified by `did`. - async fn chain_state_get(&self, did: &IotaDID) -> Result>; + /// Stores an arbitrary value for the identity specified by `did`. + async fn blob_set(&self, did: &IotaDID, value: &[u8]) -> Result<()>; - /// Set the chain state of the identity specified by `did`. - async fn chain_state_set(&self, did: &IotaDID, chain_state: &ChainState) -> Result<()>; - - /// Returns the [`IotaDocument`] of the identity specified by `did`. - async fn document_get(&self, did: &IotaDID) -> Result>; - - /// Sets a new state for the identity specified by `did`. - async fn document_set(&self, did: &IotaDID, state: &IotaDocument) -> Result<()>; + /// Returns the value stored by the identity specified by `did`. + async fn blob_get(&self, did: &IotaDID) -> Result>>; /// Persists any unsaved changes. async fn flush_changes(&self) -> Result<()>; From 3c759bdf3c7497555c31a6dae0d713fa8b23f07d Mon Sep 17 00:00:00 2001 From: Henrique Nogara Date: Wed, 20 Jul 2022 10:36:07 -0300 Subject: [PATCH 2/6] Add arbitrary storage for bindings --- bindings/stronghold-nodejs/Cargo.lock | 156 ++++++++++++++---- bindings/stronghold-nodejs/js/stronghold.ts | 32 +--- bindings/stronghold-nodejs/src/stronghold.rs | 34 +--- bindings/wasm/docs/api-reference.md | 24 +-- .../examples-account/src/custom_storage.ts | 36 ++-- bindings/wasm/src/account/storage/traits.rs | 61 ++----- 6 files changed, 177 insertions(+), 166 deletions(-) diff --git a/bindings/stronghold-nodejs/Cargo.lock b/bindings/stronghold-nodejs/Cargo.lock index 989f3b1093..cfd7a20ea0 100644 --- a/bindings/stronghold-nodejs/Cargo.lock +++ b/bindings/stronghold-nodejs/Cargo.lock @@ -134,7 +134,7 @@ dependencies = [ "bee-pow", "bee-ternary", "bytemuck", - "digest", + "digest 0.9.0", "hex", "iota-crypto 0.9.1", "serde", @@ -185,7 +185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" dependencies = [ "crypto-mac 0.8.0", - "digest", + "digest 0.9.0", "opaque-debug", ] @@ -198,6 +198,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.10.0" @@ -297,6 +306,16 @@ dependencies = [ "libc", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "crypto-mac" version = "0.8.0" @@ -343,7 +362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ "byteorder", - "digest", + "digest 0.9.0", "rand_core 0.5.1", "subtle", "zeroize", @@ -394,6 +413,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", + "subtle", +] + [[package]] name = "dirs" version = "4.0.0" @@ -444,10 +474,24 @@ dependencies = [ "curve25519-dalek", "hex", "rand_core 0.5.1", - "sha2", + "sha2 0.9.9", "thiserror", ] +[[package]] +name = "ed25519-zebra" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403ef3e961ab98f0ba902771d29f842058578bb1ce7e3c59dad5a6a93e784c69" +dependencies = [ + "curve25519-dalek", + "hex", + "rand_core 0.6.3", + "sha2 0.9.9", + "thiserror", + "zeroize", +] + [[package]] name = "fern" version = "0.6.1" @@ -634,12 +678,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" dependencies = [ - "digest", - "hmac", + "hmac 0.12.1", ] [[package]] @@ -649,12 +692,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ "crypto-mac 0.11.1", - "digest", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.3", ] [[package]] name = "identity-diff" -version = "0.5.0" +version = "0.6.0" dependencies = [ "serde", "serde_json", @@ -664,7 +716,7 @@ dependencies = [ [[package]] name = "identity-stronghold-nodejs" -version = "0.5.0" +version = "0.6.0" dependencies = [ "identity_account_storage", "identity_core", @@ -678,7 +730,7 @@ dependencies = [ [[package]] name = "identity_account_storage" -version = "0.5.0" +version = "0.6.0" dependencies = [ "async-trait", "futures", @@ -701,7 +753,7 @@ dependencies = [ [[package]] name = "identity_core" -version = "0.5.0" +version = "0.6.0" dependencies = [ "identity-diff", "iota-crypto 0.8.0", @@ -719,7 +771,7 @@ dependencies = [ [[package]] name = "identity_did" -version = "0.5.0" +version = "0.6.0" dependencies = [ "did_url", "form_urlencoded", @@ -732,7 +784,7 @@ dependencies = [ [[package]] name = "identity_iota_core" -version = "0.5.0" +version = "0.6.0" dependencies = [ "bee-message", "identity_core", @@ -778,15 +830,13 @@ dependencies = [ "blake2", "chacha20poly1305", "curve25519-dalek", - "digest", - "ed25519-zebra", + "digest 0.9.0", + "ed25519-zebra 2.2.0", "generic-array", "getrandom 0.2.6", - "hmac", - "pbkdf2", - "serde", - "sha2", - "unicode-normalization", + "hmac 0.11.0", + "pbkdf2 0.8.0", + "sha2 0.9.9", "x25519-dalek", ] @@ -798,20 +848,44 @@ checksum = "8c98a3248cde6b42cb479a52089fe4fc20d12de51b8edd923294cd5240ec89b0" dependencies = [ "bee-ternary", "blake2", - "digest", - "ed25519-zebra", + "digest 0.9.0", + "ed25519-zebra 2.2.0", "lazy_static", ] +[[package]] +name = "iota-crypto" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03717e934972fad6f1c9b4cd25f662e1753b58a7f76e3dceadeb646e034b252" +dependencies = [ + "aead", + "aes", + "aes-gcm", + "chacha20poly1305", + "curve25519-dalek", + "digest 0.10.3", + "ed25519-zebra 3.0.0", + "generic-array", + "getrandom 0.2.6", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "serde", + "sha2 0.10.2", + "unicode-normalization", + "x25519-dalek", + "zeroize", +] + [[package]] name = "iota_stronghold" -version = "0.5.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "273197e986052cac7fed586142e40497ffec2e3536a7416d23bf694f90068b96" +checksum = "89ebdd443fde5c02437469c1a318aa4d56cba83db3913743862a0e3b54ab5736" dependencies = [ "bincode", "hkdf", - "iota-crypto 0.8.0", + "iota-crypto 0.12.1", "serde", "stronghold-derive", "stronghold-rlu", @@ -1051,6 +1125,15 @@ dependencies = [ "crypto-mac 0.11.1", ] +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.3", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1285,13 +1368,24 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if", "cpufeatures 0.2.2", - "digest", + "digest 0.9.0", "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.2", + "digest 0.10.3", +] + [[package]] name = "slab" version = "0.4.6" @@ -1351,9 +1445,9 @@ dependencies = [ [[package]] name = "stronghold-utils" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d8493a083506300a7a112d927f48068e4c733f0b46c63569dea6ab6dfe175c" +checksum = "be1ce0d6205e8ea89771f2b32d64aeaecbc930320919e95ec4efcc0aa96cd951" dependencies = [ "rand", "stronghold-derive", diff --git a/bindings/stronghold-nodejs/js/stronghold.ts b/bindings/stronghold-nodejs/js/stronghold.ts index 329211140f..2a463d3dd5 100644 --- a/bindings/stronghold-nodejs/js/stronghold.ts +++ b/bindings/stronghold-nodejs/js/stronghold.ts @@ -1,4 +1,4 @@ -import { NapiStronghold, NapiDid, NapiKeyLocation, NapiChainState, NapiDocument, NapiKeyType, NapiDidLocation, NapiEncryptedData, NapiEncryptionAlgorithm, NapiCekAlgorithm } from '../napi-dist/napi'; +import { NapiStronghold, NapiDid, NapiKeyLocation, NapiKeyType, NapiDidLocation, NapiEncryptedData, NapiEncryptionAlgorithm, NapiCekAlgorithm } from '../napi-dist/napi'; import { DID, KeyLocation, Signature, ChainState, Storage, KeyType, Document, EncryptedData, EncryptionAlgorithm, CekAlgorithm } from "@iota/identity-wasm/node"; export class Stronghold implements Storage { @@ -115,38 +115,20 @@ export class Stronghold implements Storage { return Uint8Array.from(decryptedData); } - public async chainStateGet(did: DID): Promise { + public async blobGet(did: DID): Promise { const napiDID: NapiDid = NapiDid.fromJSON(did.toJSON()); - const napiChainState: NapiChainState | undefined = await this.napiStronghold.chainStateGet(napiDID); + const value: number[] | undefined = await this.napiStronghold.blobGet(napiDID); - if (napiChainState) { - return ChainState.fromJSON(napiChainState.toJSON()) + if (value) { + return Uint8Array.from(value) } else { return undefined; } } - public async chainStateSet(did: DID, chainState: ChainState): Promise { + public async blobSet(did: DID, value: Uint8Array): Promise { const napiDID: NapiDid = NapiDid.fromJSON(did.toJSON()); - const napiChainState: NapiChainState = NapiChainState.fromJSON(chainState.toJSON()); - return this.napiStronghold.chainStateSet(napiDID, napiChainState); - } - - public async documentGet(did: DID): Promise { - const napiDID: NapiDid = NapiDid.fromJSON(did.toJSON()); - const napiDocument: NapiDocument | undefined = await this.napiStronghold.documentGet(napiDID); - - if (napiDocument) { - return Document.fromJSON(napiDocument.toJSON()) - } else { - return undefined; - } - } - - public async documentSet(did: DID, document: Document): Promise { - const napiDID: NapiDid = NapiDid.fromJSON(did.toJSON()); - const napiDocument: NapiDocument = NapiDocument.fromJSON(document.toJSON()); - return this.napiStronghold.documentSet(napiDID, napiDocument); + return this.napiStronghold.blobSet(napiDID, Array.from(value)); } public async flushChanges() { diff --git a/bindings/stronghold-nodejs/src/stronghold.rs b/bindings/stronghold-nodejs/src/stronghold.rs index 30e32ab789..4b93edfcee 100644 --- a/bindings/stronghold-nodejs/src/stronghold.rs +++ b/bindings/stronghold-nodejs/src/stronghold.rs @@ -15,10 +15,8 @@ use napi_derive::napi; use crate::error::NapiResult; use crate::types::NapiCekAlgorithm; -use crate::types::NapiChainState; use crate::types::NapiDid; use crate::types::NapiDidLocation; -use crate::types::NapiDocument; use crate::types::NapiEncryptedData; use crate::types::NapiEncryptionAlgorithm; use crate::types::NapiKeyLocation; @@ -236,38 +234,22 @@ impl NapiStronghold { Ok(data.into_iter().map(u32::from).collect()) } - /// Returns the chain state of the identity specified by `did`. + /// Returns the value stored by the identity specified by `did`. #[napi] - pub async fn chain_state_get(&self, did: &NapiDid) -> Result> { + pub async fn blob_get(&self, did: &NapiDid) -> Result>> { self .0 - .chain_state_get(&did.0) + .blob_get(&did.0) .await .napi_result() - .map(|opt_chain_state| opt_chain_state.map(|chain_state| chain_state.into())) + .map(|opt_value| opt_value.map(|value| value.into_iter().map(u32::from).collect())) } - /// Set the chain state of the identity specified by `did`. + /// Stores an arbitrary value for the identity specified by `did`. #[napi] - pub async fn chain_state_set(&self, did: &NapiDid, chain_state: &NapiChainState) -> Result<()> { - self.0.chain_state_set(&did.0, &chain_state.0).await.napi_result() - } - - /// Returns the document of the identity specified by `did`. - #[napi] - pub async fn document_get(&self, did: &NapiDid) -> Result> { - self - .0 - .document_get(&did.0) - .await - .napi_result() - .map(|opt_document| opt_document.map(|doc| doc.into())) - } - - /// Sets a new state for the identity specified by `did`. - #[napi] - pub async fn document_set(&self, did: &NapiDid, state: &NapiDocument) -> Result<()> { - self.0.document_set(&did.0, &state.0).await.napi_result() + pub async fn blob_set(&self, did: &NapiDid, value: Vec) -> Result<()> { + let value: Vec = value.try_into_bytes()?; + self.0.blob_set(&did.0, &value).await.napi_result() } /// Persists any unsaved changes. diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md index 4d351c7796..bee630a644 100644 --- a/bindings/wasm/docs/api-reference.md +++ b/bindings/wasm/docs/api-reference.md @@ -243,10 +243,10 @@ publishing to the Tangle. * [.decryptData(data, encryption_algorithm, cek_algorithm, fragment)](#Account+decryptData) ⇒ Promise.<Uint8Array> * [.attachMethodRelationships(options)](#Account+attachMethodRelationships) ⇒ Promise.<void> * [.detachMethodRelationships(options)](#Account+detachMethodRelationships) ⇒ Promise.<void> + * [.deleteMethod(options)](#Account+deleteMethod) ⇒ Promise.<void> * [.deleteService(options)](#Account+deleteService) ⇒ Promise.<void> * [.setAlsoKnownAs(options)](#Account+setAlsoKnownAs) ⇒ Promise.<void> * [.setController(options)](#Account+setController) ⇒ Promise.<void> - * [.deleteMethod(options)](#Account+deleteMethod) ⇒ Promise.<void> @@ -486,6 +486,17 @@ Detaches the given relationship from the given method, if the method exists. | --- | --- | | options | DetachMethodRelationshipOptions | + + +### account.deleteMethod(options) ⇒ Promise.<void> +Deletes a verification method if the method exists. + +**Kind**: instance method of [Account](#Account) + +| Param | Type | +| --- | --- | +| options | DeleteMethodOptions | + ### account.deleteService(options) ⇒ Promise.<void> @@ -519,17 +530,6 @@ Sets the controllers of the DID document. | --- | --- | | options | SetControllerOptions | - - -### account.deleteMethod(options) ⇒ Promise.<void> -Deletes a verification method if the method exists. - -**Kind**: instance method of [Account](#Account) - -| Param | Type | -| --- | --- | -| options | DeleteMethodOptions | - ## AccountBuilder diff --git a/bindings/wasm/examples-account/src/custom_storage.ts b/bindings/wasm/examples-account/src/custom_storage.ts index cf6b58864d..86d020653e 100644 --- a/bindings/wasm/examples-account/src/custom_storage.ts +++ b/bindings/wasm/examples-account/src/custom_storage.ts @@ -1,7 +1,7 @@ // Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ChainState, DID, Document, Ed25519, KeyLocation, KeyPair, KeyType, Signature, Storage, StorageTestSuite, EncryptionAlgorithm, CekAlgorithm, EncryptedData } from '../../node/identity_wasm.js'; +import { DID, Ed25519, KeyLocation, KeyPair, KeyType, Signature, Storage, StorageTestSuite, EncryptionAlgorithm, CekAlgorithm, EncryptedData } from '../../node/identity_wasm.js'; /** An insecure, in-memory `Storage` implementation that serves as an example. This can be passed to the `AccountBuilder` to create accounts with this as the storage. */ @@ -10,17 +10,14 @@ export class MemStore implements Storage { // We use strings as keys rather than DIDs or KeyLocations because Maps use // referential equality for object keys, and thus a primitive type needs to be used instead. - // The map from DIDs to chain states. - private _chainStates: Map; - // The map from DIDs to DID documents. - private _documents: Map; + // The map from DIDs to state. + private _state: Map; // The map from DIDs to vaults. private _vaults: Map>; /** Creates a new, empty `MemStore` instance. */ constructor() { - this._chainStates = new Map(); - this._documents = new Map(); + this._state = new Map(); this._vaults = new Map(); } @@ -67,8 +64,7 @@ export class MemStore implements Storage { // so we only need to do work if the DID still exists. // The return value signals whether the DID was actually removed during this operation. if (this._vaults.has(did.toString())) { - this._chainStates.delete(did.toString()); - this._documents.delete(did.toString()); + this._state.delete(did.toString()); this._vaults.delete(did.toString()); return true; } @@ -197,24 +193,14 @@ export class MemStore implements Storage { throw new Error('not yet implemented') } - public async chainStateGet(did: DID): Promise { - // Lookup the chain state of the given DID. - return this._chainStates.get(did.toString()); + public async blobGet(did: DID): Promise { + // Lookup the state of the given DID. + return this._state.get(did.toString()); } - public async chainStateSet(did: DID, chainState: ChainState): Promise { - // Set the chain state of the given DID. - this._chainStates.set(did.toString(), chainState); - } - - public async documentGet(did: DID): Promise { - // Lookup the DID document of the given DID. - return this._documents.get(did.toString()) - } - - public async documentSet(did: DID, document: Document): Promise { - // Set the DID document of the given DID. - this._documents.set(did.toString(), document); + public async blobSet(did: DID, value: Uint8Array): Promise { + // Set the state of the given DID. + this._state.set(did.toString(), value); } public async flushChanges(): Promise { diff --git a/bindings/wasm/src/account/storage/traits.rs b/bindings/wasm/src/account/storage/traits.rs index aec23609f8..6ce7f12436 100644 --- a/bindings/wasm/src/account/storage/traits.rs +++ b/bindings/wasm/src/account/storage/traits.rs @@ -5,7 +5,6 @@ use core::fmt::Debug; use core::fmt::Formatter; use identity_iota::account_storage::CekAlgorithm; -use identity_iota::account_storage::ChainState; use identity_iota::account_storage::EncryptedData; use identity_iota::account_storage::EncryptionAlgorithm; use identity_iota::account_storage::Error as AccountStorageError; @@ -17,7 +16,6 @@ use identity_iota::crypto::PrivateKey; use identity_iota::crypto::PublicKey; use identity_iota::iota_core::IotaDID; use identity_iota::iota_core::NetworkName; -use identity_iota::prelude::IotaDocument; use identity_iota::prelude::KeyType; use js_sys::Array; use js_sys::Promise; @@ -26,7 +24,6 @@ use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; use wasm_bindgen_futures::JsFuture; -use crate::account::identity::WasmChainState; use crate::account::types::WasmCekAlgorithm; use crate::account::types::WasmEncryptedData; use crate::account::types::WasmEncryptionAlgorithm; @@ -35,7 +32,6 @@ use crate::common::PromiseBool; use crate::common::PromiseVoid; use crate::crypto::WasmKeyType; use crate::did::WasmDID; -use crate::did::WasmDocument; use crate::error::JsValueResult; #[wasm_bindgen] @@ -58,6 +54,8 @@ extern "C" { pub type PromiseEncryptedData; #[wasm_bindgen(typescript_type = "Promise")] pub type PromiseData; + #[wasm_bindgen(typescript_type = "Promise")] + pub type PromiseBytes; } #[wasm_bindgen] @@ -112,13 +110,9 @@ extern "C" { private_key: WasmKeyLocation, ) -> Uint8Array; #[wasm_bindgen(method, js_name = chainStateGet)] - pub fn chain_state_get(this: &WasmStorage, did: WasmDID) -> PromiseOptionChainState; + pub fn blob_get(this: &WasmStorage, did: WasmDID) -> PromiseBytes; #[wasm_bindgen(method, js_name = chainStateSet)] - pub fn chain_state_set(this: &WasmStorage, did: WasmDID, chain_state: WasmChainState) -> PromiseVoid; - #[wasm_bindgen(method, js_name = documentGet)] - pub fn document_get(this: &WasmStorage, did: WasmDID) -> PromiseOptionDocument; - #[wasm_bindgen(method, js_name = documentSet)] - pub fn document_set(this: &WasmStorage, did: WasmDID, document: WasmDocument) -> PromiseVoid; + pub fn blob_set(this: &WasmStorage, did: WasmDID, value: Vec) -> PromiseVoid; #[wasm_bindgen(method, js_name = flushChanges)] pub fn flush_changes(this: &WasmStorage) -> PromiseVoid; } @@ -286,40 +280,19 @@ impl Storage for WasmStorage { Ok(data) } - async fn chain_state_get(&self, did: &IotaDID) -> AccountStorageResult> { - let promise: Promise = Promise::resolve(&self.chain_state_get(did.clone().into())); + async fn blob_get(&self, did: &IotaDID) -> AccountStorageResult>> { + let promise: Promise = Promise::resolve(&self.blob_get(did.clone().into())); let result: JsValueResult = JsFuture::from(promise).await.into(); let js_value: JsValue = result.to_account_error()?; if js_value.is_null() || js_value.is_undefined() { return Ok(None); } - let chain_state: ChainState = js_value - .into_serde() - .map_err(|err| AccountStorageError::SerializationError(err.to_string()))?; - Ok(Some(chain_state)) + let value: Vec = uint8array_to_bytes(js_value)?; + Ok(Some(value)) } - async fn chain_state_set(&self, did: &IotaDID, chain_state: &ChainState) -> AccountStorageResult<()> { - let promise: Promise = Promise::resolve(&self.chain_state_set(did.clone().into(), chain_state.clone().into())); - let result: JsValueResult = JsFuture::from(promise).await.into(); - result.into() - } - - async fn document_get(&self, did: &IotaDID) -> AccountStorageResult> { - let promise: Promise = Promise::resolve(&self.document_get(did.clone().into())); - let result: JsValueResult = JsFuture::from(promise).await.into(); - let js_value: JsValue = result.to_account_error()?; - if js_value.is_null() || js_value.is_undefined() { - return Ok(None); - } - let document: IotaDocument = js_value - .into_serde() - .map_err(|err| AccountStorageError::SerializationError(err.to_string()))?; - Ok(Some(document)) - } - - async fn document_set(&self, did: &IotaDID, document: &IotaDocument) -> AccountStorageResult<()> { - let promise: Promise = Promise::resolve(&self.document_set(did.clone().into(), document.clone().into())); + async fn blob_set(&self, did: &IotaDID, value: &[u8]) -> AccountStorageResult<()> { + let promise: Promise = Promise::resolve(&self.blob_set(did.clone().into(), value.to_vec())); let result: JsValueResult = JsFuture::from(promise).await.into(); result.into() } @@ -416,17 +389,11 @@ interface Storage { */ dataDecrypt: (did: DID, data: EncryptedData, encryptionAlgorithm: EncryptionAlgorithm, cekAlgorithm: CekAlgorithm, privateKey: KeyLocation) => Promise; - /** Returns the chain state of the identity specified by `did`. */ - chainStateGet: (did: DID) => Promise; - - /** Set the chain state of the identity specified by `did`. */ - chainStateSet: (did: DID, chainState: ChainState) => Promise; - - /** Returns the document of the identity specified by `did`. */ - documentGet: (did: DID) => Promise; + /** Returns the value stored by the identity specified by `did`. */ + blobGet: (did: DID) => Promise; - /** Sets a new state for the identity specified by `did`. */ - documentSet: (did: DID, document: Document) => Promise; + /** Stores an arbitrary value for the identity specified by `did`. */ + blobSet: (did: DID, value: Uint8Array) => Promise; /** Persists any unsaved changes. */ flushChanges: () => Promise; From 8b28f137e22f6235fd4f39b30071ac052754e55e Mon Sep 17 00:00:00 2001 From: Henrique Nogara Date: Wed, 20 Jul 2022 10:57:24 -0300 Subject: [PATCH 3/6] Fix naming for storage function --- bindings/wasm/src/account/storage/traits.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/wasm/src/account/storage/traits.rs b/bindings/wasm/src/account/storage/traits.rs index 6ce7f12436..681f3a6ed9 100644 --- a/bindings/wasm/src/account/storage/traits.rs +++ b/bindings/wasm/src/account/storage/traits.rs @@ -109,9 +109,9 @@ extern "C" { cek_algorithm: WasmCekAlgorithm, private_key: WasmKeyLocation, ) -> Uint8Array; - #[wasm_bindgen(method, js_name = chainStateGet)] + #[wasm_bindgen(method, js_name = blobGet)] pub fn blob_get(this: &WasmStorage, did: WasmDID) -> PromiseBytes; - #[wasm_bindgen(method, js_name = chainStateSet)] + #[wasm_bindgen(method, js_name = blobSet)] pub fn blob_set(this: &WasmStorage, did: WasmDID, value: Vec) -> PromiseVoid; #[wasm_bindgen(method, js_name = flushChanges)] pub fn flush_changes(this: &WasmStorage) -> PromiseVoid; From 7d243efb5c6f0053b09fe9258cf521c1314efc6c Mon Sep 17 00:00:00 2001 From: Henrique Nogara Date: Mon, 25 Jul 2022 16:16:55 -0300 Subject: [PATCH 4/6] Bump MSRV to 1.62 --- README.md | 4 ++-- documentation/docs/libraries/rust/getting_started.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4fd9e6422d..d8f7db8ce6 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,8 @@ The individual libraries are developed to be agnostic about the utilized [Distri ## Prerequisites -- [Rust](https://www.rust-lang.org/) (>= 1.60) -- [Cargo](https://doc.rust-lang.org/cargo/) (>= 1.60) +- [Rust](https://www.rust-lang.org/) (>= 1.62) +- [Cargo](https://doc.rust-lang.org/cargo/) (>= 1.62) ## Getting Started diff --git a/documentation/docs/libraries/rust/getting_started.md b/documentation/docs/libraries/rust/getting_started.md index ecd62a51d5..67f46ca233 100644 --- a/documentation/docs/libraries/rust/getting_started.md +++ b/documentation/docs/libraries/rust/getting_started.md @@ -10,8 +10,8 @@ keywords: ## Requirements -- [Rust](https://www.rust-lang.org/) (>= 1.60) -- [Cargo](https://doc.rust-lang.org/cargo/) (>= 1.60) +- [Rust](https://www.rust-lang.org/) (>= 1.62) +- [Cargo](https://doc.rust-lang.org/cargo/) (>= 1.62) ## Include the Library From 365c26e19a1878da5798bd4bbaf3cc872f8db00c Mon Sep 17 00:00:00 2001 From: Henrique Nogara Date: Mon, 25 Jul 2022 16:18:55 -0300 Subject: [PATCH 5/6] Remove serde_json dependency; Rename value to blob; Take ownership of blob; Fix bindings --- bindings/stronghold-nodejs/src/stronghold.rs | 6 +- bindings/wasm/docs/api-reference.md | 54 ++++++++--------- .../examples-account/src/custom_storage.ts | 12 ++-- bindings/wasm/src/account/storage/traits.rs | 20 +++---- identity_account/Cargo.toml | 1 - identity_account/src/account/account.rs | 17 ++---- identity_account/src/error.rs | 3 - identity_account/src/tests/updates.rs | 5 +- identity_account/src/types/identity_state.rs | 59 ++++++------------- identity_account/src/types/mod.rs | 2 +- identity_account_storage/Cargo.toml | 3 +- .../src/storage/memstore.rs | 14 ++--- .../src/storage/stronghold.rs | 8 +-- .../src/storage/test_suite.rs | 12 ++-- .../src/storage/traits.rs | 6 +- 15 files changed, 94 insertions(+), 128 deletions(-) diff --git a/bindings/stronghold-nodejs/src/stronghold.rs b/bindings/stronghold-nodejs/src/stronghold.rs index 4b93edfcee..8cb27b1cef 100644 --- a/bindings/stronghold-nodejs/src/stronghold.rs +++ b/bindings/stronghold-nodejs/src/stronghold.rs @@ -247,9 +247,9 @@ impl NapiStronghold { /// Stores an arbitrary value for the identity specified by `did`. #[napi] - pub async fn blob_set(&self, did: &NapiDid, value: Vec) -> Result<()> { - let value: Vec = value.try_into_bytes()?; - self.0.blob_set(&did.0, &value).await.napi_result() + pub async fn blob_set(&self, did: &NapiDid, blob: Vec) -> Result<()> { + let blob: Vec = blob.try_into_bytes()?; + self.0.blob_set(&did.0, blob).await.napi_result() } /// Persists any unsaved changes. diff --git a/bindings/wasm/docs/api-reference.md b/bindings/wasm/docs/api-reference.md index bee630a644..c071210ff9 100644 --- a/bindings/wasm/docs/api-reference.md +++ b/bindings/wasm/docs/api-reference.md @@ -223,7 +223,9 @@ publishing to the Tangle. * [Account](#Account) * [.createService(options)](#Account+createService) ⇒ Promise.<void> + * [.attachMethodRelationships(options)](#Account+attachMethodRelationships) ⇒ Promise.<void> * [.createMethod(options)](#Account+createMethod) ⇒ Promise.<void> + * [.detachMethodRelationships(options)](#Account+detachMethodRelationships) ⇒ Promise.<void> * [.did()](#Account+did) ⇒ [DID](#DID) * [.autopublish()](#Account+autopublish) ⇒ boolean * [.autosave()](#Account+autosave) ⇒ [AutoSave](#AutoSave) @@ -241,8 +243,6 @@ publishing to the Tangle. * [.unrevokeCredentials(fragment, credentialIndices)](#Account+unrevokeCredentials) ⇒ Promise.<void> * [.encryptData(plaintext, associated_data, encryption_algorithm, cek_algorithm, public_key)](#Account+encryptData) ⇒ [Promise.<EncryptedData>](#EncryptedData) * [.decryptData(data, encryption_algorithm, cek_algorithm, fragment)](#Account+decryptData) ⇒ Promise.<Uint8Array> - * [.attachMethodRelationships(options)](#Account+attachMethodRelationships) ⇒ Promise.<void> - * [.detachMethodRelationships(options)](#Account+detachMethodRelationships) ⇒ Promise.<void> * [.deleteMethod(options)](#Account+deleteMethod) ⇒ Promise.<void> * [.deleteService(options)](#Account+deleteService) ⇒ Promise.<void> * [.setAlsoKnownAs(options)](#Account+setAlsoKnownAs) ⇒ Promise.<void> @@ -259,6 +259,20 @@ Adds a new Service to the DID Document. | --- | --- | | options | CreateServiceOptions | + + +### account.attachMethodRelationships(options) ⇒ Promise.<void> +Attach one or more verification relationships to a method. + +Note: the method must exist and be in the set of verification methods; +it cannot be an embedded method. + +**Kind**: instance method of [Account](#Account) + +| Param | Type | +| --- | --- | +| options | AttachMethodRelationshipOptions | + ### account.createMethod(options) ⇒ Promise.<void> @@ -270,6 +284,17 @@ Adds a new verification method to the DID document. | --- | --- | | options | CreateMethodOptions | + + +### account.detachMethodRelationships(options) ⇒ Promise.<void> +Detaches the given relationship from the given method, if the method exists. + +**Kind**: instance method of [Account](#Account) + +| Param | Type | +| --- | --- | +| options | DetachMethodRelationshipOptions | + ### account.did() ⇒ [DID](#DID) @@ -461,31 +486,6 @@ Returns the decrypted text. | cek_algorithm | [CekAlgorithm](#CekAlgorithm) | | fragment | string | - - -### account.attachMethodRelationships(options) ⇒ Promise.<void> -Attach one or more verification relationships to a method. - -Note: the method must exist and be in the set of verification methods; -it cannot be an embedded method. - -**Kind**: instance method of [Account](#Account) - -| Param | Type | -| --- | --- | -| options | AttachMethodRelationshipOptions | - - - -### account.detachMethodRelationships(options) ⇒ Promise.<void> -Detaches the given relationship from the given method, if the method exists. - -**Kind**: instance method of [Account](#Account) - -| Param | Type | -| --- | --- | -| options | DetachMethodRelationshipOptions | - ### account.deleteMethod(options) ⇒ Promise.<void> diff --git a/bindings/wasm/examples-account/src/custom_storage.ts b/bindings/wasm/examples-account/src/custom_storage.ts index 86d020653e..b0b3b2856d 100644 --- a/bindings/wasm/examples-account/src/custom_storage.ts +++ b/bindings/wasm/examples-account/src/custom_storage.ts @@ -11,13 +11,13 @@ export class MemStore implements Storage { // referential equality for object keys, and thus a primitive type needs to be used instead. // The map from DIDs to state. - private _state: Map; - // The map from DIDs to vaults. + private _blobs: Map; + // Map of DID state blobs. private _vaults: Map>; /** Creates a new, empty `MemStore` instance. */ constructor() { - this._state = new Map(); + this._blobs = new Map(); this._vaults = new Map(); } @@ -64,7 +64,7 @@ export class MemStore implements Storage { // so we only need to do work if the DID still exists. // The return value signals whether the DID was actually removed during this operation. if (this._vaults.has(did.toString())) { - this._state.delete(did.toString()); + this._blobs.delete(did.toString()); this._vaults.delete(did.toString()); return true; } @@ -195,12 +195,12 @@ export class MemStore implements Storage { public async blobGet(did: DID): Promise { // Lookup the state of the given DID. - return this._state.get(did.toString()); + return this._blobs.get(did.toString()); } public async blobSet(did: DID, value: Uint8Array): Promise { // Set the state of the given DID. - this._state.set(did.toString(), value); + this._blobs.set(did.toString(), value); } public async flushChanges(): Promise { diff --git a/bindings/wasm/src/account/storage/traits.rs b/bindings/wasm/src/account/storage/traits.rs index 681f3a6ed9..c9f067d753 100644 --- a/bindings/wasm/src/account/storage/traits.rs +++ b/bindings/wasm/src/account/storage/traits.rs @@ -40,10 +40,6 @@ extern "C" { pub type PromisePublicKey; #[wasm_bindgen(typescript_type = "Promise")] pub type PromiseSignature; - #[wasm_bindgen(typescript_type = "Promise")] - pub type PromiseOptionChainState; - #[wasm_bindgen(typescript_type = "Promise")] - pub type PromiseOptionDocument; #[wasm_bindgen(typescript_type = "Promise")] pub type PromiseKeyLocation; #[wasm_bindgen(typescript_type = "Promise>")] @@ -55,7 +51,7 @@ extern "C" { #[wasm_bindgen(typescript_type = "Promise")] pub type PromiseData; #[wasm_bindgen(typescript_type = "Promise")] - pub type PromiseBytes; + pub type PromiseOptionBytes; } #[wasm_bindgen] @@ -110,9 +106,9 @@ extern "C" { private_key: WasmKeyLocation, ) -> Uint8Array; #[wasm_bindgen(method, js_name = blobGet)] - pub fn blob_get(this: &WasmStorage, did: WasmDID) -> PromiseBytes; + pub fn blob_get(this: &WasmStorage, did: WasmDID) -> PromiseOptionBytes; #[wasm_bindgen(method, js_name = blobSet)] - pub fn blob_set(this: &WasmStorage, did: WasmDID, value: Vec) -> PromiseVoid; + pub fn blob_set(this: &WasmStorage, did: WasmDID, blob: Vec) -> PromiseVoid; #[wasm_bindgen(method, js_name = flushChanges)] pub fn flush_changes(this: &WasmStorage) -> PromiseVoid; } @@ -291,8 +287,8 @@ impl Storage for WasmStorage { Ok(Some(value)) } - async fn blob_set(&self, did: &IotaDID, value: &[u8]) -> AccountStorageResult<()> { - let promise: Promise = Promise::resolve(&self.blob_set(did.clone().into(), value.to_vec())); + async fn blob_set(&self, did: &IotaDID, blob: Vec) -> AccountStorageResult<()> { + let promise: Promise = Promise::resolve(&self.blob_set(did.clone().into(), blob)); let result: JsValueResult = JsFuture::from(promise).await.into(); result.into() } @@ -389,11 +385,11 @@ interface Storage { */ dataDecrypt: (did: DID, data: EncryptedData, encryptionAlgorithm: EncryptionAlgorithm, cekAlgorithm: CekAlgorithm, privateKey: KeyLocation) => Promise; - /** Returns the value stored by the identity specified by `did`. */ + /** Returns the blob stored by the identity specified by `did`. */ blobGet: (did: DID) => Promise; - /** Stores an arbitrary value for the identity specified by `did`. */ - blobSet: (did: DID, value: Uint8Array) => Promise; + /** Stores an arbitrary blob for the identity specified by `did`. */ + blobSet: (did: DID, blob: Uint8Array) => Promise; /** Persists any unsaved changes. */ flushChanges: () => Promise; diff --git a/identity_account/Cargo.toml b/identity_account/Cargo.toml index fc7f295c00..15cba9bb11 100644 --- a/identity_account/Cargo.toml +++ b/identity_account/Cargo.toml @@ -21,7 +21,6 @@ log = { version = "0.4", default-features = false } paste = { version = "1.0" } rand = { version = "0.8", default-features = false, features = ["std", "std_rng"] } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } -serde_json = { version = "1.0", default-features = false } strum = { version = "0.24.0", default-features = false, features = ["std", "derive"] } thiserror = { version = "1.0" } diff --git a/identity_account/src/account/account.rs b/identity_account/src/account/account.rs index d00884787a..a8157e2c3a 100644 --- a/identity_account/src/account/account.rs +++ b/identity_account/src/account/account.rs @@ -12,6 +12,8 @@ use identity_account_storage::crypto::RemoteKey; use identity_account_storage::identity::ChainState; use identity_account_storage::storage::Storage; use identity_account_storage::types::KeyLocation; +use identity_core::convert::FromJson; +use identity_core::convert::ToJson; use identity_core::crypto::KeyType; use identity_core::crypto::ProofOptions; use identity_core::crypto::SetSignature; @@ -128,8 +130,7 @@ where // Ensure the identity exists in storage let identity_state_bytes: Vec = setup.storage.blob_get(&did).await?.ok_or(Error::IdentityNotFound)?; - let identity_state: IdentityState = serde_json::from_slice(&identity_state_bytes) - .map_err(|e| Error::SerializationError("unable to deserialize state".to_owned(), e))?; + let identity_state: IdentityState = IdentityState::from_json_slice(&identity_state_bytes)?; let chain_state: ChainState = identity_state .chain_state()? .ok_or_else(|| Error::InvalidIdentityState("missing chain state".to_owned()))?; @@ -326,8 +327,7 @@ where .blob_get(self.did()) .await? .ok_or(Error::IdentityNotFound)?; - let identity_state: IdentityState = serde_json::from_slice(&identity_state_bytes) - .map_err(|e| Error::SerializationError("unable to deserialize state".to_owned(), e))?; + let identity_state: IdentityState = IdentityState::from_json_slice(&identity_state_bytes)?; identity_state .document()? @@ -421,14 +421,7 @@ where async fn store_state(&self) -> Result<()> { let identity_state: IdentityState = IdentityState::new(Some(&self.document), Some(&self.chain_state))?; - self - .storage - .blob_set( - self.did(), - &serde_json::to_vec(&identity_state) - .map_err(|e| Error::SerializationError("unable to serialize state".to_owned(), e))?, - ) - .await?; + self.storage.blob_set(self.did(), identity_state.to_json_vec()?).await?; self.save(false).await?; diff --git a/identity_account/src/error.rs b/identity_account/src/error.rs index 5bc41ec5e3..ad08000fc8 100644 --- a/identity_account/src/error.rs +++ b/identity_account/src/error.rs @@ -39,9 +39,6 @@ pub enum Error { /// Caused by reaching an invalid state for the identity. #[error("invalid identity state: {0}")] InvalidIdentityState(String), - /// Caused by an error when serialing or deserialing IdentityState. - #[error("serialization error: {0}")] - SerializationError(String, #[source] serde_json::Error), } impl From for Error { diff --git a/identity_account/src/tests/updates.rs b/identity_account/src/tests/updates.rs index 673c009718..0bf57b726d 100644 --- a/identity_account/src/tests/updates.rs +++ b/identity_account/src/tests/updates.rs @@ -9,6 +9,7 @@ use identity_core::common::OneOrSet; use identity_core::common::OrderedSet; use identity_core::common::Timestamp; use identity_core::common::Url; +use identity_core::convert::FromJson; use identity_core::crypto::KeyPair; use identity_core::crypto::KeyType; use identity_core::crypto::PrivateKey; @@ -133,7 +134,7 @@ async fn test_create_identity_already_exists() -> Result<()> { .unwrap(); let initial_state: Vec = account_setup.storage.blob_get(account.did()).await?.unwrap(); - let initial_state: IdentityState = serde_json::from_slice(&initial_state).unwrap(); + let initial_state: IdentityState = IdentityState::from_json_slice(&initial_state).unwrap(); let output = Account::create_identity(account_setup.clone(), identity_create).await; @@ -144,7 +145,7 @@ async fn test_create_identity_already_exists() -> Result<()> { // Ensure nothing was overwritten in storage let account_state: Vec = account_setup.storage.blob_get(account.did()).await?.unwrap(); - let account_state: IdentityState = serde_json::from_slice(&account_state).unwrap(); + let account_state: IdentityState = IdentityState::from_json_slice(&account_state).unwrap(); assert_eq!(initial_state.document()?, account_state.document()?); } Ok(()) diff --git a/identity_account/src/types/identity_state.rs b/identity_account/src/types/identity_state.rs index 20eed1c972..26299cdc95 100644 --- a/identity_account/src/types/identity_state.rs +++ b/identity_account/src/types/identity_state.rs @@ -2,16 +2,17 @@ // SPDX-License-Identifier: Apache-2.0 use identity_account_storage::identity::ChainState; +use identity_core::convert::FromJson; +use identity_core::convert::ToJson; use identity_iota_core::document::IotaDocument; use serde::Deserialize; use serde::Serialize; -use crate::error::Error; use crate::error::Result; /// Holds the internal state for the identity. #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct IdentityState { +pub(crate) struct IdentityState { version: StateVersion, document: Option>, chain_state: Option>, @@ -19,19 +20,9 @@ pub struct IdentityState { impl IdentityState { /// Creates a new [`IdentityState`]. - pub fn new(document: Option<&IotaDocument>, chain_state: Option<&ChainState>) -> Result { - let document: Option> = document - .map(|iota_doc| { - serde_json::to_vec(iota_doc) - .map_err(|e| Error::SerializationError("unable to serialize document".to_owned(), e)) - }) - .transpose()?; - let chain_state: Option> = chain_state - .map(|chain_state| { - serde_json::to_vec(chain_state) - .map_err(|e| Error::SerializationError("unable to serialize chain state".to_owned(), e)) - }) - .transpose()?; + pub(crate) fn new(document: Option<&IotaDocument>, chain_state: Option<&ChainState>) -> Result { + let document: Option> = document.map(|iota_doc| iota_doc.to_json_vec()).transpose()?; + let chain_state: Option> = chain_state.map(|chain_state| chain_state.to_json_vec()).transpose()?; Ok(IdentityState { version: StateVersion::default(), document, @@ -40,40 +31,28 @@ impl IdentityState { } /// Returns the deserialized [`IotaDocument`]. - pub fn document(&self) -> Result> { + pub(crate) fn document(&self) -> Result> { match self.version { - StateVersion::V0 => Ok( - self - .document - .as_ref() - .map(|bytes| { - serde_json::from_slice(bytes) - .map_err(|e| Error::SerializationError("unable to deserialize document".to_owned(), e)) - }) - .transpose()?, - ), + StateVersion::V1 => Ok(self.document.as_ref().map(IotaDocument::from_json_slice).transpose()?), } } /// Returns the deserialized [`ChainState`]. - pub fn chain_state(&self) -> Result> { + pub(crate) fn chain_state(&self) -> Result> { match self.version { - StateVersion::V0 => Ok( - self - .chain_state - .as_ref() - .map(|bytes| { - serde_json::from_slice(bytes) - .map_err(|e| Error::SerializationError("unable to deserialize chain state".to_owned(), e)) - }) - .transpose()?, - ), + StateVersion::V1 => Ok(self.chain_state.as_ref().map(ChainState::from_json_slice).transpose()?), } } + + #[allow(dead_code)] + /// Returns the [`StateVersion`] of the [`IdentityState`]. + pub(crate) fn version(&self) -> StateVersion { + self.version + } } -#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] -enum StateVersion { +#[derive(Copy, Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +pub(crate) enum StateVersion { #[default] - V0, + V1 = 1, } diff --git a/identity_account/src/types/mod.rs b/identity_account/src/types/mod.rs index 9c050bf776..b801500afa 100644 --- a/identity_account/src/types/mod.rs +++ b/identity_account/src/types/mod.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 pub use self::identity_setup::*; -pub use self::identity_state::*; +pub(crate) use self::identity_state::IdentityState; pub use self::identity_updater::*; pub use self::method_content::*; diff --git a/identity_account_storage/Cargo.toml b/identity_account_storage/Cargo.toml index 9a31951921..bb07c6d839 100644 --- a/identity_account_storage/Cargo.toml +++ b/identity_account_storage/Cargo.toml @@ -26,7 +26,6 @@ parking_lot = { version = "0.12" } rand = { version = "0.8", default-features = false, features = ["std", "std_rng"], optional = true } seahash = { version = "4.1.0", default-features = false } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } -serde_json = { version = "1.0", default-features = false, optional = true } strum = { version = "0.24.0", default-features = false, features = ["std", "derive"] } thiserror = { version = "1.0" } tokio = { version = "1.17.0", default-features = false, features = ["sync", "fs"], optional = true } @@ -48,6 +47,6 @@ stronghold = [ # Enables `Send` + `Sync` bounds for the Storage trait. send-sync-storage = [] # Exposes Storage `test_suite` module. -storage-test-suite = ["anyhow", "function_name", "rand", "serde_json"] +storage-test-suite = ["anyhow", "function_name", "rand"] # Enables encryption and decryption in the Storage trait. encryption = [] diff --git a/identity_account_storage/src/storage/memstore.rs b/identity_account_storage/src/storage/memstore.rs index 28842505c2..204e91469b 100644 --- a/identity_account_storage/src/storage/memstore.rs +++ b/identity_account_storage/src/storage/memstore.rs @@ -48,7 +48,7 @@ type MemVault = HashMap; pub struct MemStore { // Controls whether to print the storages content when debugging. expand: bool, - data: Shared>>, + blobs: Shared>>, vaults: Shared, } @@ -57,7 +57,7 @@ impl MemStore { pub fn new() -> Self { Self { expand: false, - data: Shared::new(HashMap::new()), + blobs: Shared::new(HashMap::new()), vaults: Shared::new(HashMap::new()), } } @@ -123,7 +123,7 @@ impl Storage for MemStore { // so we only need to do work if the DID still exists. // The return value signals whether the DID was actually removed during this operation. if self.vaults.write()?.remove(did).is_some() { - let _ = self.data.write()?.remove(did); + let _ = self.blobs.write()?.remove(did); Ok(true) } else { Ok(false) @@ -370,16 +370,16 @@ impl Storage for MemStore { } } - async fn blob_set(&self, did: &IotaDID, value: &[u8]) -> Result<()> { + async fn blob_set(&self, did: &IotaDID, value: Vec) -> Result<()> { // Set the arbitrary value for the given DID. - self.data.write()?.insert(did.clone(), value.to_vec()); + self.blobs.write()?.insert(did.clone(), value); Ok(()) } async fn blob_get(&self, did: &IotaDID) -> Result>> { // Lookup the value stored of the given DID. - self.data.read().map(|data| data.get(did).cloned()) + self.blobs.read().map(|data| data.get(did).cloned()) } async fn flush_changes(&self) -> Result<()> { @@ -509,7 +509,7 @@ impl Debug for MemStore { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { if self.expand { f.debug_struct("MemStore") - .field("data", &self.data) + .field("blobs", &self.blobs) .field("vaults", &self.vaults) .finish() } else { diff --git a/identity_account_storage/src/storage/stronghold.rs b/identity_account_storage/src/storage/stronghold.rs index c45b8a9946..e3efc91574 100644 --- a/identity_account_storage/src/storage/stronghold.rs +++ b/identity_account_storage/src/storage/stronghold.rs @@ -50,7 +50,7 @@ static INDEX_CLIENT_PATH: &str = "$index"; // The key in the index store that contains the serialized index. // This happens to be the same as the client path, but for explicitness we define them separately. static INDEX_STORE_KEY: &str = INDEX_CLIENT_PATH; -static STORE_KEY: &str = "$store"; +static BLOB_STORE_KEY: &str = "$blob"; // The static identifier for vaults inside clients. static VAULT_PATH: &[u8; 6] = b"$vault"; @@ -374,12 +374,12 @@ impl Storage for Stronghold { } } - async fn blob_set(&self, did: &IotaDID, value: &[u8]) -> Result<()> { + async fn blob_set(&self, did: &IotaDID, blob: Vec) -> Result<()> { self.mutate_client(did, |client| { let store: Store = client.store(); store - .insert(STORE_KEY.as_bytes().to_vec(), value.to_vec(), None) + .insert(BLOB_STORE_KEY.as_bytes().to_vec(), blob, None) .map(|_| ()) .map_err(|err| StrongholdError::Store(StoreOperation::Insert, err).into()) }) @@ -389,7 +389,7 @@ impl Storage for Stronghold { let client: Client = self.client(&ClientPath::from(did))?; let store: Store = client.store(); let data: Option> = store - .get(STORE_KEY.as_bytes()) + .get(BLOB_STORE_KEY.as_bytes()) .map_err(|err| StrongholdError::Store(StoreOperation::Get, err))?; Ok(data) } diff --git a/identity_account_storage/src/storage/test_suite.rs b/identity_account_storage/src/storage/test_suite.rs index f5fbcb6547..9809459800 100644 --- a/identity_account_storage/src/storage/test_suite.rs +++ b/identity_account_storage/src/storage/test_suite.rs @@ -6,6 +6,8 @@ use function_name::named; use rand::distributions::DistString; use rand::rngs::OsRng; +use identity_core::convert::FromJson; +use identity_core::convert::ToJson; use identity_core::crypto::KeyPair; use identity_core::crypto::KeyType; use identity_core::crypto::PrivateKey; @@ -396,11 +398,11 @@ impl StorageTestSuite { let expected_document: IotaDocument = IotaDocument::from_verification_method(method).unwrap(); storage - .blob_set(&did, &serde_json::to_vec(&expected_document).unwrap()) + .blob_set(&did, expected_document.to_json_vec().unwrap()) .await .context("blob_set returned an error")?; let value: Option> = storage.blob_get(&did).await.context("blob_get returned an error")?; - let document: IotaDocument = serde_json::from_slice(&value.unwrap()).unwrap(); + let document: IotaDocument = IotaDocument::from_json_slice(&value.unwrap()).unwrap(); ensure_eq!( expected_document, document, @@ -410,11 +412,11 @@ impl StorageTestSuite { let mut expected_chain_state: ChainState = ChainState::new(); expected_chain_state.set_last_integration_message_id(MessageId::new([0xff; 32])); storage - .blob_set(&did, &serde_json::to_vec(&expected_chain_state).unwrap()) + .blob_set(&did, expected_chain_state.to_json_vec().unwrap()) .await .context("blob_set returned an error")?; let value: Option> = storage.blob_get(&did).await.context("blob_get returned an error")?; - let chain_state: ChainState = serde_json::from_slice(&value.unwrap()).unwrap(); + let chain_state: ChainState = ChainState::from_json_slice(&value.unwrap()).unwrap(); ensure_eq!( expected_chain_state, chain_state, @@ -446,7 +448,7 @@ impl StorageTestSuite { expected_chain_state.set_last_integration_message_id(MessageId::new([0xff; 32])); storage - .blob_set(&did, &serde_json::to_vec(&expected_chain_state).unwrap()) + .blob_set(&did, expected_chain_state.to_json_vec().unwrap()) .await .context("chain_state_set returned an error")?; diff --git a/identity_account_storage/src/storage/traits.rs b/identity_account_storage/src/storage/traits.rs index 0bbbdc1bae..99c004e617 100644 --- a/identity_account_storage/src/storage/traits.rs +++ b/identity_account_storage/src/storage/traits.rs @@ -149,10 +149,10 @@ pub trait Storage: storage_sub_trait::StorageSendSyncMaybe + Debug { private_key: &KeyLocation, ) -> Result>; - /// Stores an arbitrary value for the identity specified by `did`. - async fn blob_set(&self, did: &IotaDID, value: &[u8]) -> Result<()>; + /// Stores an arbitrary blob for the identity specified by `did`. + async fn blob_set(&self, did: &IotaDID, blob: Vec) -> Result<()>; - /// Returns the value stored by the identity specified by `did`. + /// Returns the blob stored by the identity specified by `did`. async fn blob_get(&self, did: &IotaDID) -> Result>>; /// Persists any unsaved changes. From 42ec57beecdd0a12bed42bac003c9f4f32f7dd73 Mon Sep 17 00:00:00 2001 From: Henrique Nogara Date: Mon, 25 Jul 2022 17:53:34 -0300 Subject: [PATCH 6/6] Fix doc comments --- bindings/stronghold-nodejs/src/stronghold.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/stronghold-nodejs/src/stronghold.rs b/bindings/stronghold-nodejs/src/stronghold.rs index 8cb27b1cef..5a35dfcd5a 100644 --- a/bindings/stronghold-nodejs/src/stronghold.rs +++ b/bindings/stronghold-nodejs/src/stronghold.rs @@ -234,7 +234,7 @@ impl NapiStronghold { Ok(data.into_iter().map(u32::from).collect()) } - /// Returns the value stored by the identity specified by `did`. + /// Returns the blob stored by the identity specified by `did`. #[napi] pub async fn blob_get(&self, did: &NapiDid) -> Result>> { self @@ -245,7 +245,7 @@ impl NapiStronghold { .map(|opt_value| opt_value.map(|value| value.into_iter().map(u32::from).collect())) } - /// Stores an arbitrary value for the identity specified by `did`. + /// Stores an arbitrary blob for the identity specified by `did`. #[napi] pub async fn blob_set(&self, did: &NapiDid, blob: Vec) -> Result<()> { let blob: Vec = blob.try_into_bytes()?;