Skip to content

Commit

Permalink
Merge pull request #1511 from input-output-hk/damien/1495/add-example…
Browse files Browse the repository at this point in the history
…-crate-for-cardano-transactions

Add example crate for Cardano transactions
  • Loading branch information
dlachaume authored Feb 20, 2024
2 parents 4cbbec8 + bc4933e commit 1c37f60
Show file tree
Hide file tree
Showing 12 changed files with 273 additions and 23 deletions.
19 changes: 17 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ resolver = "2"

members = [
"demo/protocol-demo",
"examples/client-cardano-transaction",
"examples/client-mithril-stake-distribution",
"examples/client-snapshot",
"mithril-aggregator",
Expand Down
3 changes: 3 additions & 0 deletions examples/client-cardano-transaction/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
target/
client-cardano-transaction
.DS_Store
19 changes: 19 additions & 0 deletions examples/client-cardano-transaction/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "client-cardano-transaction"
description = "Mithril client cardano-transaction example"
version = "0.1.0"
authors = ["dev@iohk.io", "mithril-dev@iohk.io"]
documentation = "https://mithril.network/doc"
edition = "2021"
homepage = "https://mithril.network"
license = "Apache-2.0"
repository = "https://github.com/input-output-hk/mithril/"

[dependencies]
anyhow = "1.0.79"
clap = { version = "4.4.18", features = ["derive", "env"] }
mithril-client = { path = "../../mithril-client", features = ["unstable"] }
slog = "2.7.0"
slog-async = "2.8.0"
slog-term = "2.9.0"
tokio = { version = "1.35.1", features = ["full"] }
33 changes: 33 additions & 0 deletions examples/client-cardano-transaction/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Mithril client library example: Cardano transaction

> [!WARNING]
> This example makes use of unstable features of the Mithril client library.
> Use them at your own risk, and expect possible modifications in future releases.
> Please refer to the links provided at the end of this file for the most up-to-date developer documentation.
## Description

This example shows how to implement a Mithril client and use its features related to the `Cardano Transaction` type.

In this example, the client interacts with an aggregator and performs the following operations:
- Retrieve cryptographic proofs of membership of the Cardano transactions set for a list of transactions passed as arguments
- Verify the validity of the proofs
- Verify the validity of the validity of the certificate chain attached to the proofs
- Verify that the certificate chain signs a message computed from the proof

## Build and run the example

```bash
# Build from the crate directory
cargo build

# Run from the crate directory
AGGREGATOR_ENDPOINT=YOUR_AGGREGATOR_ENDPOINT GENESIS_VERIFICATION_KEY=YOUR_GENESIS_VERIFICATION_KEY cargo run CARDANO_TX_HASH1,CARDANO_TX_HASH2,CARDANO_TX_HASH3

# Example with from 'testing-sanchonet' network
AGGREGATOR_ENDPOINT=https://aggregator.testing-sanchonet.api.mithril.network/aggregator GENESIS_VERIFICATION_KEY=$(curl -s https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/testing-sanchonet/genesis.vkey) cargo run db0dfab664045b117375a743a925385a7a3fa6a104f8bd95fa0f748088bcaff0,b457a094439cc5e371474f5758b4ecded3e1b035fe0717e39d78080e6fe169b2
```

## Links
- **Developer documentation**: https://docs.rs/mithril-client/latest/mithril_client/
- **Crates.io**: https://crates.io/crates/mithril-client
119 changes: 119 additions & 0 deletions examples/client-cardano-transaction/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//! This example shows how to implement a Mithril client and use its features.
//!
//! In this example, the client interacts with an aggregator whose URL must be specified in the command to get the data.

use anyhow::anyhow;
use clap::Parser;
use slog::info;
use std::sync::Arc;

use mithril_client::common::TransactionHash;
use mithril_client::{ClientBuilder, MessageBuilder, MithrilResult, VerifiedCardanoTransactions};

#[derive(Parser, Debug)]
#[command(version)]
pub struct Args {
/// Genesis verification key.
#[clap(
long,
env = "GENESIS_VERIFICATION_KEY",
default_value = "5b3132372c37332c3132342c3136312c362c3133372c3133312c3231332c3230372c3131372c3139382c38352c3137362c3139392c3136322c3234312c36382c3132332c3131392c3134352c31332c3233322c3234332c34392c3232392c322c3234392c3230352c3230352c33392c3233352c34345d"
)]
genesis_verification_key: String,

