Skip to content

Commit

Permalink
Merge branch 'main' into dz/fix-scanned-blocks-cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
DZakh authored Jan 20, 2025
2 parents 65c9925 + 026de1c commit df8fbfb
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 21 deletions.
4 changes: 2 additions & 2 deletions codegenerator/cli/src/config_parsing/chain_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ pub enum Network {
#[subenum(NetworkWithExplorer)]
Taiko = 167000,

#[subenum(HypersyncNetwork, NetworkWithExplorer)]
#[subenum(NetworkWithExplorer)]
Tangle = 5845,

#[subenum(HypersyncNetwork, NetworkWithExplorer)]
Expand Down Expand Up @@ -518,7 +518,7 @@ impl HypersyncNetwork {
| ArbitrumOne | Merlin => Silver,

Zora | MoonbaseAlpha | Morph | Kroma | Lukso | C1Milkomeda | Crab | Sophon | Flare
| PolygonZkevm | MevCommit | Tangle => Bronze,
| PolygonZkevm | MevCommit => Bronze,

SophonTestnet | MorphTestnet | GaladrielDevnet | CitreaTestnet | Goerli
| BscTestnet | UnichainSepolia | Zircuit | Celo | Opbnb | GnosisChiado
Expand Down
2 changes: 2 additions & 0 deletions codegenerator/cli/src/config_parsing/human_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,10 @@ pub mod evm {
CumulativeGasUsed,
EffectiveGasPrice,
GasUsed,
#[subenum(RpcTransactionField)]
Input,
Nonce,
#[subenum(RpcTransactionField)]
Value,
V,
R,
Expand Down
96 changes: 77 additions & 19 deletions codegenerator/cli/templates/static/codegen/src/EventFetching.res
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
open Belt

exception QueryTimout(string)
exception EventRoutingFailed

Expand Down Expand Up @@ -31,6 +33,51 @@ let rec getKnownBlockWithBackoff = async (~provider, ~blockNumber, ~backoffMsOnF
| result => result
}

let getSuggestedBlockIntervalFromExn = {
let suggestedRangeRegExp = %re(`/retry with the range (\d+)-(\d+)/`)

let blockRangeLimitRegExp = %re(`/limited to a (\d+) blocks range/`)

exn =>
switch exn {
| Js.Exn.Error(error) =>
try {
// Didn't use parse here since it didn't work
// because the error is some sort of weird Ethers object
let message: string = (error->Obj.magic)["error"]["message"]
message->S.assertOrRaiseWith(S.string)
switch suggestedRangeRegExp->Js.Re.exec_(message) {
| Some(execResult) =>
switch execResult->Js.Re.captures {
| [_, Js.Nullable.Value(fromBlock), Js.Nullable.Value(toBlock)] =>
switch (fromBlock->Int.fromString, toBlock->Int.fromString) {
| (Some(fromBlock), Some(toBlock)) if toBlock >= fromBlock =>
Some(toBlock - fromBlock + 1)
| _ => None
}
| _ => None
}
| None =>
switch blockRangeLimitRegExp->Js.Re.exec_(message) {
| Some(execResult) =>
switch execResult->Js.Re.captures {
| [_, Js.Nullable.Value(blockRangeLimit)] =>
switch blockRangeLimit->Int.fromString {
| Some(blockRangeLimit) if blockRangeLimit > 0 => Some(blockRangeLimit)
| _ => None
}
| _ => None
}
| None => None
}
}
} catch {
| _ => None
}
| _ => None
}
}

type eventBatchQuery = {
logs: array<Ethers.log>,
latestFetchedBlock: Ethers.JsonRpcProvider.block,
Expand Down Expand Up @@ -93,26 +140,37 @@ let getNextPage = (
[queryTimoutPromise, logsPromise]
->Promise.race
->Promise.catch(err => {
// Might fail with message "query exceeds max results 20000, retry with the range 6000438-6000934"
// Ideally to handle it and respect

logger->Logging.childWarn({
"msg": "Error getting events. Will retry after backoff time",
"backOffMilliseconds": sc.backoffMillis,
"suggestedBlockInterval": suggestedBlockInterval,
"err": err,
})
switch getSuggestedBlockIntervalFromExn(err) {
| Some(nextBlockIntervalTry) => {
logger->Logging.childTrace({
"msg": "Failed getting events for the block interval. Retrying with the block interval suggested by the RPC provider.",
"fromBlock": fromBlock,
"toBlock": fromBlock + nextBlockIntervalTry - 1,
"prevBlockInterval": suggestedBlockInterval,
})
executeQuery(~suggestedBlockInterval=nextBlockIntervalTry)
}
| None => {
logger->Logging.childWarn({
"msg": "Failed getting events for the block interval. Will retry after backoff time",
"backOffMilliseconds": sc.backoffMillis,
"prevBlockInterval": suggestedBlockInterval,
"err": err,
})

Time.resolvePromiseAfterDelay(~delayMilliseconds=sc.backoffMillis)->Promise.then(_ => {
let nextBlockIntervalTry =
(suggestedBlockInterval->Belt.Int.toFloat *. sc.backoffMultiplicative)->Belt.Int.fromFloat
logger->Logging.childTrace({
"msg": "Retrying query with a smaller block interval",
"fromBlock": fromBlock,
"toBlock": fromBlock + nextBlockIntervalTry - 1,
})
executeQuery(~suggestedBlockInterval={nextBlockIntervalTry})
})
Time.resolvePromiseAfterDelay(~delayMilliseconds=sc.backoffMillis)->Promise.then(_ => {
let nextBlockIntervalTry =
(suggestedBlockInterval->Belt.Int.toFloat *. sc.backoffMultiplicative)
->Belt.Int.fromFloat
logger->Logging.childTrace({
"msg": "Retrying query with a smaller block interval",
"fromBlock": fromBlock,
"toBlock": fromBlock + nextBlockIntervalTry - 1,
})
executeQuery(~suggestedBlockInterval={nextBlockIntervalTry})
})
}
}
})
}

Expand Down
102 changes: 102 additions & 0 deletions scenarios/test_codegen/test/RpcWorker_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -431,3 +431,105 @@ describe("RpcWorker - getSelectionConfig", () => {
},
)
})

describe("RpcWorker - getSuggestedBlockIntervalFromExn", () => {
let getSuggestedBlockIntervalFromExn = EventFetching.getSuggestedBlockIntervalFromExn

it("Should handle retry with the range", () => {
let error = JsError(
%raw(`{
"code": "UNKNOWN_ERROR",
"error": {
"code": -32602,
"message": "query exceeds max results 20000, retry with the range 6000000-6000509"
},
"payload": {
"method": "eth_getLogs",
"params": [
{
"topics": [
[
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925",
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
]
],
"fromBlock": "0x5b8d80",
"toBlock": "0x5b9168"
}
],
"id": 4,
"jsonrpc": "2.0"
},
"shortMessage": "could not coalesce error"
}`),
)

Assert.deepEqual(getSuggestedBlockIntervalFromExn(error), Some(510))
})

it("Should ignore invalid range errors where toBlock is less than fromBlock", () => {
let error = JsError(
%raw(`{
"code": "UNKNOWN_ERROR",
"error": {
"code": -32602,
"message": "query exceeds max results 20000, retry with the range 6000509-6000000"
},
"payload": {
"method": "eth_getLogs",
"params": [
{
"topics": [
[
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925",
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
]
],
"fromBlock": "0x5b8d80",
"toBlock": "0x5b9168"
}
],
"id": 4,
"jsonrpc": "2.0"
},
"shortMessage": "could not coalesce error"
}`),
)

Assert.deepEqual(getSuggestedBlockIntervalFromExn(error), None)
})

it("Should handle block range limit from https://1rpc.io/eth", () => {
let error = JsError(
%raw(`{
"code": "UNKNOWN_ERROR",
"error": {
"code": -32000,
"message": "eth_getLogs is limited to a 1000 blocks range"
},
"payload": {
"method": "eth_getLogs",
"params": [
{
"address": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"topics": [
[
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
]
],
"fromBlock": "0x5b8d80",
"toBlock": "0x5ba17f"
}
],
"id": 18,
"jsonrpc": "2.0"
},
"shortMessage": "could not coalesce error"
}`),
)

Assert.deepEqual(getSuggestedBlockIntervalFromExn(error), Some(1000))
})
})

0 comments on commit df8fbfb

Please sign in to comment.