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

Add Rust examples #22

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
3,976 changes: 1,449 additions & 2,527 deletions Rust/Cargo.lock

Large diffs are not rendered by default.

21 changes: 5 additions & 16 deletions Rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[package]
name = "iroha_2_examples"
name = "iroha_examples"
version = "0.1.0"
edition = "2021"

authors = ["Iroha 2 team <https://github.com/orgs/soramitsu/teams/iroha2>"]
description = "Example repository for Iroha 2 ledger"
description = "Hyperledger Iroha 2 code examples"
repository = "https://github.com/hyperledger/iroha-2-examples"
documentation = "https://hyperledger.github.io/iroha-2-docs"
homepage = "https://iroha.tech"
Expand All @@ -14,17 +14,6 @@ keywords = ["blockchain", "crypto", "iroha", "ledger"]
categories = ["cryptography::cryptocurrencies"]

[dependencies]
iroha = { "git" = "https://github.com/hyperledger/iroha.git", branch = "iroha2-dev" }
iroha_crypto = { "git" = "https://github.com/hyperledger/iroha.git", branch = "iroha2-dev" }
iroha_client = { "git" = "https://github.com/hyperledger/iroha.git", branch = "iroha2-dev" }
iroha_config = { "git" = "https://github.com/hyperledger/iroha.git", branch = "iroha2-dev" }
iroha_data_model = { "git" = "https://github.com/hyperledger/iroha.git", branch = "iroha2-dev" }
iroha_genesis = { "git" = "https://github.com/hyperledger/iroha.git", branch = "iroha2-dev" }
test_network = { "git" = "https://github.com/hyperledger/iroha.git", branch = "iroha2-dev" }

eyre = "0.6.8"

serde = { version = "1.0.151", default-features = false }
serde_json = { version = "1.0.91", default-features = false }

tokio = "1.23.0"
iroha = { git = "https://github.com/hyperledger/iroha.git" }
eyre = "0.6.12"
serde_json = "1.0.117"
25 changes: 12 additions & 13 deletions Rust/README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
# Rust examples for Iroha 2
# Rust examples for Hyperledger Iroha