/// Aggregator endpoint URL.
#[clap(
long,
env = "AGGREGATOR_ENDPOINT",
default_value = "https://aggregator.testing-sanchonet.api.mithril.network/aggregator"
)]
aggregator_endpoint: String,

/// Hashes of the transactions to certify.
#[clap(value_delimiter = ',', required = true)]
transactions_hashes: Vec<String>,
}

#[tokio::main]
async fn main() -> MithrilResult<()> {
let args = Args::parse();
let transactions_hashes = &args
.transactions_hashes
.iter()
.map(|s| s.as_str())
.collect::<Vec<&str>>();
let logger = build_logger();
let client =
ClientBuilder::aggregator(&args.aggregator_endpoint, &args.genesis_verification_key)
.with_logger(logger.clone())
.build()?;

info!(logger, "Fetching a proof for the given transactions...",);
let cardano_transaction_proof = client
.cardano_transaction_proof()
.get_proofs(transactions_hashes)
.await
.unwrap();

info!(logger, "Verifying the proof…",);
let verified_transactions = cardano_transaction_proof.verify().unwrap();

info!(
logger,
"Fetching the associated certificate and verifying the certificate chain…",
);
let certificate = client
.certificate()
.verify_chain(&cardano_transaction_proof.certificate_hash)
.await
.unwrap();

info!(
logger,
"Verify that the proof is signed in the associated certificate",
);
let message = MessageBuilder::new()
.compute_cardano_transactions_proofs_message(&certificate, &verified_transactions);
if !certificate.match_message(&message) {
return Err(anyhow!(
"Proof and certificate doesn't match (certificate hash = '{}').",
certificate.hash
));
}

log_certify_information(
&verified_transactions,
&cardano_transaction_proof.non_certified_transactions,
);

Ok(())
}

pub fn log_certify_information(
verified_transactions: &VerifiedCardanoTransactions,
non_certified_transactions: &[TransactionHash],
) {
println!(
r###"Cardano transactions with hashes "'{}'" have been successfully certified by Mithril."###,
verified_transactions.certified_transactions().join(","),
);

if !non_certified_transactions.is_empty() {
println!(
r###"No proof could be computed for Cardano transactions with hashes "'{}'".
Mithril may not have signed those transactions yet, please try again later."###,
non_certified_transactions.join(","),
);
}
}

fn build_logger() -> slog::Logger {
use slog::Drain;

let decorator = slog_term::TermDecorator::new().build();
let drain = slog_term::FullFormat::new(decorator).build().fuse();
let drain = slog_async::Async::new(drain).build().fuse();

slog::Logger::root(Arc::new(drain), slog::o!())
}
3 changes: 2 additions & 1 deletion examples/client-mithril-stake-distribution/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "client-mithril-stake-distribution"
description = "Mithril client stake distribution example"
version = "0.1.6"
version = "0.1.7"
authors = ["dev@iohk.io", "mithril-dev@iohk.io"]
documentation = "https://mithril.network/doc"
edition = "2021"
Expand All @@ -11,6 +11,7 @@ repository = "https://github.com/input-output-hk/mithril/"

[dependencies]
anyhow = "1.0.79"
clap = { version = "4.4.18", features = ["derive", "env"] }
mithril-client = { path = "../../mithril-client" }
slog = "2.7.0"
slog-async = "2.8.0"
Expand Down
8 changes: 7 additions & 1 deletion examples/client-mithril-stake-distribution/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

This example shows how to implement a Mithril client and use the features related to the `Mithril stake distribution` type.

In this example, the client interacts with a real aggregator on the network `testing-preview` to:
In this example, the client interacts by default with a real aggregator on the network `testing-preview` to:
- list the available Mithril stake distributions
- get a single Mithril stake distribution
- verify a certificate chain
Expand All @@ -21,6 +21,12 @@ cargo build

# Run from the crate directory
cargo run

# Run with your custom network configuration
AGGREGATOR_ENDPOINT=YOUR_AGGREGATOR_ENDPOINT GENESIS_VERIFICATION_KEY=YOUR_GENESIS_VERIFICATION_KEY cargo run

