@@ -5,14 +5,14 @@ import (
55 "sync"
66 "time"
77
8+ "github.com/mr-tron/base58"
89 "go.uber.org/zap"
910
10- "github.com/code-payments/ocp-server/database/query"
1111 "github.com/code-payments/ocp-server/metrics"
1212 "github.com/code-payments/ocp-server/ocp/common"
1313 "github.com/code-payments/ocp-server/ocp/data/account"
1414 "github.com/code-payments/ocp-server/ocp/data/timelock"
15- timelock_token "github.com/code-payments/ocp-server/solana/timelock/v1 "
15+ "github.com/code-payments/ocp-server/solana/vm "
1616)
1717
1818// Backup system workers can be found here. This is necessary because we can't rely
@@ -21,7 +21,7 @@ import (
2121// the case? Real time updates. Backup workers likely won't be able to guarantee
2222// real time (or near real time) updates at scale.
2323
24- func (p * runtime ) backupTimelockStateWorker (runtimeCtx context.Context , state timelock_token. TimelockState , interval time.Duration ) error {
24+ func (p * runtime ) backupTimelockStateWorker (runtimeCtx context.Context , interval time.Duration ) error {
2525 log := p .log .With (zap .String ("method" , "backupTimelockStateWorker" ))
2626 log .Debug ("worker started" )
2727
@@ -36,76 +36,74 @@ func (p *runtime) backupTimelockStateWorker(runtimeCtx context.Context, state ti
3636 log .Debug ("worker stopped" )
3737 }()
3838
39- start := time .Now ()
40- cursor := query .EmptyCursor
4139 delay := 0 * time .Second // Initially no delay, so we can run right after a deploy
4240 for {
4341 select {
4442 case <- time .After (delay ):
45- batchStart := time .Now ()
43+ start := time .Now ()
4644
4745 func () {
4846 provider := runtimeCtx .Value (metrics .ProviderContextKey ).(metrics.Provider )
4947 trace := provider .StartTrace ("geyser_consumer_runtime__backup_timelock_state_worker" )
5048 defer trace .End ()
5149 tracedCtx := metrics .NewContext (runtimeCtx , trace )
5250
53- timelockRecords , err := p .data .GetAllTimelocksByState (
51+ // todo: Also filter on unlock at if the result set gets too large
52+ programAccounts , slot , err := p .data .GetBlockchainFilteredProgramAccounts (
5453 tracedCtx ,
55- state ,
56- query .WithDirection (query .Ascending ),
57- query .WithCursor (cursor ),
58- query .WithLimit (p .conf .backupTimelockWorkerBatchSize .Get (runtimeCtx )),
54+ base58 .Encode (vm .PROGRAM_ID ),
55+ 0 ,
56+ vm .UnlockStateAccountDiscriminator ,
5957 )
60- if err == timelock .ErrTimelockNotFound {
61- p .metricStatusLock .Lock ()
62- duration := time .Since (start )
63- if p .backupTimelockStateWorkerDuration == nil || * p .backupTimelockStateWorkerDuration < duration {
64- p .backupTimelockStateWorkerDuration = & duration
65- }
66- p .metricStatusLock .Unlock ()
67-
68- start = time .Now ()
69- cursor = query .EmptyCursor
70- return
71- } else if err != nil {
72- log .With (zap .Error (err )).Warn ("failed to get timelock records" )
58+ if err != nil {
59+ log .With (zap .Error (err )).Warn ("failed to get unlock state program accounts" )
7360 return
7461 }
7562
7663 reprocessDelay := p .conf .backupTimelockWorkerReprocessDelay .Get (runtimeCtx )
7764
78- var wg sync.WaitGroup
79- for _ , timelockRecord := range timelockRecords {
80- if lastProcessed , ok := p .backupTimelockProcessedCache .Load (timelockRecord .Address ); ok {
65+ for _ , programAccount := range programAccounts {
66+ var unlockState vm.UnlockStateAccount
67+ if err := unlockState .Unmarshal (programAccount .Data ); err != nil {
68+ log .With (zap .Error (err )).Warn ("failed to unmarshal unlock state account" )
69+ continue
70+ }
71+
72+ stateAddress := base58 .Encode (unlockState .Address )
73+ log := log .With (zap .String ("timelock" , stateAddress ))
74+
75+ if lastProcessed , ok := p .backupTimelockProcessedCache .Load (stateAddress ); ok {
8176 if time .Since (lastProcessed .(time.Time )) < reprocessDelay {
8277 continue
8378 }
8479 }
8580
86- wg .Add (1 )
87-
88- go func (timelockRecord * timelock.Record ) {
89- defer wg .Done ()
90-
91- log := log .With (zap .String ("timelock" , timelockRecord .Address ))
81+ timelockRecord , err := p .data .GetTimelockByAddress (tracedCtx , stateAddress )
82+ if err == timelock .ErrTimelockNotFound {
83+ p .backupTimelockProcessedCache .Store (stateAddress , time .Now ())
84+ continue
85+ } else if err != nil {
86+ log .With (zap .Error (err )).Warn ("failed to get timelock record" )
87+ continue
88+ }
9289
93- err := updateTimelockAccountRecord (tracedCtx , p .data , timelockRecord )
94- if err != nil {
95- log .With (zap .Error (err )).Warn ("failed to update timelock account" )
96- return
97- }
90+ if err := updateTimelockAccountRecord (tracedCtx , p .data , timelockRecord , & unlockState , slot ); err != nil && err != timelock .ErrStaleTimelockState {
91+ log .With (zap .Error (err )).Warn ("failed to update timelock account" )
92+ continue
93+ }
9894
99- p .backupTimelockProcessedCache .Store (timelockRecord .Address , time .Now ())
100- }(timelockRecord )
95+ p .backupTimelockProcessedCache .Store (stateAddress , time .Now ())
10196 }
10297
103- wg .Wait ()
104-
105- cursor = query .ToCursor (timelockRecords [len (timelockRecords )- 1 ].Id )
98+ p .metricStatusLock .Lock ()
99+ duration := time .Since (start )
100+ if p .backupTimelockStateWorkerDuration == nil || * p .backupTimelockStateWorkerDuration < duration {
101+ p .backupTimelockStateWorkerDuration = & duration
102+ }
103+ p .metricStatusLock .Unlock ()
106104 }()
107105
108- delay = interval - time .Since (batchStart )
106+ delay = interval - time .Since (start )
109107 case <- runtimeCtx .Done ():
110108 return runtimeCtx .Err ()
111109 }
0 commit comments