-
-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
♻️ Chore: move newFilter to actions package
- Loading branch information
William Cory
authored and
William Cory
committed
Aug 1, 2024
1 parent
7529b8e
commit d140058
Showing
7 changed files
with
199 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { createAddress } from '@tevm/address' | ||
import { bytesToHex, hexToBytes } from '@tevm/utils' | ||
import { generateRandomId } from './utils/generateRandomId.js' | ||
import { parseBlockTag } from './utils/parseBlockTag.js' | ||
import { InvalidBlockError, UnknownBlockError } from '@tevm/errors' | ||
|
||
/** | ||
* @typedef {UnknownBlockError | InvalidBlockError} EthNewFilterError | ||
*/ | ||
|
||
/** | ||
* @param {import('@tevm/base-client').BaseClient} client | ||
* @returns {import('./EthHandler.js').EthNewFilterHandler} ethNewFilterHandler | ||
*/ | ||
export const ethNewFilterHandler = (client) => { | ||
return async (params) => { | ||
const { topics, address, toBlock = 'latest', fromBlock = 'latest' } = params | ||
const vm = await client.getVm() | ||
/** | ||
* @param {typeof toBlock} tag | ||
*/ | ||
const getBlock = async (tag) => { | ||
const parsedTag = parseBlockTag(tag) | ||
if ( | ||
parsedTag === 'safe' || | ||
parsedTag === 'latest' || | ||
parsedTag === 'finalized' || | ||
parsedTag === 'earliest' || | ||
parsedTag === 'pending' || | ||
parsedTag === /** @type any*/ ('forked') | ||
) { | ||
return vm.blockchain.blocksByTag.get(parsedTag) | ||
} | ||
if (typeof parsedTag === 'string') { | ||
return vm.blockchain.getBlock(hexToBytes(parsedTag)) | ||
} | ||
if (typeof tag === 'bigint') { | ||
return vm.blockchain.getBlock(tag) | ||
} | ||
throw new InvalidBlockError(`Invalid block tag ${tag}`) | ||
} | ||
const _toBlock = await getBlock(toBlock) | ||
if (!_toBlock) { | ||
throw new UnknownBlockError(`Unknown block tag ${toBlock}`) | ||
} | ||
const _fromBlock = await getBlock(fromBlock) | ||
if (!_fromBlock) { | ||
throw new UnknownBlockError(`Unknown block tag ${fromBlock}`) | ||
} | ||
|
||
const id = generateRandomId() | ||
/** | ||
* @param {import('@tevm/base-client').Filter['logs'][number]} log | ||
*/ | ||
const listener = (log) => { | ||
const filter = client.getFilters().get(id) | ||
if (!filter) { | ||
return | ||
} | ||
filter.logs.push(log) | ||
} | ||
client.on('newLog', listener) | ||
// populate with past blocks | ||
const receiptsManager = await client.getReceiptsManager() | ||
const pastLogs = await receiptsManager.getLogs( | ||
_fromBlock, | ||
_toBlock, | ||
address !== undefined ? [createAddress(address).bytes] : [], | ||
topics?.map((topic) => hexToBytes(topic)), | ||
) | ||
client.setFilter({ | ||
id, | ||
type: 'Log', | ||
created: Date.now(), | ||
logs: pastLogs.map((log) => { | ||
const [address, topics, data] = log.log | ||
return { | ||
topics: /** @type {[import('@tevm/utils').Hex, ...Array<import('@tevm/utils').Hex>]}*/ ( | ||
topics.map((topic) => bytesToHex(topic)) | ||
), | ||
address: bytesToHex(address), | ||
data: bytesToHex(data), | ||
blockNumber: log.block.header.number, | ||
transactionHash: bytesToHex(log.tx.hash()), | ||
removed: false, | ||
logIndex: log.logIndex, | ||
blockHash: bytesToHex(log.block.hash()), | ||
transactionIndex: log.txIndex, | ||
} | ||
}), | ||
tx: [], | ||
blocks: [], | ||
logsCriteria: { | ||
topics, | ||
address, | ||
toBlock: toBlock, | ||
fromBlock: fromBlock, | ||
}, | ||
installed: {}, | ||
err: undefined, | ||
registeredListeners: [listener], | ||
}) | ||
return id | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* @returns {import("@tevm/utils").Hex} | ||
*/ | ||
export const generateRandomId = () => { | ||
return `0x${Array.from(crypto.getRandomValues(new Uint8Array(16))) | ||
.map((b) => b.toString(16).padStart(2, '0')) | ||
.join('')}` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { describe, expect, it } from 'vitest' | ||
import { generateRandomId } from './generateRandomId.js' | ||
|
||
describe('generateRandomId', () => { | ||
it('should generate a valid hex string of length 34', () => { | ||
const id = generateRandomId() | ||
expect(id).toMatch(/^0x[a-f0-9]{32}$/) | ||
}) | ||
|
||
it('should generate different ids on multiple calls', () => { | ||
const id1 = generateRandomId() | ||
const id2 = generateRandomId() | ||
expect(id1).not.toBe(id2) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { hexToBigInt } from '@tevm/utils' | ||
|
||
/** | ||
* @param {import('@tevm/utils').Hex | import('@tevm/utils').BlockTag | bigint} blockTag | ||
* @returns {bigint | import('@tevm/utils').Hex | import('@tevm/utils').BlockTag} | ||
*/ | ||
export const parseBlockTag = (blockTag) => { | ||
const blockHashLength = 64 + '0x'.length | ||
const isBlockNumber = typeof blockTag === 'string' && blockTag.startsWith('0x') && blockTag.length !== blockHashLength | ||
if (isBlockNumber) { | ||
return hexToBigInt(/** @type {import('@tevm/utils').Hex}*/ (blockTag)) | ||
} | ||
return blockTag | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { hexToBigInt } from '@tevm/utils' | ||
import { describe, expect, it } from 'vitest' | ||
import { parseBlockTag } from './parseBlockTag.js' | ||
|
||
describe('parseBlockTag', () => { | ||
it('should parse hex block numbers to bigint', () => { | ||
const blockTag = '0x10' | ||
const result = parseBlockTag(blockTag) | ||
expect(result).toBe(hexToBigInt(blockTag)) | ||
}) | ||
|
||
it('should return block hash as is', () => { | ||
const blockHash = `0x${'a'.repeat(64)}` as const | ||
const result = parseBlockTag(blockHash) | ||
expect(result).toBe(blockHash) | ||
}) | ||
|
||
it('should return special block tags as is', () => { | ||
const tags = ['latest', 'earliest', 'pending'] as const | ||
tags.forEach((tag) => { | ||
const result = parseBlockTag(tag) | ||
expect(result).toBe(tag) | ||
}) | ||
}) | ||
|
||
it('should return block number as bigint for valid hex strings', () => { | ||
const blockTag = '0x1a' | ||
const result = parseBlockTag(blockTag) | ||
expect(result).toBe(26n) | ||
}) | ||
|
||
it('should handle block tag as a number string correctly', () => { | ||
const blockTag = '0x10' | ||
const result = parseBlockTag(blockTag) | ||
expect(result).toBe(16n) | ||
}) | ||
|
||
it('should return blockTag unchanged if it is a non-hex string', () => { | ||
const blockTag = 'pending' | ||
const result = parseBlockTag(blockTag) | ||
expect(result).toBe(blockTag) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters