@@ -492,6 +492,38 @@ impl BlobFactory {
492492// Blob file storage
493493// =====================
494494
495+ /// Sorts arrays of HashSet-backed fields that have non-deterministic iteration order.
496+ /// Object keys are already deterministic because serde_json::Value uses BTreeMap.
497+ fn normalize_set_arrays ( value : & mut serde_json:: Value ) {
498+ const SET_FIELDS : & [ & str ] =
499+ & [ "accessed_blocks" , "accessed_contract_addresses" , "accessed_storage_keys" ] ;
500+ match value {
501+ serde_json:: Value :: Object ( map) => {
502+ for ( key, val) in map. iter_mut ( ) {
503+ if SET_FIELDS . contains ( & key. as_str ( ) ) {
504+ if let serde_json:: Value :: Array ( arr) = val {
505+ arr. sort_by_key ( |a| a. to_string ( ) ) ;
506+ }
507+ } else {
508+ normalize_set_arrays ( val) ;
509+ }
510+ }
511+ }
512+ serde_json:: Value :: Array ( arr) => {
513+ for item in arr. iter_mut ( ) {
514+ normalize_set_arrays ( item) ;
515+ }
516+ }
517+ _ => { }
518+ }
519+ }
520+
521+ fn to_normalized_json ( value : & impl serde:: Serialize ) -> String {
522+ let mut json_value = serde_json:: to_value ( value) . unwrap ( ) ;
523+ normalize_set_arrays ( & mut json_value) ;
524+ format ! ( "{}\n " , serde_json:: to_string_pretty( & json_value) . unwrap( ) )
525+ }
526+
495527async fn gcs_client ( ) -> Client {
496528 Client :: new ( ClientConfig :: default ( ) . with_auth ( ) . await . expect (
497529 "Failed to create GCS client config. Did you run `gcloud auth application-default login`?" ,
@@ -532,8 +564,8 @@ async fn fetch_raw_blobs_at_generation(
532564}
533565
534566/// Pushes the blobs to GCS.
535- async fn bump_generation_and_store_blob_file ( blobs : & [ AerospikeBlob ] , client : & Client ) {
536- let blobs_json = serde_json :: to_string_pretty ( blobs) . unwrap ( ) ;
567+ async fn bump_generation_and_store_blob_file ( blobs : Vec < AerospikeBlob > , client : & Client ) {
568+ let blobs_json = to_normalized_json ( & blobs) ;
537569 let next_generation = find_next_available_blobs_generation ( client) . await ;
538570 client
539571 . upload_object (
@@ -568,13 +600,12 @@ async fn test_make_data() {
568600 // TODO(Dori): create txs.
569601 let ( blobs, preconfirmed_block) = blob_factory. finalize ( ) . await ;
570602 expect_file ! [ CHAIN_INFO_PATH ] . assert_eq ( & serde_json:: to_string_pretty ( & chain_info) . unwrap ( ) ) ;
571- expect_file ! [ PRECONFIRMED_BLOCK_PATH ]
572- . assert_eq ( & serde_json:: to_string_pretty ( & preconfirmed_block) . unwrap ( ) ) ;
603+ expect_file ! [ PRECONFIRMED_BLOCK_PATH ] . assert_eq ( & to_normalized_json ( & preconfirmed_block) ) ;
573604
574605 // Upload or download blobs depending on the fix mode.
575606 let client = gcs_client ( ) . await ;
576607 if env:: var ( "UPDATE_EXPECT" ) . is_ok ( ) {
577- bump_generation_and_store_blob_file ( & blobs, & client) . await ;
608+ bump_generation_and_store_blob_file ( blobs, & client) . await ;
578609 } else {
579610 let fetched_blobs = fetch_blob_file ( & client) . await ;
580611 assert_eq ! (
0 commit comments