Skip to content

Commit

Permalink
Update some things in response to manual testing
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmire committed Sep 30, 2021
1 parent a2dff55 commit 884a9f9
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 124 deletions.
2 changes: 1 addition & 1 deletion src/gas/GasFeeController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ export class GasFeeController extends BaseController<
numberOfBlocks: 100,
percentiles: [50],
});
const sortedPriorityFees: number[] = feeHistory.blocks
const sortedPriorityFees = feeHistory.blocks
.map((block) => block.priorityFeesByPercentile.get(50))
.filter(isNumber)
.sort((a, b) => a - b);
Expand Down
82 changes: 35 additions & 47 deletions src/gas/fetchFeeHistory.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { fetchFeeHistory } from './fetchFeeHistory';

type EthFeeHistoryResponse = {
jsonrpc: string;
id: number;
result: {
oldestBlock: string;
baseFeePerGas: string[];
gasUsedRatio: number[];
reward: string[][];
};
oldestBlock: string;
baseFeePerGas: string[];
gasUsedRatio: number[];
reward: string[][];
};

describe('fetchRecentFeeHistory', () => {
Expand All @@ -31,37 +27,33 @@ describe('fetchRecentFeeHistory', () => {
// "params": ["0x5", "latest", [10, 20, 30]]
// }' https://mainnet.infura.io/v3/<PROJECT_ID>
const ethQuery = buildEthQuery({
jsonrpc: '2.0',
id: 1,
result: {
oldestBlock: '0xcb1939',
// Note that this array contains 6 items when we requested 5. Per
// <https://github.com/ethereum/go-ethereum/blob/57a3fab8a75eeb9c2f4fab770b73b51b9fe672c5/eth/gasprice/feehistory.go#L191-L192>,
// baseFeePerGas will always include an extra item which is the calculated base fee for the
// next (future) block.
baseFeePerGas: [
'0x16eb46a3bb',
'0x14cd6f0628',
'0x1763700ef2',
'0x1477020d14',
'0x129c9eb46b',
'0x134002f480',
],
gasUsedRatio: [
0.13060046666666666,
0.9972395333333334,
0,
0.13780313333333333,
0.6371707333333333,
],
reward: [
['0x59682f00', '0x59682f00', '0x59682f00'],
['0x540ae480', '0x59682f00', '0x59682f00'],
['0x0', '0x0', '0x0'],
['0x3b9aca00', '0x3b9aca00', '0x3b9aca00'],
['0x59682f00', '0x59682f00', '0x59682f00'],
],
},
oldestBlock: '0xcb1939',
// Note that this array contains 6 items when we requested 5. Per
// <https://github.com/ethereum/go-ethereum/blob/57a3fab8a75eeb9c2f4fab770b73b51b9fe672c5/eth/gasprice/feehistory.go#L191-L192>,
// baseFeePerGas will always include an extra item which is the calculated base fee for the
// next (future) block.
baseFeePerGas: [
'0x16eb46a3bb',
'0x14cd6f0628',
'0x1763700ef2',
'0x1477020d14',
'0x129c9eb46b',
'0x134002f480',
],
gasUsedRatio: [
0.13060046666666666,
0.9972395333333334,
0,
0.13780313333333333,
0.6371707333333333,
],
reward: [
['0x59682f00', '0x59682f00', '0x59682f00'],
['0x540ae480', '0x59682f00', '0x59682f00'],
['0x0', '0x0', '0x0'],
['0x3b9aca00', '0x3b9aca00', '0x3b9aca00'],
['0x59682f00', '0x59682f00', '0x59682f00'],
],
});

const feeHistory = await fetchFeeHistory({
Expand Down Expand Up @@ -124,14 +116,10 @@ describe('fetchRecentFeeHistory', () => {

it('should handle an "empty" response from eth_feeHistory', async () => {
const ethQuery = buildEthQuery({
jsonrpc: '2.0',
id: 1,
result: {
oldestBlock: '0x0',
baseFeePerGas: [],
gasUsedRatio: [],
reward: [],
},
oldestBlock: '0x0',
baseFeePerGas: [],
gasUsedRatio: [],
reward: [],
});

const feeHistory = await fetchFeeHistory({
Expand Down
43 changes: 25 additions & 18 deletions src/gas/fetchFeeHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,33 @@ type BlockFeeHistory = {
};

type EthFeeHistoryResponse = {
jsonrpc: string;
id: number;
result: {
oldestBlock: HexString;
baseFeePerGas: HexString[];
gasUsedRatio: number[];
reward: HexString[][];
};
oldestBlock: HexString;
baseFeePerGas: HexString[];
gasUsedRatio: number[];
reward: HexString[][];
};

/**
* Converts a hexadecimal string to a decimal number.
*
* @param hex - A string encoding a hexadecimal number (with a "0x") prefix.
* @param hex - A string encoding a hexadecimal number (with a "0x" prefix).
* @returns The number in decimal.
*/
function hexToDec(hex: string): number {
return parseInt(new BN(stripHexPrefix(hex), 16).toString(10), 10);
}

/**
* Converts a decimal number to a hexadecimal string.
*
* @param dec - A number in decimal.
* @returns A string encoding that number in hexadecimal (with a "0x" prefix).
*/
function decToHex(dec: number): string {
const hexString = new BN(dec.toString(), 10).toString(16);
return `0x${hexString}`;
}

/**
* Uses eth_feeHistory (an EIP-1559 feature) to obtain information about gas and priority fees from
* a range of blocks that appeared on a network, starting from a particular block and working
Expand Down Expand Up @@ -97,29 +104,29 @@ export async function fetchFeeHistory({
numberOfBlocks: number;
percentiles: number[];
}): Promise<FeeHistory> {
const { result }: EthFeeHistoryResponse = await query(
const response: EthFeeHistoryResponse = await query(
ethQuery,
'eth_feeHistory',
[{ params: [numberOfBlocks, endBlock, percentiles] }],
[decToHex(numberOfBlocks), endBlock, percentiles],
);

const startBlockId = result.oldestBlock;
const startBlockId = response.oldestBlock;
let blocks: BlockFeeHistory[] = [];

if (
result.baseFeePerGas.length > 0 &&
result.gasUsedRatio.length > 0 &&
result.reward.length > 0
response.baseFeePerGas.length > 0 &&
response.gasUsedRatio.length > 0 &&
response.reward.length > 0
) {
blocks = zipEqualSizedTuples({
tuples: [
// Per
// <https://github.com/ethereum/go-ethereum/blob/57a3fab8a75eeb9c2f4fab770b73b51b9fe672c5/eth/gasprice/feehistory.go#L191-L192>,
// baseFeePerGas will always include an extra item which is the calculated base fee for the
// next (future) block. We don't care about this, so chop it off.
result.baseFeePerGas.slice(0, numberOfBlocks),
result.gasUsedRatio,
result.reward,
response.baseFeePerGas.slice(0, numberOfBlocks),
response.gasUsedRatio,
response.reward,
],
numberOfColumnsPerTuple: numberOfBlocks,
}).map(([baseFeePerGasAsHex, gasUsedRatio, priorityFeesAsHex]) => {
Expand Down
100 changes: 44 additions & 56 deletions src/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import 'isomorphic-fetch';
import { BN } from 'ethereumjs-util';
import nock from 'nock';
import HttpProvider from 'ethjs-provider-http';
import EthQuery from 'eth-query';
import * as util from './util';
import {
Transaction,
Expand All @@ -20,50 +18,6 @@ const GAS_PRICE = 'gasPrice';
const FAIL = 'lol';
const PASS = '0x1';

const mockFlags: { [key: string]: any } = {
estimateGas: null,
gasPrice: null,
};
const PROVIDER = new HttpProvider(
'https://ropsten.infura.io/v3/341eacb578dd44a1a049cbc5f6fd4035',
);

jest.mock('eth-query', () =>
jest.fn().mockImplementation(() => {
return {
estimateGas: (_transaction: any, callback: any) => {
callback(undefined, '0x0');
},
gasPrice: (callback: any) => {
if (mockFlags.gasPrice) {
callback(new Error(mockFlags.gasPrice));
return;
}
callback(undefined, '0x0');
},
getBlockByNumber: (
_blocknumber: any,
_fetchTxs: boolean,
callback: any,
) => {
callback(undefined, { gasLimit: '0x0' });
},
getCode: (_to: any, callback: any) => {
callback(undefined, '0x0');
},
getTransactionByHash: (_hash: any, callback: any) => {
callback(undefined, { blockNumber: '0x1' });
},
getTransactionCount: (_from: any, _to: any, callback: any) => {
callback(undefined, '0x0');
},
sendRawTransaction: (_transaction: any, callback: any) => {
callback(undefined, '1337');
},
};
}),
);

describe('util', () => {
beforeEach(() => {
nock.cleanAll();
Expand Down Expand Up @@ -931,18 +885,52 @@ describe('util', () => {
});

describe('query', () => {
it('should query and resolve', async () => {
const ethQuery = new EthQuery(PROVIDER);
const gasPrice = await util.query(ethQuery, 'gasPrice', []);
expect(gasPrice).toStrictEqual('0x0');
describe('when the given method exists directly on the EthQuery', () => {
it('should call the method on the EthQuery and, if it is successful, return a promise that resolves to the result', async () => {
const ethQuery = {
getBlockByHash: (blockId: any, cb: any) => cb(null, { id: blockId }),
};
const result = await util.query(ethQuery, 'getBlockByHash', ['0x1234']);
expect(result).toStrictEqual({ id: '0x1234' });
});

it('should call the method on the EthQuery and, if it errors, return a promise that is rejected with the error', async () => {
const ethQuery = {
getBlockByHash: (_blockId: any, cb: any) =>
cb(new Error('uh oh'), null),
};
await expect(
util.query(ethQuery, 'getBlockByHash', ['0x1234']),
).rejects.toThrow('uh oh');
});
});

it('should query and reject if error', async () => {
const ethQuery = new EthQuery(PROVIDER);
mockFlags.gasPrice = 'Uh oh';
await expect(util.query(ethQuery, 'gasPrice', [])).rejects.toThrow(
'Uh oh',
);
describe('when the given method does not exist directly on the EthQuery', () => {
it('should use sendAsync to call the RPC endpoint and, if it is successful, return a promise that resolves to the result', async () => {
const ethQuery = {
sendAsync: ({ method, params }: any, cb: any) => {
if (method === 'eth_getBlockByHash') {
return cb(null, { id: params[0] });
}
throw new Error(`Unsupported method ${method}`);
},
};
const result = await util.query(ethQuery, 'eth_getBlockByHash', [
'0x1234',
]);
expect(result).toStrictEqual({ id: '0x1234' });
});

it('should use sendAsync to call the RPC endpoint and, if it errors, return a promise that is rejected with the error', async () => {
const ethQuery = {
sendAsync: (_args: any, cb: any) => {
cb(new Error('uh oh'), null);
},
};
await expect(
util.query(ethQuery, 'eth_getBlockByHash', ['0x1234']),
).rejects.toThrow('uh oh');
});
});
});

Expand Down
10 changes: 8 additions & 2 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -687,13 +687,19 @@ export function query(
args: any[] = [],
): Promise<any> {
return new Promise((resolve, reject) => {
ethQuery[method](...args, (error: Error, result: any) => {
const cb = (error: Error, result: any) => {
if (error) {
reject(error);
return;
}
resolve(result);
});
};

if (typeof ethQuery[method] === 'function') {
ethQuery[method](...args, cb);
} else {
ethQuery.sendAsync({ method, params: args }, cb);
}
});
}

Expand Down

0 comments on commit 884a9f9

Please sign in to comment.