Skip to content

Commit

Permalink
Extend and refactor Stardust examples (#981)
Browse files Browse the repository at this point in the history
* Commit example for testing/debugging

* Working alias-controls-alias example

* Impl `StardustDID` -> `AliasId` conversion

* Add more (unfinished) examples

* Fix native assets example

* Remove adding Sender Feature by default

* Polish alias-controls-alias example

* Use latest draft PR commit

* Use `AliasId::from` instead of `AliasId::try_from`

* Use `iota-client` crates version

* Add token issue example

* Add nft owns did example

* Rename examples

* Refactor examples into separate project

* Polish examples

* Rename examples stardust directory

* Update CI examples instructions

* Remove `./`

* Remove unknown clippy lint

* Polish examples

* Polish utils

* Remove unused manifest key in examples

* Polish examples more

* Revert "Remove unknown clippy lint"

This reverts commit 7dd77e9.

* Remove dedicated stardust build step in CI

* Integrated stardust crates into root workspace

* Bump bee-block version to match iota-client

* Impl `From` for re-exported `AliasId`

* Inline NFT example creation

* Use Stronghold secret manager

* Use double-digits in example names

* Improve examples with suggestions

* Remove unnecessary CI steps

* Rename package to `examples`

* Add examples README

* Number sub-folders

* Improve variable names in DPP example

* Use single-digit within folders after all

* Rename old examples to examples_legacy

* Add key exchange example

* Rename example stronghold file

* Use network bech 32 in utils

* Use Shimmer Testnet

* Use "basic" instead of "crud" folder name

* Fix links to examples in Wiki

* Use new banner

* Fix example paths in CI

* Use Shimmer Testnet in Wasm examples

* Clarify issuer feature in example

* Use explicit digit regex

* Remove stronghold file in CI

* Revert "Remove stronghold file in CI"

This reverts commit e7ee199.

* Improve examples README

* Revert "Revert "Remove stronghold file in CI""

This reverts commit ef80751.

* Enable `fs` tokio feature

* Remove stronghold removal for CI

* Use random stronghold paths
  • Loading branch information
PhilippGackstatter authored Aug 24, 2022
1 parent 9a7e68d commit 67a3bf5
Show file tree
Hide file tree
Showing 57 changed files with 1,218 additions and 294 deletions.
57 changes: 4 additions & 53 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,67 +114,18 @@ jobs:
# run examples only on ubuntu for now
if: matrix.os == 'ubuntu-latest'
run: |
cargo read-manifest --manifest-path ./examples/Cargo.toml | \
cargo read-manifest --manifest-path ./examples_legacy/Cargo.toml | \
jq -r '.targets[].name' | \
parallel -k -j 4 --retries 3 cargo run --example {} --all-features --release
- name: Stop sccache
uses: './.github/actions/rust/sccache/stop-sccache'
with:
os: ${{matrix.os}}

build-and-test-stardust:
needs: [ check-for-run-condition, check-for-modification ]
if: ${{ needs.check-for-run-condition.outputs.should-run == 'true' && needs.check-for-modification.outputs.core-modified == 'true' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
include:
- os: ubuntu-latest
sccache-path: /home/runner/.cache/sccache
env:
SCCACHE_DIR: ${{ matrix.sccache-path }}
RUSTC_WRAPPER: sccache

steps:
- uses: actions/checkout@v2

- name: Setup Rust and cache
uses: './.github/actions/rust/rust-setup'
with:
os: ${{ runner.os }}
job: ${{ github.job }}
target-cache-enabled: false
sccache-enabled: true
sccache-path: ${{ matrix.sccache-path }}

- name: Setup sccache
uses: './.github/actions/rust/sccache/setup-sccache'
with:
os: ${{matrix.os}}

- name: Build Stardust
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path ./identity_stardust/Cargo.toml --workspace --tests --examples --all-features --release

- name: Run Stardust tests
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path ./identity_stardust/Cargo.toml --workspace --all-features --release

- name: Run Stardust Rust examples
# run examples only on ubuntu for now
if: matrix.os == 'ubuntu-latest'
run: |
cargo read-manifest --manifest-path ./identity_stardust/Cargo.toml | \
cargo read-manifest --manifest-path ./examples/Cargo.toml | \
jq -r '.targets[].name' | \
awk '$1 ~ /ex.*/' | \
parallel -k -j 4 --retries 3 cargo run --manifest-path ./identity_stardust/Cargo.toml --example {} --all-features --release
awk '$1 ~ /[0-9].*/' | \
parallel -k -j 4 --retries 3 cargo run --manifest-path ./examples/Cargo.toml --example {} --all-features --release
- name: Stop sccache
uses: './.github/actions/rust/sccache/stop-sccache'
Expand Down
7 changes: 0 additions & 7 deletions .github/workflows/clippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,6 @@ jobs:
args: --all-targets --all-features -- -D warnings
name: core

- name: Stardust clippy check
uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --manifest-path ./identity_stardust/Cargo.toml --all-targets --all-features -- -D warnings
name: stardust

- name: Wasm clippy check
uses: actions-rs/clippy-check@v1
with:
Expand Down
6 changes: 0 additions & 6 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,6 @@ jobs:
command: fmt
args: --all -- --check

- name: Stardust fmt check
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path ./identity_stardust/Cargo.toml --all -- --check

- name: wasm fmt check
uses: actions-rs/cargo@v1
with:
Expand Down
Binary file removed .meta/identity_banner.png
Binary file not shown.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ members = [
"identity_iota",
"identity_iota_client",
"identity_iota_core",
"identity_stardust",

"examples_legacy",
"examples",
]

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![banner](https://github.com/iotaledger/identity.rs/raw/HEAD/.meta/identity_banner.png)
![banner](https://github.com/iotaledger/identity.rs/raw/HEAD/documentation/static/img/Banner/banner_identity.svg)

<p align="center">
<a href="https://iota.stackexchange.com/" style="text-decoration:none;"><img src="https://img.shields.io/badge/StackExchange-9cf.svg?logo=stackexchange" alt="StackExchange"></a>
Expand Down
2 changes: 1 addition & 1 deletion bindings/wasm/examples-account/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![banner](./../../../.meta/identity_banner.png)
![banner](./../../../documentation/static/img/Banner/banner_identity.svg)


## IOTA Identity Account Examples
Expand Down
2 changes: 1 addition & 1 deletion bindings/wasm/examples-stardust/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![banner](./../../../.meta/identity_banner.png)
![banner](./../../../documentation/static/img/Banner/banner_identity.svg)

## IOTA Identity UTXO Examples

Expand Down
5 changes: 2 additions & 3 deletions bindings/wasm/examples-stardust/src/ex0_create_did.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ import {Bip39} from "@iota/crypto.js";
import fetch from "node-fetch";
import {Client, MnemonicSecretManager, SecretManager} from "@cycraig/iota-client-wasm/node";

const EXPLORER = "https://explorer.alphanet.iotaledger.net/alphanet";
const API_ENDPOINT = "https://api.alphanet.iotaledger.net/";
const FAUCET = "https://faucet.alphanet.iotaledger.net/api/enqueue";
const API_ENDPOINT = "https://api.testnet.shimmer.network/";
const FAUCET = "https://faucet.testnet.shimmer.network/api/enqueue";

/** Demonstrate how to create a DID Document and publish it in a new Alias Output. */
export async function createIdentity(): Promise<{
Expand Down
2 changes: 1 addition & 1 deletion bindings/wasm/examples/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![banner](./../../../.meta/identity_banner.png)
![banner](./../../../documentation/static/img/Banner/banner_identity.svg)

## IOTA Identity Examples

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ keywords:
- Publish
---
import CodeSnippet from '../../../src/components/CodeSnippetComponent'
import createDidRustExample from '!!raw-loader!../../../../examples/account/create_did.rs';
import createDidRustExample from '!!raw-loader!../../../../examples_legacy/account/create_did.rs';

When someone or something wants to benefit from Self-Sovereign Identity, they must first create a Decentralized Identity. This identity consists of many parts that have different functions. This page will cover both the basics and the details about identity creation, storage, and publishing to the Tangle.

Expand All @@ -29,7 +29,7 @@ Select your programming language of choice and press the green play button to ex
nodeReplitLink="https://repl.it/@IOTAFoundation/create-did?lite=true"
rustContent={createDidRustExample}
nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/create_did.ts"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/create_did.rs"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/create_did.rs"
/>

The first step in this example is the creation of an account. This acts as a stateful object that manages one or more identities. The account provides an interface to execute high-level operations on identities, such as creating, updating, and storing them.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
import private_tangle_js from '!!raw-loader!../../../../bindings/wasm/examples/src/private_tangle.js';
import private_tangle_rs from '!!raw-loader!../../../../examples/low-level-api/private_tangle.rs';
import account_private_tangle_rs from '!!raw-loader!../../../../examples/account/config.rs';
import private_tangle_rs from '!!raw-loader!../../../../examples_legacy/low-level-api/private_tangle.rs';
import account_private_tangle_rs from '!!raw-loader!../../../../examples_legacy/account/config.rs';

## Example

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ image: /img/Identity_icon.png
keywords:
- Resolve
---
import resolve_did_rs from '!!raw-loader!../../../../examples/low-level-api/resolve_did.rs';
import resolve_history_rs from '!!raw-loader!../../../../examples/low-level-api/resolve_history.rs';
import resolve_did_rs from '!!raw-loader!../../../../examples_legacy/low-level-api/resolve_did.rs';
import resolve_history_rs from '!!raw-loader!../../../../examples_legacy/low-level-api/resolve_history.rs';
import resolve_did_js from '!!raw-loader!../../../../bindings/wasm/examples/src/resolve_did.js';
import resolve_history_js from '!!raw-loader!../../../../bindings/wasm/examples/src/resolve_history.js';
import CodeSnippet from '../../../src/components/CodeSnippetComponent'
Expand Down Expand Up @@ -61,7 +61,7 @@ What happens in this example can be explained on a high level as follows: The Re

## Resolving from a private tangle
Resolving a DID from a private tangle is similar to resolving a DID from the main net. The only difference is that
the resolver needs to be configured to have a client capable of operating on said private tangle. Building a `Client` configured for a specified Tangle is explained in [this example in Rust](https://github.com/iotaledger/identity.rs/blob/dev/examples/low-level-api/private_tangle.rs) and [this example in Javascript](https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples/src/private_tangle.js).
the resolver needs to be configured to have a client capable of operating on said private tangle. Building a `Client` configured for a specified Tangle is explained in [this example in Rust](https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/low-level-api/private_tangle.rs) and [this example in Javascript](https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples/src/private_tangle.js).

The following example demonstrates how one can setup a `Resolver` with a given `client` and then attempt resolving a specified `did` which may be on any Tangle (public or private).
<Tabs>
Expand Down Expand Up @@ -168,7 +168,7 @@ This section shows complete examples from the Iota Identity Framework code base.
nodeReplitLink="https://repl.it/@IOTAFoundation/resolve-did?lite=true"
rustContent={resolve_did_rs}
nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples/src/resolve_did.js"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/low-level-api/resolve_did.rs"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/low-level-api/resolve_did.rs"
/>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ keywords:
- Update
- Publish
---
import account_manipulate_did_rs from '!!raw-loader!../../../../examples/account/manipulate_did.rs';
import account_manipulate_did_rs from '!!raw-loader!../../../../examples_legacy/account/manipulate_did.rs';
import CodeSnippet from '../../../src/components/CodeSnippetComponent'
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
Expand Down Expand Up @@ -72,7 +72,7 @@ The following example demonstrates adding verification methods and services to a
nodeReplitLink="https://repl.it/@IOTAFoundation/manipulate-did?lite=true"
rustContent={account_manipulate_did_rs}
nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/manipulate_did.ts"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/manipulate_did.rs"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/manipulate_did.rs"
/>

### Creating Identity
Expand Down Expand Up @@ -404,5 +404,5 @@ Furthermore and similar to deleting verification methods, services can be delete

:::tip
In this example, a message is published to the tangle every time the document is updated. These messages can be unnecessary. Instead, one message can be published that contains all the updates to the DID Document.
See the [lazy example for Rust](https://github.com/iotaledger/identity.rs/blob/dev/examples/account/lazy.rs) and [lazy example for JS](https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/lazy.ts) to learn more about lazy publishing.
See the [lazy example for Rust](https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/lazy.rs) and [lazy example for JS](https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/lazy.ts) to learn more about lazy publishing.
:::
4 changes: 2 additions & 2 deletions documentation/docs/concepts/verifiable_credentials/create.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ keywords:
- Create
- sign
---
import create_vc_rs from '!!raw-loader!../../../../examples/account/create_vc.rs';
import create_vc_rs from '!!raw-loader!../../../../examples_legacy/account/create_vc.rs';
import CodeSnippet from '../../../src/components/CodeSnippetComponent'

A [verifiable credential (VC)](./overview.md) can represent all information that a physical credential represents, such as a passport or university degree. However, by allowing other parties to cryptographically verify the authorship and integrity of the claims, verifiable credentials can be seen as more tamper-evident and more trustworthy than their physical counterparts.
Expand Down Expand Up @@ -82,5 +82,5 @@ This Verifiable Credential can be [verified by anyone](./verifiable_presentation
nodeReplitLink="https://repl.it/@IOTAFoundation/create-vc?lite=true"
rustContent={create_vc_rs}
nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/create_vc.ts"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/create_vc.rs"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/create_vc.rs"
/>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ keywords:
- revocation
---

import revoke_vc_rs from "!!raw-loader!../../../../examples/account/revoke_vc.rs";
import revoke_vc_rs from "!!raw-loader!../../../../examples_legacy/account/revoke_vc.rs";
import CodeSnippet from "../../../src/components/CodeSnippetComponent";

## Overview
Expand Down Expand Up @@ -58,5 +58,5 @@ The following code exemplifies how you can revoke a [Verifiable Credential (VC)]
nodeReplitLink="https://replit.com/@IOTAFoundation/revoke-vc-06?lite=true"
rustContent={revoke_vc_rs}
nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/revoke_vc.ts"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/revoke_vc.rs"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/revoke_vc.rs"
/>
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ keywords:
- verifiable
- presentations
---
import create_vp_rs from '!!raw-loader!../../../../examples/account/create_vp.rs';
import create_vp_rs from '!!raw-loader!../../../../examples_legacy/account/create_vp.rs';
import CodeSnippet from '../../../src/components/CodeSnippetComponent'

A verifiable presentation is the recommended data format for sharing one or more [verifiable credentials](./overview.md).
Expand Down Expand Up @@ -169,5 +169,5 @@ serialize it to JSON for transmission, deserialize it on the receiving side as a
nodeReplitLink="https://repl.it/@IOTAFoundation/create-vp?lite=true"
rustContent={create_vp_rs}
nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/create_vp.ts"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/create_vp.rs"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/create_vp.rs"
/>
4 changes: 2 additions & 2 deletions documentation/docs/getting_started/create_and_publish.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ keywords:
- Publish
---
import CodeSnippet from '../../src/components/CodeSnippetComponent'
import createDidRustExample from '!!raw-loader!../../../examples/account/create_did.rs';
import createDidRustExample from '!!raw-loader!../../../examples_legacy/account/create_did.rs';

If you want to benefit from Self-Sovereign Identity, you need to create a [Decentralized Identity](../concepts/decentralized_identifiers/overview). This identity consists of many parts that have different functions. This page will cover the basics about identity creation and publishing to the Tangle.

Expand All @@ -33,7 +33,7 @@ Select your programming language of choice and press the green play button to ex
nodeReplitLink="https://repl.it/@IOTAFoundation/create-did?lite=true"
rustContent={createDidRustExample}
nodeGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/bindings/wasm/examples-account/src/create_did.ts"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples/account/create_did.rs"
rustGithubLink = "https://github.com/iotaledger/identity.rs/blob/dev/examples_legacy/account/create_did.rs"
/>

The first step in this example is the creation of an account. The account is a stateful object that manages one or more identities. The account provides an interface to execute high-level operations on identities, such as [creating](../concepts/decentralized_identifiers/create) and [updating](../concepts/decentralized_identifiers/update)) them.
Expand Down
64 changes: 64 additions & 0 deletions examples/0_basic/0_create_did.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2020-2022 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use anyhow::Context;
use examples::get_address_with_funds;
use examples::random_stronghold_path;
use examples::NETWORK_ENDPOINT;
use identity_core::convert::ToJson;
use identity_core::crypto::KeyPair;
use identity_core::crypto::KeyType;
use identity_did::verification::MethodScope;
use identity_stardust::NetworkName;
use identity_stardust::StardustClientExt;
use identity_stardust::StardustDocument;
use identity_stardust::StardustIdentityClientExt;
use identity_stardust::StardustVerificationMethod;
use iota_client::block::address::Address;
use iota_client::block::output::AliasOutput;
use iota_client::secret::stronghold::StrongholdSecretManager;
use iota_client::secret::SecretManager;
use iota_client::Client;

/// Demonstrates how to create a DID Document and publish it in a new Alias Output.
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Create a new client to interact with the IOTA ledger.
let client: Client = Client::builder().with_primary_node(NETWORK_ENDPOINT, None)?.finish()?;

// Create a new secret manager backed by a Stronghold.
let mut secret_manager: SecretManager = SecretManager::Stronghold(
StrongholdSecretManager::builder()
.password("secure_password")
.try_build(random_stronghold_path())?,
);

// Get an address and with funds for testing.
let address: Address = get_address_with_funds(&client, &mut secret_manager)
.await
.context("failed to get address with funds")?;

// Get the Bech32 human-readable part (HRP) of the network.
let network_name: NetworkName = client.network_name().await?;

// Create a new DID document with a placeholder DID.
// The DID will be derived from the Alias Id of the Alias Output after publishing.
let mut document: StardustDocument = StardustDocument::new(&network_name);

// Insert a new Ed25519 verification method in the DID document.
let keypair: KeyPair = KeyPair::new(KeyType::Ed25519)?;
let method: StardustVerificationMethod =
StardustVerificationMethod::new(document.id().clone(), keypair.type_(), keypair.public(), "#key-1")?;
document.insert_method(method, MethodScope::VerificationMethod)?;

// Construct an Alias Output containing the DID document, with the wallet address
// set as both the state controller and governor.
let alias_output: AliasOutput = client.new_did_output(address, document, None).await?;
println!("Alias Output: {}", alias_output.to_json()?);

// Publish the Alias Output and get the published DID document.
let document: StardustDocument = client.publish_did_output(&secret_manager, alias_output).await?;
println!("Published DID document: {:#}", document);

Ok(())
}
Loading

0 comments on commit 67a3bf5

Please sign in to comment.