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

feat(sol-types): rm validate: bool #863

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions crates/dyn-abi/benches/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ fn sol_types_decode(c: &mut Criterion) {

g.bench_function("word", |b| {
let input = decode_word_input();
b.iter(|| sol_data::Uint::<256>::abi_decode(black_box(&input), false).unwrap());
b.iter(|| sol_data::Uint::<256>::abi_decode(black_box(&input)).unwrap());
});

g.bench_function("dynamic", |b| {
let input = decode_dynamic_input();
b.iter(|| sol_data::String::abi_decode(black_box(&input), false).unwrap());
b.iter(|| sol_data::String::abi_decode(black_box(&input)).unwrap());
});

g.finish();
Expand Down
20 changes: 8 additions & 12 deletions crates/dyn-abi/src/dynamic/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ impl DynSolCall {
}

/// ABI decode the given data as function returns.
pub fn abi_decode_input(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.parameters, validate)
pub fn abi_decode_input(&self, data: &[u8]) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.parameters)
}

/// ABI encode the given values as function return values.
Expand All @@ -71,8 +71,8 @@ impl DynSolCall {
}

/// ABI decode the given data as function return values.
pub fn abi_decode_output(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
self.returns.abi_decode_output(data, validate)
pub fn abi_decode_output(&self, data: &[u8]) -> Result<Vec<DynSolValue>> {
self.returns.abi_decode_output(data)
}
}

Expand Down Expand Up @@ -109,8 +109,8 @@ impl DynSolReturns {
}

/// ABI decode the given data as function return values.
pub fn abi_decode_output(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
abi_decode(data, self.types(), validate)
pub fn abi_decode_output(&self, data: &[u8]) -> Result<Vec<DynSolValue>> {
abi_decode(data, self.types())
}
}

Expand Down Expand Up @@ -146,13 +146,9 @@ pub(crate) fn abi_encode(values: &[DynSolValue]) -> Vec<u8> {
DynSolValue::encode_seq(values)
}

pub(crate) fn abi_decode(
data: &[u8],
tys: &[DynSolType],
validate: bool,
) -> Result<Vec<DynSolValue>> {
pub(crate) fn abi_decode(data: &[u8], tys: &[DynSolType]) -> Result<Vec<DynSolValue>> {
let mut values = Vec::with_capacity(tys.len());
let mut decoder = Decoder::new(data, validate);
let mut decoder = Decoder::new(data);
for ty in tys {
let value = ty.abi_decode_inner(&mut decoder, crate::DynToken::decode_single_populate)?;
values.push(value);
Expand Down
52 changes: 7 additions & 45 deletions crates/dyn-abi/src/dynamic/event.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{DynSolType, DynSolValue, Error, Result};
use crate::{DynSolType, DynSolValue, Result};
use alloc::vec::Vec;
use alloy_primitives::{IntoLogData, Log, LogData, B256};

Expand Down Expand Up @@ -45,43 +45,15 @@ impl DynSolEvent {
}

/// Decode the event from the given log info.
pub fn decode_log_parts<I>(
&self,
topics: I,
data: &[u8],
validate: bool,
) -> Result<DecodedEvent>
pub fn decode_log_parts<I>(&self, topics: I, data: &[u8]) -> Result<DecodedEvent>
where
I: IntoIterator<Item = B256>,
{
let mut topics = topics.into_iter();
let num_topics = self.indexed.len() + !self.is_anonymous() as usize;
if validate {
match topics.size_hint() {
(n, Some(m)) if n == m && n != num_topics => {
return Err(Error::TopicLengthMismatch { expected: num_topics, actual: n })
}
_ => {}
}
}

// skip event hash if not anonymous
if !self.is_anonymous() {
let t = topics.next();
// Validate only if requested
if validate {
match t {
Some(sig) => {
let expected = self.topic_0.expect("not anonymous");
if sig != expected {
return Err(Error::EventSignatureMismatch { expected, actual: sig });
}
}
None => {
return Err(Error::TopicLengthMismatch { expected: num_topics, actual: 0 })
}
}
}
topics.next();
}

let indexed = self
Expand All @@ -96,22 +68,12 @@ impl DynSolEvent {

let body = self.body.abi_decode_sequence(data)?.into_fixed_seq().expect("body is a tuple");

if validate {
let remaining = topics.count();
if remaining > 0 {
return Err(Error::TopicLengthMismatch {
expected: num_topics,
actual: num_topics + remaining,
});
}
}

Ok(DecodedEvent { selector: self.topic_0, indexed, body })
}

/// Decode the event from the given log info.
pub fn decode_log_data(&self, log: &LogData, validate: bool) -> Result<DecodedEvent> {
self.decode_log_parts(log.topics().iter().copied(), &log.data, validate)
pub fn decode_log_data(&self, log: &LogData) -> Result<DecodedEvent> {
self.decode_log_parts(log.topics().iter().copied(), &log.data)
}

/// Get the selector for this event, if any.
Expand Down Expand Up @@ -195,7 +157,7 @@ mod test {
indexed: vec![],
body: DynSolType::Tuple(vec![DynSolType::Uint(256)]),
};
event.decode_log_data(&log, true).unwrap();
event.decode_log_data(&log).unwrap();
}

#[test]
Expand All @@ -219,7 +181,7 @@ mod test {
])]),
};

