1- use serde_with:: serde_as;
1+ use serde:: Deserialize ;
2+ use serde_with:: { serde_as, DeserializeAs , SerializeAs } ;
23use std:: {
34 fs:: { create_dir_all, File } ,
4- io:: { self , Read , Write } ,
5+ io:: { self , BufReader , Read , Write } ,
56 path:: Path ,
67 rc:: Rc ,
78} ;
@@ -12,6 +13,9 @@ use soroban_env_host::{
1213 HostError , LedgerInfo ,
1314} ;
1415
16+ #[ cfg( test) ]
17+ mod tests;
18+
1519#[ derive( thiserror:: Error , Debug ) ]
1620pub enum Error {
1721 #[ error( "io" ) ]
@@ -35,11 +39,80 @@ pub struct LedgerSnapshot {
3539 pub min_persistent_entry_ttl : u32 ,
3640 pub min_temp_entry_ttl : u32 ,
3741 pub max_entry_ttl : u32 ,
42+ #[ serde_as( as = "LedgerEntryVec" ) ]
3843 pub ledger_entries : Vec < ( Box < LedgerKey > , ( Box < LedgerEntry > , Option < u32 > ) ) > ,
3944}
4045
46+ /// Extended ledger entry that includes the live util ledger sequence. Provides a more compact
47+ /// form of the tuple used in [`LedgerSnapshot::ledger_entries`], to reduce the size of the snapshot
48+ /// when serialized to JSON.
49+ #[ derive( Debug , Clone , serde:: Deserialize ) ]
50+ struct LedgerEntryExt {
51+ entry : Box < LedgerEntry > ,
52+ live_until : Option < u32 > ,
53+ }
54+
55+ /// Extended ledger entry that includes the live util ledger sequence, and the entry by reference.
56+ /// Used to reduce memory usage during serialization.
57+ #[ derive( serde:: Serialize ) ]
58+ struct LedgerEntryExtRef < ' a > {
59+ entry : & ' a Box < LedgerEntry > , // Reference = no clone
60+ live_until : Option < u32 > ,
61+ }
62+
63+ struct LedgerEntryVec ;
64+
65+ impl < ' a > SerializeAs < Vec < ( Box < LedgerKey > , ( Box < LedgerEntry > , Option < u32 > ) ) > > for LedgerEntryVec {
66+ fn serialize_as < S > (
67+ source : & Vec < ( Box < LedgerKey > , ( Box < LedgerEntry > , Option < u32 > ) ) > ,
68+ serializer : S ,
69+ ) -> Result < S :: Ok , S :: Error >
70+ where
71+ S : serde:: Serializer ,
72+ {
73+ use serde:: ser:: SerializeSeq ;
74+ let mut seq = serializer. serialize_seq ( Some ( source. len ( ) ) ) ?;
75+ for ( _, ( entry, live_until) ) in source {
76+ seq. serialize_element ( & LedgerEntryExtRef {
77+ entry,
78+ live_until : * live_until,
79+ } ) ?;
80+ }
81+ seq. end ( )
82+ }
83+ }
84+
85+ impl < ' de > DeserializeAs < ' de , Vec < ( Box < LedgerKey > , ( Box < LedgerEntry > , Option < u32 > ) ) > >
86+ for LedgerEntryVec
87+ {
88+ fn deserialize_as < D > (
89+ deserializer : D ,
90+ ) -> Result < Vec < ( Box < LedgerKey > , ( Box < LedgerEntry > , Option < u32 > ) ) > , D :: Error >
91+ where
92+ D : serde:: Deserializer < ' de > ,
93+ {
94+ #[ derive( serde:: Deserialize ) ]
95+ #[ serde( untagged) ]
96+ enum Format {
97+ V2 ( Vec < LedgerEntryExt > ) ,
98+ V1 ( Vec < ( Box < LedgerKey > , ( Box < LedgerEntry > , Option < u32 > ) ) > ) ,
99+ }
100+
101+ match Format :: deserialize ( deserializer) ? {
102+ Format :: V2 ( entries) => Ok ( entries
103+ . into_iter ( )
104+ . map ( |LedgerEntryExt { entry, live_until } | {
105+ let key = Box :: new ( entry. to_key ( ) ) ;
106+ ( key, ( entry, live_until) )
107+ } )
108+ . collect ( ) ) ,
109+ Format :: V1 ( entries) => Ok ( entries) ,
110+ }
111+ }
112+ }
113+
41114impl LedgerSnapshot {
42- // Create a ledger snapshot from ledger info and a set of entries.
115+ /// Create a [`LedgerSnapshot`] from [`LedgerInfo`] and a set of entries.
43116 pub fn from < ' a > (
44117 info : LedgerInfo ,
45118 entries : impl IntoIterator < Item = ( & ' a Box < LedgerKey > , ( & ' a Box < LedgerEntry > , Option < u32 > ) ) > ,
@@ -65,7 +138,7 @@ impl LedgerSnapshot {
65138 self . update_entries ( & host. get_stored_entries ( ) . unwrap ( ) ) ;
66139 }
67140
68- // Get the ledger info in the snapshot.
141+ /// Get the ledger info in the snapshot.
69142 pub fn ledger_info ( & self ) -> LedgerInfo {
70143 LedgerInfo {
71144 protocol_version : self . protocol_version ,
@@ -136,22 +209,23 @@ impl LedgerSnapshot {
136209}
137210
138211impl LedgerSnapshot {
139- // Read in a [`LedgerSnapshot`] from a reader.
212+ /// Read in a [`LedgerSnapshot`] from a reader.
140213 pub fn read ( r : impl Read ) -> Result < LedgerSnapshot , Error > {
141214 Ok ( serde_json:: from_reader :: < _ , LedgerSnapshot > ( r) ?)
142215 }
143216
144- // Read in a [`LedgerSnapshot`] from a file.
217+ /// Read in a [`LedgerSnapshot`] from a file.
145218 pub fn read_file ( p : impl AsRef < Path > ) -> Result < LedgerSnapshot , Error > {
146- Self :: read ( File :: open ( p) ?)
219+ let reader = BufReader :: new ( File :: open ( p) ?) ;
220+ Self :: read ( reader)
147221 }
148222
149- // Write a [`LedgerSnapshot`] to a writer.
223+ /// Write a [`LedgerSnapshot`] to a writer.
150224 pub fn write ( & self , w : impl Write ) -> Result < ( ) , Error > {
151225 Ok ( serde_json:: to_writer_pretty ( w, self ) ?)
152226 }
153227
154- // Write a [`LedgerSnapshot`] to file.
228+ /// Write a [`LedgerSnapshot`] to file.
155229 pub fn write_file ( & self , p : impl AsRef < Path > ) -> Result < ( ) , Error > {
156230 let p = p. as_ref ( ) ;
157231 if let Some ( dir) = p. parent ( ) {
0 commit comments