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

Improve Network type to support private tangles #360

Merged
merged 32 commits into from
Aug 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5a7aaa7
Make `Network` not `Copy`
PhilippGackstatter Aug 18, 2021
be2c01e
Add `Other` variant in `Network`
PhilippGackstatter Aug 18, 2021
10b48a4
Add node.js DID creation on private tangle example
PhilippGackstatter Aug 18, 2021
881a92e
Add `from_name` in Wasm and fix absence of `Copy`
PhilippGackstatter Aug 18, 2021
5ae4edc
Remove superfluous imports
PhilippGackstatter Aug 18, 2021
e7f181e
Add browser Wasm example
PhilippGackstatter Aug 18, 2021
0bcd82f
Remove old variable
PhilippGackstatter Aug 18, 2021
3d6214a
Add low-level Rust API example
PhilippGackstatter Aug 19, 2021
eb278e0
Format Wasm network source code
PhilippGackstatter Aug 19, 2021
cf3e998
Add account Rust API example
PhilippGackstatter Aug 19, 2021
463314d
Use same ideas for account & low-level examples
PhilippGackstatter Aug 19, 2021
b445f72
Rename `Network::as_str` to `name`
PhilippGackstatter Aug 19, 2021
88b1328
Impl spec compliance check for `Network` names
PhilippGackstatter Aug 20, 2021
c2e5ef5
Change `IotaDID::network` return type to `Result`
PhilippGackstatter Aug 20, 2021
8e6b829
Change bindings according to new return type
PhilippGackstatter Aug 20, 2021
df4c266
Improve Wasm examples with resolution step
PhilippGackstatter Aug 20, 2021
6ce77c8
Add private tangle test
PhilippGackstatter Aug 23, 2021
d8f9431
Add cypress browser test
PhilippGackstatter Aug 23, 2021
48d5aed
Use `?` instead of `unwrap` where possible
PhilippGackstatter Aug 23, 2021
41d04fc
Add explorer url to `Network::Other` variant
PhilippGackstatter Aug 23, 2021
756ac08
Add explorer_url tests
PhilippGackstatter Aug 23, 2021
4472d4b
Merge branch 'dev' into feat/private-tangle-network
PhilippGackstatter Aug 23, 2021
6a22273
Fix `explorer_url` conversion
PhilippGackstatter Aug 23, 2021
13d1306
Fix `message_url` in new examples
PhilippGackstatter Aug 23, 2021
3de21e2
Fix network names in Rust private tangle examples
PhilippGackstatter Aug 23, 2021
2b3cc1c
Update bindings/wasm/examples/node/test.js
PhilippGackstatter Aug 23, 2021
60ca500
Update bindings/wasm/cypress/integration/browser_test.js
PhilippGackstatter Aug 23, 2021
aca013f
Update bindings/wasm/examples/node/private_tangle.js
PhilippGackstatter Aug 23, 2021
696a0a5
Update bindings/wasm/examples/browser/private_tangle.js
PhilippGackstatter Aug 23, 2021
45d1034
Update examples/account/private_tangle.rs
PhilippGackstatter Aug 23, 2021
73d4c63
Update examples/low-level-api/private_tangle.rs
PhilippGackstatter Aug 23, 2021
81a9685
Merge branch 'dev' into feat/private-tangle-network
PhilippGackstatter Aug 23, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions bindings/wasm/cypress/integration/browser_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { createVP } from "../../examples/browser/create_vp.js";
import { createDiff } from "../../examples/browser/diff_chain.js";
import { revoke } from "../../examples/browser/revoke_vc.js";
import { merkleKey } from "../../examples/browser/merkle_key.js";
import { createIdentityPrivateTangle } from "../../examples/browser/private_tangle";
import { resolveHistory } from "../../examples/browser/resolve_history";

// Test that the browser examples do not throw uncaught exceptions twice, including syntax errors etc.
Expand Down Expand Up @@ -83,13 +84,26 @@ describe(
await merkleKey(defaultClientConfig(), false);
}
});