let decoded = event.decode_log_data(&log, true).unwrap();
let decoded = event.decode_log_data(&log).unwrap();
assert_eq!(
decoded.indexed,
vec![DynSolValue::Address(address!("0x0000000000000000000000000000000000012321"))]
Expand Down
4 changes: 2 additions & 2 deletions crates/dyn-abi/src/dynamic/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ impl DynSolType {
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
pub fn abi_decode(&self, data: &[u8]) -> Result<DynSolValue> {
self.abi_decode_inner(&mut Decoder::new(data, false), DynToken::decode_single_populate)
self.abi_decode_inner(&mut Decoder::new(data), DynToken::decode_single_populate)
}

/// Decode a [`DynSolValue`] from a byte slice. Fails if the value does not
Expand Down Expand Up @@ -555,7 +555,7 @@ impl DynSolType {
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
pub fn abi_decode_sequence(&self, data: &[u8]) -> Result<DynSolValue> {
self.abi_decode_inner(&mut Decoder::new(data, false), DynToken::decode_sequence_populate)
self.abi_decode_inner(&mut Decoder::new(data), DynToken::decode_sequence_populate)
}

/// Calculate the minimum number of ABI words necessary to encode this
Expand Down
29 changes: 14 additions & 15 deletions crates/dyn-abi/src/ext/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub trait JsonAbiExt: Sealed {
///
/// This function will return an error if the decoded data does not match
/// the expected input types.
fn abi_decode_input(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>>;
fn abi_decode_input(&self, data: &[u8]) -> Result<Vec<DynSolValue>>;
}

/// Provide ABI encoding and decoding for the [`Function`] type.
Expand All @@ -79,7 +79,7 @@ pub trait FunctionExt: JsonAbiExt + Sealed {
/// ABI-decodes the given data according to this functions's output types.
///
/// This method does not check for any prefixes or selectors.
fn abi_decode_output(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>>;
fn abi_decode_output(&self, data: &[u8]) -> Result<Vec<DynSolValue>>;
}

impl JsonAbiExt for Constructor {
Expand All @@ -94,8 +94,8 @@ impl JsonAbiExt for Constructor {
}

#[inline]
fn abi_decode_input(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.inputs, validate)
fn abi_decode_input(&self, data: &[u8]) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.inputs)
}
}

Expand All @@ -111,8 +111,8 @@ impl JsonAbiExt for Error {
}

#[inline]
fn abi_decode_input(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.inputs, validate)
fn abi_decode_input(&self, data: &[u8]) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.inputs)
}
}

Expand All @@ -128,8 +128,8 @@ impl JsonAbiExt for Function {
}

