@@ -110,8 +110,9 @@ impl<'de> Deserialize<'de> for TracerConfig {
110110 }
111111
112112 match TracerConfigHelper :: deserialize ( deserializer) ? {
113- TracerConfigHelper :: WithType ( cfg) =>
114- Ok ( TracerConfig { config : cfg. config , timeout : cfg. timeout } ) ,
113+ TracerConfigHelper :: WithType ( cfg) => {
114+ Ok ( TracerConfig { config : cfg. config , timeout : cfg. timeout } )
115+ } ,
115116 TracerConfigHelper :: Inline ( cfg) => Ok ( TracerConfig {
116117 config : TracerType :: ExecutionTracer ( Some ( cfg. execution_tracer_config ) ) ,
117118 timeout : cfg. timeout ,
@@ -482,7 +483,7 @@ where
482483#[ derive(
483484 Default , TypeInfo , Encode , Decode , Serialize , Deserialize , Clone , Debug , Eq , PartialEq ,
484485) ]
485- #[ serde( rename_all = "camelCase" ) ]
486+ #[ serde( default , rename_all = "camelCase" ) ]
486487pub struct ExecutionTrace {
487488 /// Total gas used by the transaction.
488489 pub gas : u64 ,
@@ -499,8 +500,10 @@ pub struct ExecutionTrace {
499500}
500501
501502/// An execution step which can be either an EVM opcode or a PVM syscall.
502- #[ derive( TypeInfo , Encode , Decode , Serialize , Deserialize , Clone , Debug , Eq , PartialEq ) ]
503- #[ serde( rename_all = "camelCase" ) ]
503+ #[ derive(
504+ TypeInfo , Encode , Decode , Serialize , Deserialize , Clone , Debug , Eq , PartialEq , Default ,
505+ ) ]
506+ #[ serde( default , rename_all = "camelCase" ) ]
504507pub struct ExecutionStep {
505508 /// Remaining gas before executing this step.
506509 #[ codec( compact) ]
@@ -513,10 +516,10 @@ pub struct ExecutionStep {
513516 /// Current call depth.
514517 pub depth : u16 ,
515518 /// Return data from last frame output.
516- #[ serde( skip_serializing_if = "Bytes::is_empty" ) ]
519+ #[ serde( default , skip_serializing_if = "Bytes::is_empty" ) ]
517520 pub return_data : Bytes ,
518521 /// Any error that occurred during execution.
519- #[ serde( skip_serializing_if = "Option::is_none" ) ]
522+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
520523 pub error : Option < String > ,
521524 /// The kind of execution step (EVM opcode or PVM syscall).
522525 #[ serde( flatten) ]
@@ -536,16 +539,22 @@ pub enum ExecutionStepKind {
536539 #[ serde( serialize_with = "serialize_opcode" , deserialize_with = "deserialize_opcode" ) ]
537540 op : u8 ,
538541 /// EVM stack contents.
539- #[ serde( serialize_with = "serialize_stack_minimal" ) ]
542+ #[ serde(
543+ default ,
544+ serialize_with = "serialize_stack_minimal" ,
545+ deserialize_with = "deserialize_stack_minimal"
546+ ) ]
540547 stack : Vec < Bytes > ,
541548 /// EVM memory contents.
542549 #[ serde(
550+ default ,
543551 skip_serializing_if = "Vec::is_empty" ,
544552 serialize_with = "serialize_memory_no_prefix"
545553 ) ]
546554 memory : Vec < Bytes > ,
547555 /// Contract storage changes.
548556 #[ serde(
557+ default ,
549558 skip_serializing_if = "Option::is_none" ,
550559 serialize_with = "serialize_storage_no_prefix"
551560 ) ]
@@ -554,19 +563,32 @@ pub enum ExecutionStepKind {
554563 /// A PVM syscall execution.
555564 PVMSyscall {
556565 /// The executed syscall.
557- #[ serde( serialize_with = "serialize_syscall_op" ) ]
566+ #[ serde(
567+ serialize_with = "serialize_syscall_op" ,
568+ deserialize_with = "deserialize_syscall_op"
569+ ) ]
558570 op : u8 ,
559571 /// The syscall arguments (register values a0-a5).
560572 /// Omitted when `disable_syscall_details` is true in ExecutionTracerConfig.
561- #[ serde( skip_serializing_if = "Vec::is_empty" , with = "super::hex_serde::vec" ) ]
573+ #[ serde( default , skip_serializing_if = "Vec::is_empty" , with = "super::hex_serde::vec" ) ]
562574 args : Vec < u64 > ,
563575 /// The syscall return value.
564576 /// Omitted when `disable_syscall_details` is true in ExecutionTracerConfig.
565- #[ serde( skip_serializing_if = "Option::is_none" , with = "super::hex_serde::option" ) ]
577+ #[ serde(
578+ default ,
579+ skip_serializing_if = "Option::is_none" ,
580+ with = "super::hex_serde::option"
581+ ) ]
566582 returned : Option < u64 > ,
567583 } ,
568584}
569585
586+ impl Default for ExecutionStepKind {
587+ fn default ( ) -> Self {
588+ Self :: EVMOpcode { pc : 0 , op : 0 , stack : Vec :: new ( ) , memory : Vec :: new ( ) , storage : None }
589+ }
590+ }
591+
570592macro_rules! define_opcode_functions {
571593 ( $( $op: ident) ,* $( , ) ?) => {
572594 /// Get opcode name from byte value using opcode names
@@ -761,7 +783,7 @@ where
761783{
762784 use crate :: vm:: pvm:: env:: list_syscalls;
763785 let Some ( syscall_name_bytes) = list_syscalls ( ) . get ( * idx as usize ) else {
764- return Err ( serde:: ser:: Error :: custom ( alloc:: format!( "Unknown syscall: {idx}" ) ) )
786+ return Err ( serde:: ser:: Error :: custom ( alloc:: format!( "Unknown syscall: {idx}" ) ) ) ;
765787 } ;
766788 let name = core:: str:: from_utf8 ( syscall_name_bytes) . unwrap_or_default ( ) ;
767789 serializer. serialize_str ( name)
@@ -777,6 +799,21 @@ where
777799 . ok_or_else ( || serde:: de:: Error :: custom ( alloc:: format!( "Unknown opcode: {}" , s) ) )
778800}
779801
802+ /// Deserialize syscall from string name to index
803+ fn deserialize_syscall_op < ' de , D > ( deserializer : D ) -> Result < u8 , D :: Error >
804+ where
805+ D : serde:: Deserializer < ' de > ,
806+ {
807+ use crate :: vm:: pvm:: env:: list_syscalls;
808+ let s = String :: deserialize ( deserializer) ?;
809+ let syscalls = list_syscalls ( ) ;
810+ syscalls
811+ . iter ( )
812+ . position ( |name| core:: str:: from_utf8 ( name) . unwrap_or_default ( ) == s)
813+ . map ( |i| i as u8 )
814+ . ok_or_else ( || serde:: de:: Error :: custom ( alloc:: format!( "Unknown syscall: {}" , s) ) )
815+ }
816+
780817/// A smart contract execution call trace.
781818#[ derive(
782819 TypeInfo , Default , Encode , Decode , Serialize , Deserialize , Clone , Debug , Eq , PartialEq ,
@@ -859,6 +896,31 @@ where
859896 minimal_values. serialize ( serializer)
860897}
861898
899+ /// Deserialize stack values from minimal hex format
900+ fn deserialize_stack_minimal < ' de , D > ( deserializer : D ) -> Result < Vec < Bytes > , D :: Error >
901+ where
902+ D : serde:: Deserializer < ' de > ,
903+ {
904+ let strings = Vec :: < String > :: deserialize ( deserializer) ?;
905+ strings
906+ . into_iter ( )
907+ . map ( |s| {
908+ // Parse as U256 to handle minimal hex like "0x0" or "0x4"
909+ let s = s. trim_start_matches ( "0x" ) ;
910+ let value = sp_core:: U256 :: from_str_radix ( s, 16 )
911+ . map_err ( |e| serde:: de:: Error :: custom ( alloc:: format!( "{:?}" , e) ) ) ?;
912+ // Convert to bytes, trimming leading zeros to match serialization
913+ let bytes = value. to_big_endian ( ) ;
914+ let trimmed = bytes
915+ . iter ( )
916+ . position ( |& b| b != 0 )
917+ . map ( |pos| bytes[ pos..] . to_vec ( ) )
918+ . unwrap_or_else ( || vec ! [ 0u8 ] ) ;
919+ Ok ( Bytes :: from ( trimmed) )
920+ } )
921+ . collect ( )
922+ }
923+
862924/// Serialize memory values without "0x" prefix (like Geth)
863925fn serialize_memory_no_prefix < S > ( memory : & Vec < Bytes > , serializer : S ) -> Result < S :: Ok , S :: Error >
864926where
0 commit comments