Skip to content

Commit

Permalink
TOB-DQK-007 remove panics (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarioDfinity authored Jan 31, 2022
1 parent 44df760 commit 310d7d6
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 89 deletions.
20 changes: 15 additions & 5 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,8 @@ serde_json = "1.0.57"
tiny-hderive = "0.3.0"
tokio = { version = "1.2.0", features = [ "fs" ] }

[dev-dependencies]
tempfile = "3.3.0"

[features]
static-ssl = ["openssl/vendored"]
2 changes: 1 addition & 1 deletion default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ with pkgs; rustPlatform.buildRustPackage rec {

src = ./.;

cargoSha256 = "sha256-zFRMDnSNOVDCh+cupe7ZieR5UPrwHDZ9oi7MnzWpk2s=";
cargoSha256 = "sha256-t+N0UoVOJIxi1q0SBfCqxNIcmXVBo44hhKE0SllJ63M=";

cargoBuildFlags = [];

Expand Down
6 changes: 3 additions & 3 deletions src/commands/generate.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::lib::{mnemonic_to_pem, AnyhowResult};
use anyhow::anyhow;
use anyhow::{anyhow, Context};
use bip39::{Language, Mnemonic};
use clap::Parser;
use rand::{rngs::OsRng, RngCore};
Expand Down Expand Up @@ -49,14 +49,14 @@ pub fn exec(opts: GenerateOpts) -> AnyhowResult {
_ => return Err(anyhow!("Words must be 12 or 24.")),
};
let mnemonic = match opts.phrase {
Some(phrase) => Mnemonic::parse(phrase).unwrap(),
Some(phrase) => Mnemonic::parse(phrase).context("Failed to parse mnemonic")?,
None => {
let mut key = vec![0u8; bytes];
OsRng.fill_bytes(&mut key);
Mnemonic::from_entropy_in(Language::English, &key).unwrap()
}
};
let pem = mnemonic_to_pem(&mnemonic);
let pem = mnemonic_to_pem(&mnemonic).context("Failed to convert mnemonic to PEM")?;
let mut phrase = mnemonic
.word_iter()
.collect::<Vec<&'static str>>()
Expand Down
3 changes: 2 additions & 1 deletion src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This module implements the command-line API.
use crate::lib::{qr, require_pem, AnyhowResult};
use anyhow::Context;
use clap::Parser;
use std::io::{self, Write};
use tokio::runtime::Runtime;
Expand Down Expand Up @@ -159,7 +160,7 @@ where
print(arg)
} else {
for (i, a) in arg.iter().enumerate() {
print_qr(&a, i != arg.len() - 1).expect("print_qr");
print_qr(&a, i != arg.len() - 1).context("Failed to print QR code")?;
}
Ok(())
}
Expand Down
14 changes: 8 additions & 6 deletions src/commands/neuron_manage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::lib::{
signing::{sign_ingress_with_request_status_query, IngressWithRequestId},
AnyhowResult,
};
use anyhow::anyhow;
use anyhow::{anyhow, Context};
use candid::{CandidType, Encode};
use clap::Parser;
use ic_types::Principal;
Expand Down Expand Up @@ -166,7 +166,7 @@ pub fn exec(pem: &str, opts: ManageOpts) -> AnyhowResult<Vec<IngressWithRequestI
let mut msgs = Vec::new();

let id = Some(NeuronId {
id: parse_neuron_id(opts.neuron_id),
id: parse_neuron_id(opts.neuron_id)?,
});
if opts.add_hot_key.is_some() {
let args = Encode!(&ManageNeuron {
Expand Down Expand Up @@ -252,7 +252,9 @@ pub fn exec(pem: &str, opts: ManageOpts) -> AnyhowResult<Vec<IngressWithRequestI
"SEVEN_YEARS" => ONE_YEAR_SECONDS * 7,
"EIGHT_YEARS" => ONE_YEAR_SECONDS * 8,

s => s.parse::<u32>().expect("Couldn't parse the dissolve delay"),
s => s
.parse::<u32>()
.context("Failed to parse the dissolve delay")?,
}
}))
})),
Expand Down Expand Up @@ -298,7 +300,7 @@ pub fn exec(pem: &str, opts: ManageOpts) -> AnyhowResult<Vec<IngressWithRequestI
id,
command: Some(Command::Merge(Merge {
source_neuron_id: NeuronId {
id: parse_neuron_id(neuron_id)
id: parse_neuron_id(neuron_id)?
},
})),
neuron_id_or_subaccount: None,
Expand Down Expand Up @@ -349,8 +351,8 @@ pub fn exec(pem: &str, opts: ManageOpts) -> AnyhowResult<Vec<IngressWithRequestI
Ok(generated)
}