#[inline]
fn abi_decode_input(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.inputs, validate)
fn abi_decode_input(&self, data: &[u8]) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.inputs)
}
}

Expand All @@ -140,8 +140,8 @@ impl FunctionExt for Function {
}

#[inline]
fn abi_decode_output(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.outputs, validate)
fn abi_decode_output(&self, data: &[u8]) -> Result<Vec<DynSolValue>> {
abi_decode(data, &self.outputs)
}
}

Expand Down Expand Up @@ -180,9 +180,9 @@ fn abi_encode(values: &[DynSolValue]) -> Vec<u8> {
DynSolValue::encode_seq(values)
}

fn abi_decode(data: &[u8], params: &[Param], validate: bool) -> Result<Vec<DynSolValue>> {
fn abi_decode(data: &[u8], params: &[Param]) -> Result<Vec<DynSolValue>> {
let mut values = Vec::with_capacity(params.len());
let mut decoder = Decoder::new(data, validate);
let mut decoder = Decoder::new(data);
for param in params {
let ty = param.resolve()?;
let value = ty.abi_decode_inner(&mut decoder, crate::DynToken::decode_single_populate)?;
Expand Down Expand Up @@ -250,13 +250,12 @@ mod tests {

// decode
let response = U256::from(1u8).to_be_bytes_vec();
let decoded = func.abi_decode_output(&response, true).unwrap();
let decoded = func.abi_decode_output(&response).unwrap();
assert_eq!(decoded, [DynSolValue::Uint(U256::from(1u8), 256)]);

// Fail on wrong response type
let bad_response = Address::repeat_byte(3u8).to_vec();
assert!(func.abi_decode_output(&bad_response, true).is_err());
assert!(func.abi_decode_output(&bad_response, false).is_err());
assert!(func.abi_decode_output(&bad_response).is_err());
}

// https://github.com/foundry-rs/foundry/issues/7280
Expand Down
29 changes: 12 additions & 17 deletions crates/dyn-abi/src/ext/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,25 @@ pub trait EventExt: Sealed {
///
/// This function will return an error if the decoded data does not match
/// the expected input types.
fn decode_log_parts<I>(&self, topics: I, data: &[u8], validate: bool) -> Result<DecodedEvent>
fn decode_log_parts<I>(&self, topics: I, data: &[u8]) -> Result<DecodedEvent>
where
I: IntoIterator<Item = B256>;

/// Decodes the given log object according to this item's input types.
///
/// See [`decode_log`](EventExt::decode_log).
#[inline]
fn decode_log(&self, log: &LogData, validate: bool) -> Result<DecodedEvent> {
self.decode_log_parts(log.topics().iter().copied(), &log.data, validate)
fn decode_log(&self, log: &LogData) -> Result<DecodedEvent> {
self.decode_log_parts(log.topics().iter().copied(), &log.data)
}
}

impl EventExt for Event {
fn decode_log_parts<I>(&self, topics: I, data: &[u8], validate: bool) -> Result<DecodedEvent>
fn decode_log_parts<I>(&self, topics: I, data: &[u8]) -> Result<DecodedEvent>
where
I: IntoIterator<Item = B256>,
{
self.resolve()?.decode_log_parts(topics, data, validate)
self.resolve()?.decode_log_parts(topics, data)
}
}

Expand All @@ -87,22 +87,18 @@ mod tests {
let mut event = Event { name: "MyEvent".into(), inputs: vec![], anonymous: false };

// skips over hash
let values = event.decode_log_parts(None, &[], false).unwrap();
let values = event.decode_log_parts(None, &[]).unwrap();
assert!(values.indexed.is_empty());
assert!(values.body.is_empty());

// but if we validate, we get an error
let err = event.decode_log_parts(None, &[], true).unwrap_err();
assert_eq!(err, Error::TopicLengthMismatch { expected: 1, actual: 0 });

let values = event.decode_log_parts(Some(keccak256("MyEvent()")), &[], true).unwrap();
let values = event.decode_log_parts(Some(keccak256("MyEvent()")), &[]).unwrap();
assert!(values.indexed.is_empty());
assert!(values.body.is_empty());
event.anonymous = true;
let values = event.decode_log_parts(None, &[], false).unwrap();
let values = event.decode_log_parts(None, &[]).unwrap();
assert!(values.indexed.is_empty());
assert!(values.body.is_empty());
let values = event.decode_log_parts(None, &[], true).unwrap();
let values = event.decode_log_parts(None, &[]).unwrap();
assert!(values.indexed.is_empty());
assert!(values.body.is_empty());
}
Expand Down Expand Up @@ -138,7 +134,6 @@ mod tests {
0000000000000000000000002222222222222222222222222222222222222222
"
),
false,
)
.unwrap();

Expand Down Expand Up @@ -200,10 +195,10 @@ mod tests {
),
);

wrong_event.decode_log(&log, false).unwrap();
wrong_event.decode_log(&log).unwrap();
// TODO: How do we verify here?
// wrong_event.decode_log_object(&log, true).unwrap_err();
correct_event.decode_log(&log, false).unwrap();
correct_event.decode_log(&log, true).unwrap();
correct_event.decode_log(&log).unwrap();
correct_event.decode_log(&log).unwrap();
}
}
15 changes: 7 additions & 8 deletions crates/sol-macro-expander/src/expand/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,12 +719,11 @@ impl CallLikeExpander<'_> {
fn abi_decode_raw(
selector: [u8; 4],
data: &[u8],
validate: bool
)-> alloy_sol_types::Result<Self> {
static DECODE_SHIMS: &[fn(&[u8], bool) -> alloy_sol_types::Result<#name>] = &[
static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result<#name>] = &[
#({
fn #sorted_variants(data: &[u8], validate: bool) -> alloy_sol_types::Result<#name> {
<#sorted_types as alloy_sol_types::#trait_>::abi_decode_raw(data, validate)
fn #sorted_variants(data: &[u8]) -> alloy_sol_types::Result<#name> {
<#sorted_types as alloy_sol_types::#trait_>::abi_decode_raw(data)
.map(#name::#sorted_variants)
}
#sorted_variants
Expand All @@ -738,7 +737,7 @@ impl CallLikeExpander<'_> {
));
};
// `SELECTORS` and `DECODE_SHIMS` have the same length and are sorted in the same order.
DECODE_SHIMS[idx](data, validate)
DECODE_SHIMS[idx](data)
}

