Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stdtx: replace anomaly with eyre #555

Merged
merged 1 commit into from
Nov 12, 2020
Merged
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
18 changes: 17 additions & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion stdtx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ edition = "2018"
circle-ci = { repository = "tendermint/kms" }

[dependencies]
anomaly = { version = "0.2", path = "../anomaly" }
ecdsa = { version = "0.8", features = ["std"] }
eyre = "0.6"
k256 = { version = "0.5", features = ["ecdsa", "sha256"] }
prost-amino = { version = "0.6", optional = true }
prost-amino-derive = { version = "0.6", optional = true }
Expand Down
22 changes: 12 additions & 10 deletions stdtx/src/address.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Address types (account or validator)

use crate::error::{Error, ErrorKind};
use anomaly::ensure;
use crate::Error;
use eyre::{Result, WrapErr};
use serde::{de, Deserialize};
use std::convert::TryInto;
use subtle_encoding::bech32;
Expand All @@ -15,16 +15,18 @@ pub struct Address(pub [u8; ADDRESS_SIZE]);

impl Address {
/// Parse an address from its Bech32 form
pub fn from_bech32(addr_bech32: impl AsRef<str>) -> Result<(String, Address), Error> {
pub fn from_bech32(addr_bech32: impl AsRef<str>) -> Result<(String, Address)> {
let (hrp, addr) = bech32::decode(addr_bech32.as_ref())?;

ensure!(
addr.len() == ADDRESS_SIZE,
ErrorKind::Address,
"invalid length for decoded address: {} (expected {})",
addr.len(),
ADDRESS_SIZE
);
if addr.len() != ADDRESS_SIZE {
return Err(Error::Address).wrap_err_with(|| {
format!(
"invalid length for decoded address: {} (expected {})",
addr.len(),
ADDRESS_SIZE
)
});
}

Ok((hrp, Address(addr.as_slice().try_into().unwrap())))
}
Expand Down
7 changes: 4 additions & 3 deletions stdtx/src/amino/builder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Builder for `StdTx` transactions which handles construction and signing.

use super::{Msg, Schema, StdFee, StdSignature, StdTx};
use crate::{Error, Signer};
use crate::Signer;
use eyre::Result;
use serde_json::json;

/// [`StdTx`] transaction builder, which handles construction, signing, and
Expand Down Expand Up @@ -50,7 +51,7 @@ impl Builder {
fee: StdFee,
memo: &str,
messages: &[Msg],
) -> Result<StdTx, Error> {
) -> Result<StdTx> {
let sign_msg = self.create_sign_msg(sequence, &fee, memo, messages);
let signature = StdSignature::from(signer.try_sign(sign_msg.as_bytes())?);
Ok(StdTx::new(messages, fee, vec![signature], memo))
Expand All @@ -64,7 +65,7 @@ impl Builder {
fee: StdFee,
memo: &str,
messages: &[Msg],
) -> Result<Vec<u8>, Error> {
) -> Result<Vec<u8>> {
let tx = self.sign_tx(signer, sequence, fee, memo, messages)?;
Ok(tx.to_amino_bytes(self.schema.namespace()))
}
Expand Down
55 changes: 29 additions & 26 deletions stdtx/src/amino/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ mod value;
pub use self::{builder::Builder, field::Field, value::Value};

use super::{schema::ValueType, Schema, TypeName};
use crate::{error::ErrorKind, Address, Decimal, Error};
use anomaly::{fail, format_err};
use crate::{Address, Decimal, Error};
use eyre::{Result, WrapErr};
use prost_amino::encode_length_delimiter as encode_leb128; // Little-endian Base 128
use std::{collections::BTreeMap, iter::FromIterator};
use subtle_encoding::hex;
Expand All @@ -35,36 +35,34 @@ pub struct Msg {
impl Msg {
/// Parse a [`Msg`] from a [`serde_json::Value`] following the provided
/// [`Schema`] for field definitions.
pub fn from_json_value(schema: &Schema, json_value: serde_json::Value) -> Result<Self, Error> {
pub fn from_json_value(schema: &Schema, json_value: serde_json::Value) -> Result<Self> {
let json_obj = match json_value.as_object() {
Some(obj) => obj,
None => fail!(ErrorKind::Type, "expected JSON object"),
None => return Err(Error::Type).wrap_err("expected JSON object"),
};

if json_obj.len() != 2 {
fail!(ErrorKind::Parse, "unexpected keys in JSON object");
return Err(Error::Parse).wrap_err("unexpected keys in JSON object");
}

let type_name = match json_obj.get("type").and_then(|v| v.as_str()) {
Some(name) => name.parse::<TypeName>()?,
None => fail!(ErrorKind::Parse, "no `type` key in JSON object"),
None => return Err(Error::Parse).wrap_err("no `type` key in JSON object"),
};

let type_def = match schema.get_definition(&type_name) {
Some(def) => def,
None => fail!(
ErrorKind::FieldName,
"no type definition for `{}`",
type_name
),
None => {
return Err(Error::FieldName)
.wrap_err_with(|| format!("no type definition for `{}`", type_name))
}
};

let value_obj = match json_obj.get("value").and_then(|v| v.as_object()) {
Some(obj) => obj,
None => fail!(
ErrorKind::Parse,
"missing or invalid `value` key in JSON object"
),
None => {
return Err(Error::Parse).wrap_err("missing or invalid `value` key in JSON object")
}
};

let mut fields = vec![];
Expand All @@ -74,27 +72,31 @@ impl Msg {

let field_def = match type_def.get_field(&field_name) {
Some(def) => def,
None => fail!(ErrorKind::FieldName, "unknown field name: `{}`", field_name),
None => {
return Err(Error::FieldName)
.wrap_err_with(|| format!("unknown field name: `{}`", field_name))
}
};

let value_str = match json_value.as_str() {
Some(s) => s,
None => fail!(
ErrorKind::Parse,
"couldn't parse JSON value: `{}`",
field_name
),
None => {
return Err(Error::Parse)
.wrap_err_with(|| format!("couldn't parse JSON value: `{}`", field_name))
}
};

let value = match field_def.value_type() {
ValueType::Bytes => hex::decode(value_str).map(Value::Bytes).map_err(|e| {
format_err!(ErrorKind::Parse, "invalid hex-encoded bytes: {}", e)
})?,
ValueType::Bytes => hex::decode(value_str)
.map(Value::Bytes)
.map_err(|_| Error::Parse)
.wrap_err_with(|| format!("invalid hex-encoded bytes: '{}'", value_str))?,
ValueType::SdkAccAddress => {
let (hrp, addr) = Address::from_bech32(value_str)?;

if schema.acc_prefix() != hrp {
fail!(ErrorKind::Parse, "invalid account prefix: {}", value_str);
return Err(Error::Parse)
.wrap_err_with(|| format!("invalid account prefix: {}", value_str));
}

Value::SdkAccAddress(addr)
Expand All @@ -103,7 +105,8 @@ impl Msg {
let (hrp, addr) = Address::from_bech32(value_str)?;

if schema.val_prefix() != hrp {
fail!(ErrorKind::Parse, "invalid validator prefix: {}", value_str);
return Err(Error::Parse)
.wrap_err_with(|| format!("invalid validator prefix: {}", value_str));
}

Value::SdkValAddress(addr)
Expand Down
79 changes: 38 additions & 41 deletions stdtx/src/amino/msg/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@

use super::{Field, Msg, Value};
use crate::{
address::Address,
amino::{
schema::{Definition, Schema, ValueType},
type_name::TypeName,
},
decimal::Decimal,
error::{Error, ErrorKind},
Address, Decimal, Error,
};
use anomaly::{ensure, format_err};
use eyre::{Result, WrapErr};
use std::convert::TryInto;

/// Transaction message builder
Expand All @@ -35,17 +33,14 @@ impl<'a> Builder<'a> {
/// Create a new message builder for the given schema and message type
pub fn new(
schema: &'a Schema,
type_name: impl TryInto<TypeName, Error = Error>,
) -> Result<Self, Error> {
type_name: impl TryInto<TypeName, Error = eyre::Report>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ooo we should serialize to JSON and send report to datadog. Time to revive #492

) -> Result<Self> {
let type_name = type_name.try_into()?;

let schema_definition = schema.get_definition(&type_name).ok_or_else(|| {
format_err!(
ErrorKind::Type,
"type not found in schema: `{}`",
&type_name
)
})?;
let schema_definition = schema
.get_definition(&type_name)
.ok_or_else(|| Error::Type)
.wrap_err_with(|| format!("type not found in schema: `{}`", &type_name))?;

Ok(Self {
schema_definition,
Expand All @@ -60,9 +55,9 @@ impl<'a> Builder<'a> {
/// <https://godoc.org/github.com/cosmos/cosmos-sdk/types#AccAddress>
pub fn acc_address(
&mut self,
field_name: impl TryInto<TypeName, Error = Error>,
field_name: impl TryInto<TypeName, Error = eyre::Report>,
address: Address,
) -> Result<&mut Self, Error> {
) -> Result<&mut Self> {
let field_name = field_name.try_into()?;
let tag = self
.schema_definition
Expand All @@ -77,28 +72,29 @@ impl<'a> Builder<'a> {
/// `sdk.AccAddress` encoded as Bech32
pub fn acc_address_bech32(
&mut self,
field_name: impl TryInto<TypeName, Error = Error>,
field_name: impl TryInto<TypeName, Error = eyre::Report>,
addr_bech32: impl AsRef<str>,
) -> Result<&mut Self, Error> {
) -> Result<&mut Self> {
let (hrp, address) = Address::from_bech32(addr_bech32)?;

ensure!(
hrp == self.acc_prefix,
ErrorKind::Address,
"invalid account address prefix: `{}` (expected `{}`)",
hrp,
self.acc_prefix,
);
if hrp != self.acc_prefix {
return Err(Error::Address).wrap_err_with(|| {
format!(
"invalid account address prefix: `{}` (expected `{}`)",
hrp, self.acc_prefix
)
});
}

self.acc_address(field_name, address)
}

/// Bytes
pub fn bytes(
&mut self,
field_name: impl TryInto<TypeName, Error = Error>,
field_name: impl TryInto<TypeName, Error = eyre::Report>,
b: impl Into<Vec<u8>>,
) -> Result<&mut Self, Error> {
) -> Result<&mut Self> {
let field_name = field_name.try_into()?;
let tag = self
.schema_definition
Expand All @@ -114,9 +110,9 @@ impl<'a> Builder<'a> {
/// <https://godoc.org/github.com/cosmos/cosmos-sdk/types#Dec>s
pub fn decimal(
&mut self,
field_name: impl TryInto<TypeName, Error = Error>,
field_name: impl TryInto<TypeName, Error = eyre::Report>,
value: impl Into<Decimal>,
) -> Result<&mut Self, Error> {
) -> Result<&mut Self> {
let field_name = field_name.try_into()?;

let tag = self
Expand All @@ -133,9 +129,9 @@ impl<'a> Builder<'a> {
/// <https://godoc.org/github.com/cosmos/cosmos-sdk/types#ValAddress>
pub fn val_address(
&mut self,
field_name: impl TryInto<TypeName, Error = Error>,
field_name: impl TryInto<TypeName, Error = eyre::Report>,
address: Address,
) -> Result<&mut Self, Error> {
) -> Result<&mut Self> {
let field_name = field_name.try_into()?;
let tag = self
.schema_definition
Expand All @@ -150,28 +146,29 @@ impl<'a> Builder<'a> {
/// `sdk.ValAddress` encoded as Bech32
pub fn val_address_bech32(
&mut self,
field_name: impl TryInto<TypeName, Error = Error>,
field_name: impl TryInto<TypeName, Error = eyre::Report>,
addr_bech32: impl AsRef<str>,
) -> Result<&mut Self, Error> {
) -> Result<&mut Self> {
let (hrp, address) = Address::from_bech32(addr_bech32)?;

ensure!(
hrp == self.val_prefix,
ErrorKind::Address,
"invalid validator address prefix: `{}` (expected `{}`)",
hrp,
self.val_prefix,
);
if hrp != self.val_prefix {
return Err(Error::Address).wrap_err_with(|| {
format!(
"invalid validator address prefix: `{}` (expected `{}`)",
hrp, self.val_prefix
)
});
}

self.val_address(field_name, address)
}

/// Strings
pub fn string(
&mut self,
field_name: impl TryInto<TypeName, Error = Error>,
field_name: impl TryInto<TypeName, Error = eyre::Report>,
s: impl Into<String>,
) -> Result<&mut Self, Error> {
) -> Result<&mut Self> {
let field_name = field_name.try_into()?;
let tag = self
.schema_definition
Expand Down
Loading