17
17
use std:: { error, fmt, fs, io} ;
18
18
19
19
use clarity:: vm:: types:: PrincipalData ;
20
- use serde:: { Deserialize , Serialize , Serializer } ;
20
+ use serde:: de:: Error as DeError ;
21
+ use serde:: { Deserialize , Deserializer , Serialize , Serializer } ;
21
22
use serde_json:: json;
22
23
use stacks_common:: types:: chainstate:: {
23
24
BlockHeaderHash , BurnchainHeaderHash , StacksAddress , StacksBlockId , TrieHash , VRFSeed ,
@@ -374,6 +375,32 @@ pub fn stacks_addr_serialize(addr: &StacksAddress) -> serde_json::Value {
374
375
} )
375
376
}
376
377
378
+ fn normalize_stacks_addr_fields < ' de , D > (
379
+ inner : & mut serde_json:: Map < String , serde_json:: Value > ,
380
+ ) -> Result < ( ) , D :: Error >
381
+ where
382
+ D : Deserializer < ' de > ,
383
+ {
384
+ // Rename `address_version` to `version`
385
+ if let Some ( address_version) = inner. remove ( "address_version" ) {
386
+ inner. insert ( "version" . to_string ( ) , address_version) ;
387
+ }
388
+
389
+ // Rename `address_hash_bytes` to `bytes` and convert to bytes
390
+ if let Some ( address_bytes) = inner
391
+ . remove ( "address_hash_bytes" )
392
+ . and_then ( |addr| serde_json:: Value :: as_str ( & addr) . map ( |x| x. to_string ( ) ) )
393
+ {
394
+ let address_hex: String = address_bytes. chars ( ) . skip ( 2 ) . collect ( ) ; // Remove "0x" prefix
395
+ inner. insert (
396
+ "bytes" . to_string ( ) ,
397
+ serde_json:: to_value ( & address_hex) . map_err ( DeError :: custom) ?,
398
+ ) ;
399
+ }
400
+
401
+ Ok ( ( ) )
402
+ }
403
+
377
404
/// Serialization function for serializing extended information within the BlockstackOperationType
378
405
/// that is not printed via the standard serde implementation. Specifically, serializes additional
379
406
/// StacksAddress information.
@@ -390,6 +417,101 @@ pub fn blockstack_op_extended_serialize_opt<S: Serializer>(
390
417
}
391
418
}
392
419
420
+ /// Deserialize the burnchain op that was serialized with blockstack_op_to_json
421
+ pub fn deserialize_extended_blockstack_op < ' de , D > (
422
+ deserializer : D ,
423
+ ) -> Result < Option < BlockstackOperationType > , D :: Error >
424
+ where
425
+ D : Deserializer < ' de > ,
426
+ {
427
+ use serde:: de:: Error as DeError ;
428
+ use serde_json:: { Map , Value } ;
429
+
430
+ let raw: Option < Value > = Option :: deserialize ( deserializer) ?;
431
+ let Some ( Value :: Object ( mut obj) ) = raw else {
432
+ return Ok ( None ) ;
433
+ } ;
434
+
435
+ let Some ( ( key, value) ) = obj. iter_mut ( ) . next ( ) else {
436
+ return Ok ( None ) ;
437
+ } ;
438
+
439
+ let inner = value
440
+ . as_object_mut ( )
441
+ . ok_or_else ( || DeError :: custom ( "Expected blockstack op to be an object" ) ) ?;
442
+
443
+ let normalized_key = match key. as_str ( ) {
444
+ "pre_stx" => {
445
+ BlockstackOperationType :: normalize_pre_stx_fields :: < D > ( inner) ?;
446
+ "PreStx"
447
+ }
448
+ "stack_stx" => {
449
+ BlockstackOperationType :: normalize_stack_stx_fields :: < D > ( inner) ?;
450
+ "StackStx"
451
+ }
452
+ "transfer_stx" => {
453
+ BlockstackOperationType :: normalize_transfer_stx_fields :: < D > ( inner) ?;
454
+ "TransferStx"
455
+ }
456
+ "delegate_stx" => {
457
+ BlockstackOperationType :: normalize_delegate_stx_fields :: < D > ( inner) ?;
458
+ "DelegateStx"
459
+ }
460
+ "vote_for_aggregate_key" => {
461
+ BlockstackOperationType :: normalize_vote_for_aggregate_key_fields :: < D > ( inner) ?;
462
+ "VoteForAggregateKey"
463
+ }
464
+ "leader_key_register" => "LeaderKeyRegister" ,
465
+ "leader_block_commit" => "LeaderBlockCommit" ,
466
+ other => other,
467
+ } ;
468
+
469
+ let mut map = Map :: new ( ) ;
470
+ map. insert ( normalized_key. to_string ( ) , value. clone ( ) ) ;
471
+
472
+ let normalized = Value :: Object ( map) ;
473
+
474
+ serde_json:: from_value ( normalized)
475
+ . map ( Some )
476
+ . map_err ( serde:: de:: Error :: custom)
477
+ }
478
+
479
+ macro_rules! normalize_common_fields {
480
+ ( $map: ident, $de: ident) => { {
481
+ normalize_hex_field:: <$de, _>( & mut $map, "burn_header_hash" , |s| {
482
+ BurnchainHeaderHash :: from_hex( s) . map_err( DeError :: custom)
483
+ } ) ?;
484
+ rename_field( & mut $map, "burn_txid" , "txid" ) ;
485
+ rename_field( & mut $map, "burn_block_height" , "block_height" ) ;
486
+ } } ;
487
+ }
488
+
489
+ // Utility function to normalize a hex string to a BurnchainHeaderHash JSON value
490
+ fn normalize_hex_field < ' de , D , T > (
491
+ map : & mut serde_json:: Map < String , serde_json:: Value > ,
492
+ field : & str ,
493
+ from_hex : fn ( & str ) -> Result < T , D :: Error > ,
494
+ ) -> Result < ( ) , D :: Error >
495
+ where
496
+ D : Deserializer < ' de > ,
497
+ T : serde:: Serialize ,
498
+ {
499
+ if let Some ( hex_str) = map. get ( field) . and_then ( serde_json:: Value :: as_str) {
500
+ let cleaned = hex_str. strip_prefix ( "0x" ) . unwrap_or ( hex_str) ;
501
+ let val = from_hex ( cleaned) . map_err ( DeError :: custom) ?;
502
+ let ser_val = serde_json:: to_value ( val) . map_err ( DeError :: custom) ?;
503
+ map. insert ( field. to_string ( ) , ser_val) ;
504
+ }
505
+ Ok ( ( ) )
506
+ }
507
+
508
+ // Normalize renamed field
509
+ fn rename_field ( map : & mut serde_json:: Map < String , serde_json:: Value > , from : & str , to : & str ) {
510
+ if let Some ( val) = map. remove ( from) {
511
+ map. insert ( to. to_string ( ) , val) ;
512
+ }
513
+ }
514
+
393
515
impl BlockstackOperationType {
394
516
pub fn opcode ( & self ) -> Opcodes {
395
517
match * self {
@@ -491,6 +613,114 @@ impl BlockstackOperationType {
491
613
} ;
492
614
}
493
615
616
+ // Replace all the normalize_* functions with minimal implementations
617
+ fn normalize_pre_stx_fields < ' de , D > (
618
+ mut map : & mut serde_json:: Map < String , serde_json:: Value > ,
619
+ ) -> Result < ( ) , D :: Error >
620
+ where
621
+ D : Deserializer < ' de > ,
622
+ {
623
+ normalize_common_fields ! ( map, D ) ;
624
+ if let Some ( serde_json:: Value :: Object ( obj) ) = map. get_mut ( "output" ) {
625
+ normalize_stacks_addr_fields :: < D > ( obj) ?;
626
+ }
627
+ Ok ( ( ) )
628
+ }
629
+
630
+ fn normalize_stack_stx_fields < ' de , D > (
631
+ mut map : & mut serde_json:: Map < String , serde_json:: Value > ,
632
+ ) -> Result < ( ) , D :: Error >
633
+ where
634
+ D : Deserializer < ' de > ,
635
+ {
636
+ normalize_common_fields ! ( map, D ) ;
637
+ if let Some ( serde_json:: Value :: Object ( obj) ) = map. get_mut ( "sender" ) {
638
+ normalize_stacks_addr_fields :: < D > ( obj) ?;
639
+ }
640
+ if let Some ( reward_val) = map. get ( "reward_addr" ) {
641
+ let b58_str = reward_val
642
+ . as_str ( )
643
+ . ok_or_else ( || DeError :: custom ( "Expected base58 string in reward_addr" ) ) ?;
644
+ let addr = PoxAddress :: from_b58 ( b58_str)
645
+ . ok_or_else ( || DeError :: custom ( "Invalid stacks address" ) ) ?;
646
+ let val = serde_json:: to_value ( addr) . map_err ( DeError :: custom) ?;
647
+ map. insert ( "reward_addr" . into ( ) , val) ;
648
+ }
649
+ Ok ( ( ) )
650
+ }
651
+
652
+ fn normalize_transfer_stx_fields < ' de , D > (
653
+ mut map : & mut serde_json:: Map < String , serde_json:: Value > ,
654
+ ) -> Result < ( ) , D :: Error >
655
+ where
656
+ D : Deserializer < ' de > ,
657
+ {
658
+ normalize_common_fields ! ( map, D ) ;
659
+ for field in [ "recipient" , "sender" ] {
660
+ if let Some ( serde_json:: Value :: Object ( obj) ) = map. get_mut ( field) {
661
+ normalize_stacks_addr_fields :: < D > ( obj) ?;
662
+ }
663
+ }
664
+ if let Some ( memo_str) = map. get ( "memo" ) . and_then ( serde_json:: Value :: as_str) {
665
+ let memo_hex = memo_str. trim_start_matches ( "0x" ) ;
666
+ let memo_bytes = hex_bytes ( memo_hex) . map_err ( DeError :: custom) ?;
667
+ let val = serde_json:: to_value ( memo_bytes) . map_err ( DeError :: custom) ?;
668
+ map. insert ( "memo" . into ( ) , val) ;
669
+ }
670
+ Ok ( ( ) )
671
+ }
672
+
673
+ fn normalize_delegate_stx_fields < ' de , D > (
674
+ mut map : & mut serde_json:: Map < String , serde_json:: Value > ,
675
+ ) -> Result < ( ) , D :: Error >
676
+ where
677
+ D : Deserializer < ' de > ,
678
+ {
679
+ normalize_common_fields ! ( map, D ) ;
680
+ if let Some ( serde_json:: Value :: Array ( arr) ) = map. get ( "reward_addr" ) {
681
+ if arr. len ( ) == 2 {
682
+ let index = arr[ 0 ]
683
+ . as_u64 ( )
684
+ . ok_or_else ( || DeError :: custom ( "Expected u64 index" ) ) ?
685
+ as u32 ;
686
+ let b58_str = arr[ 1 ]
687
+ . as_str ( )
688
+ . ok_or_else ( || DeError :: custom ( "Expected base58 string" ) ) ?;
689
+ let addr = PoxAddress :: from_b58 ( b58_str)
690
+ . ok_or_else ( || DeError :: custom ( "Invalid stacks address" ) ) ?;
691
+ let val = serde_json:: to_value ( ( index, addr) ) . map_err ( DeError :: custom) ?;
692
+ map. insert ( "reward_addr" . into ( ) , val) ;
693
+ }
694
+ }
695
+ for field in [ "delegate_to" , "sender" ] {
696
+ if let Some ( serde_json:: Value :: Object ( obj) ) = map. get_mut ( field) {
697
+ normalize_stacks_addr_fields :: < D > ( obj) ?;
698
+ }
699
+ }
700
+ Ok ( ( ) )
701
+ }
702
+
703
+ fn normalize_vote_for_aggregate_key_fields < ' de , D > (
704
+ mut map : & mut serde_json:: Map < String , serde_json:: Value > ,
705
+ ) -> Result < ( ) , D :: Error >
706
+ where
707
+ D : Deserializer < ' de > ,
708
+ {
709
+ normalize_common_fields ! ( map, D ) ;
710
+ for field in [ "aggregate_key" , "signer_key" ] {
711
+ if let Some ( hex_str) = map. get ( field) . and_then ( serde_json:: Value :: as_str) {
712
+ let cleaned = hex_str. strip_prefix ( "0x" ) . unwrap_or ( hex_str) ;
713
+ let val = StacksPublicKeyBuffer :: from_hex ( cleaned) . map_err ( DeError :: custom) ?;
714
+ let ser_val = serde_json:: to_value ( val) . map_err ( DeError :: custom) ?;
715
+ map. insert ( field. to_string ( ) , ser_val) ;
716
+ }
717
+ }
718
+ if let Some ( serde_json:: Value :: Object ( obj) ) = map. get_mut ( "sender" ) {
719
+ normalize_stacks_addr_fields :: < D > ( obj) ?;
720
+ }
721
+ Ok ( ( ) )
722
+ }
723
+
494
724
pub fn pre_stx_to_json ( op : & PreStxOp ) -> serde_json:: Value {
495
725
json ! ( {
496
726
"pre_stx" : {
0 commit comments