Skip to content

Commit 386ec98

Browse files
authored
feat: refactor precompiles decoding, show output (#11382)
* feat: refactor precompiles decoding, show output * ret
1 parent bdbe379 commit 386ec98

File tree

1 file changed

+248
-82
lines changed

1 file changed

+248
-82
lines changed

crates/evm/traces/src/decoder/precompiles.rs

Lines changed: 248 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,6 @@ interface Precompiles {
3737
}
3838
use Precompiles::*;
3939

40-
macro_rules! tri {
41-
($e:expr) => {
42-
match $e {
43-
Ok(x) => x,
44-
Err(_) => return None,
45-
}
46-
};
47-
}
48-
4940
pub(super) fn is_known_precompile(address: Address, _chain_id: u64) -> bool {
5041
address[..19].iter().all(|&x| x == 0)
5142
&& matches!(
@@ -69,72 +60,241 @@ pub(super) fn decode(trace: &CallTrace, _chain_id: u64) -> Option<DecodedCallTra
6960
return None;
7061
}
7162

72-
let data = &trace.data;
63+
for &precompile in PRECOMPILES {
64+
if trace.address == precompile.address() {
65+
let signature = precompile.signature();
7366

74-
let (signature, args) = match trace.address {
75-
EC_RECOVER => {
76-
let (sig, ecrecoverCall { hash, v, r, s }) = tri!(abi_decode_call(data));
77-
(sig, vec![hash.to_string(), v.to_string(), r.to_string(), s.to_string()])
78-
}
79-
SHA_256 => (sha256Call::SIGNATURE, vec![data.to_string()]),
80-
RIPEMD_160 => (ripemdCall::SIGNATURE, vec![data.to_string()]),
81-
IDENTITY => (identityCall::SIGNATURE, vec![data.to_string()]),
82-
MOD_EXP => (modexpCall::SIGNATURE, tri!(decode_modexp(data))),
83-
EC_ADD => {
84-
let (sig, ecaddCall { x1, y1, x2, y2 }) = tri!(abi_decode_call(data));
85-
(sig, vec![x1.to_string(), y1.to_string(), x2.to_string(), y2.to_string()])
86-
}
87-
EC_MUL => {
88-
let (sig, ecmulCall { x1, y1, s }) = tri!(abi_decode_call(data));
89-
(sig, vec![x1.to_string(), y1.to_string(), s.to_string()])
67+
let args = precompile
68+
.decode_call(&trace.data)
69+
.unwrap_or_else(|_| vec![trace.data.to_string()]);
70+
71+
let return_data = precompile
72+
.decode_return(&trace.output)
73+
.unwrap_or_else(|_| vec![trace.output.to_string()]);
74+
let return_data = if return_data.len() == 1 {
75+
return_data.into_iter().next().unwrap()
76+
} else {
77+
format!("({})", return_data.join(", "))
78+
};
79+
80+
return Some(DecodedCallTrace {
81+
label: Some("PRECOMPILES".to_string()),
82+
call_data: Some(DecodedCallData { signature: signature.to_string(), args }),
83+
return_data: Some(return_data),
84+
});
9085
}
91-
EC_PAIRING => (ecpairingCall::SIGNATURE, tri!(decode_ecpairing(data))),
92-
BLAKE_2F => (blake2fCall::SIGNATURE, tri!(decode_blake2f(data))),
93-
POINT_EVALUATION => (pointEvaluationCall::SIGNATURE, tri!(decode_kzg(data))),
94-
_ => return None,
95-
};
86+
}
9687

97-
Some(DecodedCallTrace {
98-
label: Some("PRECOMPILES".to_string()),
99-
call_data: Some(DecodedCallData { signature: signature.to_string(), args }),
100-
// TODO: Decode return data too.
101-
return_data: None,
102-
})
88+
None
89+
}
90+
91+
pub(super) trait Precompile {
92+
fn address(&self) -> Address;
93+
fn signature(&self) -> &'static str;
94+
95+
fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
96+
Ok(vec![hex::encode_prefixed(data)])
97+
}
98+
99+
fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
100+
Ok(vec![hex::encode_prefixed(data)])
101+
}
103102
}
104103

105104
// Note: we use the ABI decoder, but this is not necessarily ABI-encoded data. It's just a
106105
// convenient way to decode the data.
107106