#[inline]
Expand Down Expand Up @@ -794,7 +793,7 @@ impl CallLikeExpander<'_> {
match topics.first().copied() {
#(
Some(<#variants as alloy_sol_types::#trait_>::SIGNATURE_HASH) =>
#ret <#variants as alloy_sol_types::#trait_>::decode_raw_log(topics, data, validate)
#ret <#variants as alloy_sol_types::#trait_>::decode_raw_log(topics, data)
.map(Self::#variants),
)*
_ => { #ret_err }
Expand All @@ -805,7 +804,7 @@ impl CallLikeExpander<'_> {
let variants = events.iter().filter(|e| e.is_anonymous()).map(e_name);
quote! {
#(
if let Ok(res) = <#variants as alloy_sol_types::#trait_>::decode_raw_log(topics, data, validate) {
if let Ok(res) = <#variants as alloy_sol_types::#trait_>::decode_raw_log(topics, data) {
return Ok(Self::#variants(res));
}
)*
Expand Down Expand Up @@ -844,7 +843,7 @@ impl CallLikeExpander<'_> {
const NAME: &'static str = #name_s;
const COUNT: usize = #count;

fn decode_raw_log(topics: &[alloy_sol_types::Word], data: &[u8], validate: bool) -> alloy_sol_types::Result<Self> {
fn decode_raw_log(topics: &[alloy_sol_types::Word], data: &[u8]) -> alloy_sol_types::Result<Self> {
#non_anon_impl
#anon_impl
}
Expand Down
Loading