1use super::types::{EthAddress, EthBytes};
5use crate::prelude::*;
6use crate::rpc::state::{MessageTrace, ReturnTrace};
7use crate::shim::actors::{EVMActorStateLoad as _, evm, is_evm_actor};
8use crate::shim::address::Address as FilecoinAddress;
9use crate::shim::fvm_shared_latest::IDENTITY_HASH;
10use crate::shim::state_tree::{ActorState, StateTree};
11use crate::utils::encoding::hex;
12use ahash::HashMap;
13
14use crate::rpc::eth::{EVM_WORD_LENGTH, EthUint64};
15use anyhow::{Result, bail};
16use cbor4ii::core::Value;
17use cbor4ii::core::dec::Decode as _;
18use fvm_ipld_encoding::{CBOR, DAG_CBOR, IPLD_RAW, RawBytes};
19use serde::de;
20use std::sync::LazyLock;
21use tracing::log;
22
23pub fn lookup_eth_address<DB: Blockstore>(
24 addr: &FilecoinAddress,
25 state: &StateTree<DB>,
26) -> Result<Option<EthAddress>> {
27 if let Ok(eth_addr) = EthAddress::from_filecoin_address(addr)
29 && !eth_addr.is_masked_id()
30 {
31 return Ok(Some(eth_addr));
32 }
33
34 let id_addr = match state.lookup_id(addr)? {
36 Some(id) => id,
37 _ => return Ok(None),
38 };
39
40 let result = state.get_actor(addr);
42 if let Ok(Some(actor_state)) = result {
43 if let Some(addr) = actor_state.delegated_address {
44 if let Ok(eth_addr) = EthAddress::from_filecoin_address(&addr.into())
45 && !eth_addr.is_masked_id()
46 {
47 return Ok(Some(eth_addr));
49 }
50 } else {
51 }
53 } else if let Ok(None) = result {
54 } else {
56 result?;
58 }
59
60 Ok(Some(EthAddress::from_actor_id(id_addr)))
62}
63
64pub(crate) trait ActorStateEthExt {
66 fn eth_nonce<DB: Blockstore>(&self, store: &DB) -> anyhow::Result<EthUint64>;
68 fn eth_bytecode<DB: Blockstore>(&self, store: &DB) -> anyhow::Result<Option<EthBytes>>;
70}
71
72impl ActorStateEthExt for ActorState {
73 fn eth_nonce<DB: Blockstore>(&self, store: &DB) -> anyhow::Result<EthUint64> {
74 if is_evm_actor(&self.code) {
75 let evm_state = evm::State::load(store, self.code, self.state)
76 .context("failed to load EVM state for nonce")?;
77 Ok(EthUint64::from(evm_state.nonce()))
78 } else {
79 Ok(EthUint64::from(self.sequence))
80 }
81 }
82
83 fn eth_bytecode<DB: Blockstore>(&self, store: &DB) -> anyhow::Result<Option<EthBytes>> {
84 if !is_evm_actor(&self.code) {
85 return Ok(None);
86 }
87 let evm_state = evm::State::load(store, self.code, self.state)
88 .context("failed to load EVM state for bytecode")?;
89 let bytecode = store
90 .get(&evm_state.bytecode())
91 .context("failed to read EVM bytecode")?;
92 Ok(bytecode.map(EthBytes))
93 }
94}
95
96pub fn decode_payload(payload: &RawBytes, codec: u64) -> Result<EthBytes> {
98 match codec {
99 IDENTITY_HASH => Ok(EthBytes::default()),
100 DAG_CBOR | CBOR => {
101 let mut reader = cbor4ii::core::utils::SliceReader::new(payload.bytes());
102 match Value::decode(&mut reader) {
103 Ok(Value::Bytes(bytes)) => Ok(EthBytes(bytes)),
104 other => {
105 tracing::debug!(
106 "failed to decode params byte array: {other:?}, codec: {codec}, payload: {}",
107 hex::encode(payload.bytes())
108 );
109 bail!("failed to decode params byte array");
110 }
111 }
112 }
113 IPLD_RAW => Ok(EthBytes(payload.to_vec())),
114 _ => bail!("decode_payload: unsupported codec {codec}"),
115 }
116}
117
118pub fn decode_params<'a, T>(trace: &'a MessageTrace) -> anyhow::Result<T>
120where
121 T: de::Deserialize<'a>,
122{
123 let codec = trace.params_codec;
124 match codec {
125 DAG_CBOR | CBOR => fvm_ipld_encoding::from_slice(&trace.params)
126 .map_err(|e| anyhow::anyhow!("failed to decode params: {}", e)),
127 _ => bail!("Method called an unexpected codec {codec}"),
128 }
129}
130
131pub fn decode_return<'a, T>(trace: &'a ReturnTrace) -> anyhow::Result<T>
133where
134 T: de::Deserialize<'a>,
135{
136 let codec = trace.return_codec;
137 match codec {
138 DAG_CBOR | CBOR => fvm_ipld_encoding::from_slice(trace.r#return.bytes())
139 .map_err(|e| anyhow::anyhow!("failed to decode return value: {}", e)),
140 _ => bail!("Method returned an unexpected codec {codec}"),
141 }
142}
143
144pub fn decode_revert_reason(return_data: RawBytes) -> (Vec<u8>, String) {
146 let (data, reason) = match decode_payload(&return_data, CBOR) {
147 Err(e) => {
148 log::warn!("failed to unmarshal cbor bytes from message receipt return error: {e}");
149 (EthBytes::default(), String::default())
150 }
151 Ok(data) if !data.is_empty() => (data.clone(), parse_eth_revert(data.as_slice())),
152 Ok(data) => (data.clone(), "none".to_string()),
153 };
154
155 (data.0, reason)
156}
157
158const ERROR_FUNCTION_SELECTOR: [u8; 4] = [0x08, 0xc3, 0x79, 0xa0]; const PANIC_FUNCTION_SELECTOR: [u8; 4] = [0x4e, 0x48, 0x7b, 0x71]; static PANIC_ERROR_CODES: LazyLock<HashMap<u64, &'static str>> = LazyLock::new(|| {
163 let mut m = HashMap::new();
164 m.insert(0x00, "Panic()");
165 m.insert(0x01, "Assert()");
166 m.insert(0x11, "ArithmeticOverflow()");
167 m.insert(0x12, "DivideByZero()");
168 m.insert(0x21, "InvalidEnumVariant()");
169 m.insert(0x22, "InvalidStorageArray()");
170 m.insert(0x31, "PopEmptyArray()");
171 m.insert(0x32, "ArrayIndexOutOfBounds()");
172 m.insert(0x41, "OutOfMemory()");
173 m.insert(0x51, "CalledUninitializedFunction()");
174 m
175});
176
177const EVM_FUNC_SELECTOR_LENGTH: usize = 4;
179const EVM_PANIC_CODE_LENGTH: usize = 32;
180const EVM_UINT_PADDING_LENGTH: usize = 24;
181
182pub(crate) fn parse_eth_revert(data: &[u8]) -> String {
189 if data.len() < EVM_FUNC_SELECTOR_LENGTH + EVM_WORD_LENGTH {
191 return hex::encode_prefixed(data);
192 }
193
194 let selector = data
196 .get(..EVM_FUNC_SELECTOR_LENGTH)
197 .expect("checked data length >= 4");
198
199 match selector {
200 selector if selector == PANIC_FUNCTION_SELECTOR.as_slice() => parse_panic_revert(data),
201 selector if selector == ERROR_FUNCTION_SELECTOR.as_slice() => parse_error_revert(data),
202 _ => hex::encode_prefixed(data),
203 }
204}
205
206fn parse_error_revert(data: &[u8]) -> String {
207 let fallback = || hex::encode_prefixed(data);
208
209 let parse_result: Result<String, ()> = (|| {
210 let data = data
211 .get(EVM_FUNC_SELECTOR_LENGTH..)
212 .filter(|d| d.len() >= EVM_WORD_LENGTH)
213 .ok_or(())?;
214
215 let offset_bytes = data.get(..EVM_WORD_LENGTH).ok_or(())?;
217 let offset = EthUint64::from_bytes(offset_bytes).map_err(|_| ())?.0 as usize;
218
219 if offset >= data.len() || data.len().saturating_sub(offset) < EVM_WORD_LENGTH {
221 return Err(());
222 }
223
224 let length_bytes = data.get(offset..offset + EVM_WORD_LENGTH).ok_or(())?;
226 let len = EthUint64::from_bytes(length_bytes).map_err(|_| ())?.0 as usize;
227
228 let string_start = offset + EVM_WORD_LENGTH;
230 if string_start > data.len() || len > data.len() - string_start {
231 return Err(());
232 }
233
234 let string = data.get(string_start..string_start + len).ok_or(())?;
236 Ok(format!(
237 "Error({})",
238 std::str::from_utf8(string).map_err(|_| ())?
239 ))
240 })();
241
242 parse_result.unwrap_or_else(|_| fallback())
243}
244
245fn parse_panic_revert(data: &[u8]) -> String {
246 let fallback = || hex::encode_prefixed(data);
247
248 let parse_result: Result<String, ()> = (|| {
249 let code_bytes = data
250 .get(EVM_FUNC_SELECTOR_LENGTH..EVM_FUNC_SELECTOR_LENGTH + EVM_PANIC_CODE_LENGTH)
251 .ok_or(())?;
252
253 if !code_bytes
255 .get(..EVM_UINT_PADDING_LENGTH)
256 .ok_or(())?
257 .iter()
258 .all(|&v| v == 0)
259 {
260 return Ok(format!("Panic(0x{})", hex::encode(code_bytes)));
261 }
262
263 let code_data = code_bytes.get(..EVM_WORD_LENGTH).ok_or(())?;
264 let code = EthUint64::from_bytes(code_data).map_err(|_| ())?.0;
265 Ok(PANIC_ERROR_CODES
266 .get(&code)
267 .map(|s| s.to_string())
268 .unwrap_or_else(|| format!("Panic(0x{code:x})")))
269 })();
270
271 parse_result.unwrap_or_else(|_| fallback())
272}
273
274#[cfg(test)]
275mod test {
276 use super::*;
277 use cbor4ii::core::{enc::Encode, utils::BufWriter};
278 use cbor4ii::serde::Serializer;
279
280 fn create_error_data(msg: &str) -> Vec<u8> {
281 let mut encoded = Vec::new();
282
283 encoded.extend_from_slice(&[0x08, 0xc3, 0x79, 0xa0]);
285
286 let mut offset_bytes = [0u8; 32];
289 offset_bytes[24..32].copy_from_slice(&32u64.to_be_bytes());
290 encoded.extend_from_slice(&offset_bytes);
291
292 let mut length_bytes = [0u8; 32];
294 length_bytes[24..32].copy_from_slice(&(msg.len() as u64).to_be_bytes());
295 encoded.extend_from_slice(&length_bytes);
296
297 encoded.extend_from_slice(msg.as_bytes());
299
300 let padding_needed = (32 - (msg.len() % 32)) % 32;
302 encoded.extend_from_slice(&vec![0; padding_needed]);
303
304 encoded
305 }
306
307 fn create_panic_data(code: u64) -> Vec<u8> {
308 let mut data = Vec::new();
309 data.extend_from_slice(&PANIC_FUNCTION_SELECTOR);
310
311 data.extend_from_slice(&[0; 24]);
313 data.extend_from_slice(&code.to_be_bytes());
314 data
315 }
316
317 #[test]
318 fn test_all_valid_parse_panic_revert() {
319 for (code, msg) in PANIC_ERROR_CODES.iter() {
320 let data = create_panic_data(*code);
321 assert_eq!(parse_panic_revert(&data), format!("{msg}"));
322 }
323 }
324
325 #[test]
326 fn test_all_valid_hex_parse_error_revert() {
327 let panic_data =
328 hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000000")
329 .unwrap();
330 assert_eq!(parse_panic_revert(&panic_data), "Panic()");
331
332 let assert_data =
333 hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000001")
334 .unwrap();
335 assert_eq!(parse_panic_revert(&assert_data), "Assert()");
336
337 let arithmetic_overflow_data =
338 hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000011")
339 .unwrap();
340 assert_eq!(
341 parse_panic_revert(&arithmetic_overflow_data),
342 "ArithmeticOverflow()"
343 );
344
345 let divide_by_zero_data =
346 hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000012")
347 .unwrap();
348 assert_eq!(parse_panic_revert(÷_by_zero_data), "DivideByZero()");
349
350 let invalid_enum_variant_data =
351 hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000021")
352 .unwrap();
353 assert_eq!(
354 parse_panic_revert(&invalid_enum_variant_data),
355 "InvalidEnumVariant()"
356 );
357
358 let invalid_storage_array_data =
359 hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000022")
360 .unwrap();
361 assert_eq!(
362 parse_panic_revert(&invalid_storage_array_data),
363 "InvalidStorageArray()"
364 );
365
366 let pop_empty_array_data =
367 hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000031")
368 .unwrap();
369 assert_eq!(parse_panic_revert(&pop_empty_array_data), "PopEmptyArray()");
370
371 let array_index_out_of_bounds_data =
372 hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000032")
373 .unwrap();
374 assert_eq!(
375 parse_panic_revert(&array_index_out_of_bounds_data),
376 "ArrayIndexOutOfBounds()"
377 );
378
379 let out_of_memory_data =
380 hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000041")
381 .unwrap();
382 assert_eq!(parse_panic_revert(&out_of_memory_data), "OutOfMemory()");
383
384 let call_uninitialized_data =
385 hex::decode("4e487b710000000000000000000000000000000000000000000000000000000000000051")
386 .unwrap();
387 assert_eq!(
388 parse_panic_revert(&call_uninitialized_data),
389 "CalledUninitializedFunction()"
390 );
391 }
392
393 #[test]
394 fn test_parse_error_revert() {
395 let err_msg = "Not enough Ether provided";
396 let error_data = create_error_data(err_msg);
397 assert_eq!(parse_error_revert(&error_data), format!("Error({err_msg})"));
398
399 let err_data = hex::decode(
401 "\
402 08c379a0\
403 0000000000000000000000000000000000000000000000000000000000000020\
404 000000000000000000000000000000000000000000000000000000000000000b\
405 48656c6c6f20576f726c64000000000000000000000000000000000000000000\
406 ",
407 )
408 .unwrap();
409 assert_eq!(parse_error_revert(&err_data), "Error(Hello World)");
410
411 let insufficient = hex::decode(
413 "08c379a0\
414 0000000000000000000000000000000000000000000000000000000000000020\
415 0000000000000000000000000000000000000000000000000000000000000026\
416 45524332303a207472616e7366657220616d6f756e7420657863656564732062\
417 616c616e63650000000000000000000000000000000000000000000000000000",
418 )
419 .unwrap();
420 assert_eq!(
421 parse_eth_revert(&insufficient),
422 "Error(ERC20: transfer amount exceeds balance)"
423 );
424 }
425
426 #[test]
427 fn test_parse_eth_revert_main_function() {
428 let message = "Transaction failed";
430 let data = create_error_data(message);
431 assert_eq!(parse_eth_revert(&data), format!("Error({message})"));
432
433 let panic_data = create_panic_data(0x01); assert_eq!(parse_eth_revert(&panic_data), "Assert()");
436
437 let short_data = vec![0x1, 0x2, 0x3];
439 assert_eq!(
440 parse_eth_revert(&short_data),
441 format!("0x{}", hex::encode(&short_data))
442 );
443
444 let mut unknown_selector = vec![0; EVM_FUNC_SELECTOR_LENGTH + EVM_WORD_LENGTH];
446 unknown_selector[0] = 0xAA;
447 unknown_selector[1] = 0xBB;
448 unknown_selector[2] = 0xCC;
449 unknown_selector[3] = 0xDD;
450 assert_eq!(
451 parse_eth_revert(&unknown_selector),
452 format!("0x{}", hex::encode(&unknown_selector))
453 );
454 }
455
456 #[test]
457 fn test_parse_error_revert_special_cases() {
458 let data = create_error_data("");
460 assert_eq!(parse_error_revert(&data), "Error()");
461
462 let special = "Error message with special chars: !@#$%6^&*()_+{}|:<>!?";
464 let data = create_error_data(special);
465 assert_eq!(parse_error_revert(&data), format!("Error({special})"));
466
467 let unicode = "Error with Unicode: 你好世界";
469 let data = create_error_data(unicode);
470 assert_eq!(parse_error_revert(&data), format!("Error({unicode})"));
471
472 let mut invalid_offset = create_error_data("Test");
474 invalid_offset
476 .iter_mut()
477 .skip(24)
478 .take(8)
479 .for_each(|byte| *byte = 0xFF);
480 assert_eq!(
481 parse_error_revert(&invalid_offset),
482 format!("0x{}", hex::encode(&invalid_offset))
483 );
484
485 let mut invalid_length = create_error_data("Test");
487 invalid_length
489 .iter_mut()
490 .skip(32 + 24)
491 .take(8)
492 .for_each(|byte| *byte = 0xFF);
493 assert_eq!(
494 parse_error_revert(&invalid_length),
495 format!("0x{}", hex::encode(&invalid_length))
496 );
497
498 let truncated = create_error_data("Test");
500 let truncated = &truncated[0..70]; assert_eq!(
502 parse_error_revert(truncated),
503 format!("0x{}", hex::encode(truncated))
504 );
505
506 let mut invalid_utf8 = create_error_data("Test string");
508 let string_start = 32 + 32;
510 invalid_utf8[string_start + 2] = 0xFF;
511 assert_eq!(
512 parse_error_revert(&invalid_utf8),
513 format!("0x{}", hex::encode(&invalid_utf8))
514 );
515 }
516
517 #[test]
518 fn test_eth_revert_boundary_conditions() {
519 let min_size = vec![0; EVM_FUNC_SELECTOR_LENGTH + EVM_WORD_LENGTH];
521 assert_eq!(
522 parse_eth_revert(&min_size),
523 format!("0x{}", hex::encode(&min_size))
524 );
525
526 let too_small = vec![0; EVM_FUNC_SELECTOR_LENGTH + EVM_WORD_LENGTH - 1];
528 assert_eq!(
529 parse_eth_revert(&too_small),
530 format!("0x{}", hex::encode(&too_small))
531 );
532 }
533
534 #[test]
535 fn test_decode_payload() {
536 let result = decode_payload(&RawBytes::default(), 0);
538 assert!(result.unwrap().0.is_empty());
539
540 let result = decode_payload(&RawBytes::default(), IPLD_RAW);
542 assert!(result.unwrap().0.is_empty());
543
544 let result = decode_payload(&RawBytes::new(vec![1]), IPLD_RAW);
546 assert_eq!(result.unwrap(), EthBytes(vec![1]));
547
548 let result = decode_payload(&RawBytes::default(), DAG_CBOR);
550 assert!(result.is_err());
551
552 let mut writer = BufWriter::new(Vec::new());
554 Value::Bytes(vec![1]).encode(&mut writer).unwrap();
555 let serializer = Serializer::new(writer);
556 let encoded = serializer.into_inner().into_inner();
557
558 let result = decode_payload(&RawBytes::new(encoded.clone()), DAG_CBOR);
559 assert_eq!(result.unwrap(), EthBytes(vec![1]));
560
561 let result = decode_payload(&RawBytes::new(encoded), CBOR);
563 assert_eq!(result.unwrap(), EthBytes(vec![1]));
564
565 let result = decode_payload(&RawBytes::default(), 42);
567 assert!(result.is_err());
568
569 assert_eq!(
571 decode_payload(
572 &RawBytes::new(
573 hex::decode(
574 "58200000000000000000000000000000000000000000000000000000000000002710"
575 )
576 .unwrap(),
577 ),
578 CBOR
579 )
580 .unwrap(),
581 EthBytes(vec![
582 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
583 0, 0, 39, 16,
584 ])
585 );
586
587 let result = decode_payload(&RawBytes::new(vec![1]), IDENTITY_HASH);
589 assert!(result.unwrap().0.is_empty());
590 }
591}