Skip to content

Commit

Permalink
Address infinite loop when fetching events
Browse files Browse the repository at this point in the history
  • Loading branch information
corrideat committed Jan 24, 2025
1 parent dae6ad6 commit 76b6a9c
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 5 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 19 additions & 3 deletions shared/domains/chelonia/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ export function eventsAfter (contractID: string, sinceHeight: number, limit?: nu
let remainingEvents = limit ?? Number.POSITIVE_INFINITY
let eventsStreamReader
let latestHeight
let state: 'fetch' | 'read-eos' | 'read-new-response' | 'read' | 'events' = 'fetch'
let state: 'fetch' | 'read-eos' | 'read-new-response' | 'read' | 'events' | 'eod' = 'fetch'
let requestLimit: number
let count: number
let buffer: string = ''
Expand Down Expand Up @@ -616,7 +616,9 @@ export function eventsAfter (contractID: string, sinceHeight: number, limit?: nu
// data by making a new request
if (done) {
// No more events to process or reached the latest event
if (remainingEvents === 0 || sinceHeight === latestHeight) {
// Using `>=` instead of `===` to avoid an infinite loop in the
// event of data loss on the server.
if (remainingEvents === 0 || sinceHeight >= latestHeight) {
controller.close()
return
} else if (state === 'read-new-response' || buffer) {
Expand Down Expand Up @@ -707,8 +709,14 @@ export function eventsAfter (contractID: string, sinceHeight: number, limit?: nu
const deserialized = GIMessage.deserializeHEAD(currentEvent)
sinceHeight = deserialized.head.height
sinceHash = deserialized.hash
state = 'read-eos'
} else {
// If the response came empty, assume there are no more events
// after. Mostly this prevents infinite loops if a server is
// claiming there are more events than it's willing to return
// data for.
state = 'eod'
}
state = 'read-eos'
// This should be an empty string now
buffer = buffer.slice(nextIdx + 1).trim()
} else if (currentEvent) {
Expand All @@ -731,6 +739,14 @@ export function eventsAfter (contractID: string, sinceHeight: number, limit?: nu
}
break
}
case 'eod': {
if (remainingEvents === 0 || sinceHeight >= latestHeight) {
controller.close()
} else {
controller.error(new Error('Unexpected end of data'))
}
return
}
}
}
}
Expand Down

0 comments on commit 76b6a9c

Please sign in to comment.