This directory contains the examples from the [Rust tutorial](https://hyperledger.github.io/iroha-2-docs/guide/rust.html#_2-configuring-iroha-2).
This project contains code examples to help you get started using the Rust SDK for Hyperledger Iroha, as well as understand Iroha conceptually.

## Running the examples

To run the examples, you need to install [`cargo-nextest`](https://nexte.st/) first.
To run the examples, you should have a running Iroha network with the default genesis block configuration. Some examples depend on other examples being executed. Examples without dependencies are good starting points:

```bash
cargo install cargo-nextest
```
- [`domain_register`](examples/domain_register.rs)

After it is installed, type:
## Helper library

```bash
cargo nextest run
```
A small helper library is included to facilitate the creation of code examples that demonstrate Iroha usage patterns while focusing on high-level concepts.

You'll Cargo install the packages that are needed for the tests and the test code will run.
Users can learn to use the lower-level APIs by checking out the implementations of the building blocks.

## Extending the example set
### Usage

Simply add a file with Rust code to the [`examples`](./examples/) directory. It will be launched by `cargo-nextest` on its next run.
* Define primitives like domains (`Wonderland`, `Chess`), signatories (`Alice`, `Bob`, `Magnus`), assets (`Roses`, `Pawns`, `Book`), and more using traits like `ExampleDomain`, `ExampleSignatory` `ExampleAssetName` and others.
* Combine primitives into compound types for accounts (`AliceInWonderland`, `BobInChess`), asset definitions (`WonderlandRoses`, `GardenCabbages`) and more using `ExampleAccount`, `ExampleAssetDefinition`, etc.
* Easily construct identifiers (`BobInWonderland::account_id()`, `ChessBookOfAliceInWonderland::asset_id()`) as needed.
* Construct clients acting on behalf of various accounts using `AliceInWonderland::client()`, `BobInChess::client()`.
11 changes: 11 additions & 0 deletions Rust/configs/alice_chess.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
chain = "00000000-0000-0000-0000-000000000000"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we emphasize somewhere in the docs that this value must be generated as UUID (and why). This here is just a dummy value

torii_url = "http://127.0.0.1:8080/"

[basic_auth]
web_login = "mad_hatter"
password = "ilovetea"

[account]
domain = "chess"
public_key = "ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03"
private_key = "802640CCF31D85E3B32A4BEA59987CE0C78E3B8E2DB93881468AB2435FE45D5C9DCD53CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03"
11 changes: 11 additions & 0 deletions Rust/configs/alice_wonderland.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
chain = "00000000-0000-0000-0000-000000000000"
torii_url = "http://127.0.0.1:8080/"

[basic_auth]
web_login = "mad_hatter"
password = "ilovetea"

[account]
domain = "wonderland"
public_key = "ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03"
private_key = "802640CCF31D85E3B32A4BEA59987CE0C78E3B8E2DB93881468AB2435FE45D5C9DCD53CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03"
11 changes: 11 additions & 0 deletions Rust/configs/bob_chess.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
chain = "00000000-0000-0000-0000-000000000000"
torii_url = "http://127.0.0.1:8080/"

[basic_auth]
web_login = "mad_hatter"
password = "ilovetea"

[account]
domain = "chess"
public_key = "ed012004FF5B81046DDCCF19E2E451C45DFB6F53759D4EB30FA2EFA807284D1CC33016"
private_key = "802640AF3F96DEEF44348FEB516C057558972CEC4C75C4DB9C5B3AAC843668854BF82804FF5B81046DDCCF19E2E451C45DFB6F53759D4EB30FA2EFA807284D1CC33016"
nxsaken marked this conversation as resolved.
Show resolved Hide resolved
11 changes: 11 additions & 0 deletions Rust/configs/bob_wonderland.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
chain = "00000000-0000-0000-0000-000000000000"
torii_url = "http://127.0.0.1:8080/"

[basic_auth]
web_login = "mad_hatter"
password = "ilovetea"

[account]
domain = "wonderland"
public_key = "ed012004FF5B81046DDCCF19E2E451C45DFB6F53759D4EB30FA2EFA807284D1CC33016"
private_key = "802640AF3F96DEEF44348FEB516C057558972CEC4C75C4DB9C5B3AAC843668854BF82804FF5B81046DDCCF19E2E451C45DFB6F53759D4EB30FA2EFA807284D1CC33016"
57 changes: 57 additions & 0 deletions Rust/examples/account_register.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! Shows how to register an account.
//!
//! Depends on the `domain_register` example.

use iroha::client::{account, Client};
use iroha::data_model::prelude::{
Account, AccountId, Grant, Permission, PermissionId, Register, Revoke,
};

use iroha_examples::{
AliceInChess, AliceInWonderland, BobInChess, BobInWonderland, Chess, ExampleDomain,
MagnusInChess,
};

fn main() -> iroha_examples::Result<()> {
// An account is created for a signatory in a domain.
// By default, only the owner of the domain can register accounts in it.
let as_alice_in_wonderland = AliceInWonderland::client();
// The same signatory can have an account in different domains.
register(&as_alice_in_wonderland, AliceInChess::account_id())?;

// The domain owner can also grant a permission to register accounts in the domain.
let can_register_accounts_in_chess = Permission::new(
"CanRegisterAccountInDomain".parse::<PermissionId>()?,
serde_json::json!({ "domain": Chess::domain_id() }),
);
// Grant the permission to Bob from Wonderland.
let bob_in_wonderland = BobInWonderland::account_id();
as_alice_in_wonderland.submit_blocking(Grant::permission(
can_register_accounts_in_chess.clone(),
bob_in_wonderland.clone(),
))?;
// Bob in Wonderland can now register accounts in Chess.
let as_bob_in_wonderland = BobInWonderland::client();
register(&as_bob_in_wonderland, BobInChess::account_id())?;
register(&as_bob_in_wonderland, MagnusInChess::account_id())?;
// Revoke the permission from Bob in Wonderland.
as_alice_in_wonderland.submit_blocking(Revoke::permission(
can_register_accounts_in_chess,
bob_in_wonderland,
))?;
Ok(())
}

fn register(as_who: &Client, account: AccountId) -> iroha_examples::Result<()> {
let register_account = Register::account(Account::new(account.clone()));
as_who.submit_blocking(register_account)?;
// Observe that the account has really been registered.
let account = as_who.request(account::by_id(account))?;
println!(
"---------------\n\
`account_id`: {}\n\
Registered by {}",
account.id, as_who.account,
);
nxsaken marked this conversation as resolved.
Show resolved Hide resolved
Ok(())
}
36 changes: 36 additions & 0 deletions Rust/examples/account_unregister.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! Shows how to unregister an account.
//!
//! Depends on the `account_register` example.

use iroha::client::{account, Client};
use iroha::data_model::account::AccountId;
use iroha::data_model::prelude::Unregister;

use iroha_examples::{AliceInChess, AliceInWonderland, BobInChess, MagnusInChess};

fn main() -> iroha_examples::Result<()> {
// An account's owner can unregister that account.
let as_bob_in_chess = BobInChess::client();
unregister(&as_bob_in_chess, BobInChess::account_id())?;
// A domain owner can unregister any account in that domain.
let as_alice_in_wonderland = AliceInWonderland::client();
unregister(&as_alice_in_wonderland, AliceInChess::account_id())?;
unregister(&as_alice_in_wonderland, MagnusInChess::account_id())?;
Ok(())
}

fn unregister(as_who: &Client, account: AccountId) -> iroha_examples::Result<()> {
let unregister_account = Unregister::account(account.clone());
as_who.submit_blocking(unregister_account)?;
// Observe that the account has really been unregistered.
as_who
.request(account::by_id(account.clone()))
.expect_err("account should not be found");
println!(
"---------------\n\
`account_id`: {account}\n\
Unregistered by {}",
as_who.account
);
Ok(())
}
61 changes: 61 additions & 0 deletions Rust/examples/asset_definition_register.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! Shows how to register asset definitions.
//!
//! Depends on `account_register`.

use iroha::client::{asset, Client};
use iroha::data_model::ipfs::IpfsPath;
use iroha::data_model::prelude::{Metadata, NewAssetDefinition, Register};
use iroha_examples::{
AliceInWonderland, BobInChess, ChessBook, ChessPawns, WonderlandMoney, WonderlandRoses,
};

fn main() -> iroha_examples::Result<()> {
let as_alice_in_wonderland = AliceInWonderland::client();
// Roses in Wonderland are defined in the default genesis block.
let wonderland_roses = as_alice_in_wonderland.request(asset::definition_by_id(
WonderlandRoses::asset_definition_id(),
))?;
println!(
"---------------\n\
{wonderland_roses:#?}"
);
// Assets can be defined as either numeric or store.
// Numeric assets can be minted (increased) or burned (decreased).
// Wonderland Money is a numeric asset with fractional values up to 2 decimal places.
register(&as_alice_in_wonderland, WonderlandMoney::asset_definition())?;
// Chess Pawns is a numeric asset with integer values that can only be minted once.
// It means that a certain amount of an asset can be given
// to an account one time, and from that point it can only be burnt.
// Mintability is covered in detail in the TODO(`asset_numeric`) example.
//
// Bob in Chess will be the owner of the definition of Chess Pawns,
// meaning he will have the default right to mint/burn Chess Pawns.
// Since Alice in Wonderland owns Chess, she will also have that right.
register(&BobInChess::client(), ChessPawns::asset_definition())?;
// Chess Book is a store asset. Store assets are not minted or burned.
// Instead, key-value pairs are set or removed for them.
//
// Here we also provide the optional IPFS path to the asset logo,
// and some metadata. Metadata is covered in detail in TODO(`metadata`)
register(
&as_alice_in_wonderland,
ChessBook::asset_definition()
.with_logo("QmQqzMTavQgT4f4T5v6PWBp7XNKtoPmC9jvn12WPT3gkSE".parse::<IpfsPath>()?)
.with_metadata(Metadata::default()),
)?;
Ok(())
}

fn register(as_who: &Client, asset_definition: NewAssetDefinition) -> iroha_examples::Result<()> {
let asset_definition_id = asset_definition.id.clone();
let define_asset = Register::asset_definition(asset_definition);
as_who.submit_blocking(define_asset)?;
let chess_pawns = as_who.request(asset::definition_by_id(asset_definition_id))?;
println!(
"---------------\n\
`asset_definition_id`: {}\n\
Registered by {}",
chess_pawns.id, as_who.account
);
Ok(())
}
27 changes: 0 additions & 27 deletions Rust/examples/client_account_definition.rs

This file was deleted.

85 changes: 0 additions & 85 deletions Rust/examples/client_account_registration.rs

This file was deleted.

Loading