Skip to content

Commit

Permalink
Port to thiserror + anyhow (#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
vorot93 authored Dec 11, 2020
1 parent 310579c commit 945352f
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 162 deletions.
1 change: 1 addition & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ license = "MIT/Apache-2.0"
edition = "2018"

[dependencies]
anyhow = "1"
rustc-hex = "2.0"
ethabi = { version = "12.0.0", path = "../ethabi" }
sha3 = "0.9"
Expand Down
67 changes: 0 additions & 67 deletions cli/src/error.rs

This file was deleted.

46 changes: 25 additions & 21 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
mod error;

use crate::error::Error;
use anyhow::anyhow;
use ethabi::{
decode, encode,
param_type::{ParamType, Reader},
Expand Down Expand Up @@ -69,13 +67,13 @@ enum Decode {
},
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
fn main() -> anyhow::Result<()> {
println!("{}", execute(std::env::args())?);

Ok(())
}

fn execute<I>(args: I) -> Result<String, Error>
fn execute<I>(args: I) -> anyhow::Result<String>
where
I: IntoIterator,
I::Item: Into<std::ffi::OsString> + Clone,
Expand All @@ -97,7 +95,7 @@ where
}
}

fn load_function(path: &str, name_or_signature: &str) -> Result<Function, Error> {
fn load_function(path: &str, name_or_signature: &str) -> anyhow::Result<Function> {
let file = File::open(path)?;
let contract = Contract::load(file)?;
let params_start = name_or_signature.find('(');
Expand All @@ -112,7 +110,7 @@ fn load_function(path: &str, name_or_signature: &str) -> Result<Function, Error>
.iter()
.find(|f| f.signature() == name_or_signature)
.cloned()
.ok_or_else(|| Error::InvalidFunctionSignature(name_or_signature.to_owned()))
.ok_or_else(|| anyhow!("invalid function signature `{}`", name_or_signature))
}

// It's a name
Expand All @@ -121,13 +119,16 @@ fn load_function(path: &str, name_or_signature: &str) -> Result<Function, Error>
match functions.len() {
0 => unreachable!(),
1 => Ok(functions[0].clone()),
_ => Err(Error::AmbiguousFunctionName(name_or_signature.to_owned())),
_ => Err(anyhow!(
"More than one function found for name `{}`, try providing the full signature",
name_or_signature
)),
}
}
}
}

fn load_event(path: &str, name_or_signature: &str) -> Result<Event, Error> {
fn load_event(path: &str, name_or_signature: &str) -> anyhow::Result<Event> {
let file = File::open(path)?;
let contract = Contract::load(file)?;
let params_start = name_or_signature.find('(');
Expand All @@ -142,7 +143,7 @@ fn load_event(path: &str, name_or_signature: &str) -> Result<Event, Error> {
.iter()
.find(|event| event.signature() == signature)
.cloned()
.ok_or(Error::InvalidSignature(signature))
.ok_or_else(|| anyhow!("Invalid signature `{}`", signature))
}

// It's a name.
Expand All @@ -151,13 +152,16 @@ fn load_event(path: &str, name_or_signature: &str) -> Result<Event, Error> {
match events.len() {
0 => unreachable!(),
1 => Ok(events[0].clone()),
_ => Err(Error::AmbiguousEventName(name_or_signature.to_string())),
_ => Err(anyhow!(
"More than one function found for name `{}`, try providing the full signature",
name_or_signature
)),
}
}
}
}