108-
fn decode_modexp(data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
109-
let mut decoder = abi::Decoder::new(data);
110-
let b_size = decoder.take_offset()?;
111-
let e_size = decoder.take_offset()?;
112-
let m_size = decoder.take_offset()?;
113-
let b = decoder.take_slice(b_size)?;
114-
let e = decoder.take_slice(e_size)?;
115-
let m = decoder.take_slice(m_size)?;
116-
Ok(vec![
117-
b_size.to_string(),
118-
e_size.to_string(),
119-
m_size.to_string(),
120-
hex::encode_prefixed(b),
121-
hex::encode_prefixed(e),
122-
hex::encode_prefixed(m),
123-
])
107+
const PRECOMPILES: &[&dyn Precompile] = &[
108+
&Ecrecover,
109+
&Sha256,
110+
&Ripemd160,
111+
&Identity,
112+
&ModExp,
113+
&EcAdd,
114+
&Ecmul,
115+
&Ecpairing,
116+
&Blake2f,
117+
&PointEvaluation,
118+
];
119+
120+
struct Ecrecover;
121+
impl Precompile for Ecrecover {
122+
fn address(&self) -> Address {
123+
EC_RECOVER
124+
}
125+
126+
fn signature(&self) -> &'static str {
127+
ecrecoverCall::SIGNATURE
128+
}
129+
130+
fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
131+
let ecrecoverCall { hash, v, r, s } = ecrecoverCall::abi_decode_raw(data)?;
132+
Ok(vec![hash.to_string(), v.to_string(), r.to_string(), s.to_string()])
133+
}
134+
135+
fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
136+
let ret = ecrecoverCall::abi_decode_returns(data)?;
137+
Ok(vec![ret.to_string()])
138+
}
124139
}
125140

126-
fn decode_ecpairing(data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
127-
let mut decoder = abi::Decoder::new(data);
128-
let mut values = Vec::new();
129-
// input must be either empty or a multiple of 6 32-byte values
130-
let mut tmp = <[&B256; 6]>::default();
131-
while !decoder.is_empty() {
132-
for tmp in &mut tmp {
133-
*tmp = decoder.take_word()?;
141+
struct Sha256;
142+
impl Precompile for Sha256 {
143+
fn address(&self) -> Address {
144+
SHA_256
145+
}
146+
147+
fn signature(&self) -> &'static str {
148+
sha256Call::SIGNATURE
149+
}
150+
151+
fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
152+
let ret = sha256Call::abi_decode_returns(data)?;
153+
Ok(vec![ret.to_string()])
154+
}
155+
}
156+
157+
struct Ripemd160;
158+
impl Precompile for Ripemd160 {
159+
fn address(&self) -> Address {
160+
RIPEMD_160
161+
}
162+
163+
fn signature(&self) -> &'static str {
164+
ripemdCall::SIGNATURE
165+
}
166+
167+
fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
168+
let ret = ripemdCall::abi_decode_returns(data)?;
169+
Ok(vec![ret.to_string()])
170+
}
171+
}
172+
173+
struct Identity;
174+
impl Precompile for Identity {
175+
fn address(&self) -> Address {
176+
IDENTITY
177+
}
178+
179+
fn signature(&self) -> &'static str {
180+
identityCall::SIGNATURE
181+
}
182+
}
183+
184+
struct ModExp;
185+
impl Precompile for ModExp {
186+
fn address(&self) -> Address {
187+
MOD_EXP
188+
}
189+
190+
fn signature(&self) -> &'static str {
191+
modexpCall::SIGNATURE
192+
}
193+
194+
fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
195+
let mut decoder = abi::Decoder::new(data);
196+
let b_size = decoder.take_offset()?;
197+
let e_size = decoder.take_offset()?;
198+
let m_size = decoder.take_offset()?;
199+
let b = decoder.take_slice(b_size)?;
200+
let e = decoder.take_slice(e_size)?;
201+
let m = decoder.take_slice(m_size)?;
202+
Ok(vec![
203+
b_size.to_string(),
204+
e_size.to_string(),
205+
m_size.to_string(),
206+
hex::encode_prefixed(b),
207+
hex::encode_prefixed(e),
208+
hex::encode_prefixed(m),
209+
])
210+
}
211+
}
212+
213+
struct EcAdd;
214+
impl Precompile for EcAdd {
215+
fn address(&self) -> Address {
216+
EC_ADD
217+
}
218+
219+
fn signature(&self) -> &'static str {
220+
ecaddCall::SIGNATURE
221+
}
222+
223+
fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
224+
let ecaddCall { x1, y1, x2, y2 } = ecaddCall::abi_decode_raw(data)?;
225+
Ok(vec![x1.to_string(), y1.to_string(), x2.to_string(), y2.to_string()])
226+
}
227+
228+
fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
229+
let ecaddReturn { x, y } = ecaddCall::abi_decode_returns(data)?;
230+
Ok(vec![x.to_string(), y.to_string()])
231+
}
232+
}
233+
234+
struct Ecmul;
235+
impl Precompile for Ecmul {
236+
fn address(&self) -> Address {
237+
EC_MUL
238+
}
239+
240+
fn signature(&self) -> &'static str {
241+
ecmulCall::SIGNATURE
242+
}
243+
244+
fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
245+
let ecmulCall { x1, y1, s } = ecmulCall::abi_decode_raw(data)?;
246+
Ok(vec![x1.to_string(), y1.to_string(), s.to_string()])
247+
}
248+
249+
fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
250+
let ecmulReturn { x, y } = ecmulCall::abi_decode_returns(data)?;
251+
Ok(vec![x.to_string(), y.to_string()])
252+
}
253+
}
254+
255+
struct Ecpairing;
256+
impl Precompile for Ecpairing {
257+
fn address(&self) -> Address {
258+
EC_PAIRING
259+
}
260+
261+
fn signature(&self) -> &'static str {
262+
ecpairingCall::SIGNATURE
263+
}
264+
265+
fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
266+
let mut decoder = abi::Decoder::new(data);
267+
let mut values = Vec::new();
268+
// input must be either empty or a multiple of 6 32-byte values
269+
let mut tmp = <[&B256; 6]>::default();
270+
while !decoder.is_empty() {
271+
for tmp in &mut tmp {
272+
*tmp = decoder.take_word()?;
273+
}
274+
values.push(iter_to_string(tmp.iter().map(|x| U256::from_be_bytes(x.0))));
134275
}
135-
values.push(iter_to_string(tmp.iter().map(|x| U256::from_be_bytes(x.0))));
276+
Ok(values)
277+
}
278+
279+
fn decode_return(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
280+
let ret = ecpairingCall::abi_decode_returns(data)?;
281+
Ok(vec![ret.to_string()])
282+
}
283+
}
284+
285+
struct Blake2f;
286+
impl Precompile for Blake2f {
287+
fn address(&self) -> Address {
288+
BLAKE_2F
289+
}
290+
291+
fn signature(&self) -> &'static str {
292+
blake2fCall::SIGNATURE
293+
}
294+
295+
fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
296+
decode_blake2f(data)
136297
}
137-
Ok(values)
138298
}
139299

