Misc Fixes (#97)

* fix: use generic instead of impl Trait

* fix: do not skip first 4 bytes when decoding outputs
This commit is contained in:
Georgios Konstantopoulos 2020-11-12 12:08:20 +02:00 committed by GitHub
parent c30f45fc72
commit 84aafbbd1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 26 additions and 24 deletions

View File

@ -21,6 +21,9 @@ pub enum AbiError {
/// Thrown when detokenizing an argument /// Thrown when detokenizing an argument
#[error(transparent)] #[error(transparent)]
DetokenizationError(#[from] InvalidOutputType), DetokenizationError(#[from] InvalidOutputType),
#[error("missing or wrong function selector")]
WrongSelector,
} }
/// A reduced form of `Contract` which just takes the `abi` and produces /// A reduced form of `Contract` which just takes the `abi` and produces
@ -33,7 +36,7 @@ pub struct BaseContract {
/// functions in the contract ABI. This is used to avoid allocation when /// functions in the contract ABI. This is used to avoid allocation when
/// searching for matching functions by signature. /// searching for matching functions by signature.
// Adapted from: https://github.com/gnosis/ethcontract-rs/blob/master/src/contract.rs // Adapted from: https://github.com/gnosis/ethcontract-rs/blob/master/src/contract.rs
pub(crate) methods: HashMap<Selector, (String, usize)>, pub methods: HashMap<Selector, (String, usize)>,
} }
impl From<Abi> for BaseContract { impl From<Abi> for BaseContract {
@ -68,10 +71,10 @@ impl BaseContract {
/// ///
/// If the function exists multiple times and you want to use one of the overloaded /// If the function exists multiple times and you want to use one of the overloaded
/// versions, consider using `decode_with_selector` /// versions, consider using `decode_with_selector`
pub fn decode<D: Detokenize>( pub fn decode<D: Detokenize, T: AsRef<[u8]>>(
&self, &self,
name: &str, name: &str,
bytes: impl AsRef<[u8]>, bytes: T,
) -> Result<D, AbiError> { ) -> Result<D, AbiError> {
let function = self.abi.function(name)?; let function = self.abi.function(name)?;
decode_fn(function, bytes, true) decode_fn(function, bytes, true)
@ -90,10 +93,10 @@ impl BaseContract {
} }
/// Decodes the provided ABI encoded bytes with the selected function selector /// Decodes the provided ABI encoded bytes with the selected function selector
pub fn decode_with_selector<D: Detokenize>( pub fn decode_with_selector<D: Detokenize, T: AsRef<[u8]>>(
&self, &self,
signature: Selector, signature: Selector,
bytes: impl AsRef<[u8]>, bytes: T,
) -> Result<D, AbiError> { ) -> Result<D, AbiError> {
let function = self.get_from_signature(signature)?; let function = self.get_from_signature(signature)?;
decode_fn(function, bytes, true) decode_fn(function, bytes, true)
@ -152,20 +155,19 @@ pub(crate) fn encode_fn<T: Tokenize>(function: &Function, args: T) -> Result<Byt
} }
// Helper for decoding bytes from a specific function // Helper for decoding bytes from a specific function
pub(crate) fn decode_fn<D: Detokenize>( pub fn decode_fn<D: Detokenize, T: AsRef<[u8]>>(
function: &Function, function: &Function,
bytes: impl AsRef<[u8]>, bytes: T,
is_input: bool, is_input: bool,
) -> Result<D, AbiError> { ) -> Result<D, AbiError> {
let mut bytes = bytes.as_ref(); let bytes = bytes.as_ref();
if bytes.starts_with(&function.selector()) {
bytes = &bytes[4..];
}
let tokens = if is_input { let tokens = if is_input {
function.decode_input(bytes.as_ref())? if bytes.len() < 4 || bytes[..4] != function.selector() {
return Err(AbiError::WrongSelector);
}
function.decode_input(&bytes[4..])?
} else { } else {
function.decode_output(bytes.as_ref())? function.decode_output(bytes)?
}; };
Ok(D::from_tokens(tokens)?) Ok(D::from_tokens(tokens)?)

View File

@ -17,7 +17,7 @@ mod contract;
pub use contract::Contract; pub use contract::Contract;
mod base; mod base;
pub use base::BaseContract; pub use base::{decode_fn, BaseContract};
mod call; mod call;
pub use call::ContractError; pub use call::ContractError;

View File

@ -3,7 +3,7 @@ use serde::de::{Error, Unexpected};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// Wrapper type around Vec<u8> to deserialize/serialize "0x" prefixed ethereum hex strings /// Wrapper type around Vec<u8> to deserialize/serialize "0x" prefixed ethereum hex strings
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
pub struct Bytes( pub struct Bytes(
#[serde( #[serde(
serialize_with = "serialize_bytes", serialize_with = "serialize_bytes",

View File

@ -380,7 +380,7 @@ pub trait Middleware: Sync + Send + Debug {
req: TransactionRequest, req: TransactionRequest,
trace_type: Vec<TraceType>, trace_type: Vec<TraceType>,
block: Option<BlockNumber>, block: Option<BlockNumber>,
) -> Result<BlockTrace, ProviderError> { ) -> Result<BlockTrace, Self::Error> {
self.inner() self.inner()
.trace_call(req, trace_type, block) .trace_call(req, trace_type, block)
.await .await
@ -392,7 +392,7 @@ pub trait Middleware: Sync + Send + Debug {
&self, &self,
data: Bytes, data: Bytes,
trace_type: Vec<TraceType>, trace_type: Vec<TraceType>,
) -> Result<BlockTrace, ProviderError> { ) -> Result<BlockTrace, Self::Error> {
self.inner() self.inner()
.trace_raw_transaction(data, trace_type) .trace_raw_transaction(data, trace_type)
.await .await
@ -404,7 +404,7 @@ pub trait Middleware: Sync + Send + Debug {
&self, &self,
hash: H256, hash: H256,
trace_type: Vec<TraceType>, trace_type: Vec<TraceType>,
) -> Result<BlockTrace, ProviderError> { ) -> Result<BlockTrace, Self::Error> {
self.inner() self.inner()
.trace_replay_transaction(hash, trace_type) .trace_replay_transaction(hash, trace_type)
.await .await
@ -416,7 +416,7 @@ pub trait Middleware: Sync + Send + Debug {
&self, &self,
block: BlockNumber, block: BlockNumber,
trace_type: Vec<TraceType>, trace_type: Vec<TraceType>,
) -> Result<Vec<BlockTrace>, ProviderError> { ) -> Result<Vec<BlockTrace>, Self::Error> {
self.inner() self.inner()
.trace_replay_block_transactions(block, trace_type) .trace_replay_block_transactions(block, trace_type)
.await .await
@ -424,12 +424,12 @@ pub trait Middleware: Sync + Send + Debug {
} }
/// Returns traces created at given block /// Returns traces created at given block
async fn trace_block(&self, block: BlockNumber) -> Result<Vec<Trace>, ProviderError> { async fn trace_block(&self, block: BlockNumber) -> Result<Vec<Trace>, Self::Error> {
self.inner().trace_block(block).await.map_err(FromErr::from) self.inner().trace_block(block).await.map_err(FromErr::from)
} }
/// Return traces matching the given filter /// Return traces matching the given filter
async fn trace_filter(&self, filter: TraceFilter) -> Result<Vec<Trace>, ProviderError> { async fn trace_filter(&self, filter: TraceFilter) -> Result<Vec<Trace>, Self::Error> {
self.inner() self.inner()
.trace_filter(filter) .trace_filter(filter)
.await .await
@ -441,7 +441,7 @@ pub trait Middleware: Sync + Send + Debug {
&self, &self,
hash: H256, hash: H256,
index: Vec<T>, index: Vec<T>,
) -> Result<Trace, ProviderError> { ) -> Result<Trace, Self::Error> {
self.inner() self.inner()
.trace_get(hash, index) .trace_get(hash, index)
.await .await
@ -449,7 +449,7 @@ pub trait Middleware: Sync + Send + Debug {
} }
/// Returns all traces of a given transaction /// Returns all traces of a given transaction
async fn trace_transaction(&self, hash: H256) -> Result<Vec<Trace>, ProviderError> { async fn trace_transaction(&self, hash: H256) -> Result<Vec<Trace>, Self::Error> {
self.inner() self.inner()
.trace_transaction(hash) .trace_transaction(hash)
.await .await