Skip to content

Commit

Permalink
improve(BlockUtils): Simplify getBlockForTimestamp() (#791)
Browse files Browse the repository at this point in the history
Two improvements here:
 - Remove the need to supply the HubPool chain ID to this function.
   I've been unable to find any other places in the code where the
   HubPool chain ID block numbers are accessed via the key
   `block_number_<timestamp>`, so just normalise all keys to be
   `<chainId>_block_number_<timestamp>`. This frees the caller from
   having to know what the HubPool chainId is.

 - Remove the need to supply the externally-supplied `currentChainTime`.
   This argument was _always_ supplied with the output of
   `getCurrentTime()`, which is not necessarily the current chain time
   anyway, and goes against the naming of the variable `currentTimeTime`.
   Instead, use the timestamp of the latest block to determine whether
   it's old enough to be cached.

As background, the motivation for this change is that the Relayer now
needs to apply its "max lookback" on RefundRequest events as well, so we
have a common need for resolving timestamps to a previous block number.
Simplifying getBlockForTimestamp() allows us to benefit from the caching
that it implements.
  • Loading branch information
pxrl authored Jul 5, 2023
1 parent e9d1f54 commit a59334f
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 45 deletions.
15 changes: 3 additions & 12 deletions src/common/ClientHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,7 @@ export async function constructSpokePoolClientsWithLookback(

// Use the first block that we'll query on mainnet to figure out which chains were enabled between then
// and the the latest mainnet block. These chains were enabled via the ConfigStore.
const fromBlock_1 = await getBlockForTimestamp(
hubPoolChainId,
hubPoolChainId,
currentTime - initialLookBackOverride,
currentTime
);

const fromBlock_1 = await getBlockForTimestamp(hubPoolChainId, currentTime - initialLookBackOverride);
const enabledChains = getEnabledChainsInBlockRange(configStoreClient, config.spokePoolChainsOverride, fromBlock_1);

// Get full list of fromBlocks now for chains that are enabled. This way we don't send RPC requests to
Expand All @@ -83,10 +77,7 @@ export async function constructSpokePoolClientsWithLookback(
if (chainId === 1) {
return [chainId, fromBlock_1];
} else {
return [
chainId,
await getBlockForTimestamp(hubPoolChainId, chainId, currentTime - initialLookBackOverride, currentTime),
];
return [chainId, await getBlockForTimestamp(chainId, currentTime - initialLookBackOverride)];
}
})
)
Expand Down Expand Up @@ -167,7 +158,7 @@ export async function constructSpokePoolClientsWithStartBlocks(
const spokePoolContract = new Contract(latestSpokePool, SpokePool.abi, spokePoolSigners[chainId]);
const spokePoolRegistrationBlock = hubPoolClient.getSpokePoolActivationBlock(chainId, latestSpokePool);
const time = (await hubPoolClient.hubPool.provider.getBlock(spokePoolRegistrationBlock)).timestamp;
const registrationBlock = await getBlockForTimestamp(hubPoolClient.chainId, chainId, time, getCurrentTime());
const registrationBlock = await getBlockForTimestamp(chainId, time);
return { chainId, contract: spokePoolContract, registrationBlock };
})
);
Expand Down
16 changes: 4 additions & 12 deletions src/finalizer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,11 @@ export async function finalize(
}
const tokensBridged = client.getTokensBridged();