# Example with 'pre-release-preview' network
AGGREGATOR_ENDPOINT=https://aggregator.pre-release-preview.api.mithril.network/aggregator GENESIS_VERIFICATION_KEY=$(curl -s https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/pre-release-preview/genesis.vkey) cargo run
```

## Links
Expand Down
39 changes: 31 additions & 8 deletions examples/client-mithril-stake-distribution/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,44 @@
//! This example shows how to implement a Mithril client and use its features.
//!
//! In this example, the client interacts with a real aggregator (`testing-preview`) to get the data.
//! In this example, the client interacts by default with a real aggregator (`testing-preview`) to get the data.
//!
//! The [SlogFeedbackReceiver] is used to report the progress to the console.

use anyhow::anyhow;
use mithril_client::{ClientBuilder, MessageBuilder, MithrilResult};
use clap::Parser;
use slog::info;
use std::sync::Arc;

use mithril_client::{ClientBuilder, MessageBuilder, MithrilResult};

#[derive(Parser, Debug)]
#[command(version)]
pub struct Args {
/// Genesis verification key.
#[clap(
long,
env = "GENESIS_VERIFICATION_KEY",
default_value = "5b3132372c37332c3132342c3136312c362c3133372c3133312c3231332c3230372c3131372c3139382c38352c3137362c3139392c3136322c3234312c36382c3132332c3131392c3134352c31332c3233322c3234332c34392c3232392c322c3234392c3230352c3230352c33392c3233352c34345d"
)]
genesis_verification_key: String,

/// Aggregator endpoint URL.
#[clap(
long,
env = "AGGREGATOR_ENDPOINT",
default_value = "https://aggregator.testing-preview.api.mithril.network/aggregator"
)]
aggregator_endpoint: String,
}

#[tokio::main]
async fn main() -> MithrilResult<()> {
let aggregator_endpoint = "https://aggregator.testing-preview.api.mithril.network/aggregator";
let genesis_verification_key = "5b3132372c37332c3132342c3136312c362c3133372c3133312c3231332c3230372c3131372c3139382c38352c3137362c3139392c3136322c3234312c36382c3132332c3131392c3134352c31332c3233322c3234332c34392c3232392c322c3234392c3230352c3230352c33392c3233352c34345d";
let args = Args::parse();
let logger = build_logger();
let client = ClientBuilder::aggregator(aggregator_endpoint, genesis_verification_key)
.with_logger(logger.clone())
.build()?;
let client =
ClientBuilder::aggregator(&args.aggregator_endpoint, &args.genesis_verification_key)
.with_logger(logger.clone())
.build()?;

let mithril_stake_distributions = client.mithril_stake_distribution().list().await?;
info!(
Expand All @@ -27,7 +49,8 @@ async fn main() -> MithrilResult<()> {
let last_hash = mithril_stake_distributions
.first()
.ok_or(anyhow!(
"No Mithril stake distributions could be listed from aggregator: '{aggregator_endpoint}'"
"No Mithril stake distributions could be listed from aggregator: '{}'",
args.aggregator_endpoint
))?
.hash
.as_ref();
Expand Down
3 changes: 2 additions & 1 deletion examples/client-snapshot/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "client-snapshot"
description = "Mithril client snapshot example"
version = "0.1.6"
version = "0.1.7"
authors = ["dev@iohk.io", "mithril-dev@iohk.io"]
documentation = "https://mithril.network/doc"
edition = "2021"
Expand All @@ -12,6 +12,7 @@ repository = "https://github.com/input-output-hk/mithril/"
[dependencies]
anyhow = "1.0.79"
async-trait = "0.1.77"
clap = { version = "4.4.18", features = ["derive", "env"] }
futures = "0.3.30"
indicatif = "0.17.7"
mithril-client = { path = "../../mithril-client", features = ["fs"] }
Expand Down
8 changes: 7 additions & 1 deletion examples/client-snapshot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

This example shows how to implement a Mithril client and use its features related to the `Snapshot` type.

In this example, the client interacts with a real aggregator on the network `testing-preview` to:
In this example, the client interacts by default with a real aggregator on the network `testing-preview` to:
- list the available snapshots
- get a single snapshot
- download and unpack a snapshot archive
Expand All @@ -23,6 +23,12 @@ cargo build

# Run from the crate directory
cargo run

# Run with your custom network configuration
AGGREGATOR_ENDPOINT=YOUR_AGGREGATOR_ENDPOINT GENESIS_VERIFICATION_KEY=YOUR_GENESIS_VERIFICATION_KEY cargo run

# Example with 'pre-release-preview' network
AGGREGATOR_ENDPOINT=https://aggregator.pre-release-preview.api.mithril.network/aggregator GENESIS_VERIFICATION_KEY=$(curl -s https://raw.githubusercontent.com/input-output-hk/mithril/main/mithril-infra/configuration/pre-release-preview/genesis.vkey) cargo run
```

## Links
Expand Down
Loading

0 comments on commit 1c37f60

Please sign in to comment.