fn parse_tokens(params: &[(ParamType, &str)], lenient: bool) -> Result<Vec<Token>, Error> {
fn parse_tokens(params: &[(ParamType, &str)], lenient: bool) -> anyhow::Result<Vec<Token>> {
params
.iter()
.map(|&(ref param, value)| match lenient {
Expand All @@ -168,7 +172,7 @@ fn parse_tokens(params: &[(ParamType, &str)], lenient: bool) -> Result<Vec<Token
.map_err(From::from)
}

fn encode_input(path: &str, name_or_signature: &str, values: &[String], lenient: bool) -> Result<String, Error> {
fn encode_input(path: &str, name_or_signature: &str, values: &[String], lenient: bool) -> anyhow::Result<String> {
let function = load_function(path, name_or_signature)?;

let params: Vec<_> =
Expand All @@ -180,7 +184,7 @@ fn encode_input(path: &str, name_or_signature: &str, values: &[String], lenient:
Ok(result.to_hex())
}

fn encode_params(params: &[String], lenient: bool) -> Result<String, Error> {
fn encode_params(params: &[String], lenient: bool) -> anyhow::Result<String> {
assert_eq!(params.len() % 2, 0);

let params = params
Expand All @@ -195,7 +199,7 @@ fn encode_params(params: &[String], lenient: bool) -> Result<String, Error> {
Ok(result.to_hex())
}

fn decode_call_output(path: &str, name_or_signature: &str, data: &str) -> Result<String, Error> {
fn decode_call_output(path: &str, name_or_signature: &str, data: &str) -> anyhow::Result<String> {
let function = load_function(path, name_or_signature)?;
let data: Vec<u8> = data.from_hex()?;
let tokens = function.decode_output(&data)?;
Expand All @@ -213,7 +217,7 @@ fn decode_call_output(path: &str, name_or_signature: &str, data: &str) -> Result
Ok(result)
}

fn decode_params(types: &[String], data: &str) -> Result<String, Error> {
fn decode_params(types: &[String], data: &str) -> anyhow::Result<String> {
let types: Vec<ParamType> = types.iter().map(|s| Reader::read(s)).collect::<Result<_, _>>()?;

let data: Vec<u8> = data.from_hex()?;
Expand All @@ -228,7 +232,7 @@ fn decode_params(types: &[String], data: &str) -> Result<String, Error> {
Ok(result)
}

fn decode_log(path: &str, name_or_signature: &str, topics: &[String], data: &str) -> Result<String, Error> {
fn decode_log(path: &str, name_or_signature: &str, topics: &[String], data: &str) -> anyhow::Result<String> {
let event = load_event(path, name_or_signature)?;
let topics: Vec<Hash> = topics.iter().map(|t| t.parse()).collect::<Result<_, _>>()?;
let data = data.from_hex()?;
Expand Down Expand Up @@ -282,7 +286,7 @@ mod tests {
let result = execute(command);
assert!(result.is_err());
let err = result.unwrap_err();
assert_eq!(err.to_string(), "Ethabi error: Uint parse error: InvalidCharacter");
assert_eq!(err.to_string(), "Uint parse error: InvalidCharacter");
}

#[test]
Expand All @@ -303,14 +307,14 @@ mod tests {

// i256::min_value() - 1 is too much
let command = "ethabi encode params -v int256 -57896044618658097711785492504343953926634992332820282019728792003956564819969 --lenient".split(' ');
assert_eq!(execute(command).unwrap_err().to_string(), "Ethabi error: int256 parse error: Underflow");
assert_eq!(execute(command).unwrap_err().to_string(), "int256 parse error: Underflow");
}

#[test]
fn int_encode_large_positive_numbers() {
// Overflow
let command = "ethabi encode params -v int256 100000000000000000000000000000000022222222222222221111111111111333333333344556 --lenient".split(' ');
assert_eq!(execute(command).unwrap_err().to_string(), "Ethabi error: int256 parse error: Overflow");
assert_eq!(execute(command).unwrap_err().to_string(), "int256 parse error: Overflow");

// i256::max_value() is ok
let command = "ethabi encode params -v int256 57896044618658097711785492504343953926634992332820282019728792003956564819967 --lenient".split(' ');
Expand All @@ -319,7 +323,7 @@ mod tests {

// i256::max_value() + 1 is too much
let command = "ethabi encode params -v int256 57896044618658097711785492504343953926634992332820282019728792003956564819968 --lenient".split(' ');
assert_eq!(execute(command).unwrap_err().to_string(), "Ethabi error: int256 parse error: Overflow");
assert_eq!(execute(command).unwrap_err().to_string(), "int256 parse error: Overflow");
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ edition = "2018"
proc-macro = true

[dependencies]
anyhow = "1"
ethabi = { path = "../ethabi", version = "12.0.0" }
heck = "0.3.1"
syn = { version = "1.0.13", default-features = false, features = ["derive", "parsing", "printing", "proc-macro"] }
Expand Down
11 changes: 6 additions & 5 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod contract;
mod event;
mod function;

use anyhow::anyhow;
use ethabi::{Contract, Param, ParamType, Result};
use heck::SnakeCase;
use quote::quote;
Expand All @@ -35,7 +36,7 @@ fn impl_ethabi_derive(ast: &syn::DeriveInput) -> Result<proc_macro2::TokenStream
let path = get_option(&options, "path")?;
let normalized_path = normalize_path(&path)?;
let source_file = fs::File::open(&normalized_path)
.map_err(|_| format!("Cannot load contract abi from `{}`", normalized_path.display()))?;
.map_err(|_| anyhow!("Cannot load contract abi from `{}`", normalized_path.display()))?;
let contract = Contract::load(source_file)?;
let c = contract::Contract::from(&contract);
Ok(c.generate())
Expand All @@ -46,7 +47,7 @@ fn get_options(attrs: &[syn::Attribute], name: &str) -> Result<Vec<syn::NestedMe

match options {
Some(syn::Meta::List(list)) => Ok(list.nested.into_iter().collect()),
_ => Err("Unexpected meta item".into()),
_ => Err(anyhow!("Unexpected meta item").into()),
}
}

Expand All @@ -58,7 +59,7 @@ fn get_option(options: &[syn::NestedMeta], name: &str) -> Result<String> {
_ => None,
})
.find(|meta| meta.path().is_ident(name))
.ok_or_else(|| format!("Expected to find option {}", name))?;
.ok_or_else(|| anyhow!("Expected to find option {}", name))?;

str_value_of_meta_item(item, name)
}
Expand All @@ -70,12 +71,12 @@ fn str_value_of_meta_item(item: &syn::Meta, name: &str) -> Result<String> {
}
}

Err(format!(r#"`{}` must be in the form `#[{}="something"]`"#, name, name).into())
Err(anyhow!(r#"`{}` must be in the form `#[{}="something"]`"#, name, name).into())
}

fn normalize_path(relative_path: &str) -> Result<PathBuf> {
// workaround for https://github.com/rust-lang/rust/issues/43860
let cargo_toml_directory = env::var("CARGO_MANIFEST_DIR").map_err(|_| "Cannot find manifest file")?;
let cargo_toml_directory = env::var("CARGO_MANIFEST_DIR").map_err(|_| anyhow!("Cannot find manifest file"))?;
let mut path: PathBuf = cargo_toml_directory.into();
path.push(relative_path);
Ok(path)
Expand Down
2 changes: 2 additions & 0 deletions ethabi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ description = "Easy to use conversion of ethereum contract calls to bytecode."
edition = "2018"

[dependencies]
anyhow = "1"
hex = { version = "2.0", package = "rustc-hex" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sha3 = "0.9"
ethereum-types = "0.9.0"
thiserror = "1"
uint = "0.8.2"

[dev-dependencies]
Expand Down
Loading

0 comments on commit 945352f

Please sign in to comment.