const currentTime = getCurrentTime();
if (chainId === 42161) {
const firstBlockToFinalize = await getBlockForTimestamp(
hubPoolClient.chainId,
chainId,
getCurrentTime() - optimisticRollupFinalizationWindow,
getCurrentTime()
currentTime - optimisticRollupFinalizationWindow
);
logger.debug({
at: "Finalizer",
Expand All @@ -106,12 +105,7 @@ export async function finalize(
finalizationsToBatch.withdrawals.push(...finalizations.withdrawals);
} else if (chainId === 137) {
const posClient = await getPosClient(hubSigner);
const lastBlockToFinalize = await getBlockForTimestamp(
hubPoolClient.chainId,
chainId,
getCurrentTime() - polygonFinalizationWindow,
getCurrentTime()
);
const lastBlockToFinalize = await getBlockForTimestamp(chainId, currentTime - polygonFinalizationWindow);
logger.debug({
at: "Finalizer",
message: `Earliest TokensBridged block to attempt to finalize for ${getNetworkName(chainId)}`,
Expand All @@ -132,10 +126,8 @@ export async function finalize(
} else if (chainId === 10) {
const crossChainMessenger = getOptimismClient(chainId, hubSigner) as optimismSDK.CrossChainMessenger;
const firstBlockToFinalize = await getBlockForTimestamp(
hubPoolClient.chainId,
chainId,
getCurrentTime() - optimisticRollupFinalizationWindow,
getCurrentTime()
currentTime - optimisticRollupFinalizationWindow
);

// First submit proofs for any newly withdrawn tokens. You can submit proofs for any withdrawals that have been
Expand Down
8 changes: 1 addition & 7 deletions src/scripts/validateRootBundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
getDvmContract,
getDisputedProposal,
getBlockForTimestamp,
getCurrentTime,
sortEventsDescending,
getDisputeForTimestamp,
disconnectRedisClient,
Expand Down Expand Up @@ -61,12 +60,7 @@ export async function validate(_logger: winston.Logger, baseSigner: Wallet): Pro
});

// Figure out which block corresponds with the disputed price request time.
const priceRequestBlock = await getBlockForTimestamp(
clients.hubPoolClient.chainId,
clients.hubPoolClient.chainId,
priceRequestTime,
getCurrentTime()
);
const priceRequestBlock = await getBlockForTimestamp(clients.hubPoolClient.chainId, priceRequestTime);
logger.debug({
at: "Dataworker#validate",
message: `Price request block found for request time ${priceRequestTime}`,
Expand Down
16 changes: 9 additions & 7 deletions src/utils/BlockUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,14 @@ export async function getBlockFinder(chainId: number): Promise<BlockFinder<Block
* @notice Get the block number for a given timestamp fresh from on-chain data if not found in redis cache.
* If redis cache is not available, then requests block from blockFinder.
* @param chainId Chain to load block finder for.
* @param timestamp Approximate timestamp of the to requested block number.
* @param blockFinder Caller can optionally pass in a block finder object to use instead of creating a new one
* or loading from cache. This is useful for testing primarily.
* @returns
*/
export async function getBlockForTimestamp(
hubPoolChainId: number,
chainId: number,
timestamp: number,
currentChainTime: number,
blockFinder?: BlockFinder<Block>
): Promise<number> {
blockFinder ??= await getBlockFinder(chainId);
Expand All @@ -40,14 +39,17 @@ export async function getBlockForTimestamp(
return (await blockFinder.getBlockForTimestamp(timestamp)).number;
}

// We already cache blocks in the ConfigStore on the HubPool chain so re-use that key if the chainId
// matches the HubPool's.
const key = chainId === hubPoolChainId ? `block_number_${timestamp}` : `${chainId}_block_number_${timestamp}`;
const key = `${chainId}_block_number_${timestamp}`;
const result = await redisClient.get(key);
if (result === null) {
const blockNumber = (await blockFinder.getBlockForTimestamp(timestamp)).number;
const provider = await getProvider(chainId);
const [currentBlock, { number: blockNumber }] = await Promise.all([
provider.getBlock("latest"),
blockFinder.getBlockForTimestamp(timestamp),
]);

// Expire key after 90 days.
if (shouldCache(timestamp, currentChainTime)) {
if (shouldCache(timestamp, currentBlock.timestamp)) {
await setRedisKey(key, blockNumber.toString(), redisClient, 60 * 60 * 24 * 90);
}
return blockNumber;
Expand Down
10 changes: 3 additions & 7 deletions src/utils/UmaUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Contract, ethers, getBlockForTimestamp, getCurrentTime, isEventOlder, sortEventsDescending } from ".";
import { Contract, ethers, getBlockForTimestamp, isEventOlder, sortEventsDescending } from ".";
import * as uma from "@uma/contracts-node";
import { HubPoolClient } from "../clients";
import { ProposedRootBundle, SortableEvent } from "../interfaces";
Expand All @@ -25,12 +25,8 @@ export async function getDisputeForTimestamp(
const priceRequestBlock =
disputeRequestBlock !== undefined
? disputeRequestBlock
: await getBlockForTimestamp(
hubPoolClient.chainId,
hubPoolClient.chainId,
disputeRequestTimestamp,
getCurrentTime()
);
: await getBlockForTimestamp(hubPoolClient.chainId, disputeRequestTimestamp);

const disputes = await dvm.queryFilter(filter, priceRequestBlock, priceRequestBlock);
return disputes.find((e) => e.args.time.toString() === disputeRequestTimestamp.toString()) as SortableEvent;
}

0 comments on commit a59334f

Please sign in to comment.