Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1,585 changes: 674 additions & 911 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ miden-faucet-lib = { path = "crates/faucet", version = "0.15.0" }
miden-pow-rate-limiter = { path = "crates/pow", version = "0.15.0" }

# Miden dependencies.
miden-client = { version = "0.14" }
miden-client-cli = { version = "0.14" }
miden-client-sqlite-store = { version = "0.14" }
miden-client = { git = "https://github.com/0xMiden/miden-client", rev = "4adc065b3cd3c83a12e99f7cd8c9776a160a5db4" }
miden-client-cli = { git = "https://github.com/0xMiden/miden-client", rev = "4adc065b3cd3c83a12e99f7cd8c9776a160a5db4" }
miden-client-sqlite-store = { git = "https://github.com/0xMiden/miden-client", rev = "4adc065b3cd3c83a12e99f7cd8c9776a160a5db4" }
# `AuthMethod` (required by `create_fungible_faucet`) is not re-exported by miden-client, so we
# depend on miden-standards directly. Must match the version miden-client resolves (0.15.0).
miden-standards = { version = "0.15" }

# External dependencies
anyhow = { version = "1.0" }
Expand Down
7 changes: 4 additions & 3 deletions bin/faucet-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ tokio = { features = ["macros", "net", "rt-multi-thread", "sync
url = { workspace = true }

[dev-dependencies]
axum = { features = ["tokio"], version = "0.8" }
serde = { workspace = true }
tokio = { features = ["macros", "net", "rt-multi-thread", "time"], workspace = true }
axum = { features = ["tokio"], version = "0.8" }
miden-client = { features = ["testing"], workspace = true }
serde = { workspace = true }
tokio = { features = ["macros", "net", "rt-multi-thread", "time"], workspace = true }
4 changes: 2 additions & 2 deletions bin/faucet-client/tests/mint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use axum::{Json, Router};
use clap::Parser;
use miden_client::account::AccountId;
use miden_client::note::NoteId;
use miden_client::testing::account_id::ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE;
use miden_client::utils::ToHex;
use miden_faucet_client::mint::MintCmd;
use miden_faucet_lib::requests::{
Expand Down Expand Up @@ -35,8 +36,7 @@ struct AppState {

#[tokio::test]
async fn mint_command_requests_public_note() {
let account_hex = "0xca8203e8e58cf72049b061afca78ce";
let account_id = AccountId::from_hex(account_hex).unwrap();
let account_id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap();
let expected_amount = 123_000;

// Create a valid Challenge with target = u64::MAX so any nonce will solve it
Expand Down
10 changes: 7 additions & 3 deletions bin/faucet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ miden-pow-rate-limiter = { features = ["tokio"], workspace = true }
# Miden dependencies.
miden-client = { features = ["tonic"], workspace = true }
miden-client-sqlite-store = { workspace = true }
miden-standards = { workspace = true }
Comment thread
SantiagoPittella marked this conversation as resolved.

# External dependencies.
anyhow = { workspace = true }
Expand Down Expand Up @@ -51,9 +52,12 @@ tracing-subscriber = { workspace = true }
url = { workspace = true }

[dev-dependencies]
fantoccini = { version = "0.22" }
miden-node-proto = { version = "0.14" }
miden-testing = { version = "0.14" }
fantoccini = { version = "0.22" }
miden-client = { workspace = true }
# Pinned to the same node commit miden-client resolves so the gRPC stub's proto types match the
# client's (the `igamigo-export-ntxauth` branch tip).
miden-node-proto = { version = "0.15.0-rc.0" }
miden-testing = { default-features = false, version = "0.15" }
reqwest = { features = ["json"], workspace = true }
serde_json = { workspace = true }
tokio = { features = ["macros", "process"], workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion bin/faucet/src/api/send_note.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub async fn send_note(
.ok_or(SendNoteError::NoteNotFound)?;

let note = Note::try_from(note_record).unwrap();
let header = note.header().clone();
let header = *note.header();
let details: NoteDetails = note.into();

note_transport_client.send_note(header, details.to_bytes()).await?;
Expand Down
89 changes: 59 additions & 30 deletions bin/faucet/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,21 @@ use std::time::Duration;

use anyhow::Context;
use clap::{Parser, Subcommand};
use miden_client::account::component::{AuthControlled, BasicFungibleFaucet};
use miden_client::account::{
Account,
AccountBuilder,
AccountFile,
AccountStorageMode,
AccountType,
use miden_client::account::component::{
AccessControl,
AuthScheme,
BurnPolicyConfig,
FungibleFaucet,
MintPolicyConfig,
PolicyRegistration,
TokenName,
TokenPolicyManager,
TransferPolicy,
create_fungible_faucet,
};
use miden_client::account::{Account, AccountFile, AccountType};
use miden_client::asset::TokenSymbol;
use miden_client::auth::{AuthSchemeId, AuthSecretKey, AuthSingleSig};
use miden_client::auth::AuthSecretKey;
use miden_client::crypto::RandomCoin;
use miden_client::crypto::rpo_falcon512::SecretKey;
use miden_client::note_transport::grpc::GrpcNoteTransportClient;
Expand All @@ -33,6 +38,7 @@ use miden_client_sqlite_store::SqliteStore;
use miden_faucet_lib::types::AssetAmount;
use miden_faucet_lib::{Faucet, FaucetConfig};
use miden_pow_rate_limiter::PoWRateLimiterConfig;
use miden_standards::AuthMethod;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha20Rng;
use tokio::sync::mpsc;
Expand Down Expand Up @@ -101,7 +107,7 @@ pub enum Command {
short,
long,
value_name = "STRING",
required_unless_present = "import_account_path",
required_unless_present = "import_account_path",
env = ENV_TOKEN_SYMBOL
)]
token_symbol: Option<String>,
Expand Down Expand Up @@ -436,9 +442,9 @@ async fn run_faucet_command(cli: Cli) -> anyhow::Result<()> {
baseline: pow_baseline,
};
let faucet_account = faucet.faucet_account().await?;
let faucet_component = BasicFungibleFaucet::try_from(&faucet_account)?;
let max_supply = AssetAmount::new(faucet_component.max_supply().as_canonical_u64())?;
let decimals = faucet_component.decimals();
let token_metadata = FungibleFaucet::try_from(faucet_account.storage())?;
let max_supply = AssetAmount::new(token_metadata.max_supply().as_u64())?;
let decimals = token_metadata.decimals();

let note_transport_client = note_transport_url.as_ref().map(|url| {
Arc::new(GrpcNoteTransportClient::new(
Expand Down Expand Up @@ -571,27 +577,48 @@ fn create_faucet_account(
let mut rng = ChaCha20Rng::from_seed(rand::random());
let secret = {
let auth_seed: [u64; 4] = rng.random();
let rng_seed = Word::from(auth_seed.map(Felt::new));
let rng_seed = Word::from(auth_seed.map(Felt::new_unchecked));
SecretKey::with_rng(&mut RandomCoin::new(rng_seed))
};

let symbol = TokenSymbol::try_from(token_symbol).context("failed to parse token symbol")?;
let max_supply = Felt::try_from(max_supply)
.map_err(anyhow::Error::msg)
.context("max supply value is greater than or equal to the field modulus")?;
let auth_component = AuthSingleSig::new(
secret.public_key().to_commitment().into(),
AuthSchemeId::Falcon512Poseidon2,
);

let account = AccountBuilder::new(rng.random())
.account_type(AccountType::FungibleFaucet)
.storage_mode(AccountStorageMode::Public)
.with_component(BasicFungibleFaucet::new(symbol, decimals, max_supply)?)
.with_component(AuthControlled::allow_all())
.with_auth_component(auth_component)
let name = TokenName::new(&symbol.to_string()).context("failed to derive token name")?;

let faucet = FungibleFaucet::builder()
.name(name)
.symbol(symbol)
.decimals(decimals)
.max_supply(
miden_client::asset::AssetAmount::new(max_supply)
.context("max supply exceeds the maximum asset amount")?,
)
.build()
.context("failed to create basic fungible faucet account")?;
.context("failed to build fungible faucet component")?;

let auth_method = AuthMethod::SingleSig {
approver: (secret.public_key().to_commitment().into(), AuthScheme::Falcon512Poseidon2),
};

// Permissionless mint/burn/send/receive policies.
let token_policy_manager = TokenPolicyManager::new()
.with_mint_policy(MintPolicyConfig::AllowAll, PolicyRegistration::Active)
.context("failed to set mint policy")?
.with_burn_policy(BurnPolicyConfig::AllowAll, PolicyRegistration::Active)
.context("failed to set burn policy")?
.with_send_policy(TransferPolicy::AllowAll, PolicyRegistration::Active)
.context("failed to set send policy")?
.with_receive_policy(TransferPolicy::AllowAll, PolicyRegistration::Active)
.context("failed to set receive policy")?;

let account = create_fungible_faucet(
rng.random(),
faucet,
AccountType::Public,
auth_method,
AccessControl::AuthControlled,
token_policy_manager,
)
.context("failed to create basic fungible faucet account")?;

Ok((account, AuthSecretKey::Falcon512Poseidon2(secret)))
}
Expand All @@ -609,6 +636,7 @@ mod tests {
use clap::Parser;
use fantoccini::ClientBuilder;
use miden_client::account::{AccountFile, AccountId, Address, NetworkId};
use miden_client::testing::account_id::ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE;
use miden_client_sqlite_store::SqliteStore;
use rand::SeedableRng;
use serde_json::{Map, json};
Expand Down Expand Up @@ -822,7 +850,8 @@ mod tests {
assert_eq!(title, "Miden Faucet");

let network_id = NetworkId::Testnet;
let account_id = AccountId::try_from(0).unwrap();
let account_id =
AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap();
let address = Address::new(account_id);
let address_bech32 = address.encode(network_id);

Expand Down Expand Up @@ -903,7 +932,7 @@ mod tests {
async fn run_faucet_server(stub_node_url: Url) -> String {
let config = ClientConfig {
node_url: Some(stub_node_url.clone()),
timeout: Duration::from_millis(5000),
timeout: Duration::from_secs(5),
network: FaucetNetwork::Localhost,
store_path: temp_dir().join(format!("{}.sqlite3", Uuid::new_v4())),
remote_tx_prover_url: None,
Expand Down
48 changes: 35 additions & 13 deletions bin/faucet/src/testing/stub_rpc_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,6 @@ pub struct StubRpcApi;

#[tonic::async_trait]
impl api_server::Api for StubRpcApi {
async fn check_nullifiers(
&self,
_request: Request<proto::rpc::NullifierList>,
) -> Result<Response<proto::rpc::CheckNullifiersResponse>, Status> {
unimplemented!()
}

async fn get_block_header_by_number(
&self,
_request: Request<proto::rpc::BlockHeaderByNumberRequest>,
Expand Down Expand Up @@ -49,20 +42,48 @@ impl api_server::Api for StubRpcApi {
unimplemented!()
}

async fn submit_proven_transaction(
async fn submit_proven_tx(
&self,
_request: Request<proto::transaction::ProvenTransaction>,
) -> Result<Response<proto::blockchain::BlockNumber>, Status> {
Ok(Response::new(proto::blockchain::BlockNumber { block_num: 0 }))
}

async fn submit_proven_batch(
async fn submit_proven_tx_batch(
&self,
_request: Request<proto::transaction::TransactionBatch>,
) -> Result<Response<proto::blockchain::BlockNumber>, Status> {
unimplemented!()
}

type BlockSubscriptionStream = std::pin::Pin<
Box<
dyn tokio_stream::Stream<Item = Result<proto::rpc::BlockSubscriptionResponse, Status>>
+ Send,
>,
>;

async fn block_subscription(
&self,
_request: Request<proto::rpc::BlockSubscriptionRequest>,
) -> Result<Response<Self::BlockSubscriptionStream>, Status> {
unimplemented!()
}

type ProofSubscriptionStream = std::pin::Pin<
Box<
dyn tokio_stream::Stream<Item = Result<proto::rpc::ProofSubscriptionResponse, Status>>
+ Send,
>,
>;

async fn proof_subscription(
&self,
_request: Request<proto::rpc::ProofSubscriptionRequest>,
) -> Result<Response<Self::ProofSubscriptionStream>, Status> {
unimplemented!()
}

async fn get_account(
&self,
_request: Request<proto::rpc::AccountRequest>,
Expand All @@ -72,7 +93,7 @@ impl api_server::Api for StubRpcApi {

async fn get_block_by_number(
&self,
_request: Request<proto::blockchain::BlockNumber>,
_request: Request<proto::blockchain::BlockRequest>,
) -> Result<Response<proto::blockchain::MaybeBlock>, Status> {
unimplemented!()
}
Expand Down Expand Up @@ -150,16 +171,17 @@ impl api_server::Api for StubRpcApi {
let mock_chain = MockChain::new();

Ok(Response::new(proto::rpc::SyncChainMmrResponse {
block_range: Some(proto::rpc::BlockRange { block_from: 0, block_to: Some(0) }),
block_range: Some(proto::rpc::BlockRange { block_from: 0, block_to: 0 }),
mmr_delta: Some(proto::primitives::MmrDelta { forest: 0, data: vec![] }),
block_header: Some(mock_chain.latest_block_header().into()),
block_signature: None,
}))
}

async fn get_note_error(
async fn get_network_note_status(
&self,
_request: Request<proto::note::NoteId>,
) -> Result<Response<proto::rpc::GetNoteErrorResponse>, Status> {
) -> Result<Response<proto::rpc::GetNetworkNoteStatusResponse>, Status> {
unimplemented!()
}
}
Expand Down
5 changes: 3 additions & 2 deletions crates/faucet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ url = { workspace = true }
miden-client = { workspace = true }

[dev-dependencies]
miden-client = { features = ["testing", "tonic"], workspace = true }
uuid = { workspace = true }
miden-client = { features = ["testing", "tonic"], workspace = true }
miden-standards = { workspace = true }
uuid = { workspace = true }
Loading
Loading