@@ -37,15 +37,6 @@ interface Precompiles {
37
37
}
38
38
use Precompiles :: * ;
39
39
40
- macro_rules! tri {
41
- ( $e: expr) => {
42
- match $e {
43
- Ok ( x) => x,
44
- Err ( _) => return None ,
45
- }
46
- } ;
47
- }
48
-
49
40
pub ( super ) fn is_known_precompile ( address : Address , _chain_id : u64 ) -> bool {
50
41
address[ ..19 ] . iter ( ) . all ( |& x| x == 0 )
51
42
&& matches ! (
@@ -69,72 +60,241 @@ pub(super) fn decode(trace: &CallTrace, _chain_id: u64) -> Option<DecodedCallTra
69
60
return None ;
70
61
}
71
62
72
- let data = & trace. data ;
63
+ for & precompile in PRECOMPILES {
64
+ if trace. address == precompile. address ( ) {
65
+ let signature = precompile. signature ( ) ;
73
66
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
+ } ) ;
90
85
}
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
+ }
96
87
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
+ }
103
102
}
104
103
105
104
// Note: we use the ABI decoder, but this is not necessarily ABI-encoded data. It's just a
106
105
// convenient way to decode the data.
107
106
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
+ }
124
139
}
125
140
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 ) ) ) ) ;
134
275
}
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)
136
297
}
137
- Ok ( values)
138
298
}
139
299
140
300
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>> {
155
315
] )
156
316
}
157
317
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
+ }
173
323
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
+ }
177
343
}
178
344
179
345
fn iter_to_string < I : Iterator < Item = T > , T : std:: fmt:: Display > ( iter : I ) -> String {
@@ -216,7 +382,7 @@ mod tests {
216
382
30364cd4f8a293b1a04f0153548d3e01baad091c69097ca4e9f26be63e4095b5
217
383
"
218
384
) ;
219
- let decoded = decode_ecpairing ( & data) . unwrap ( ) ;
385
+ let decoded = Ecpairing . decode_call ( & data) . unwrap ( ) ;
220
386
// 4 arrays of 6 32-byte values
221
387
assert_eq ! ( decoded. len( ) , 4 ) ;
222
388
}
0 commit comments