Skip to content

Commit

Permalink
Merge branch 'main' into feat/add-statements
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes committed Aug 16, 2023
2 parents 72ad57f + 23d108e commit b795c0c
Show file tree
Hide file tree
Showing 24 changed files with 450 additions and 212 deletions.
6 changes: 5 additions & 1 deletion crates/dyn-abi/src/arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#![allow(clippy::arc_with_non_send_sync)]

use crate::{DynSolType, DynSolValue};
use alloy_primitives::{Address, B256, I256, U256};
use alloy_primitives::{Address, Function, B256, I256, U256};
use arbitrary::{size_hint, Unstructured};
use core::ops::RangeInclusive;
use proptest::{
Expand Down Expand Up @@ -133,6 +133,7 @@ enum Choice {
Int,
Uint,
Address,
Function,
FixedBytes,
Bytes,
String,
Expand All @@ -151,6 +152,7 @@ impl<'a> arbitrary::Arbitrary<'a> for DynSolType {
Choice::Int => u.arbitrary().map(int_size).map(Self::Int),
Choice::Uint => u.arbitrary().map(int_size).map(Self::Uint),
Choice::Address => Ok(Self::Address),
Choice::Function => Ok(Self::Function),
Choice::FixedBytes => Ok(Self::FixedBytes(u.int_in_range(1..=32)?)),
Choice::Bytes => Ok(Self::Bytes),
Choice::String => Ok(Self::String),
Expand Down Expand Up @@ -359,6 +361,7 @@ impl DynSolValue {
match ty {
DynSolType::Bool => u.arbitrary().map(Self::Bool),
DynSolType::Address => u.arbitrary().map(Self::Address),
DynSolType::Function => u.arbitrary().map(Self::Function),
&DynSolType::Int(sz) => u.arbitrary().map(|x| Self::Int(x, sz)),
&DynSolType::Uint(sz) => u.arbitrary().map(|x| Self::Uint(x, sz)),
&DynSolType::FixedBytes(sz) => u.arbitrary().map(|x| Self::FixedBytes(x, sz)),
Expand Down Expand Up @@ -410,6 +413,7 @@ impl DynSolValue {
match ty {
DynSolType::Bool => any::<bool>().prop_map(Self::Bool).sboxed(),
DynSolType::Address => any::<Address>().prop_map(Self::Address).sboxed(),
DynSolType::Function => any::<Function>().prop_map(Self::Function).sboxed(),
&DynSolType::Int(sz) => any::<I256>().prop_map(move |x| Self::Int(x, sz)).sboxed(),
&DynSolType::Uint(sz) => any::<U256>().prop_map(move |x| Self::Uint(x, sz)).sboxed(),
&DynSolType::FixedBytes(sz) => any::<B256>()
Expand Down
15 changes: 14 additions & 1 deletion crates/dyn-abi/src/eip712/coerce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ use alloc::{
string::{String, ToString},
vec::Vec,
};
use alloy_primitives::{Address, I256, U256};
use alloy_primitives::{Address, Function, I256, U256};

impl DynSolType {
/// Coerce a [`serde_json::Value`] to a [`DynSolValue`] via this type.
pub fn coerce(&self, value: &serde_json::Value) -> DynAbiResult<DynSolValue> {
match self {
DynSolType::Address => address(value),
DynSolType::Function => function(value),
DynSolType::Bool => bool(value),
DynSolType::Int(n) => int(*n, value),
DynSolType::Uint(n) => uint(*n, value),
Expand Down Expand Up @@ -41,6 +42,18 @@ fn address(value: &serde_json::Value) -> DynAbiResult<DynSolValue> {
Ok(DynSolValue::Address(address))
}

fn function(value: &serde_json::Value) -> DynAbiResult<DynSolValue> {
let function = value
.as_str()
.map(|s| {
s.parse::<Function>()
.map_err(|_| DynAbiError::type_mismatch(DynSolType::Function, value))
})
.ok_or_else(|| DynAbiError::type_mismatch(DynSolType::Function, value))??;

Ok(DynSolValue::Function(function))
}

fn bool(value: &serde_json::Value) -> DynAbiResult<DynSolValue> {
if let Some(bool) = value.as_bool() {
return Ok(DynSolValue::Bool(bool))
Expand Down
1 change: 1 addition & 0 deletions crates/dyn-abi/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ impl ResolveSolType for RootType<'_> {
fn resolve(&self) -> DynAbiResult<DynSolType> {
match self.span() {
"address" => Ok(DynSolType::Address),
"function" => Ok(DynSolType::Function),
"bool" => Ok(DynSolType::Bool),
"string" => Ok(DynSolType::String),
"bytes" => Ok(DynSolType::Bytes),
Expand Down
39 changes: 23 additions & 16 deletions crates/dyn-abi/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use alloy_sol_types::token::{PackedSeqToken, TokenType, WordToken};
// NOTE: do not derive `Hash` for this type. The derived version is not
// compatible with the current `PartialEq` implementation. If manually
// implementing `Hash`, ignore the `template` prop in the `DynSeq` variant
#[derive(Debug, Clone)]
#[derive(Clone, Debug)]
pub enum DynToken<'a> {
/// A single word.
Word(Word),
Expand Down Expand Up @@ -135,10 +135,10 @@ impl<'a> DynToken<'a> {
/// Decodes from a decoder, populating the structure with the decoded data.
#[inline]
pub(crate) fn decode_populate(&mut self, dec: &mut Decoder<'a>) -> Result<()> {
let dynamic = self.is_dynamic();
match self {
Self::Word(w) => *w = WordToken::decode_from(dec)?.0,
Self::FixedSeq(..) => {
let dynamic = self.is_dynamic();
let mut child = if dynamic {
dec.take_indirection()?
} else {
Expand All @@ -154,23 +154,31 @@ impl<'a> DynToken<'a> {
Self::DynSeq { contents, template } => {
let mut child = dec.take_indirection()?;
let size = child.take_u32()? as usize;
if size == 0 {
// should already be empty from `empty_dyn_token`
debug_assert!(contents.is_empty());
return Ok(())
}

// This appears to be an unclarity in the solidity spec. The
// spec specifies that offsets are relative to the beginning of
// `enc(X)`. But known-good test vectors have it relative to the
// word AFTER the array size
let mut child = child.raw_child();

let mut new_tokens: Vec<_> = Vec::with_capacity(size);
// This expect is safe because this is only invoked after
// `empty_dyn_token()` which always sets template
let t = template
.take()
.expect("No template. This is a bug, please report it.");
new_tokens.resize(size, *t);
let t = template.take().expect("no template for dynamic sequence");
let mut new_tokens = if size == 1 {
// re-use the box allocation
unsafe { Vec::from_raw_parts(Box::into_raw(t), 1, 1) }
} else {
vec![*t; size]
};

new_tokens
.iter_mut()
.try_for_each(|t| t.decode_populate(&mut child))?;
for t in &mut new_tokens {
t.decode_populate(&mut child)?;
}

*contents = new_tokens.into();
}
Expand All @@ -184,12 +192,11 @@ impl<'a> DynToken<'a> {
#[inline]
pub(crate) fn decode_sequence_populate(&mut self, dec: &mut Decoder<'a>) -> Result<()> {
match self {
Self::FixedSeq(buf, size) => {
for item in buf.to_mut().iter_mut().take(*size) {
item.decode_populate(dec)?;
}
Ok(())
}
Self::FixedSeq(buf, size) => buf
.to_mut()
.iter_mut()
.take(*size)
.try_for_each(|item| item.decode_populate(dec)),
Self::DynSeq { .. } => self.decode_populate(dec),
_ => Err(Error::custom(
"Called decode_sequence_populate on non-sequence token",
Expand Down
25 changes: 20 additions & 5 deletions crates/dyn-abi/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ struct StructProp {
pub enum DynSolType {
/// Address.
Address,
/// Function.
Function,
/// Boolean.
Bool,
/// Signed Integer.
Expand Down Expand Up @@ -222,6 +224,7 @@ impl DynSolType {
pub fn matches(&self, value: &DynSolValue) -> bool {
match self {
Self::Address => matches!(value, DynSolValue::Address(_)),
Self::Function => matches!(value, DynSolValue::Function(_)),
Self::Bytes => matches!(value, DynSolValue::Bytes(_)),
Self::Int(size) => matches!(value, DynSolValue::Int(_, s) if s == size),
Self::Uint(size) => matches!(value, DynSolValue::Uint(_, s) if s == size),
Expand Down Expand Up @@ -272,6 +275,9 @@ impl DynSolType {
(Self::Address, DynToken::Word(word)) => Ok(DynSolValue::Address(
sol_data::Address::detokenize(word.into()),
)),
(Self::Function, DynToken::Word(word)) => Ok(DynSolValue::Function(
sol_data::Function::detokenize(word.into()),
)),
(Self::Bool, DynToken::Word(word)) => {
Ok(DynSolValue::Bool(sol_data::Bool::detokenize(word.into())))
}
Expand Down Expand Up @@ -362,6 +368,7 @@ impl DynSolType {
fn sol_type_name_simple(&self) -> Option<&str> {
match self {
Self::Address => Some("address"),
Self::Function => Some("function"),
Self::Bool => Some("bool"),
Self::Bytes => Some("bytes"),
Self::String => Some("string"),
Expand All @@ -375,11 +382,16 @@ impl DynSolType {
fn sol_type_name_raw(&self, out: &mut String) {
match self {
#[cfg(feature = "eip712")]
Self::Address | Self::Bool | Self::Bytes | Self::String | Self::CustomStruct { .. } => {
Self::Address
| Self::Function
| Self::Bool
| Self::Bytes
| Self::String
| Self::CustomStruct { .. } => {
out.push_str(unsafe { self.sol_type_name_simple().unwrap_unchecked() });
}
#[cfg(not(feature = "eip712"))]
Self::Address | Self::Bool | Self::Bytes | Self::String => {
Self::Address | Self::Function | Self::Bool | Self::Bytes | Self::String => {
out.push_str(unsafe { self.sol_type_name_simple().unwrap_unchecked() });
}

Expand Down Expand Up @@ -450,9 +462,12 @@ impl DynSolType {
/// Instantiate an empty dyn token, to be decoded into.
pub(crate) fn empty_dyn_token(&self) -> DynToken<'_> {
match self {
Self::Address | Self::Bool | Self::FixedBytes(_) | Self::Int(_) | Self::Uint(_) => {
DynToken::Word(Word::ZERO)
}
Self::Address
| Self::Function
| Self::Bool
| Self::FixedBytes(_)
| Self::Int(_)
| Self::Uint(_) => DynToken::Word(Word::ZERO),

Self::Bytes | Self::String => DynToken::PackedSeq(&[]),

Expand Down
30 changes: 25 additions & 5 deletions crates/dyn-abi/src/value.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{DynSolType, DynToken, Word};
use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
use alloy_primitives::{Address, I256, U256};
use alloy_primitives::{Address, Function, I256, U256};
use alloy_sol_types::{utils::words_for_len, Encoder};

#[cfg(feature = "eip712")]
Expand Down Expand Up @@ -39,6 +39,8 @@ macro_rules! as_fixed_seq {
pub enum DynSolValue {
/// An address.
Address(Address),
/// A function pointer.
Function(Function),
/// A boolean.
Bool(bool),
/// A signed integer.
Expand Down Expand Up @@ -172,6 +174,7 @@ impl DynSolValue {
pub fn as_type(&self) -> Option<DynSolType> {
let ty = match self {
Self::Address(_) => DynSolType::Address,
Self::Function(_) => DynSolType::Function,
Self::Bool(_) => DynSolType::Bool,
Self::Bytes(_) => DynSolType::Bytes,
Self::FixedBytes(_, size) => DynSolType::FixedBytes(*size),
Expand Down Expand Up @@ -211,6 +214,7 @@ impl DynSolValue {
fn sol_type_name_simple(&self) -> Option<&str> {
match self {
Self::Address(_) => Some("address"),
Self::Function(_) => Some("function"),
Self::Bool(_) => Some("bool"),
Self::Bytes(_) => Some("bytes"),
Self::String(_) => Some("string"),
Expand All @@ -224,11 +228,16 @@ impl DynSolValue {
fn sol_type_name_raw(&self, out: &mut String) -> bool {
match self {
#[cfg(not(feature = "eip712"))]
Self::Address(_) | Self::Bool(_) | Self::Bytes(_) | Self::String(_) => {
Self::Address(_)
| Self::Function(_)
| Self::Bool(_)
| Self::Bytes(_)
| Self::String(_) => {
out.push_str(unsafe { self.sol_type_name_simple().unwrap_unchecked() });
}
#[cfg(feature = "eip712")]
Self::Address(_)
| Self::Function(_)
| Self::Bool(_)
| Self::Bytes(_)
| Self::String(_)
Expand Down Expand Up @@ -326,6 +335,7 @@ impl DynSolValue {
pub fn as_word(&self) -> Option<Word> {
match *self {
Self::Address(a) => Some(a.into_word()),
Self::Function(f) => Some(f.into_word()),
Self::Bool(b) => Some(Word::with_last_byte(b as u8)),
Self::FixedBytes(w, _) => Some(w),
Self::Int(i, _) => Some(i.into()),
Expand Down Expand Up @@ -490,6 +500,7 @@ impl DynSolValue {
pub fn is_dynamic(&self) -> bool {
match self {
Self::Address(_)
| Self::Function(_)
| Self::Bool(_)
| Self::Int(..)
| Self::Uint(..)
Expand Down Expand Up @@ -527,6 +538,7 @@ impl DynSolValue {
match self {
// `self.is_word()`
Self::Address(_)
| Self::Function(_)
| Self::Bool(_)
| Self::FixedBytes(..)
| Self::Int(..)
Expand Down Expand Up @@ -570,6 +582,7 @@ impl DynSolValue {
pub fn head_append(&self, enc: &mut Encoder) {
match self {
Self::Address(_)
| Self::Function(_)
| Self::Bool(_)
| Self::FixedBytes(..)
| Self::Int(..)
Expand All @@ -592,6 +605,7 @@ impl DynSolValue {
pub fn tail_append(&self, enc: &mut Encoder) {
match self {
Self::Address(_)
| Self::Function(_)
| Self::Bool(_)
| Self::FixedBytes(..)
| Self::Int(..)
Expand All @@ -617,6 +631,7 @@ impl DynSolValue {
pub fn encode_packed_to(&self, buf: &mut Vec<u8>) {
match self {
Self::Address(addr) => buf.extend_from_slice(addr.as_slice()),
Self::Function(func) => buf.extend_from_slice(func.as_slice()),
Self::Bool(b) => buf.push(*b as u8),
Self::String(s) => buf.extend_from_slice(s.as_bytes()),
Self::Bytes(bytes) => buf.extend_from_slice(bytes),
Expand Down Expand Up @@ -653,6 +668,7 @@ impl DynSolValue {
pub fn tokenize(&self) -> DynToken<'_> {
match self {
Self::Address(a) => a.into_word().into(),
Self::Function(f) => f.into_word().into(),
Self::Bool(b) => Word::with_last_byte(*b as u8).into(),
Self::Bytes(buf) => DynToken::PackedSeq(buf),
Self::FixedBytes(buf, _) => (*buf).into(),
Expand All @@ -669,11 +685,15 @@ impl DynSolValue {
let head_words = contents.iter().map(Self::head_words).sum::<usize>();
enc.push_offset(head_words as u32);

contents.iter().for_each(|t| {
for t in contents {
t.head_append(enc);
enc.bump_offset(t.tail_words() as u32);
});
contents.iter().for_each(|t| t.tail_append(enc));
}

for t in contents {
t.tail_append(enc);
}

enc.pop_offset();
}

Expand Down
Loading

0 comments on commit b795c0c

Please sign in to comment.