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