Skip to content

Commit

Permalink
Enable lazy tangle updates in the Account (#377)
Browse files Browse the repository at this point in the history
* Implement pushing unpublished commits to tangle

* Improve methods added to the storage interface

* Bail early if no commits to publish

* Implement new storage methods for `Stronghold`

* Implement clippy suggestions

* Add lazy publish example

* Add lazy publish test

* Apply format

* Replace `unwrap` with `?`

* Implement a "network-resilient" test runner

* Make identity updates thread-safe

* Expand docs, fix nitpicks

* Add lock to `publish_changes`

* Return locks lazily in `get_lock`

* Remove lock when deleting from index

* Clone locks when cloning the index

* Rename document to did in all examples

* Fix spelling, docs, naming

* Improve docs, simplify code

* Add `IdentityLock` type

* Rename `publish_changes` -> `publish_updates`
  • Loading branch information
PhilippGackstatter authored Sep 9, 2021
1 parent d5d46dc commit 60f70c9
Show file tree
Hide file tree
Showing 15 changed files with 454 additions and 37 deletions.
4 changes: 4 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ path = "account/config.rs"
name = "account_methods"
path = "account/methods.rs"

[[example]]
name = "account_lazy"
path = "account/lazy.rs"

[[example]]
name = "account_services"
path = "account/services.rs"
Expand Down
6 changes: 3 additions & 3 deletions examples/account/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async fn main() -> Result<()> {
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let document: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = snapshot.identity().try_did()?;

println!("[Example] Local Snapshot = {:#?}", snapshot);
println!("[Example] Local Document = {:#?}", snapshot.identity().to_document()?);
Expand All @@ -30,12 +30,12 @@ async fn main() -> Result<()> {
// Fetch the DID Document from the Tangle
//
// This is an optional step to ensure DID Document consistency.
let resolved: IotaDocument = account.resolve_identity(document).await?;
let resolved: IotaDocument = account.resolve_identity(did).await?;

println!("[Example] Tangle Document = {:#?}", resolved);

// Delete the identity and all associated keys
account.delete_identity(document).await?;
account.delete_identity(did).await?;

Ok(())
}
62 changes: 62 additions & 0 deletions examples/account/lazy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2020-2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

//! cargo run --example account_lazy
use identity::account::Account;
use identity::account::Command;
use identity::account::IdentityCreate;
use identity::account::IdentitySnapshot;
use identity::account::Result;
use identity::core::Url;
use identity::iota::IotaDID;

#[tokio::main]
async fn main() -> Result<()> {
pretty_env_logger::init();

// Create a new Account with auto publishing set to false.
// This means updates are not pushed to the tangle automatically.
// Rather, when we publish, multiple updates are batched together.
let account: Account = Account::builder().autopublish(false).build().await?;

// Create a new Identity with default settings.
// The identity will only be written to the local storage - not published to the tangle.
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let did: &IotaDID = snapshot.identity().try_did()?;

let command: Command = Command::create_service()
.fragment("example-service")
.type_("LinkedDomains")
.endpoint(Url::parse("https://example.org")?)
.finish()?;
account.update_identity(did, command).await?;

// Publish the newly created DID document,
// including the new service, to the tangle.
account.publish_updates(did).await?;

// Add another service.
let command: Command = Command::create_service()
.fragment("another-service")
.type_("LinkedDomains")
.endpoint(Url::parse("https://example.org")?)
.finish()?;
account.update_identity(did, command).await?;

// Delete the previously added service.
let command: Command = Command::delete_service().fragment("example-service").finish()?;
account.update_identity(did, command).await?;

// Publish the updates as one message to the tangle.
account.publish_updates(did).await?;

// Resolve the document to confirm its consistency.
let doc = account.resolve_identity(did).await?;

println!("[Example] Document: {:#?}", doc);

Ok(())
}
16 changes: 8 additions & 8 deletions examples/account/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async fn main() -> Result<()> {
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let document: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = snapshot.identity().try_did()?;

// Add a new Ed25519 (defualt) verification method to the identity - the
// verification method is included as an embedded authentication method.
Expand All @@ -32,21 +32,21 @@ async fn main() -> Result<()> {
.finish()?;

// Process the command and update the identity state.
account.update_identity(document, command).await?;
account.update_identity(did, command).await?;

// Fetch and log the DID Document from the Tangle
//
// This is an optional step to ensure DID Document consistency.
println!(
"[Example] Tangle Document (1) = {:#?}",
account.resolve_identity(document).await?
account.resolve_identity(did).await?
);

// Add another Ed25519 verification method to the identity
let command: Command = Command::create_method().fragment("my-next-key").finish()?;

// Process the command and update the identity state.
account.update_identity(document, command).await?;
account.update_identity(did, command).await?;

// Associate the newly created method with additional verification relationships
let command: Command = Command::attach_method()
Expand All @@ -56,28 +56,28 @@ async fn main() -> Result<()> {
.finish()?;

// Process the command and update the identity state.
account.update_identity(document, command).await?;
account.update_identity(did, command).await?;

// Fetch and log the DID Document from the Tangle
//
// This is an optional step to ensure DID Document consistency.
println!(
"[Example] Tangle Document (2) = {:#?}",
account.resolve_identity(document).await?
account.resolve_identity(did).await?
);

// Remove the original Ed25519 verification method
let command: Command = Command::delete_method().fragment("my-auth-key").finish()?;

// Process the command and update the identity state.
account.update_identity(document, command).await?;
account.update_identity(did, command).await?;

// Fetch and log the DID Document from the Tangle
//
// This is an optional step to ensure DID Document consistency.
println!(
"[Example] Tangle Document (3) = {:#?}",
account.resolve_identity(document).await?
account.resolve_identity(did).await?
);

Ok(())
Expand Down
6 changes: 3 additions & 3 deletions examples/account/private_tangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ async fn main() -> Result<()> {
};

// Retrieve the DID from the newly created Identity state.
let document: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = snapshot.identity().try_did()?;

println!("[Example] Local Snapshot = {:#?}", snapshot);
println!("[Example] Local Document = {:#?}", snapshot.identity().to_document()?);
Expand All @@ -65,12 +65,12 @@ async fn main() -> Result<()> {
// Fetch the DID Document from the Tangle
//
// This is an optional step to ensure DID Document consistency.
let resolved: IotaDocument = account.resolve_identity(document).await?;
let resolved: IotaDocument = account.resolve_identity(did).await?;

println!("[Example] Tangle Document = {:#?}", resolved);

// Delete the identity and all associated keys
account.delete_identity(document).await?;
account.delete_identity(did).await?;

Ok(())
}
6 changes: 3 additions & 3 deletions examples/account/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async fn main() -> Result<()> {
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let document: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = snapshot.identity().try_did()?;

let command: Command = Command::create_service()
.fragment("my-service-1")
Expand All @@ -31,14 +31,14 @@ async fn main() -> Result<()> {
.finish()?;

// Process the command and update the identity state.
account.update_identity(document, command).await?;
account.update_identity(did, command).await?;

// Fetch and log the DID Document from the Tangle
//
// This is an optional step to ensure DID Document consistency.
println!(
"[Example] Tangle Document (1) = {:#?}",
account.resolve_identity(document).await?
account.resolve_identity(did).await?
);

Ok(())
Expand Down
10 changes: 5 additions & 5 deletions examples/account/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async fn main() -> Result<()> {
let snapshot: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let document: &IotaDID = snapshot.identity().try_did()?;
let did: &IotaDID = snapshot.identity().try_did()?;

println!("[Example] Local Snapshot = {:#?}", snapshot);
println!("[Example] Local Document = {:#?}", snapshot.identity().to_document()?);
Expand All @@ -37,7 +37,7 @@ async fn main() -> Result<()> {
let command: Command = Command::create_method().fragment("key-1").finish()?;

// Process the command and update the identity state.
account.update_identity(document, command).await?;
account.update_identity(did, command).await?;

// Create a subject DID for the recipient of a `UniversityDegree` credential.
let subject_key: KeyPair = KeyPair::new_ed25519()?;
Expand All @@ -54,20 +54,20 @@ async fn main() -> Result<()> {

// Issue an unsigned Credential...
let mut credential: Credential = Credential::builder(Default::default())
.issuer(Url::parse(document.as_str())?)
.issuer(Url::parse(did.as_str())?)
.type_("UniversityDegreeCredential")
.subject(subject)
.build()?;

// ...and sign the Credential with the previously created Verification Method
account.sign(document, "key-1", &mut credential).await?;
account.sign(did, "key-1", &mut credential).await?;

println!("[Example] Local Credential = {:#}", credential);

// Fetch the DID Document from the Tangle
//
// This is an optional step to ensure DID Document consistency.
let resolved: IotaDocument = account.resolve_identity(document).await?;
let resolved: IotaDocument = account.resolve_identity(did).await?;

println!("[Example] Tangle Document = {:#?}", resolved);

Expand Down
8 changes: 4 additions & 4 deletions examples/account/stronghold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async fn main() -> Result<()> {
let snapshot1: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;

// Retrieve the DID from the newly created Identity state.
let document1: &IotaDID = snapshot1.identity().try_did()?;
let did1: &IotaDID = snapshot1.identity().try_did()?;

println!("[Example] Local Snapshot = {:#?}", snapshot1);
println!("[Example] Local Document = {:#?}", snapshot1.identity().to_document()?);
Expand All @@ -39,16 +39,16 @@ async fn main() -> Result<()> {
// Fetch the DID Document from the Tangle
//
// This is an optional step to ensure DID Document consistency.
let resolved: IotaDocument = account.resolve_identity(document1).await?;
let resolved: IotaDocument = account.resolve_identity(did1).await?;

println!("[Example] Tangle Document = {:#?}", resolved);

// Create another new Identity
let snapshot2: IdentitySnapshot = account.create_identity(IdentityCreate::default()).await?;
let document2: &IotaDID = snapshot2.identity().try_did()?;
let did2: &IotaDID = snapshot2.identity().try_did()?;

// Anndddd delete it
account.delete_identity(document2).await?;
account.delete_identity(did2).await?;

Ok(())
}
Loading

0 comments on commit 60f70c9

Please sign in to comment.