fn parse_neuron_id(id: String) -> u64 {
fn parse_neuron_id(id: String) -> AnyhowResult<u64> {
id.replace("_", "")
.parse()
.expect("Couldn't parse the neuron id")
.context("Failed to parse the neuron id")
}
6 changes: 2 additions & 4 deletions src/commands/public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ fn get_public_ids(

/// Returns the account id and the principal id if the private key was provided.
pub fn get_ids(pem: &Option<String>) -> AnyhowResult<(Principal, AccountIdentifier)> {
require_pem(pem)?;
let principal_id = get_identity(pem.as_ref().unwrap())
.sender()
.map_err(|e| anyhow!(e))?;
let pem = require_pem(pem)?;
let principal_id = get_identity(&pem).sender().map_err(|e| anyhow!(e))?;
Ok((principal_id, get_account_id(principal_id)?))
}
37 changes: 24 additions & 13 deletions src/commands/request_status.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
use crate::lib::get_ic_url;
use crate::lib::{get_agent, get_idl_string, signing::RequestStatus, AnyhowResult};
use anyhow::{anyhow, Context};
use ic_agent::agent::{Replied, RequestStatusResponse};
use ic_agent::agent::{ReplicaV2Transport, Replied, RequestStatusResponse};
use ic_agent::AgentError::MessageError;
use ic_agent::{AgentError, RequestId};
use ic_types::Principal;
use std::future::Future;
use std::pin::Pin;
use std::str::FromStr;
use std::sync::Arc;

pub async fn submit(req: &RequestStatus, method_name: Option<String>) -> AnyhowResult<String> {
let canister_id = Principal::from_text(&req.canister_id).expect("Couldn't parse canister id");
let request_id =
RequestId::from_str(&req.request_id).context("Invalid argument: request_id")?;
let canister_id =
Principal::from_text(&req.canister_id).context("Cannot parse the canister id")?;
let request_id = RequestId::from_str(&req.request_id).context("Cannot parse the request_id")?;
let mut agent = get_agent("")?;
agent.set_transport(ProxySignReplicaV2Transport {
req: req.clone(),
http_transport: Arc::new(
ic_agent::agent::http_transport::ReqwestHttpReplicaV2Transport::create(get_ic_url())
.unwrap(),
.context("Failed to create an agent")?,
),
});
let Replied::CallReplied(blob) = async {
Expand Down Expand Up @@ -57,20 +60,28 @@ pub(crate) struct ProxySignReplicaV2Transport {
http_transport: Arc<dyn 'static + ReplicaV2Transport + Send + Sync>,
}

use ic_agent::agent::ReplicaV2Transport;
use std::future::Future;
use std::pin::Pin;

impl ReplicaV2Transport for ProxySignReplicaV2Transport {
fn read_state<'a>(
&'a self,
_canister_id: Principal,
_content: Vec<u8>,
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, AgentError>> + Send + 'a>> {
self.http_transport.read_state(
Principal::from_text(self.req.canister_id.clone()).unwrap(),
hex::decode(self.req.content.clone()).unwrap(),
)
async fn run(transport: &ProxySignReplicaV2Transport) -> Result<Vec<u8>, AgentError> {
let canister_id = Principal::from_text(transport.req.canister_id.clone())
.map_err(|err| MessageError(format!("Unable to parse canister_id: {}", err)))?;
let envelope = hex::decode(transport.req.content.clone()).map_err(|err| {
MessageError(format!(
"Unable to decode request content (should be hexadecimal encoded): {}",
err
))
})?;
transport
.http_transport
.read_state(canister_id, envelope)
.await
}

Box::pin(run(self))
}

fn call<'a>(
Expand Down
4 changes: 2 additions & 2 deletions src/commands/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::lib::{
signing::{Ingress, IngressWithRequestId},
AnyhowResult,
};
use anyhow::anyhow;
use anyhow::{anyhow, Context};
use candid::CandidType;
use clap::Parser;
use ic_agent::agent::ReplicaV2Transport;
Expand Down Expand Up @@ -153,7 +153,7 @@ async fn send(message: &Ingress, opts: &SendOpts) -> AnyhowResult {
&message
.clone()
.request_id
.expect("Cannot get request_id from the update message"),
.context("Cannot get request_id from the update message")?,
)?;
transport.call(canister_id, content, request_id).await?;
let request_id = format!("0x{}", String::from(request_id));
Expand Down
27 changes: 16 additions & 11 deletions src/commands/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::lib::{
signing::{sign_ingress_with_request_status_query, IngressWithRequestId},
AnyhowResult,
};
use anyhow::anyhow;
use anyhow::{anyhow, bail, Context};
use candid::Encode;
use clap::Parser;
use ledger_canister::{ICPTs, TRANSACTION_FEE};
Expand All @@ -29,16 +29,15 @@ pub struct TransferOpts {
}

pub fn exec(pem: &str, opts: TransferOpts) -> AnyhowResult<Vec<IngressWithRequestId>> {
let amount =
parse_icpts(&opts.amount).map_err(|err| anyhow!("Could not add ICPs and e8s: {}", err))?;
let amount = parse_icpts(&opts.amount).context("Cannot parse amount")?;
let fee = opts.fee.map_or(Ok(TRANSACTION_FEE), |v| {
parse_icpts(&v).map_err(|err| anyhow!(err))
parse_icpts(&v).context("Cannot parse fee")
})?;
let memo = Memo(
opts.memo
.unwrap_or_else(|| "0".to_string())
.parse::<u64>()
.unwrap(),
.context("Failed to parse memo as unsigned integer")?,
);
let to = opts.to;

Expand All @@ -55,26 +54,32 @@ pub fn exec(pem: &str, opts: TransferOpts) -> AnyhowResult<Vec<IngressWithReques
Ok(vec![msg])
}

fn parse_icpts(amount: &str) -> Result<ICPTs, String> {
fn new_icps(icpt: u64, e8s: u64) -> AnyhowResult<ICPTs> {
ICPTs::new(icpt, e8s)
.map_err(|err| anyhow!(err))
.context("Cannot create new ICPs")
}

fn parse_icpts(amount: &str) -> AnyhowResult<ICPTs> {
let parse = |s: &str| {
s.parse::<u64>()
.map_err(|err| format!("Couldn't parse as u64: {:?}", err))
.context("Failed to parse ICPTs as unsigned integer")
};
match &amount.split('.').collect::<Vec<_>>().as_slice() {
[icpts] => ICPTs::new(parse(icpts)?, 0),
[icpts] => new_icps(parse(icpts)?, 0),
[icpts, e8s] => {
let mut e8s = e8s.to_string();
while e8s.len() < 8 {
e8s.push('0');
}
let e8s = &e8s[..8];
ICPTs::new(parse(icpts)?, parse(e8s)?)
new_icps(parse(icpts)?, parse(e8s)?)
}
_ => Err(format!("Can't parse amount {}", amount)),
_ => bail!("Cannot parse amount {}", amount),
}
}

fn icpts_amount_validator(icpts: &str) -> Result<(), String> {
fn icpts_amount_validator(icpts: &str) -> AnyhowResult<()> {
parse_icpts(icpts).map(|_| ())
}

Expand Down
Loading

0 comments on commit 310d7d6

Please sign in to comment.