Skip to content

Commit

Permalink
feat: single menmonic and db
Browse files Browse the repository at this point in the history
  • Loading branch information
Kodylow committed Oct 17, 2024
1 parent 1eb0d0e commit 6b24daa
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 99 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ fm_client_db
.DS_Store
fm_db
fm_db_dir
fm_db_mnemonic
result
/vendor

Expand Down
26 changes: 21 additions & 5 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 @@ -20,6 +20,7 @@ fedimint-mint-client = "0.4.2"
fedimint-ln-client = "0.4.2"
fedimint-ln-common = "0.4.2"
fedimint-rocksdb = "0.4.2"
fedimint-bip39 = "0.4.2"

# Config for 'cargo dist'
[workspace.metadata.dist]
Expand Down
1 change: 1 addition & 0 deletions example.env
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ FEDIMINT_CLIENTD_DB_PATH='/absolute/path/to/fm_db_dir'
FEDIMINT_CLIENTD_PASSWORD='password'
FEDIMINT_CLIENTD_BASE_URL='http://127.0.0.1:3333'
FEDIMINT_CLIENTD_ADDR='127.0.0.1:3333'
MULTIMINT_MNEMONIC_ENV='ivory put armed include entire report oblige mystery ivory reunion siren actor'
4 changes: 2 additions & 2 deletions fedimint-clientd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ time = { version = "0.3.25", features = ["formatting"] }
chrono = "0.4.31"
futures-util = "0.3.30"
clap = { version = "3", features = ["derive", "env"] }
multimint = { version = "0.4.0" }
# multimint = { path = "../multimint" }
# multimint = { version = "0.4.0" }
multimint = { path = "../multimint" }
hex = "0.4.3"