it("private tangle", async function () {
try {
await createIdentityPrivateTangle(false, false)
throw new Error("Did not throw.")
} catch (err) {
// Example is expected to throw an error because no private Tangle is running
expect(err.name).to.eq("ClientError")
expect(err.message).to.contain("error sending request")
}
});

it("diff chain", async function () {
try {
await createDiff(defaultClientConfig(), false);
} catch (e) {
await createDiff(defaultClientConfig(), false);
}
});

it("resolve history", async function () {
try {
await resolveHistory(defaultClientConfig(), false);
Expand Down
2 changes: 1 addition & 1 deletion bindings/wasm/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ The following examples are currently available:
| 7 | [revoke_vc](node/revoke_vc.js) | Remove a verification method from the Issuers DID Document, making the Verifiable Credential it signed unable to verify, effectively revoking the VC. |
| 8 | [resolution](node/resolution.js) | Resolves an existing DID to return the latest DID Document. |
| 9 | [merkle_key](node/merkle_key.js) | Adds a MerkleKeyCollection verification method to an Issuers DID Document and signs a Verifiable Credential with the key on index 0. Afterwards the key on index 0 is deactivated, making the Verifiable Credential fail its verification. |

| 10 | [private_tangle](node/private_tangle.js) | Showcases the same procedure as `create_did`, but on a private tangle - a locally running hornet node. |


### Browser Examples
Expand Down
7 changes: 6 additions & 1 deletion bindings/wasm/examples/browser/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@

<button class="ma-md block" id="merkle_key_btn">Merkle Key</button>

<div class="ma-md">
<input placeholder="Private Tangle REST API URL" id="create-private-rest-url" />
<input placeholder="Private Tangle Network Name" id="create-private-network-name" />
<button class="ma-md block" id="private_tangle_btn">Create DID on Private Tangle</button>
</div>

<button class="ma-md block" id="diff_chain_btn">
Diff Chain
</button>
Expand All @@ -55,7 +61,6 @@
Resolve History
</button>


<button
class="ma-md block"
id="clear_output"
Expand Down
6 changes: 6 additions & 0 deletions bindings/wasm/examples/browser/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { resolveIdentity } from "./resolve.js";
import { createVP } from "./create_vp.js";
import { revoke } from "./revoke_vc.js";
import { merkleKey } from "./merkle_key.js";
import { createIdentityPrivateTangle } from "./private_tangle.js";
import { createDiff } from "./diff_chain.js";
import { resolveHistory } from "./resolve_history.js";

Expand Down Expand Up @@ -47,6 +48,11 @@ document
.querySelector("#merkle_key_btn")
.addEventListener("click", () => merkleKey(clientConfig));

//handle private tangle DID creation on click event
document
.querySelector("#private_tangle_btn")
.addEventListener("click", () => createIdentityPrivateTangle());
PhilippGackstatter marked this conversation as resolved.
Show resolved Hide resolved

//handle diff chain on click event
document
.querySelector("#diff_chain_btn")
Expand Down
64 changes: 64 additions & 0 deletions bindings/wasm/examples/browser/private_tangle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2020-2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { Client, Config, Document, KeyType, Network } from "../../web/identity_wasm.js";
import {
logObjectToScreen,
logToScreen,
} from "./utils.js";

/**
This example shows how a DID document can be created on a private tangle.
It can be run together with a local hornet node.
Refer to https://github.com/iotaledger/one-click-tangle/tree/chrysalis/hornet-private-net
for setup instructions.
**/
export async function createIdentityPrivateTangle(inBrowser = true, log = true) {
if (log) logToScreen("Identity creation started...");
if (log) logToScreen("This might take a few seconds to complete proof of work!");

let restURL
let networkName

if (inBrowser) {
// Get the required parameters from the input fields
restURL = document.querySelector("#create-private-rest-url").value;
networkName = document.querySelector("#create-private-network-name").value;
} else {
restURL = "http://127.0.0.1:14265/";
networkName = "custom";
}

// This is an arbitrarily defined network name
const network = Network.from_name(networkName);

// Create a DID Document (an identity).
const { doc, key } = new Document(KeyType.Ed25519, network.toString());

// Sign the DID Document with the generated key.
doc.sign(key);

// Create a client configuration and set the custom network.
const config = new Config();
config.setNetwork(network);

// This URL should point to the REST API of a node.
config.setNode(restURL);

PhilippGackstatter marked this conversation as resolved.
Show resolved Hide resolved
// Create a client instance from the configuration to publish messages to the Tangle.
const client = Client.fromConfig(config);

// Publish the Identity to the IOTA Network, this may take a few seconds to complete Proof-of-Work.
const receipt = await client.publishDocument(doc.toJSON());

PhilippGackstatter marked this conversation as resolved.
Show resolved Hide resolved
if (log) logToScreen("Identity creation done!");

// Make sure the DID can be resolved on the private tangle
const resolved = await client.resolve(doc.id.toString());

if (log) logToScreen("Resolved DID document:");
if (log) logObjectToScreen(resolved);

// Return the results.
return { key, doc, receipt };
}
3 changes: 3 additions & 0 deletions bindings/wasm/examples/node/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

const {createIdentity} = require("./create_did");
const {manipulateIdentity} = require("./manipulate_did");
const {createIdentityPrivateTangle} = require("./private_tangle");
const {resolution} = require("./resolution");
const {createVC} = require("./create_vc");
const {createVP} = require("./create_vp");
Expand Down Expand Up @@ -35,6 +36,8 @@ async function main() {
return await createVP(CLIENT_CONFIG);
case "merkle_key":
return await merkleKey(CLIENT_CONFIG);
case "private_tangle":
return await createIdentityPrivateTangle();
case "resolve_history":
return await resolveHistory(CLIENT_CONFIG);
case "diff_chain":
Expand Down
42 changes: 42 additions & 0 deletions bindings/wasm/examples/node/private_tangle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2020-2021 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

const { Client, Config, Document, KeyType, Network } = require('../../node/identity_wasm')

/**
This example shows how a DID document can be created on a private tangle.
It can be run together with a local hornet node.
Refer to https://github.com/iotaledger/one-click-tangle/tree/chrysalis/hornet-private-net
for setup instructions.
**/
async function createIdentityPrivateTangle() {
// This is an arbitrarily defined network name
const network = Network.from_name("custom");

// Create a DID Document (an identity).
const { doc, key } = new Document(KeyType.Ed25519, network.toString());

// Sign the DID Document with the generated key.
doc.sign(key);

// Create a client configuration and set the custom network.
const config = new Config();
config.setNetwork(network);

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

// Create a client instance from the configuration to publish messages to the Tangle.
const client = Client.fromConfig(config);

// Publish the Identity to the IOTA Network, this may take a few seconds to complete Proof-of-Work.
const receipt = await client.publishDocument(doc.toJSON());

// Make sure the DID can be resolved on the private tangle
const resolved = await client.resolve(doc.id.toString());

// Return the results.
return { key, resolved, receipt };
}

exports.createIdentityPrivateTangle = createIdentityPrivateTangle;
11 changes: 11 additions & 0 deletions bindings/wasm/examples/node/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const { revokeVC } = require("./revoke_vc");
const { merkleKey } = require("./merkle_key");
const { resolveHistory } = require("./resolve_history");
const { CLIENT_CONFIG } = require("./config");
const { createIdentityPrivateTangle } = require("./private_tangle");

jest.setTimeout(180000); // 3 minutes to account for spurious network delays, most tests pass in a few seconds

Expand Down Expand Up @@ -63,6 +64,16 @@ test.concurrent("Merkle Key", async () => {
await merkleKey(CLIENT_CONFIG);
}
});
test.concurrent("Private Tangle", async () => {
try {
await createIdentityPrivateTangle()
throw new Error("Did not throw.")
} catch (err) {
// Example is expected to throw an error because no private Tangle is running
expect(err.name).toEqual("ClientError")
expect(err.message).toContain("error sending request")
}
});
test.concurrent("Diff Chain", async () => {
try {
await createDiff(CLIENT_CONFIG);
Expand Down
4 changes: 2 additions & 2 deletions bindings/wasm/src/did/wasm_did.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ impl WasmDID {

/// Returns the IOTA tangle network of the `DID`.
#[wasm_bindgen(getter)]
pub fn network(&self) -> WasmNetwork {
self.0.network().into()
pub fn network(&self) -> Result<WasmNetwork, JsValue> {
self.0.network().map(Into::into).map_err(wasm_error)
}

/// Returns the IOTA tangle network of the `DID`.
Expand Down
2 changes: 1 addition & 1 deletion bindings/wasm/src/tangle/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl Config {

#[wasm_bindgen(js_name = setNetwork)]
pub fn set_network(&mut self, network: &WasmNetwork) -> Result<(), JsValue> {
self.with_mut(|builder| builder.network((*network).into()))
self.with_mut(|builder| builder.network(network.clone().into()))
}

#[wasm_bindgen(js_name = setNode)]
Expand Down
28 changes: 20 additions & 8 deletions bindings/wasm/src/tangle/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ use identity::iota::Network as IotaNetwork;

use wasm_bindgen::prelude::*;

use crate::error::wasm_error;

#[wasm_bindgen(js_name = Network)]
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Debug)]
pub struct WasmNetwork(IotaNetwork);

#[wasm_bindgen(js_class = Network)]
impl WasmNetwork {
#[wasm_bindgen]
pub fn from_name(string: &str) -> Result<WasmNetwork, JsValue> {
let network = IotaNetwork::from_name(string).map_err(wasm_error)?;
Ok(Self(network))
}

#[wasm_bindgen]
pub fn mainnet() -> WasmNetwork {
Self(IotaNetwork::Mainnet)
Expand All @@ -23,26 +31,30 @@ impl WasmNetwork {

/// Returns the node URL of the Tangle network.
#[wasm_bindgen(getter = defaultNodeURL)]
pub fn default_node_url(&self) -> String {
self.0.default_node_url().to_string()
pub fn default_node_url(&self) -> Option<String> {
self.0.default_node_url().map(ToString::to_string)
}

/// Returns the web explorer URL of the Tangle network.
#[wasm_bindgen(getter = explorerURL)]
pub fn explorer_url(&self) -> String {
self.0.explorer_url().to_string()
pub fn explorer_url(&self) -> Result<String, JsValue> {
self.0.explorer_url().map(|url| url.to_string()).map_err(wasm_error)
}

/// Returns the web explorer URL of the given `message`.
#[wasm_bindgen(js_name = messageURL)]
pub fn message_url(&self, message_id: &str) -> String {
self.0.message_url(message_id).to_string()
pub fn message_url(&self, message_id: &str) -> Result<String, JsValue> {
self
.0
.message_url(message_id)
.map(|url| url.to_string())
.map_err(wasm_error)
}

#[allow(clippy::inherent_to_string, clippy::wrong_self_convention)]
#[wasm_bindgen(js_name = toString)]
pub fn to_string(&self) -> String {
self.0.as_str().into()
self.0.name().into()
}
}

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

[[example]]
name = "account_private_tangle"
path = "account/private_tangle.rs"

[[example]]
name = "create_did"
path = "low-level-api/create_did.rs"
Expand Down Expand Up @@ -70,6 +74,10 @@ path = "low-level-api/merkle_key.rs"
name = "resolution"
path = "low-level-api/resolution.rs"

[[example]]
name = "private_tangle"
path = "low-level-api/private_tangle.rs"

[[example]]
name = "revoke_vc"
path = "low-level-api/revoke_vc.rs"
Loading