Skip to content

Commit

Permalink
Refactor Account to handle just one identity (#436)
Browse files Browse the repository at this point in the history
* Partial impl to use did as storage identifier

* Move `CreateIdentity` into a separate type

Update Account API to return IdentityState from find_identity and create_identity (#414)

* Update Account::create_identity() to return IdentityState.

* Update Account::find_identity() to return IdentityState.

Update `IdentityUpdater` to only use account ref

Remove resolve, find and list

Replace `IdentityId` with `IotaDID` in account

Use `IotaDID` over `IdentityId` in stronghold

More replacement of id with did

Remove index from account

Fix stream impl

Fix stronghold impl, migrate `MemStore`

Re-add `resolve_identity` so tests can run

Fix Wasm network calls, pin reqwest to 0.11.4 (#439)

Rename `Command` -> `Update`

Rearrange `process_update`

* Fix clippy lints in memstore

* Let `RemoteKey` take a `dyn Storage`

* Implement `AccountConfig`

* Impl create_identity and load_identity in builder

* Rename JSON serialization field name to match spec. (#412)

* Rename JSON serialization field name to match spec.

* Rename notSupported -> representationNotSupported

* Reduce WASM build size (#427)

* reduce wasm build size

* Enable lto for Wasm release

Add `build-dev` task for Wasm for debugging.

Co-authored-by: Craig Bester <craig.bester@iota.org>

* Chore/combine examples (#420)

* Merged Stronghold with basic examples in account

* Updated explorer to identity resolver

* Added explorer URL after basic example

* Renamed examples

* Completed manipulate did example

* Fixed suggestions, removed replaced examples.

* Improved example readme

* Consistently use Stronghold and Resolver URL

* Fix examples

* Merged config example with private tangle

* low-level-api private-network example runs

* cargo fmt

* cargo fmt with nightly

* Impl suggestions

* Refactor config once more

* Update examples to use single-id account

* Don't pass did into `load_snapshot`

* Fix clippy lints

* Partially update `update` tests

* Fix update tests

* Ensure did exists in storage in `load`

* Remote `State` in account

* Rename `load` -> `load_identity`

* Remove `Identity{Id,Index,Key,Name,Tag}`

* Let `update_identity` take `&mut self`

* Document new and existing types

* Update top-level README example

* Fix visibility on `CreateIdentity`

* Add try_from implementation for ed25519 keypair

* Combine account tests

* Rename updates > commands for better reviewability

* Also rename in mod.rs

* Impl `AccountBuilder` without pub async fns

* Update README example with latest builder change

* Change visibility of setup, config, constructors

* Revert to the old `create_did` example

* Save to disk when creating identity, fix doc fmt

Co-authored-by: Craig Bester <craig.bester@iota.org>

* Use `authority` instead of `tag` in stronghold

* Rename `Config` -> `AccountConfig`

* Prevent two accounts from managing the same did

* Impl `IdentityBuilder`

* Only impl `IdentityCreate` under `#[cfg(test)]`

* Use `IdentityBuilder` in examples

* Remove unused `name` field

* Run workflow for `epic/*` branches

* Relase the lease in account tests

* Also run format, clippy and coverage workflows

* Revert "Use `IdentityBuilder` in examples"

This reverts commit 3d1b716.

* Revert "Only impl `IdentityCreate` under `#[cfg(test)]`"

This reverts commit 08ada09.

* Revert "Impl `IdentityBuilder`"

This reverts commit 1a5d645.

* Rename `IdentityCreate` -> `IdentitySetup`

* Add multi-identity example

* Simplify README example

* Rename `identity_setup` module

* Implement the `IdentityLease` newtype

* Rename `IdentityLease` -> `DIDLease`

* Update `resolve_identity` docstring

Co-authored-by: Matt Renaud <matt@m-renaud.com>
Co-authored-by: Thoralf-M <46689931+Thoralf-M@users.noreply.github.com>
Co-authored-by: Craig Bester <craig.bester@iota.org>
Co-authored-by: Jelle Femmo Millenaar <jelle.millenaar@iota.org>
  • Loading branch information
5 people authored Oct 25, 2021
1 parent ee4cce5 commit 4ce6295
Show file tree
Hide file tree
Showing 44 changed files with 1,148 additions and 1,580 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
branches:
- main
- dev
- epic/*
paths:
- '.github/workflows/build-and-test.yml'
- '**.rs'
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/clippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
branches:
- main
- dev
- epic/*
paths:
- '.github/workflows/clippy.yml'
- '**.rs'
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
branches:
- main
- dev
- epic/*
paths:
- '.github/workflows/coverage.yml'
- '.github/workflows/scripts/coverage.sh'
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
branches:
- main
- dev
- epic/*
paths:
- '.github/workflows/format.yml'
- '**.rs'
Expand Down
27 changes: 11 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,39 +91,34 @@ use std::path::PathBuf;

use identity::account::Account;
use identity::account::AccountStorage;
use identity::account::IdentityCreate;
use identity::account::IdentityState;
use identity::account::IdentitySetup;
use identity::account::Result;
use identity::iota::IotaDID;
use identity::iota::IotaDocument;

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

// The Stronghold settings for the storage.
let snapshot: PathBuf = "./example-strong.hodl".into();
let stronghold_path: PathBuf = "./example-strong.hodl".into();
let password: String = "my-password".into();

// Create a new Account with Stronghold as the storage adapter.
// Create a new identity with default settings and
// Stronghold as the storage.
let account: Account = Account::builder()
.storage(AccountStorage::Stronghold(snapshot, Some(password)))
.build()
.storage(AccountStorage::Stronghold(stronghold_path, Some(password)))
.create_identity(IdentitySetup::default())
.await?;

// Create a new Identity with default settings.
let identity: IdentityState = account.create_identity(IdentityCreate::default()).await?;

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

println!("[Example] Local Document = {:#?}", identity.to_document()?);
println!("[Example] Local Document List = {:#?}", account.list_identities().await);
println!(
"[Example] Local Document = {:#?}",
account.state().await?.to_document()?
);

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

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

Expand Down
4 changes: 4 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ path = "account/lazy.rs"
name = "account_signing"
path = "account/signing.rs"

[[example]]
name = "account_multiple"
path = "account/multiple_identities.rs"

[[example]]
name = "create_did"
path = "low-level-api/create_did.rs"
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ The following examples are available for using the basic account (A high-level A
| 4 | [account_manipulate](./account/manipulate_did.rs) | How to manipulate a DID Document by adding/removing Verification Methods and Services. |
| 5 | [account_lazy](./account/lazy.rs) | How to take control over publishing DID updates manually, instead of the default automated behavior. |
| 6 | [account_signing](./account/signing.rs) | Using a DID to sign arbitrary statements and validating them. |
| 7 | [account_multiple](./account/multiple_identities.rs) | How to create multiple identities from a builder and how to load existing identities into an account. |


The following examples are available for using the low-level APIs, which provides more flexibility at the cost of complexity:
Expand Down
33 changes: 17 additions & 16 deletions examples/account/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
//! cargo run --example account_config
use identity::account::Account;
use identity::account::AccountBuilder;
use identity::account::AccountStorage;
use identity::account::AutoSave;
use identity::account::IdentityCreate;
use identity::account::IdentityState;
use identity::account::IdentitySetup;
use identity::account::Result;
use identity::iota::IotaDID;
use identity::iota::Network;
Expand All @@ -16,24 +16,26 @@ use identity::iota::Network;
async fn main() -> Result<()> {
pretty_env_logger::init();

// Set-up for private Tangle
// Set-up for a private Tangle
// You can use https://github.com/iotaledger/one-click-tangle for a local setup.
// The `network_name` needs to match the id of the network or a part of it.
// As an example we are treating the devnet as a `private-tangle`, so we use `dev`.
// As an example we are treating the devnet as a private tangle, so we use `dev`.
// Replace this with `tangle` if you run this against a one-click private tangle.
let network_name = "dev";
let network = Network::try_from_name(network_name)?;

// In a locally running one-click tangle, this would often be `http://127.0.0.1:14265/`
let private_node_url = "https://api.lb-0.h.chrysalis-devnet.iota.cafe";

// Create a new Account with explicit configuration
let account: Account = Account::builder()
let mut builder: AccountBuilder = Account::builder()
.autosave(AutoSave::Never) // never auto-save. rely on the drop save
.autosave(AutoSave::Every) // save immediately after every action
.autosave(AutoSave::Batch(10)) // save after every 10 actions
.dropsave(false) // save the account state on drop
.autopublish(true) // publish to the tangle automatically on every update
.dropsave(true) // save the account state on drop
.milestone(4) // save a snapshot every 4 actions
.storage(AccountStorage::Memory) // use the default in-memory storage adapter
.storage(AccountStorage::Memory) // use the default in-memory storage
// configure a mainnet Tangle client with node and permanode
.client(Network::Mainnet, |builder| {
builder
Expand All @@ -49,26 +51,25 @@ async fn main() -> Result<()> {
.client(network, |builder| {
// unwrap is safe, we provided a valid node URL
builder.node(private_node_url).unwrap()
})
.build()
.await?;
});

// Create an Identity specifically on the devnet by passing `network_name`
// Create an identity specifically on the devnet by passing `network_name`
// The same applies if we wanted to create an identity on a private tangle
let id_create = IdentityCreate::new().network(network_name)?;
let id_create = IdentitySetup::new().network(network_name)?;

// Create a new Identity with the network name set.
let identity: IdentityState = match account.create_identity(id_create).await {
let identity: Account = match builder.create_identity(id_create).await {
Ok(identity) => identity,
Err(err) => {
eprintln!("[Example] Error: {:?} {}", err, err.to_string());
eprintln!("[Example] Is your Tangle node listening on {}?", private_node_url);
return Ok(());
}
};
let iota_did: &IotaDID = identity.try_did()?;

// Prints the Identity Resolver Explorer URL, the entire history can be observed on this page by "Loading History".
let iota_did: &IotaDID = identity.did();

// Prints the Identity Resolver Explorer URL.
// The entire history can be observed on this page by clicking "Loading History".
println!(
"[Example] Explore the DID Document = {}/{}",
iota_did.network()?.explorer_url().unwrap().to_string(),
Expand Down
23 changes: 12 additions & 11 deletions examples/account/create_did.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use std::path::PathBuf;

use identity::account::Account;
use identity::account::AccountStorage;
use identity::account::IdentityCreate;
use identity::account::IdentityState;
use identity::account::IdentitySetup;
use identity::account::Result;
use identity::iota::IotaDID;

Expand All @@ -23,30 +22,32 @@ async fn main() -> Result<()> {
let stronghold_path: PathBuf = "./example-strong.hodl".into();
let password: String = "my-password".into();

// Create a new Account with the default configuration
// Create a new identity using Stronghold as local storage.
//
// The creation step generates a keypair, builds an identity
// and publishes it to the IOTA mainnet.
let account: Account = Account::builder()
.storage(AccountStorage::Stronghold(stronghold_path, Some(password)))
.build()
.create_identity(IdentitySetup::default())
.await?;

// Create a new Identity with default settings
//
// This step generates a keypair, creates an identity and publishes it to the IOTA mainnet.
let identity: IdentityState = account.create_identity(IdentityCreate::default()).await?;
let iota_did: &IotaDID = identity.try_did()?;
// Retrieve the did of the newly created identity.
let iota_did: &IotaDID = account.did();

// Print the local state of the DID Document
println!(
"[Example] Local Document from {} = {:#?}",
iota_did,
identity.to_document()
account.state().await?.to_document()
);

// Prints the Identity Resolver Explorer URL, the entire history can be observed on this page by "Loading History".
// Prints the Identity Resolver Explorer URL.
// The entire history can be observed on this page by clicking "Loading History".
println!(
"[Example] Explore the DID Document = {}/{}",
iota_did.network()?.explorer_url().unwrap().to_string(),
iota_did.to_string()
);

Ok(())
}
31 changes: 14 additions & 17 deletions examples/account/lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ use std::path::PathBuf;

use identity::account::Account;
use identity::account::AccountStorage;
use identity::account::IdentityCreate;
use identity::account::IdentityState;
use identity::account::IdentitySetup;
use identity::account::Result;
use identity::core::Url;
use identity::iota::IotaDID;
Expand All @@ -23,21 +22,15 @@ async fn main() -> Result<()> {
// 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()
let mut account: Account = Account::builder()
.storage(AccountStorage::Stronghold(stronghold_path, Some(password)))
.autopublish(false)
.build()
.create_identity(IdentitySetup::default())
.await?;

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

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

// Add a new service to the local DID document.
account
.update_identity(iota_did)
.update_identity()
.create_service()
.fragment("example-service")
.type_("LinkedDomains")
Expand All @@ -47,11 +40,11 @@ async fn main() -> Result<()> {

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

// Add another service.
account
.update_identity(iota_did)
.update_identity()
.create_service()
.fragment("another-service")
.type_("LinkedDomains")
Expand All @@ -61,16 +54,20 @@ async fn main() -> Result<()> {

// Delete the previously added service.
account
.update_identity(iota_did)
.update_identity()
.delete_service()
.fragment("example-service")
.apply()
.await?;

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

// Retrieve the DID from the newly created identity.
let iota_did: &IotaDID = account.did();

// Prints the Identity Resolver Explorer URL, the entire history can be observed on this page by "Loading History".
// Prints the Identity Resolver Explorer URL.
// The entire history can be observed on this page by clicking "Loading History".
println!(
"[Example] Explore the DID Document = {}/{}",
iota_did.network()?.explorer_url().unwrap().to_string(),
Expand Down
27 changes: 12 additions & 15 deletions examples/account/manipulate_did.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use std::path::PathBuf;

use identity::account::Account;
use identity::account::AccountStorage;
use identity::account::IdentityCreate;
use identity::account::IdentityState;
use identity::account::IdentitySetup;
use identity::account::Result;
use identity::core::Url;
use identity::did::MethodScope;
Expand All @@ -27,32 +26,26 @@ async fn main() -> Result<()> {
let password: String = "my-password".into();

// Create a new Account with the default configuration
let account: Account = Account::builder()
let mut account: Account = Account::builder()
.storage(AccountStorage::Stronghold(stronghold_path, Some(password)))
.build()
.create_identity(IdentitySetup::default())
.await?;

// Create a new Identity with default settings
//
// This step generates a keypair, creates an identity and publishes it to the IOTA mainnet.
let identity: IdentityState = account.create_identity(IdentityCreate::default()).await?;
let iota_did: &IotaDID = identity.try_did()?;

// ===========================================================================
// Identity Manipulation
// ===========================================================================

// Add another Ed25519 verification method to the identity
account
.update_identity(&iota_did)
.update_identity()
.create_method()
.fragment("my-next-key")
.apply()
.await?;

// Associate the newly created method with additional verification relationships
account
.update_identity(&iota_did)
.update_identity()
.attach_method()
.fragment("my-next-key")
.scope(MethodScope::CapabilityDelegation)
Expand All @@ -62,7 +55,7 @@ async fn main() -> Result<()> {

// Add a new service to the identity.
account
.update_identity(&iota_did)
.update_identity()
.create_service()
.fragment("my-service-1")
.type_("MyCustomService")
Expand All @@ -72,13 +65,17 @@ async fn main() -> Result<()> {

// Remove the Ed25519 verification method
account
.update_identity(&iota_did)
.update_identity()
.delete_method()
.fragment("my-next-key")
.apply()
.await?;

// Prints the Identity Resolver Explorer URL, the entire history can be observed on this page by "Loading History".
// Retrieve the DID from the newly created identity.
let iota_did: &IotaDID = account.did();

// Prints the Identity Resolver Explorer URL.
// The entire history can be observed on this page by clicking "Loading History".
println!(
"[Example] Explore the DID Document = {}/{}",
iota_did.network()?.explorer_url().unwrap().to_string(),
Expand Down
Loading

0 comments on commit 4ce6295

Please sign in to comment.