Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get logs from cache #985

Merged
merged 4 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/eth-providers/src/__tests__/e2e/json-rpc-provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,27 @@ describe('JsonRpcProvider', async () => {
});
});

describe('get logs without subql', () => {
it('works', async () => {
const echoFactory = new ContractFactory(echoJson.abi, echoJson.bytecode, wallet);
const echo = await echoFactory.deploy();

const { blockNumber: block0 } = await (await echo.scream('hello Gogeta!')).wait();
let logs = await wallet.provider.getLogs({
address: echo.address,
});
expect(logs.length).to.eq(1);

const { blockNumber: block1 } = await (await echo.scream('hello Vegito!')).wait();
logs = await wallet.provider.getLogs({
address: echo.address,
fromBlock: block0,
toBlock: block1,
});
expect(logs.length).to.eq(2);
});
});

describe('subscription', () => {
it('subscribe to new block', async () => {
const curBlockNumber = await provider.getBlockNumber();
Expand Down
48 changes: 36 additions & 12 deletions packages/eth-providers/src/base-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1795,17 +1795,26 @@ export abstract class BaseProvider extends AbstractProvider {
_getSubqlMissedLogs = async (toBlock: number, filter: SanitizedLogFilter): Promise<Log[]> => {
const targetBlock = Math.min(toBlock, await this.finalizedBlockNumber); // subql upperbound is finalizedBlockNumber
const lastProcessedHeight = await this.subql.getLastProcessedHeight();
const missedBlockCount = targetBlock - lastProcessedHeight;
if (missedBlockCount <= 0) return [];

const firstMissedHeight = lastProcessedHeight + 1;
const missedHeights = Array.from(
{ length: missedBlockCount },
(_, i) => firstMissedHeight + i,

return this._getLogsFromCache(firstMissedHeight, targetBlock, filter);
};

_getLogsFromCache = async (
fromBlock: number,
toBlock: number,
filter: SanitizedLogFilter,
): Promise<Log[]> => {
const blockCount = toBlock - fromBlock + 1; // when to === from, it should return 1 block
if (blockCount <= 0) return [];

const heights = Array.from(
{ length: blockCount },
(_, i) => fromBlock + i,
);
const missedBlockHashes = await Promise.all(missedHeights.map(this._getBlockHash.bind(this)));
const blockHashes = await Promise.all(heights.map(this._getBlockHash.bind(this)));

return missedBlockHashes
return blockHashes
.map(this.blockCache.getLogsAtBlock.bind(this))
.flat()
.filter(log => filterLogByBlockNumber(log, filter.fromBlock, filter.toBlock))
Expand All @@ -1814,13 +1823,28 @@ export abstract class BaseProvider extends AbstractProvider {

// Bloom-filter Queries
getLogs = async (rawFilter: LogFilter): Promise<Log[]> => {
const filter = await this._sanitizeRawFilter(rawFilter);

if (!this.subql) {
return logger.throwError(
'missing subql url to fetch logs, to initialize base provider with subql, please provide a subqlUrl param.'
const _throwErr = (earliestCachedBlockNumber?: number) => logger.throwError(
'cache does not contain enough info to fetch requested logs, please reduce block range or initialize provider with a subql url',
Logger.errors.SERVER_ERROR,
{
requestFromBlock: filter.fromBlock,
earliestCachedBlockNumber,
},
);
}

const filter = await this._sanitizeRawFilter(rawFilter);
const earliestCachedBlockHash = this.blockCache.cachedBlockHashes[0];
if (!earliestCachedBlockHash) return _throwErr();

const earliestCachedBlockNumber = await this._getBlockNumber(earliestCachedBlockHash);
const isAllTargetLogsInCache = earliestCachedBlockNumber <= filter.fromBlock;

return isAllTargetLogsInCache
? this._getLogsFromCache(filter.fromBlock, filter.toBlock, filter)
: _throwErr(earliestCachedBlockNumber);
}

// only filter by blockNumber and address, since topics are filtered at last
const [subqlLogs, extraLogs] = await Promise.all([
Expand Down
Loading