futures = "0.3"
Expand Down
13 changes: 1 addition & 12 deletions fedimint-clientd/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,9 @@ async fn main() -> Result<()> {

let mut state = AppState::new(cli.db_path).await?;

let manual_secret = match cli.manual_secret {
Some(secret) => Some(secret),
None => match std::env::var("FEDIMINT_CLIENTD_MANUAL_SECRET") {
Ok(secret) => Some(secret),
Err(_) => None,
},
};

match InviteCode::from_str(&cli.invite_code) {
Ok(invite_code) => {
let federation_id = state
.multimint
.register_new(invite_code, manual_secret)
.await?;
let federation_id = state.multimint.register_new(invite_code).await?;
info!("Created client for federation id: {:?}", federation_id);
}
Err(e) => {
Expand Down
20 changes: 1 addition & 19 deletions fedimint-clientd/src/router/handlers/admin/join.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::env;

use anyhow::{anyhow, Error};
use axum::extract::State;
use axum::http::StatusCode;
Expand All @@ -17,7 +15,6 @@ use crate::state::AppState;
#[serde(rename_all = "camelCase")]
pub struct JoinRequest {
pub invite_code: InviteCode,
pub use_manual_secret: bool,
}

#[derive(Debug, Serialize)]
Expand All @@ -28,22 +25,7 @@ pub struct JoinResponse {
}

async fn _join(mut multimint: MultiMint, req: JoinRequest) -> Result<JoinResponse, Error> {
let manual_secret = if req.use_manual_secret {
match env::var("FEDIMINT_CLIENTD_MANUAL_SECRET") {
Ok(secret) => Some(secret),
Err(_) => {
return Err(anyhow!(
"FEDIMINT_CLIENTD_MANUAL_SECRET must be set to join with manual secret"
))
}
}
} else {
None
};

let this_federation_id = multimint
.register_new(req.invite_code.clone(), manual_secret)
.await?;
let this_federation_id = multimint.register_new(req.invite_code.clone()).await?;

let federation_ids = multimint.ids().await.into_iter().collect::<Vec<_>>();

Expand Down
2 changes: 2 additions & 0 deletions multimint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ fedimint-mint-client = { workspace = true }
fedimint-ln-client = { workspace = true }
fedimint-ln-common = { workspace = true }
fedimint-rocksdb = { workspace = true }
fedimint-bip39 = { workspace = true }
futures-util = "0.3.30"
rand = "0.8.5"
tracing = "0.1.40"
hex = "0.4.3"
bip39 = "2.1.0"
92 changes: 52 additions & 40 deletions multimint/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,36 @@

use std::collections::BTreeMap;
use std::fmt::Debug;
use std::path::PathBuf;
use std::sync::Arc;

use anyhow::Result;
use fedimint_client::secret::{PlainRootSecretStrategy, RootSecretStrategy};
use fedimint_client::Client;
use bip39::Mnemonic;
use fedimint_bip39::Bip39RootSecretStrategy;
use fedimint_client::db::ClientConfigKey;
use fedimint_client::derivable_secret::{ChildId, DerivableSecret};
use fedimint_client::module::init::ClientModuleInitRegistry;
use fedimint_client::secret::RootSecretStrategy;
use fedimint_client::{Client, ClientBuilder};
use fedimint_core::config::FederationId;
use fedimint_core::db::{
Committable, Database, DatabaseTransaction, IDatabaseTransactionOpsCoreTyped,
};
use fedimint_core::encoding::Encodable;
use fedimint_ln_client::LightningClientInit;
use fedimint_mint_client::MintClientInit;
use fedimint_wallet_client::WalletClientInit;
use futures_util::StreamExt;
use rand::thread_rng;
use tracing::info;

use crate::db::{FederationConfig, FederationIdKey, FederationIdKeyPrefix};

#[derive(Debug, Clone)]
pub struct LocalClientBuilder {
work_dir: PathBuf,
mnemonic: Mnemonic,
}

impl LocalClientBuilder {
pub fn new(work_dir: PathBuf) -> Self {
Self { work_dir }
pub fn new(mnemonic: Mnemonic) -> Self {
Self { mnemonic }
}
}

Expand All @@ -37,48 +41,23 @@ impl LocalClientBuilder {
#[allow(clippy::too_many_arguments)]
pub async fn build(
&self,
db: &Database,
config: FederationConfig,
manual_secret: Option<[u8; 64]>,
) -> Result<fedimint_client::ClientHandleArc> {
let federation_id = config.invite_code.federation_id();
let db = db.with_prefix(federation_id.consensus_encode_to_vec());
let secret = self.derive_federation_secret(&federation_id);
Self::verify_client_config(&db, federation_id).await?;

let db_path = self.work_dir.join(format!("{federation_id}.db"));
let client_builder = self.create_client_builder(db.clone()).await?;

let db = Database::new(
fedimint_rocksdb::RocksDb::open(db_path.clone())?,
Default::default(),
);

let mut client_builder = Client::builder(db.clone()).await?;
client_builder.with_module(WalletClientInit(None));
client_builder.with_module(MintClientInit);
client_builder.with_module(LightningClientInit::default());
client_builder.with_primary_module(1);

let client_secret = match Client::load_decodable_client_secret::<[u8; 64]>(&db).await {
Ok(secret) => secret,
Err(_) => {
if let Some(manual_secret) = manual_secret {
info!("Using manual secret provided by user and writing to client storage");
Client::store_encodable_client_secret(&db, manual_secret).await?;
manual_secret
} else {
info!("Generating new secret and writing to client storage");
let secret = PlainRootSecretStrategy::random(&mut thread_rng());
Client::store_encodable_client_secret(&db, secret).await?;
secret
}
}
};

let root_secret = PlainRootSecretStrategy::to_root_secret(&client_secret);
let client_res = if Client::is_initialized(&db).await {
client_builder.open(root_secret).await
client_builder.open(secret).await
} else {
let client_config =
fedimint_api_client::download_from_invite_code(&config.invite_code).await?;
client_builder
.join(root_secret, client_config.to_owned(), None)
.join(secret, client_config.to_owned(), None)
.await
}?;

Expand Down Expand Up @@ -107,4 +86,37 @@ impl LocalClientBuilder {
.cloned()
.collect::<Vec<_>>()
}

pub fn derive_federation_secret(&self, federation_id: &FederationId) -> DerivableSecret {
let global_root_secret = Bip39RootSecretStrategy::<12>::to_root_secret(&self.mnemonic);
let multi_federation_root_secret = global_root_secret.child_key(ChildId(0));
let federation_root_secret = multi_federation_root_secret.federation_key(federation_id);
let federation_wallet_root_secret = federation_root_secret.child_key(ChildId(0));
federation_wallet_root_secret.child_key(ChildId(0))
}

/// Verifies that the saved `ClientConfig` contains the expected
/// federation's config.
async fn verify_client_config(db: &Database, federation_id: FederationId) -> Result<()> {
let mut dbtx = db.begin_transaction_nc().await;
if let Some(config) = dbtx.get_value(&ClientConfigKey).await {
if config.calculate_federation_id() != federation_id {
anyhow::bail!("Federation Id did not match saved federation ID")
}
}
Ok(())
}

/// Constructs the client builder with the modules, database, and connector
/// used to create clients for connected federations.
async fn create_client_builder(&self, db: Database) -> Result<ClientBuilder> {
let mut registry = ClientModuleInitRegistry::new();
registry.attach(WalletClientInit::default());
registry.attach(MintClientInit);
registry.attach(LightningClientInit::default());
let mut client_builder = Client::builder(db).await?;
client_builder.with_module_inits(registry);
client_builder.with_primary_module(1);
Ok(client_builder)
}
}
Loading

0 comments on commit 6b24daa

Please sign in to comment.