@@ -57,10 +57,12 @@ type LiteStorage struct {
5757 logger * zap.Logger
5858 client * liteapi.Client
5959 executor abi.Executor
60+ cachedExecutor * CachedExecutor
6061 jettonMetaCache * xsync.MapOf [string , tep64.Metadata ]
6162 transactionsIndexByHash * xsync.MapOf [tongo.Bits256 , * core.Transaction ]
6263 transactionsByInMsgLT * xsync.MapOf [inMsgCreatedLT , tongo.Bits256 ]
63- blockCache * xsync.MapOf [tongo.BlockIDExt , * tlb.Block ]
64+ blockCache Cache [tongo.BlockID , Tuple2 [tongo.BlockIDExt , * tlb.Block ]]
65+ accountCodeCache Cache [tongo.AccountID , []byte ]
6466 accountInterfacesCache * xsync.MapOf [tongo.AccountID , []abi.ContractInterface ]
6567 // tvmLibraryCache contains public tvm libraries.
6668 // As a library is immutable, it's ok to cache it.
@@ -132,13 +134,38 @@ func NewLiteStorage(log *zap.Logger, cli *liteapi.Client, opts ...Option) (*Lite
132134 if o .executor == nil {
133135 o .executor = cli
134136 }
137+ blockBolt , err := NewBoltCache ("./cache/blocks.db" )
138+ if err != nil {
139+ return nil , fmt .Errorf ("failed to init block cache: %w" , err )
140+ }
141+ blockCache := & JsonTlbDiskCache [tongo.BlockID , Tuple2 [tongo.BlockIDExt , * tlb.Block ]]{
142+ cache : blockBolt ,
143+ }
144+ codeBolt , err := NewBoltCache ("./cache/accountcode.db" )
145+ if err != nil {
146+ return nil , fmt .Errorf ("failed to init account code cache: %w" , err )
147+ }
148+ codeCache := & BytesDiskCache [ton.AccountID ]{
149+ cache : codeBolt ,
150+ }
151+ execBolt , err := NewBoltCache ("./cache/executor.db" )
152+ if err != nil {
153+ return nil , fmt .Errorf ("failed to init executor cache: %w" , err )
154+ }
155+ cachedExecutor := & CachedExecutor {
156+ executor : cli ,
157+ cache : & JsonTlbDiskCache [wrappedString , CachedExecResult ]{
158+ cache : execBolt ,
159+ },
160+ }
135161 storage := & LiteStorage {
136162 logger : log ,
137163 // TODO: introduce an env variable to configure this number
138- maxGoroutines : 5 ,
139- client : cli ,
140- executor : o .executor ,
141- stopCh : make (chan struct {}),
164+ maxGoroutines : 5 ,
165+ client : cli ,
166+ executor : o .executor ,
167+ cachedExecutor : cachedExecutor ,
168+ stopCh : make (chan struct {}),
142169 // read-only data
143170 knownAccounts : make (map [string ][]tongo.AccountID ),
144171 trackingAccounts : map [tongo.AccountID ]struct {}{},
@@ -147,7 +174,8 @@ func NewLiteStorage(log *zap.Logger, cli *liteapi.Client, opts ...Option) (*Lite
147174 jettonMetaCache : xsync .NewMapOf [tep64.Metadata ](),
148175 transactionsIndexByHash : xsync.NewTypedMapOf [tongo.Bits256 , * core.Transaction ](hashBits256 ),
149176 transactionsByInMsgLT : xsync.NewTypedMapOf [inMsgCreatedLT , tongo.Bits256 ](hashInMsgCreatedLT ),
150- blockCache : xsync.NewTypedMapOf [tongo.BlockIDExt , * tlb.Block ](hashBlockIDExt ),
177+ blockCache : blockCache ,
178+ accountCodeCache : codeCache ,
151179 accountInterfacesCache : xsync.NewTypedMapOf [tongo.AccountID , []abi.ContractInterface ](hashAccountID ),
152180 tvmLibraryCache : cache .NewLRUCache [string , boc.Cell ](10000 , "tvm_libraries" ),
153181 configCache : cache .NewLRUCache [int , ton.BlockchainConfig ](4 , "config" ),
@@ -160,14 +188,20 @@ func NewLiteStorage(log *zap.Logger, cli *liteapi.Client, opts ...Option) (*Lite
160188 }
161189
162190 blockIterator := iter.Iterator [tongo.BlockID ]{MaxGoroutines : storage .maxGoroutines }
191+ log .Info ("preloading blocks" , zap .Int ("count" , len (o .preloadBlocks )))
192+ var blockWG sync.WaitGroup
163193 blockIterator .ForEach (o .preloadBlocks , func (id * tongo.BlockID ) {
164- if err := storage .preloadBlock (* id ); err != nil {
165- log .Error ("failed to preload block" ,
166- zap .String ("blockID" , id .String ()),
167- zap .Error (err ))
168- }
194+ blockWG .Go (func () {
195+ if err := storage .preloadBlock (* id ); err != nil {
196+ log .Error ("failed to preload block" ,
197+ zap .String ("blockID" , id .String ()),
198+ zap .Error (err ))
199+ }
200+ })
169201 })
202+ blockWG .Wait ()
170203 iterator := iter.Iterator [tongo.AccountID ]{MaxGoroutines : storage .maxGoroutines }
204+ log .Info ("preloading acounts" , zap .Int ("count" , len (o .preloadAccounts )))
171205 iterator .ForEach (o .preloadAccounts , func (accountID * tongo.AccountID ) {
172206 if err := storage .preloadAccount (* accountID ); err != nil {
173207 log .Error ("failed to preload account" ,
@@ -306,28 +340,54 @@ func (s *LiteStorage) preloadAccount(a tongo.AccountID) error {
306340 return nil
307341}
308342
309- func (s * LiteStorage ) preloadBlock (id tongo.BlockID ) error {
310- ctx := context .Background ()
343+ func (s * LiteStorage ) getCachedBlock (ctx context.Context , id tongo.BlockID ) (tongo.BlockIDExt , * tlb.Block , error ) {
344+ cached , ok := s .blockCache .Load (id )
345+ if ok {
346+ return cached .V1 , cached .V2 , nil
347+ }
311348 extID , _ , err := s .client .LookupBlock (ctx , id , 1 , nil , nil )
312349 if err != nil {
313- return err
350+ return tongo. BlockIDExt {}, nil , err
314351 }
315352 block , err := s .client .GetBlock (ctx , extID )
353+ if err != nil {
354+ return tongo.BlockIDExt {}, nil , err
355+ }
356+ cached .V1 = extID
357+ cached .V2 = & block
358+ s .blockCache .Store (id , cached )
359+ return cached .V1 , cached .V2 , nil
360+ }
361+
362+ func (s * LiteStorage ) getCachedAccountCode (ctx context.Context , id tongo.AccountID ) ([]byte , error ) {
363+ if code , ok := s .accountCodeCache .Load (id ); ok {
364+ return code , nil
365+ }
366+ account , err := s .GetRawAccount (ctx , id )
367+ if err != nil {
368+ return nil , err
369+ }
370+ s .accountCodeCache .Store (id , account .Code )
371+ return account .Code , nil
372+ }
373+
374+ func (s * LiteStorage ) preloadBlock (id tongo.BlockID ) error {
375+ ctx := context .Background ()
376+ extID , block , err := s .getCachedBlock (ctx , id )
316377 if err != nil {
317378 return err
318379 }
319- s .blockCache .Store (extID , & block )
320380 for _ , tx := range block .AllTransactions () {
321381 accountID := tongo.AccountID {
322382 Workchain : extID .Workchain ,
323383 Address : tx .AccountAddr ,
324384 }
325385 inspector := abi .NewContractInspector (abi .InspectWithLibraryResolver (s ))
326- account , err := s .GetRawAccount (ctx , accountID )
386+ accountCode , err := s .getCachedAccountCode (ctx , accountID )
327387 if err != nil {
328388 return err
329389 }
330- cd , err := inspector .InspectContract (ctx , account . Code , s .executor , accountID )
390+ cd , err := inspector .InspectContract (ctx , accountCode , s .cachedExecutor , accountID )
331391 t , err := core .ConvertTransaction (extID .Workchain , tongo.Transaction {Transaction : * tx , BlockID : extID }, cd )
332392 if err != nil {
333393 return err
@@ -346,17 +406,11 @@ func (s *LiteStorage) GetBlockHeader(ctx context.Context, id tongo.BlockID) (*co
346406 storageTimeHistogramVec .WithLabelValues ("get_block_header" ).Observe (v )
347407 }))
348408 defer timer .ObserveDuration ()
349- blockID , _ , err := s .client .LookupBlock (ctx , id , 1 , nil , nil )
350- if err != nil {
351- return nil , err
352- }
353- block , err := s .client .GetBlock (ctx , blockID )
409+ blockID , block , err := s .getCachedBlock (ctx , id )
354410 if err != nil {
355411 return nil , err
356412 }
357-
358- s .blockCache .Store (blockID , & block )
359- header , err := core .ConvertToBlockHeader (blockID , & block )
413+ header , err := core .ConvertToBlockHeader (blockID , block )
360414 if err != nil {
361415 return nil , err
362416 }
0 commit comments