Skip to content

Commit

Permalink
fix: increase debug & temporarily disable goerli (#241)
Browse files Browse the repository at this point in the history
* enh: increase debugging for price updater

* fix: disable goerli temporarily
  • Loading branch information
bard authored Aug 18, 2023
1 parent ed22b3e commit 1c7f8bb
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 86 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"main": "dist/src/indexer/index.js",
"types": "dist/src/indexer/index.d.ts",
"scripts": {
"start": "node dist/src/index.js --chains=mainnet,optimism,goerli,fantom,pgn-testnet,pgn-mainnet",
"start": "node dist/src/index.js --chains=mainnet,optimism,fantom,pgn-testnet,pgn-mainnet",
"dev": "tsx watch src/index.ts --chains=mainnet,optimism,goerli,fantom,pgn-testnet,pgn-mainnet | pino-pretty",
"build": "tsc",
"lint": "eslint src",
Expand Down
163 changes: 85 additions & 78 deletions src/prices/updater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,102 +63,109 @@ export function createPriceUpdater(
};

async function update(toBlock: ToBlock) {
const { rpcProvider: provider } = config;

logger.debug(`updating prices to block: ${toBlock}`);
const currentPrices = await readPricesFile(
config.chain.id,
config.storageDir
);

// get last updated price
const lastPriceAt = currentPrices.reduce(
(acc, price) => Math.max(price.timestamp + hours(1), acc),
config.chain.pricesFromTimestamp
);

let toDate = undefined;

if (toBlock === "latest") {
toDate = new Date();
} else {
const block = await provider.getBlock(toBlock);
toDate = new Date(block.timestamp * 1000);
}

// time elapsed from the last update, rounded to hours
const timeElapsed =
Math.floor((toDate.getTime() - lastPriceAt) / hours(1)) * hours(1);
try {
const { rpcProvider: provider } = config;

// only fetch new prices every new hour
if (timeElapsed < hours(1)) {
return;
}
logger.debug(`updating prices to block: ${toBlock}`);
const currentPrices = await readPricesFile(
config.chain.id,
config.storageDir
);

const getBlockTimestamp = async (blockNumber: number) => {
const block = await withCacheMaybe(
`block-${config.chain.id}-${blockNumber}`,
() => provider.getBlock(blockNumber)
// get last updated price
const lastPriceAt = currentPrices.reduce(
(acc, price) => Math.max(price.timestamp + hours(1), acc),
config.chain.pricesFromTimestamp
);

return block.timestamp;
};
let toDate = undefined;

const lastBlockNumber = await provider.getBlockNumber();
if (toBlock === "latest") {
toDate = new Date();
} else {
const block = await provider.getBlock(toBlock);
toDate = new Date(block.timestamp * 1000);
}

// get prices in 90 day chunks to get the most of Coingecko's granularity
const timeChunks = chunkTimeBy(timeElapsed, days(90));
// time elapsed from the last update, rounded to hours
const timeElapsed =
Math.floor((toDate.getTime() - lastPriceAt) / hours(1)) * hours(1);

for (const chunk of timeChunks) {
for (const token of config.chain.tokens) {
const cacheKey = `${config.chain.id}-${token.address}-${
lastPriceAt + chunk[0]
}-${lastPriceAt + chunk[1]}`;
// only fetch new prices every new hour
if (timeElapsed < hours(1)) {
return;
}

logger.debug(
`fetching prices for ${token.code} from ${new Date(
lastPriceAt + chunk[0]
).toISOString()} to ${new Date(lastPriceAt + chunk[1]).toISOString()}`
const getBlockTimestamp = async (blockNumber: number) => {
const block = await withCacheMaybe(
`block-${config.chain.id}-${blockNumber}`,
() => provider.getBlock(blockNumber)
);

const prices = await withCacheMaybe(cacheKey, () =>
getPricesByHour(
token,
(lastPriceAt + chunk[0]) / 1000,
(lastPriceAt + chunk[1]) / 1000,
config
)
);
return block.timestamp;
};

const newPrices: Price[] = [];
const lastBlockNumber = await provider.getBlockNumber();

for (const [timestamp, price] of prices) {
const blockNumber = await getBlockFromTimestamp(
timestamp,
0,
lastBlockNumber,
getBlockTimestamp
// get prices in 90 day chunks to get the most of Coingecko's granularity
const timeChunks = chunkTimeBy(timeElapsed, days(90));

for (const chunk of timeChunks) {
for (const token of config.chain.tokens) {
const cacheKey = `${config.chain.id}-${token.address}-${
lastPriceAt + chunk[0]
}-${lastPriceAt + chunk[1]}`;

logger.debug(
`fetching prices for ${token.code} from ${new Date(
lastPriceAt + chunk[0]
).toISOString()} to ${new Date(
lastPriceAt + chunk[1]
).toISOString()}`
);

if (blockNumber === undefined) {
throw new Error(
`Could not find block number for timestamp: ${timestamp}`
);
}
const prices = await withCacheMaybe(cacheKey, () =>
getPricesByHour(
token,
(lastPriceAt + chunk[0]) / 1000,
(lastPriceAt + chunk[1]) / 1000,
config
)
);

newPrices.push({
token: token.address.toLowerCase(),
code: token.code,
price,
timestamp,
block: blockNumber,
});
}
const newPrices: Price[] = [];

for (const [timestamp, price] of prices) {
try {
const blockNumber = await getBlockFromTimestamp(
timestamp,
0,
lastBlockNumber,
getBlockTimestamp
);

newPrices.push({
token: token.address.toLowerCase(),
code: token.code,
price,
timestamp,
block: blockNumber,
});
} catch (err) {
throw new Error(
`Error getting block number for token ${token.code} at timestamp ${timestamp}`,
{ cause: err }
);
}
}

logger.debug(`fetched ${newPrices.length} prices`);
logger.debug(`fetched ${newPrices.length} prices`);

await appendPrices(config.chain.id, newPrices);
await appendPrices(config.chain.id, newPrices);
}
}
} catch (err) {
logger.error({ msg: "error updating prices", err });
}
}

Expand Down
19 changes: 17 additions & 2 deletions src/utils/getBlockFromTimestamp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@ async function estimateBlockNumber(
const secondsToTarget = targetTimestamp - startTimestamp;
if (secondsToTarget < 0) {
throw new Error(
"Estimated block is negative, this probably means that the timestamp precedes the deployment of the chain. Check chain config and ensure that `pricesFromTimestamp` is correct."
`Estimated block is negative, this probably means that the timestamp precedes the deployment of the chain. Check chain config and ensure that pricesFromTimestamp() is correct. (${JSON.stringify(
{
targetTimestamp,
startBlock,
endBlock,
startTimestamp,
endTimestamp,
timeDistanceInSeconds,
}
)})`
);
}
const estimatedBlocksToTarget = blocksPerSecond * secondsToTarget;
Expand All @@ -45,7 +54,7 @@ export async function getBlockFromTimestamp(
startBlock: number,
endBlock: number,
getBlockTimestamp: (blockNumber: number) => Promise<number>
): Promise<number | undefined> {
): Promise<number> {
const blockEstimationThreshold = 10000;
const targetTimestamp = Math.floor(timestampInMs / 1000);

Expand Down Expand Up @@ -114,5 +123,11 @@ export async function getBlockFromTimestamp(
}
}

if (blockNumber === undefined) {
throw new Error(
`Could not find block number at timestamp: ${timestampInMs}`
);
}

return blockNumber;
}
7 changes: 2 additions & 5 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"include": ["src/**/*"],
"compilerOptions": {
"target": "es2021",
"target": "es2022",
"module": "esnext",
"allowJs": true,
"esModuleInterop": true,
Expand All @@ -15,8 +15,5 @@
"resolveJsonModule": true,
"declaration": false
},
"exclude": [
"node_modules",
"dist",
]
"exclude": ["node_modules", "dist"]
}

0 comments on commit 1c7f8bb

Please sign in to comment.