Skip to content

Commit

Permalink
fix: dpc nits
Browse files Browse the repository at this point in the history
fix: backwards compatibility tests

fix: fix

fix: test

fix: hold

fix: tests fix

fix: encoding ecash

fix: decode on OOBNotesData

feat: encode dev command for notes and invite-code

feat: decode notes to json
  • Loading branch information
Kodylow committed Mar 11, 2024
1 parent e08dd65 commit 0b6732f
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 32 deletions.
38 changes: 29 additions & 9 deletions devimint/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,29 @@ pub async fn cli_tests(dev_fed: DevFed) -> Result<()> {

let fed_id = fed.calculate_federation_id().await;
let invite = fed.invite_code()?;
let invite_code = cmd!(client, "dev", "decode-invite-code", invite.clone())
.out_json()
.await?;
anyhow::ensure!(

let fedimint_cli_version = crate::util::FedimintCli::version_or_default().await;
let version_req = VersionReq::parse(">=0.3.0-alpha")?;

let invite_code = if version_req.matches(&fedimint_cli_version) {
cmd!(client, "dev", "decode", "invite-code", invite.clone())
} else {
cmd!(client, "dev", "decode-invite-code", invite.clone())
}
.out_json()
.await?;

let encode_invite_output = if version_req.matches(&fedimint_cli_version) {
cmd!(
client,
"dev",
"encode",
"invite-code",
format!("--url={}", invite_code["url"].as_str().unwrap()),
"--federation_id={fed_id}",
"--peer=0"
)
} else {
cmd!(
client,
"dev",
Expand All @@ -422,11 +441,12 @@ pub async fn cli_tests(dev_fed: DevFed) -> Result<()> {
"--federation_id={fed_id}",
"--peer=0"
)
.out_json()
.await?["invite_code"]
.as_str()
.unwrap()
== invite,
}
.out_json()
.await?;

anyhow::ensure!(
encode_invite_output["invite_code"].as_str().unwrap() == invite,
"failed to decode and encode the client invite code",
);

Expand Down
89 changes: 66 additions & 23 deletions fedimint-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ use fedimint_core::admin_client::WsAdminClient;
use fedimint_core::api::{
FederationApiExt, FederationError, IRawFederationApi, InviteCode, WsFederationApi,
};
use fedimint_core::config::{ClientConfig, FederationId};
use fedimint_core::config::{ClientConfig, FederationId, FederationIdPrefix};
use fedimint_core::core::OperationId;
use fedimint_core::db::{Database, DatabaseValue};
use fedimint_core::module::{ApiAuth, ApiRequestErased};
use fedimint_core::util::{handle_version_hash_command, SafeUrl};
use fedimint_core::{fedimint_build_code_version_env, task, PeerId, TieredMulti};
use fedimint_ln_client::LightningClientInit;
use fedimint_logging::{TracingSetup, LOG_CLIENT};
use fedimint_mint_client::{MintClientInit, MintClientModule, SpendableNote};
use fedimint_mint_client::{MintClientInit, MintClientModule, OOBNotes, SpendableNote};
use fedimint_server::config::io::SALT_FILE;
use fedimint_wallet_client::api::WalletFederationApi;
use fedimint_wallet_client::{WalletClientInit, WalletClientModule};
Expand Down Expand Up @@ -359,6 +359,36 @@ enum AdminCmd {
GuardianConfigBackup,
}

#[derive(Debug, Clone, Subcommand)]
enum DecodeType {
/// Decode an invite code string into a JSON representation
InviteCode { invite_code: InviteCode },
/// Decode a string of ecash notes into a JSON representation
Notes { notes: OOBNotes },
}

#[derive(Debug, Clone, Deserialize, Serialize)]
struct OOBNotesJson {
federation_id_prefix: String,
notes: TieredMulti<SpendableNote>,
}

#[derive(Debug, Clone, Subcommand)]
enum EncodeType {
/// Encode connection info from its constituent parts
InviteCode {
#[clap(long)]
url: SafeUrl,
#[clap(long = "federation_id")]
federation_id: FederationId,
#[clap(long = "peer")]
peer: PeerId,
},

/// Encode a JSON string of notes to an ecash string
Notes { notes_json: String },
}

#[derive(Debug, Clone, Subcommand)]
enum DevCmd {
/// Send direct method call to the API. If you specify --peer-id, it will
Expand Down Expand Up @@ -393,17 +423,16 @@ Examples:
/// Wait for all state machines to complete
WaitComplete,

/// Decode connection info into its JSON representation
DecodeInviteCode { invite_code: InviteCode },
/// Decode invite code or ecash notes string into a JSON representation
Decode {
#[clap(subcommand)]
decode_type: DecodeType,
},

/// Encode connection info from its constituent parts
EncodeInviteCode {
#[clap(long = "url")]
url: SafeUrl,
#[clap(long = "federation_id")]
federation_id: FederationId,
#[clap(long = "peer")]
peer: PeerId,
/// Encode an invite code or ecash notes into binary
Encode {
#[clap(subcommand)]
encode_type: EncodeType,
},

/// Gets the current fedimint AlephBFT block count
Expand Down Expand Up @@ -765,19 +794,33 @@ impl FedimintCli {
.map_err_cli_general()?;
Ok(CliOutput::Raw(serde_json::Value::Null))
}
Command::Dev(DevCmd::DecodeInviteCode { invite_code }) => {
Ok(CliOutput::DecodeInviteCode {
Command::Dev(DevCmd::Decode { decode_type }) => match decode_type {
DecodeType::InviteCode { invite_code } => Ok(CliOutput::DecodeInviteCode {
url: invite_code.url(),
federation_id: invite_code.federation_id(),
})
}
Command::Dev(DevCmd::EncodeInviteCode {
url,
federation_id,
peer,
}) => Ok(CliOutput::InviteCode {
invite_code: InviteCode::new(url, peer, federation_id),
}),
}),
DecodeType::Notes { notes } => {
let notes_json = notes.notes_json().map_err_cli_general()?;
Ok(CliOutput::Raw(notes_json))
}
},
Command::Dev(DevCmd::Encode { encode_type }) => match encode_type {
EncodeType::InviteCode {
url,
federation_id,
peer,
} => Ok(CliOutput::InviteCode {
invite_code: InviteCode::new(url, peer, federation_id),
}),
EncodeType::Notes { notes_json } => {
let notes =
serde_json::from_str::<OOBNotesJson>(&notes_json).map_err_cli_general()?;
let prefix = FederationIdPrefix::from_str(&notes.federation_id_prefix)
.map_err_cli_general()?;
let notes = OOBNotes::new(prefix, notes.notes);
Ok(CliOutput::Raw(notes.to_string().into()))
}
},
Command::Dev(DevCmd::SessionCount) => {
let client = self.client_open(&cli).await?;
let count = client.api().session_count().await?;
Expand Down
10 changes: 10 additions & 0 deletions fedimint-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,16 @@ impl Display for FederationId {
}
}

impl FromStr for FederationIdPrefix {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(Vec::from_hex(s)?.try_into().map_err(
|bytes: Vec<u8>| hex::Error::InvalidLength(4, bytes.len()),
)?))
}
}

/// Display as a hex encoding
impl FederationId {
/// Random dummy id for testing
Expand Down
39 changes: 39 additions & 0 deletions modules/fedimint-mint-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use anyhow::{anyhow, bail, ensure, Context as _};
use async_stream::stream;
use backup::recovery::MintRecovery;
use base64::Engine as _;
use bitcoin_hashes::hex::ToHex;
use bitcoin_hashes::{sha256, sha256t, Hash, HashEngine as BitcoinHashEngine};
use client_db::DbKeyPrefix;
use fedimint_client::module::init::{
Expand Down Expand Up @@ -154,6 +155,44 @@ impl OOBNotes {
.expect("Invariant violated: OOBNotes does not contain any notes")
}

pub fn notes_json(&self) -> Result<serde_json::Value, serde_json::Error> {
let mut notes_map = serde_json::Map::new();
for notes in self.0.iter() {
match notes {
OOBNotesData::Notes(notes) => {
let notes_json = serde_json::to_value(notes).expect("serialization can't fail");
notes_map.insert("notes".to_string(), notes_json);
}
OOBNotesData::FederationIdPrefix(prefix) => {
notes_map.insert(
"federation_id_prefix".to_string(),
serde_json::to_value(prefix.to_string())?,
);
}
OOBNotesData::Invite {
peer_apis,
federation_id,
} => {
let (peer_id, api) = peer_apis
.first()
.cloned()
.expect("Decoding makes sure peer_apis isn't empty");
notes_map.insert(
"invite".to_string(),
serde_json::to_value(InviteCode::new(api, peer_id, *federation_id))?,
);
}
OOBNotesData::Default { variant, bytes } => {
notes_map.insert(
format!("default_{}", variant),
serde_json::to_value(bytes.to_hex())?,
);
}
}
}
Ok(serde_json::Value::Object(notes_map))
}

pub fn federation_invite(&self) -> Option<InviteCode> {
self.0.iter().find_map(|data| {
let OOBNotesData::Invite {
Expand Down

0 comments on commit 0b6732f

Please sign in to comment.