@@ -64,12 +64,13 @@ export const integrityCheckProgramAccounts = async ({
64
64
}
65
65
66
66
const performIntegrityCheck = async ( ) => {
67
- const startTime = new Date ( ) ;
67
+ const snapshotTime = new Date ( ) ;
68
68
const t = await sequelize . transaction ( {
69
69
isolationLevel : Transaction . ISOLATION_LEVELS . READ_COMMITTED ,
70
70
} ) ;
71
71
72
72
try {
73
+ let limiter : pLimit . Limit ;
73
74
const program = new anchor . Program ( idl , provider ) ;
74
75
const currentSlot = await connection . getSlot ( ) ;
75
76
let blockTime24HoursAgo : number | null = null ;
@@ -117,7 +118,7 @@ export const integrityCheckProgramAccounts = async ({
117
118
throw new Error ( "Unable to get blocktime from 24 hours ago" ) ;
118
119
}
119
120
120
- const limiter = pLimit ( 25 ) ;
121
+ limiter = pLimit ( 10 ) ;
121
122
const parsedTransactions = (
122
123
await Promise . all (
123
124
chunks (
@@ -126,7 +127,7 @@ export const integrityCheckProgramAccounts = async ({
126
127
blockTime : blockTime24HoursAgo ,
127
128
provider,
128
129
} ) ,
129
- 75
130
+ 100
130
131
) . map ( ( chunk ) =>
131
132
limiter ( async ( ) => {
132
133
await new Promise ( ( resolve ) => setTimeout ( resolve , 250 ) ) ;
@@ -144,39 +145,20 @@ export const integrityCheckProgramAccounts = async ({
144
145
) . flat ( ) ;
145
146
146
147
const uniqueWritableAccounts = new Set < string > ( ) ;
147
- for ( const parsed of parsedTransactions ) {
148
- parsed ?. transaction . message . accountKeys
149
- . filter ( ( acc ) => acc . writable )
150
- . map ( ( acc ) => {
151
- uniqueWritableAccounts . add ( acc . pubkey . toBase58 ( ) ) ;
152
- txIdsByAccountId [ acc . pubkey . toBase58 ( ) ] = [
153
- ...parsed . transaction . signatures ,
154
- ...( txIdsByAccountId [ acc . pubkey . toBase58 ( ) ] || [ ] ) ,
148
+ parsedTransactions . forEach ( ( parsed ) => {
149
+ if ( ! parsed ) return ;
150
+ const signatures = parsed . transaction . signatures ;
151
+ parsed . transaction . message . accountKeys . forEach ( ( acc ) => {
152
+ if ( acc . writable ) {
153
+ const pubkey = acc . pubkey . toBase58 ( ) ;
154
+ uniqueWritableAccounts . add ( pubkey ) ;
155
+ txIdsByAccountId [ pubkey ] = [
156
+ ...signatures ,
157
+ ...( txIdsByAccountId [ pubkey ] || [ ] ) ,
155
158
] ;
156
- } ) ;
157
- }
158
-
159
- const accountInfosWithPk = (
160
- await Promise . all (
161
- chunks ( [ ...uniqueWritableAccounts . values ( ) ] , 100 ) . map ( ( chunk ) =>
162
- pLimit ( 100 ) ( ( ) =>
163
- retry (
164
- ( ) =>
165
- connection . getMultipleAccountsInfo (
166
- chunk . map ( ( c ) => new PublicKey ( c ) ) ,
167
- "confirmed"
168
- ) ,
169
- retryOptions
170
- )
171
- )
172
- )
173
- )
174
- )
175
- . flat ( )
176
- . map ( ( accountInfo , idx ) => ( {
177
- pubkey : [ ...uniqueWritableAccounts . values ( ) ] [ idx ] ,
178
- ...accountInfo ,
179
- } ) ) ;
159
+ }
160
+ } ) ;
161
+ } ) ;
180
162
181
163
const pluginsByAccountType = (
182
164
await Promise . all (
@@ -199,10 +181,28 @@ export const integrityCheckProgramAccounts = async ({
199
181
] )
200
182
) ;
201
183
184
+ limiter = pLimit ( 100 ) ;
185
+ const uniqueWritableAccountsArray = [ ...uniqueWritableAccounts . values ( ) ] ;
202
186
await Promise . all (
203
- chunks ( accountInfosWithPk , 1000 ) . map ( async ( chunk ) => {
204
- const accountsByType : Record < string , typeof accountInfosWithPk > = { } ;
205
- chunk . forEach ( ( accountInfo ) => {
187
+ chunks ( uniqueWritableAccountsArray , 100 ) . map ( async ( chunk ) => {
188
+ const accountInfos = await limiter ( ( ) =>
189
+ retry (
190
+ ( ) =>
191
+ connection . getMultipleAccountsInfo (
192
+ chunk . map ( ( c ) => new PublicKey ( c ) ) ,
193
+ "confirmed"
194
+ ) ,
195
+ retryOptions
196
+ )
197
+ ) ;
198
+
199
+ const accountInfosWithPk = accountInfos . map ( ( accountInfo , idx ) => ( {
200
+ pubkey : chunk [ idx ] ,
201
+ ...accountInfo ,
202
+ } ) ) ;
203
+
204
+ const accsByType : Record < string , typeof accountInfosWithPk > = { } ;
205
+ accountInfosWithPk . forEach ( ( accountInfo ) => {
206
206
const accName = accounts . find (
207
207
( { type } ) =>
208
208
accountInfo . data &&
@@ -212,24 +212,34 @@ export const integrityCheckProgramAccounts = async ({
212
212
) ?. type ;
213
213
214
214
if ( accName ) {
215
- accountsByType [ accName ] = accountsByType [ accName ] || [ ] ;
216
- accountsByType [ accName ] . push ( accountInfo ) ;
215
+ accsByType [ accName ] = accsByType [ accName ] || [ ] ;
216
+ accsByType [ accName ] . push ( accountInfo ) ;
217
217
}
218
218
} ) ;
219
219
220
220
await Promise . all (
221
- Object . entries ( accountsByType ) . map ( async ( [ accName , accounts ] ) => {
221
+ Object . entries ( accsByType ) . map ( async ( [ accName , accounts ] ) => {
222
222
const model = sequelize . models [ accName ] ;
223
+ const pubkeys = accounts . map ( ( c ) => c . pubkey ) ;
224
+ const existingAccs = await model . findAll ( {
225
+ where : { address : pubkeys } ,
226
+ transaction : t ,
227
+ } ) ;
228
+
229
+ const existingAccMap = new Map (
230
+ existingAccs . map ( ( acc ) => [ acc . get ( "address" ) , acc ] )
231
+ ) ;
232
+
223
233
await Promise . all (
224
- accounts . map ( async ( c ) => {
234
+ accounts . map ( async ( acc ) => {
225
235
const decodedAcc = program . coder . accounts . decode (
226
236
lowerFirstChar ( accName ) ,
227
- c . data as Buffer
237
+ acc . data as Buffer
228
238
) ;
229
239
230
240
let sanitized = {
231
241
refreshed_at : new Date ( ) . toISOString ( ) ,
232
- address : c . pubkey ,
242
+ address : acc . pubkey ,
233
243
...sanitizeAccount ( decodedAcc ) ,
234
244
} ;
235
245
@@ -239,35 +249,31 @@ export const integrityCheckProgramAccounts = async ({
239
249
sanitized = await plugin . processAccount ( sanitized , t ) ;
240
250
} catch ( err ) {
241
251
console . log (
242
- `Plugin processing failed for account ${ c . pubkey } ` ,
252
+ `Plugin processing failed for account ${ acc . pubkey } ` ,
243
253
err
244
254
) ;
245
- // Continue with unmodified sanitized data instead of failing
246
255
continue ;
247
256
}
248
257
}
249
258
}
250
259
251
- const existing = await model . findByPk ( c . pubkey , {
252
- transaction : t ,
253
- } ) ;
260
+ const existing = existingAccMap . get ( acc . pubkey ) ;
261
+ const refreshedAt = existing ?. dataValues . refreshed_at
262
+ ? new Date ( existing . dataValues . refreshed_at )
263
+ : null ;
254
264
255
265
const shouldUpdate =
256
266
! deepEqual (
257
267
_omit ( sanitized , OMIT_KEYS ) ,
258
268
_omit ( existing ?. dataValues , OMIT_KEYS )
259
269
) &&
260
- ! (
261
- existing ?. dataValues . refreshed_at &&
262
- new Date ( existing . dataValues . refreshed_at ) >= startTime &&
263
- new Date ( existing . dataValues . refreshed_at ) <= new Date ( )
264
- ) ;
270
+ ( ! refreshedAt || refreshedAt < snapshotTime ) ;
265
271
266
272
if ( shouldUpdate ) {
267
273
corrections . push ( {
268
274
type : accName ,
269
- accountId : c . pubkey ,
270
- txSignatures : txIdsByAccountId [ c . pubkey ] ,
275
+ accountId : acc . pubkey ,
276
+ txSignatures : txIdsByAccountId [ acc . pubkey ] ,
271
277
currentValues : existing ? existing . dataValues : null ,
272
278
newValues : sanitized ,
273
279
} ) ;
0 commit comments