Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace ClientMap with Client in Account #582

Merged
merged 11 commits into from
Jan 13, 2022
4 changes: 2 additions & 2 deletions bindings/wasm/examples/src/private_tangle.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020-2021 IOTA Stiftung
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import {
Expand Down Expand Up @@ -33,7 +33,7 @@ async function privateTangle(restURL, networkName) {
config.setNetwork(network);

// This URL points to the REST API of the locally running hornet node.
config.setNode(restURL || "http://127.0.0.1:14265/");
config.setPrimaryNode(restURL || "http://127.0.0.1:14265/");

// Use DIDMessageEncoding.Json instead to publish plaintext messages to the Tangle for debugging.
config.setEncoding(DIDMessageEncoding.JsonBrotli);
Expand Down
36 changes: 13 additions & 23 deletions examples/account/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020-2021 IOTA Stiftung
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

//! cargo run --example account_config
Expand All @@ -9,6 +9,7 @@ use identity::account::AccountStorage;
use identity::account::AutoSave;
use identity::account::IdentitySetup;
use identity::account::Result;
use identity::iota::ClientBuilder;
use identity::iota::ExplorerUrl;
use identity::iota::IotaDID;
use identity::iota::Network;
Expand All @@ -30,7 +31,7 @@ async fn main() -> Result<()> {
// If you deployed an explorer locally this would usually be `http://127.0.0.1:8082`
let explorer = ExplorerUrl::parse("https://explorer.iota.org/devnet")?;

// In a locally running one-click tangle, this would often be `http://127.0.0.1:14265`
// In a locally running one-click tangle, this would usually 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
Expand All @@ -41,28 +42,17 @@ async fn main() -> Result<()> {
.autopublish(true) // publish to the tangle automatically on every update
.milestone(4) // save a snapshot every 4 actions
.storage(AccountStorage::Memory) // use the default in-memory storage
// configure a mainnet Tangle client with node and permanode
.client(Network::Mainnet, |builder| {
builder
// Manipulate this in order to manually appoint nodes
.node("https://chrysalis-nodes.iota.org")
.unwrap() // unwrap is safe, we provided a valid node URL
// Set a permanode from the same network (Important)
.permanode("https://chrysalis-chronicle.iota.org/api/mainnet/", None, None)
.unwrap() // unwrap is safe, we provided a valid permanode URL
})
// Configure a client for the private network, here `dev`
// Also set the URL that points to the REST API of the node
.client(network.clone(), |builder| {
// unwrap is safe, we provided a valid node URL
builder.node(private_node_url).unwrap()
});
.client_builder(
// Configure a client for the private network
ClientBuilder::new()
.network(network.clone())
.primary_node(private_node_url, None, None)?
// .permanode(<permanode_url>, None, None)? // set a permanode for the same network
);

// 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 identity_setup: IdentitySetup = IdentitySetup::new().network(network_name)?;

let identity: Account = match builder.create_identity(identity_setup).await {
// Create an identity and publish it.
// The created DID will use the network name configured for the client.
let identity: Account = match builder.create_identity(IdentitySetup::default()).await {
Ok(identity) => identity,
Err(err) => {
eprintln!("[Example] Error: {:?}", err);
Expand Down
6 changes: 3 additions & 3 deletions examples/low-level-api/private_tangle.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020-2021 IOTA Stiftung
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

//! A basic example that generates and publishes a DID Document
Expand Down Expand Up @@ -31,7 +31,7 @@ pub async fn main() -> Result<()> {
// If you deployed an explorer locally this would usually be `http://127.0.0.1:8082`
let explorer = ExplorerUrl::parse("https://explorer.iota.org/devnet")?;

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

// Use DIDMessageEncoding::Json instead to publish plaintext messages to the Tangle for debugging.
Expand All @@ -40,7 +40,7 @@ pub async fn main() -> Result<()> {
let client = ClientBuilder::new()
.network(network.clone())
.encoding(encoding)
.node(private_node_url)?
.primary_node(private_node_url, None, None)?
.build()
.await?;

Expand Down
51 changes: 29 additions & 22 deletions identity-account/src/account/account.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020-2021 IOTA Stiftung
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use std::sync::atomic::AtomicUsize;
Expand All @@ -16,15 +16,12 @@ use identity_iota::document::IotaDocument;
use identity_iota::document::IotaVerificationMethod;
use identity_iota::document::ResolvedIotaDocument;
use identity_iota::tangle::Client;
use identity_iota::tangle::ClientMap;
use identity_iota::tangle::MessageId;
use identity_iota::tangle::MessageIdExt;
use identity_iota::tangle::PublishType;
use identity_iota::tangle::TangleResolve;

use crate::account::AccountBuilder;
use crate::account::PublishOptions;
use crate::error::Result;
use crate::identity::ChainState;
use crate::identity::DIDLease;
use crate::identity::IdentitySetup;
Expand All @@ -35,6 +32,7 @@ use crate::types::KeyLocation;
use crate::updates::create_identity;
use crate::updates::Update;
use crate::Error;
use crate::Result;

use super::config::AccountSetup;
use super::config::AutoSave;
Expand All @@ -48,13 +46,12 @@ use super::AccountConfig;
pub struct Account {
config: AccountConfig,
storage: Arc<dyn Storage>,
client_map: Arc<ClientMap>,
client: Arc<Client>,
actions: AtomicUsize,
chain_state: ChainState,
state: IdentityState,
// The lease is not read, but releases the DID storage lease when the Account is dropped.
_did_lease: DIDLease,
/* This field is not read, but has special behaviour on drop which is why it is needed in
* the Account. */
}

impl Account {
Expand All @@ -77,7 +74,7 @@ impl Account {
Ok(Self {
config: setup.config,
storage: setup.storage,
client_map: setup.client_map,
client: setup.client,
actions: AtomicUsize::new(0),
chain_state,
state,
Expand All @@ -86,14 +83,20 @@ impl Account {
}

/// Creates a new identity and returns an [`Account`] instance to manage it.
/// The identity is stored locally in the [`Storage`] given in [`AccountSetup`], and published
/// using the [`ClientMap`].
///
/// The identity is stored locally in the [`Storage`] given in [`AccountSetup`]. The DID network
/// is automatically determined by the [`Client`] used to publish it.
///
/// See [`IdentitySetup`] to customize the identity creation.
pub(crate) async fn create_identity(setup: AccountSetup, input: IdentitySetup) -> Result<Self> {
let (did_lease, state): (DIDLease, IdentityState) = create_identity(input, setup.storage.as_ref()).await?;
pub(crate) async fn create_identity(account_setup: AccountSetup, identity_setup: IdentitySetup) -> Result<Self> {
let (did_lease, state): (DIDLease, IdentityState) = create_identity(
identity_setup,
account_setup.client.network().name(),
account_setup.storage.as_ref(),
)
.await?;

let mut account = Self::with_setup(setup, ChainState::new(), state, did_lease).await?;
let mut account = Self::with_setup(account_setup, ChainState::new(), state, did_lease).await?;

account.store_state().await?;

Expand All @@ -104,6 +107,15 @@ impl Account {

/// Creates an [`Account`] for an existing identity, if it exists in the [`Storage`].
pub(crate) async fn load_identity(setup: AccountSetup, did: IotaDID) -> Result<Self> {
// Ensure the DID matches the client network.
if did.network_str() != setup.client.network().name_str() {
return Err(Error::IotaError(identity_iota::Error::IncompatibleNetwork(format!(
"DID network {} does not match account network {}",
did.network_str(),
setup.client.network().name_str()
))));
}

// Ensure the did exists in storage
let state = setup.storage.state(&did).await?.ok_or(Error::IdentityNotFound)?;
let chain_state = setup.storage.chain_state(&did).await?.ok_or(Error::IdentityNotFound)?;
Expand Down Expand Up @@ -142,11 +154,6 @@ impl Account {
self.actions.fetch_add(1, Ordering::SeqCst);
}

/// Adds a pre-configured `Client` for Tangle interactions.
pub fn set_client(&self, client: Client) {
self.client_map.insert(client);
}

/// Returns the did of the managed identity.
pub fn did(&self) -> &IotaDID {
self.document().id()
Expand Down Expand Up @@ -185,7 +192,7 @@ impl Account {

/// Resolves the DID Document associated with this `Account` from the Tangle.
pub async fn resolve_identity(&self) -> Result<ResolvedIotaDocument> {
self.client_map.resolve(self.did()).await.map_err(Into::into)
self.client.read_document(self.did()).await.map_err(Into::into)
}

/// Returns the [`IdentityUpdater`] for this identity.
Expand Down Expand Up @@ -270,7 +277,7 @@ impl Account {
/// to the identity, to avoid publishing updates that would be ignored.
pub async fn fetch_state(&mut self) -> Result<()> {
let iota_did: &IotaDID = self.did();
let mut document_chain: DocumentChain = self.client_map.read_document_chain(iota_did).await?;
let mut document_chain: DocumentChain = self.client.read_document_chain(iota_did).await?;
// Checks if the local document is up to date
if document_chain.integration_message_id() == self.chain_state.last_integration_message_id()
&& (document_chain.diff().is_empty()
Expand Down Expand Up @@ -440,7 +447,7 @@ impl Account {
// Fake publishing by returning a random message id.
MessageId::new(unsafe { crypto::utils::rand::gen::<[u8; 32]>().unwrap() })
} else {
self.client_map.publish_document(&new_doc).await?.into()
self.client.publish_document(&new_doc).await?.into()
};

self.chain_state.set_last_integration_message_id(message_id);
Expand Down Expand Up @@ -506,7 +513,7 @@ impl Account {
MessageId::new(unsafe { crypto::utils::rand::gen::<[u8; 32]>().unwrap() })
} else {
self
.client_map
.client
.publish_diff(self.chain_state().last_integration_message_id(), &diff)
.await?
.into()
Expand Down
Loading