Skip to content

Commit

Permalink
Replace ethjs-query with @metamask/eth-query (#129)
Browse files Browse the repository at this point in the history
For some reason, we are using `@metamask/eth-query` for consumer-facing
code, but we are using `ethjs-query` for tests. There is no reason to do
this, and `@metamask/eth-query` works just fine.

This means we can also drop `@ethereumjs/util` since we were also only
using it for tests.
  • Loading branch information
mcmire authored Nov 20, 2023
1 parent 3374b7f commit 29546fb
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 92 deletions.
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@
"pify": "^5.0.0"
},
"devDependencies": {
"@ethereumjs/util": "^8.1.0",
"@lavamoat/allow-scripts": "^2.5.1",
"@metamask/auto-changelog": "^3.3.0",
"@metamask/eth-json-rpc-middleware": "^12.0.0",
"eth-block-tracker": "^8.0.0",
"ethjs-query": "^0.3.8",
"ganache-core": "^2.13.2",
"sinon": "^15.2.0",
"tape": "^5.7.0"
Expand Down Expand Up @@ -59,7 +57,8 @@
"ganache-core>websocket>bufferutil": false,
"ganache-core>websocket>utf-8-validate": false,
"ganache-core>ethereumjs-util>ethereum-cryptography>keccak": false,
"ganache-core>ethereumjs-util>ethereum-cryptography>secp256k1": false
"ganache-core>ethereumjs-util>ethereum-cryptography>secp256k1": false,
"ganache-core>web3-provider-engine>eth-block-tracker>json-rpc-engine>babelify>babel-core>babel-runtime>core-js": false
}
}
}
96 changes: 72 additions & 24 deletions test/ganache.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const test = require('tape')
const ethUtil = require('@ethereumjs/util')
const {
createTestSetup,
asyncTest,
Expand All @@ -9,50 +8,74 @@ const {
test('LogFilter - basic', asyncTest(async (t) => {

const tools = createTestSetup()
const eth = tools.query
const { sendAsync } = tools

// deploy log-echo contract
const coinbase = await eth.coinbase()
const coinbase = await sendAsync({ method: 'eth_coinbase' })
const { contractAddress } = await deployLogEchoContract({ tools, from: coinbase })
t.ok(contractAddress, 'got deployed contract address')

// create filter
const blockNumber = (await eth.blockNumber()).toNumber()
const blockNumber = await sendAsync({ method: 'eth_blockNumber' })
const targetTopic = '0xaabbcce106361d4f6cd9098051596d565c1dbf7bc20b4c3acb3aaa4204aabbcc'
const filterParams = { address: contractAddress, topics: [targetTopic], fromBlock: blockNumber, toBlock: 'latest' }
const filterId = ethUtil.intToHex((await eth.newFilter(filterParams)).toNumber())
const filterId = await sendAsync({
method: 'eth_newFilter',
params: {
address: contractAddress,
topics: [targetTopic],
fromBlock: blockNumber,
toBlock: 'latest'
}
})
t.ok(filterId, `got filter id: ${filterId} (${typeof filterId})`)

// trigger filter
const triggeringTxHash = await eth.sendTransaction({ from: coinbase, to: contractAddress, data: targetTopic })
const triggeringTxHash = await sendAsync({
method: 'eth_sendTransaction',
params: {
from: coinbase,
to: contractAddress,
data: targetTopic
}
})
await tools.trackNextBlock()
// check filter
const filterChanges = await eth.getFilterChanges(filterId)
const filterChanges = await sendAsync({
method: 'eth_getFilterChanges',
params: [filterId]
})
t.equal(filterChanges.length, 1, 'only one matched filter')
const matchingFilter = filterChanges[0]
t.equal(matchingFilter.transactionHash, triggeringTxHash, 'tx hash should match')
t.equal(matchingFilter.topics.length, 1, 'emitted a single log topic')
const matchedTopic = matchingFilter.topics[0]
t.equal(matchedTopic, targetTopic, 'topic matches expected')

await eth.uninstallFilter(filterId)
await sendAsync({ method: 'eth_uninstallFilter', params: [filterId] })
}))

test('LogFilter - multiple blocks', asyncTest(async (t) => {

const tools = createTestSetup()
const eth = tools.query
const { sendAsync } = tools

// deploy log-echo contract
const coinbase = await eth.coinbase()
const coinbase = await sendAsync({ method: 'eth_coinbase' })
const { contractAddress } = await deployLogEchoContract({ tools, from: coinbase })
t.ok(contractAddress, 'got deployed contract address')

// create filter
const blockNumber = (await eth.blockNumber()).toNumber()
const blockNumber = await sendAsync({ method: 'eth_blockNumber' })
const targetTopic = '0x112233e106361d4f6cd9098051596d565c1dbf7bc20b4c3acb3aaa4204112233'
const filterParams = { address: contractAddress, topics: [targetTopic], fromBlock: blockNumber, toBlock: 'latest' }
const filterId = ethUtil.intToHex((await eth.newFilter(filterParams)).toNumber())
const filterId = await sendAsync({
method: 'eth_newFilter',
params: {
address: contractAddress,
topics: [targetTopic],
fromBlock: blockNumber,
toBlock: 'latest'
}
})
t.ok(filterId, `got filter id: ${filterId} (${typeof filterId})`)

// await multiple blocks
Expand All @@ -64,7 +87,14 @@ test('LogFilter - multiple blocks', asyncTest(async (t) => {
await tools.trackNextBlock()

// trigger filter
const triggeringTxHash = await eth.sendTransaction({ from: coinbase, to: contractAddress, data: targetTopic })
const triggeringTxHash = await sendAsync({
method: 'eth_sendTransaction',
params: {
from: coinbase,
to: contractAddress,
data: targetTopic
}
})
await tools.trackNextBlock()

// await multiple blocks
Expand All @@ -74,44 +104,56 @@ test('LogFilter - multiple blocks', asyncTest(async (t) => {
await tools.trackNextBlock()

// check filter
const filterChanges = await eth.getFilterChanges(filterId)
const filterChanges = await sendAsync({
method: 'eth_getFilterChanges',
params: [filterId]
})
t.equal(filterChanges.length, 1, 'only one matched filter')
const matchingFilter = filterChanges[0]
t.equal(matchingFilter.transactionHash, triggeringTxHash, 'tx hash should match')
t.equal(matchingFilter.topics.length, 1, 'emitted a single log topic')
const matchedTopic = matchingFilter.topics[0]
t.equal(matchedTopic, targetTopic, 'topic matches expected')

await eth.uninstallFilter(filterId)
await sendAsync({ method: 'eth_uninstallFilter', params: [filterId] })
}))

test('BlockFilter - basic', asyncTest(async (t) => {

const tools = createTestSetup()
const eth = tools.query
const { sendAsync } = tools

// await first block
await tools.trackNextBlock()

// create filter
const filterId = ethUtil.intToHex((await eth.newBlockFilter()).toNumber())
const filterId = await sendAsync({ method: 'eth_newBlockFilter', })
t.ok(filterId, `got filter id: ${filterId} (${typeof filterId})`)

// check filter
const filterChanges1 = await eth.getFilterChanges(filterId)
const filterChanges1 = await sendAsync({
method: 'eth_getFilterChanges',
params: [filterId]
})
t.equal(filterChanges1.length, 0, 'no matched filters yet')

// await one block
await tools.forceNextBlock()
await tools.trackNextBlock()

// check filter
const filterChanges2 = await eth.getFilterChanges(filterId)
const filterChanges2 = await sendAsync({
method: 'eth_getFilterChanges',
params: [filterId]
})
t.equal(filterChanges2.length, 1, 'only one matched filter')
const matchingFilter1 = filterChanges2[0]
t.equal(matchingFilter1.length, 2 + 32 * 2, 'result is correct length for block hash')
// check filter
const filterChanges3 = await eth.getFilterChanges(filterId)
const filterChanges3 = await sendAsync({
method: 'eth_getFilterChanges',
params: [filterId]
})
t.equal(filterChanges3.length, 0, 'matched filters reset')

// await two blocks
Expand All @@ -121,13 +163,19 @@ test('BlockFilter - basic', asyncTest(async (t) => {
await tools.trackNextBlock()

// check filter
const filterChanges4 = await eth.getFilterChanges(filterId)
const filterChanges4 = await sendAsync({
method: 'eth_getFilterChanges',
params: [filterId]
})
t.equal(filterChanges4.length, 2, 'two matched filter')
const matchingFilter2 = filterChanges4[0]
const matchingFilter3 = filterChanges4[1]
t.equal(matchingFilter2.length, 2 + 32 * 2, 'result is correct length for block hash')
t.equal(matchingFilter3.length, 2 + 32 * 2, 'result is correct length for block hash')
t.notEqual(matchingFilter2, matchingFilter3, 'hashes are different')

await eth.uninstallFilter(filterId)
await sendAsync({
method: 'eth_uninstallFilter',
params: [filterId]
})
}))
2 changes: 1 addition & 1 deletion test/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
process.on('unhandledRejection', function(err){
process.on('unhandledRejection', function (err) {
throw err
})

Expand Down
28 changes: 18 additions & 10 deletions test/subscriptions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const test = require('tape')
const {
createTestSetup,
createPayload,
asyncTest,
timeout,
deployLogEchoContract,
Expand All @@ -10,11 +9,8 @@ const {
test('subscriptions - newHeads', asyncTest(async (t) => {

const tools = createTestSetup()
const eth = tools.query
const subs = tools.subs

const { blockTracker } = tools

// await first block
await tools.forceNextBlock()
await tools.trackNextBlock()
Expand Down Expand Up @@ -57,11 +53,10 @@ test('subscriptions - newHeads', asyncTest(async (t) => {
test('subscriptions - log', asyncTest(async (t) => {

const tools = createTestSetup()
const eth = tools.query
const { query, subs, blockTracker } = tools
const { sendAsync, subs, blockTracker } = tools

// deploy log-echo contract
const coinbase = await query.coinbase()
const coinbase = await sendAsync({ method: 'eth_coinbase' })
const { contractAddress } = await deployLogEchoContract({ tools, from: coinbase })
t.ok(contractAddress, 'got deployed contract address')
// deploy secondary "wrong" log contract
Expand All @@ -84,15 +79,28 @@ test('subscriptions - log', asyncTest(async (t) => {
t.equal(typeof subId, 'string', `got sub id as hex string (${typeof subId})`)

// trigger matching log
const triggeringTxHash = await query.sendTransaction({ from: coinbase, to: contractAddress, data: targetTopic })
const triggeringTxHash = await sendAsync({
method: 'eth_sendTransaction',
params: { from: coinbase, to: contractAddress, data: targetTopic }
})
await tools.trackNextBlock()

// trigger non-matching log
await query.sendTransaction({ from: coinbase, to: contractAddress, data: wrongTopic })
await sendAsync({
method: 'eth_sendTransaction',
params: {
from: coinbase,
to: contractAddress,
data: wrongTopic
}
})
await tools.trackNextBlock()

// trigger non-matching contract
await query.sendTransaction({ from: coinbase, to: wrongContractAddress, data: targetTopic })
await sendAsync({
method: 'eth_sendTransaction',
params: { from: coinbase, to: wrongContractAddress, data: targetTopic }
})
await tools.trackNextBlock()

// wait for subscription results to update
Expand Down
34 changes: 22 additions & 12 deletions test/util.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const EventEmitter = require('events')
const { PollingBlockTracker } = require('eth-block-tracker')
const EthQuery = require('ethjs-query')
const EthQuery = require('@metamask/eth-query')
const { JsonRpcEngine } = require('@metamask/json-rpc-engine')
const { providerAsMiddleware } = require('@metamask/eth-json-rpc-middleware')
const { providerFromEngine } = require('@metamask/eth-json-rpc-provider')
Expand All @@ -19,7 +19,7 @@ module.exports = {
deployLogEchoContract,
}

function createTestSetup () {
function createTestSetup() {
// raw data source
const { ganacheProvider, forceNextBlock } = createEngineFromGanacheCore()
// create block trackerfilterId
Expand All @@ -31,6 +31,7 @@ function createTestSetup () {
const engine = new JsonRpcEngine()
const provider = providerFromEngine(engine)
const query = new EthQuery(provider)
const sendAsync = pify(query.sendAsync.bind(query));
// add filter middleware
engine.push(createFilterMiddleware({ blockTracker, provider }))
// add subscription middleware
Expand All @@ -43,7 +44,7 @@ function createTestSetup () {
// subs helper
const subs = createSubsHelper({ provider })

return { ganacheProvider, forceNextBlock, engine, provider, query, subs, blockTracker, trackNextBlock }
return { ganacheProvider, forceNextBlock, engine, provider, sendAsync, subs, blockTracker, trackNextBlock }

async function trackNextBlock() {
return new Promise((resolve) => blockTracker.once('latest', resolve))
Expand All @@ -59,7 +60,7 @@ function createSubsHelper({ provider }) {
}

function createSubGenerator({ subType, provider }) {
return pify(function() {
return pify(function () {
const args = [].slice.call(arguments)
const cb = args.pop()
args.unshift(subType)
Expand Down Expand Up @@ -98,7 +99,7 @@ function createNewSub({ id, provider }) {
}
}

function createEngineFromGanacheCore () {
function createEngineFromGanacheCore() {
const ganacheProvider = GanacheCore.provider()
return { ganacheProvider, forceNextBlock }

Expand All @@ -108,7 +109,7 @@ function createEngineFromGanacheCore () {
}
}

function createEngineFromTestBlockMiddleware () {
function createEngineFromTestBlockMiddleware() {
const engine = new JsonRpcEngine()
const testBlockSource = new TestBlockMiddleware()
engine.push(testBlockSource.createMiddleware())
Expand All @@ -119,8 +120,8 @@ function createPayload(payload) {
return Object.assign({ id: 1, jsonrpc: '2.0', params: [] }, payload)
}

function asyncTest(asyncTestFn){
return async function(t) {
function asyncTest(asyncTestFn) {
return async function (t) {
try {
await asyncTestFn(t)
t.end()
Expand All @@ -135,12 +136,21 @@ function timeout(duration) {
}


async function deployLogEchoContract({ tools, from }){
async function deployLogEchoContract({ tools, from }) {
// https://github.com/kumavis/eth-needlepoint/blob/master/examples/emit-log.js
const eth = tools.query
const deployTxHash = await eth.sendTransaction({ from, data: '0x600e600c600039600e6000f336600060003760005160206000a1' })
const { sendAsync } = tools;
const deployTxHash = await sendAsync({
method: 'eth_sendTransaction',
params: {
from,
data: '0x600e600c600039600e6000f336600060003760005160206000a1'
}
})
await tools.trackNextBlock()
const deployTxRx = await eth.getTransactionReceipt(deployTxHash)
const deployTxRx = await sendAsync({
method: 'eth_getTransactionReceipt',
params: [deployTxHash]
})
const contractAddress = deployTxRx.contractAddress
return {
deployTxHash,
Expand Down
Loading

0 comments on commit 29546fb

Please sign in to comment.