140300
fn decode_blake2f<'a>(data: &'a [u8]) -> alloy_sol_types::Result<Vec<String>> {
@@ -155,25 +315,31 @@ fn decode_blake2f<'a>(data: &'a [u8]) -> alloy_sol_types::Result<Vec<String>> {
155315
])
156316
}
157317

158-
fn decode_kzg(data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
159-
let mut decoder = abi::Decoder::new(data);
160-
let versioned_hash = decoder.take_word()?;
161-
let z = decoder.take_word()?;
162-
let y = decoder.take_word()?;
163-
let commitment = decoder.take_slice(48)?;
164-
let proof = decoder.take_slice(48)?;
165-
Ok(vec![
166-
versioned_hash.to_string(),
167-
z.to_string(),
168-
y.to_string(),
169-
hex::encode_prefixed(commitment),
170-
hex::encode_prefixed(proof),
171-
])
172-
}
318+
struct PointEvaluation;
319+
impl Precompile for PointEvaluation {
320+
fn address(&self) -> Address {
321+
POINT_EVALUATION
322+
}
173323

174-
fn abi_decode_call<T: SolCall>(data: &[u8]) -> alloy_sol_types::Result<(&'static str, T)> {
175-
// raw because there are no selectors here
176-
Ok((T::SIGNATURE, T::abi_decode_raw(data)?))
324+
fn signature(&self) -> &'static str {
325+
pointEvaluationCall::SIGNATURE
326+
}
327+
328+
fn decode_call(&self, data: &[u8]) -> alloy_sol_types::Result<Vec<String>> {
329+
let mut decoder = abi::Decoder::new(data);
330+
let versioned_hash = decoder.take_word()?;
331+
let z = decoder.take_word()?;
332+
let y = decoder.take_word()?;
333+
let commitment = decoder.take_slice(48)?;
334+
let proof = decoder.take_slice(48)?;
335+
Ok(vec![
336+
versioned_hash.to_string(),
337+
z.to_string(),
338+
y.to_string(),
339+
hex::encode_prefixed(commitment),
340+
hex::encode_prefixed(proof),
341+
])
342+
}
177343
}
178344

179345
fn iter_to_string<I: Iterator<Item = T>, T: std::fmt::Display>(iter: I) -> String {
@@ -216,7 +382,7 @@ mod tests {
216382
30364cd4f8a293b1a04f0153548d3e01baad091c69097ca4e9f26be63e4095b5
217383
"
218384
);
219-
let decoded = decode_ecpairing(&data).unwrap();
385+
let decoded = Ecpairing.decode_call(&data).unwrap();
220386
// 4 arrays of 6 32-byte values
221387
assert_eq!(decoded.len(), 4);
222388
}

0 commit comments

Comments
 (0)