ethers.js/packages/providers/src.ts/tests/test-blockchain-data.ts

289 lines
11 KiB
TypeScript
Raw Permalink Normal View History

2022-04-11 17:09:17 -04:00
import assert from "assert";
import { retryIt, stats } from "./utils.js";
import { providerNames, getProvider } from "./create-provider.js";
import { BlockchainData } from "./blockchain-data.js";
import type {
TestCaseBlockchain,
2022-04-11 17:09:17 -04:00
TestCaseBlockchainBlock,
TestCaseBlockchainLog,
TestCaseBlockchainTransaction,
TestCaseBlockchainReceipt,
} from "./blockchain-data.js";
import type { Provider } from "../index.js";
2022-04-11 17:09:17 -04:00
function sumhash(hash: string): string {
return `${ hash.substring(0, 6) }..${ hash.substring(hash.length - 4) }`;
}
function checkBlock(actual: any, test: TestCaseBlockchainBlock): void {
assert.equal(actual.hash, test.hash, "hash");
assert.equal(actual.parentHash, test.parentHash, "parentHash");
assert.equal(actual.number, test.number, "number");
assert.equal(actual.timestamp, test.timestamp, "timestamp");
assert.equal(actual.nonce, test.nonce, "nonce");
assert.equal(actual.difficulty, test.difficulty, "difficulty");
assert.equal(actual.gasLimit, test.gasLimit, "gasLimit");
assert.equal(actual.gasUsed, test.gasUsed, "gasUsed");
assert.equal(actual.miner, test.miner, "miner");
assert.equal(actual.extraData, test.extraData, "extraData");
if (test.baseFeePerGas != null) {
assert.equal(actual.baseFeePerGas, test.baseFeePerGas, "baseFeePerGas");
}
assert.ok(!!actual.transactions, "hasTxs");
assert.equal(actual.transactions.length, test.transactions.length, "txs.length");
for (let i = 0; i < actual.transactions.length; i++) {
const atx = actual.transactions[i];
const ttx = test.transactions[i];
assert.equal(atx, ttx, `txs[${ i }]`);
}
}
function checkTransaction(actual: any, test: TestCaseBlockchainTransaction): void {
assert.equal(actual.hash, test.hash, "hash");
assert.equal(actual.blockHash, test.blockHash, "blockHash");
assert.equal(actual.blockNumber, test.blockNumber, "blockNumber");
assert.equal(actual.type, test.type, "type");
assert.equal(actual.index, test.index, "index");
assert.equal(actual.from, test.from, "from");
assert.equal(actual.to, test.to, "to");
assert.equal(actual.gasLimit, test.gasLimit, "gasLimit");
assert.equal(actual.gasPrice, test.gasPrice, "gasPrice");
if (test.type === 2) {
assert.equal(actual.maxFeePerGas, test.maxFeePerGas, "maxFeePerGas");
assert.equal(actual.maxPriorityFeePerGas, test.maxPriorityFeePerGas, "maxPriorityFeePerGas");
} else {
assert.equal(actual.maxFeePerGas, null, "maxFeePerGas:null");
assert.equal(actual.maxPriorityFeePerGas, null, "maxPriorityFeePerGas:null");
}
assert.equal(actual.value, test.value, "value");
assert.equal(actual.nonce, test.nonce, "nonce");
assert.equal(actual.data, test.data, "data");
assert.equal(actual.creates, test.creates, "creates");
assert.equal(actual.signature.r, test.signature.r, "signature.r");
assert.equal(actual.signature.s, test.signature.s, "signature.s");
if (test.type === 1 || test.type === 2) {
// EIP-2930; v is the yParity
assert.equal(actual.signature.yParity, test.signature.v, "signature.v (EIP-2930)");
} else if (test.signature.v > 28) {
// EIP-155; v is a the encoded chainId
assert.equal(actual.signature.networkV, test.signature.v, "signature.networkV (EIP-155)");
assert.equal(actual.signature.yParity, 1 - (test.signature.v % 2), "signature.yParity (EIP-155)");
} else {
// Pre-EIP-155 legacy; canonical v
assert.equal(actual.signature.v, test.signature.v, "signature.v (Legacy)");
assert.equal(actual.signature.networkV, null, "signature.netwrokV:!null (Legacy)");
}
2022-04-11 17:09:17 -04:00
}
function checkLog(actual: any, test: TestCaseBlockchainLog): void {
assert.equal(actual.address, test.address, "address");
assert.equal(actual.blockHash, test.blockHash, "blockHash");
assert.equal(actual.blockNumber, test.blockNumber, "blockNumber");
assert.equal(actual.data, test.data, "data");
assert.equal(actual.index, test.index, "logIndex");
assert.equal(actual.topics.join(","), test.topics.join(","), "topics");
assert.equal(actual.transactionHash, test.transactionHash, "transactionHash");
assert.equal(actual.transactionIndex, test.transactionIndex, "transactionIndex");
}
function checkTransactionReceipt(actual: any, test: TestCaseBlockchainReceipt): void {
assert.equal(actual.hash, test.hash, "hash");
assert.equal(actual.index, test.index, "index");
assert.equal(actual.to, test.to, "to");
assert.equal(actual.from, test.from, "from");
assert.equal(actual.contractAddress, test.contractAddress, "contractAddress");
assert.equal(actual.blockHash, test.blockHash, "blockHash");
assert.equal(actual.blockNumber, test.blockNumber, "blockNumber");
assert.equal(actual.logsBloom, test.logsBloom, "logsBloom");
// @TODO: Logs
assert.ok(actual.logs != null, "logs != null");
assert.equal(actual.logs.length, test.logs.length, "logs.length");
for (let i = 0; i < actual.logs.length; i++) {
checkLog(actual.logs[i], test.logs[i]);
}
assert.equal(actual.gasUsed, test.gasUsed, "gasUsed");
assert.equal(actual.cumulativeGasUsed, test.cumulativeGasUsed, "cumulativeGasUsed");
assert.equal(actual.gasPrice, test.gasPrice, "gasPrice");
// Some nodes add status to pre-byzantium nodes, so don't include it at all
if (actual.status != null) {
assert.equal(actual.status, test.status, `status: ${ actual.status } != ${ test.status }`);
}
// Some nodes dropped root, event on pre-byzantium blocks
if (actual.root != null) {
assert.equal(actual.root, test.root, `root ${ actual.root } != ${ test.root }`);
}
}
function stall(duration: number) {
return new Promise((resolve) => {
setTimeout(resolve, duration);
});
}
type TestSet = {
providerName: string;
provider: Provider;
network: string;
tests: TestCaseBlockchain;
};
2022-04-11 17:09:17 -04:00
describe("Test Provider Methods", function() {
before(() => {
2022-04-11 17:09:17 -04:00
stats.start("Test Provider Methods");
});
// Wait before each testcase so the backends don't throttle
// use as much
beforeEach(async function() {
await stall(1000);
});
after(() => {
stats.end(this);
2022-04-11 17:09:17 -04:00
});
// Etherscan does not support this
const skipGetBlockByBlockHash = [ "EtherscanProvider" ];
const testSets: Array<TestSet> = [ ];
2022-04-11 17:09:17 -04:00
for (const providerName of providerNames) {
for (const network in BlockchainData) {
const provider = getProvider(providerName, network);
if (provider == null || providerName === "CloudflareProvider") {
//log(`Skipping ${providerName}:${ network }...`);
2022-04-11 17:09:17 -04:00
continue;
}
const tests = BlockchainData[network];
testSets.push({ providerName, provider, network, tests });
}
}
2022-04-11 17:09:17 -04:00
for (const { providerName, network, provider, tests } of testSets) {
for (const test of tests.addresses) {
if (test.balance == null) { continue; }
2022-04-11 17:09:17 -04:00
retryIt(`fetches address balance: ${ providerName }.${ network }.${ sumhash(test.address) }`, async function() {
assert.equal(await provider.getBalanceOf(test.address), test.balance, "balance");
});
}
}
2022-04-11 17:09:17 -04:00
for (const { providerName, network, provider, tests } of testSets) {
for (const test of tests.addresses) {
if (test.code == null) { continue; }
2022-04-11 17:09:17 -04:00
retryIt(`fetches address code: ${ providerName }.${ network }.${ sumhash(test.address) }`, async function() {
assert.equal(await provider.getCode(test.address), test.code, "code");
});
}
}
2022-04-11 17:09:17 -04:00
for (const { providerName, network, provider, tests } of testSets) {
for (const test of tests.addresses) {
if (test.name == null) { continue; }
2022-04-11 17:09:17 -04:00
retryIt(`fetches address reverse record: ${ providerName }.${ network }.${ sumhash(test.address) }`, async function() {
this.skip();
assert.equal(await provider.lookupAddress(test.address), test.name, "name");
});
}
}
for (const { providerName, network, provider, tests } of testSets) {
for (const test of tests.addresses) {
if (test.storage == null) { continue; }
retryIt(`fetches address storage: ${ providerName }.${ network }.${ sumhash(test.address) }`, async function() {
for (const slot in test.storage) {
const value = test.storage[slot];
assert.equal(await provider.getStorageAt(test.address, slot), value, `storage:${ slot }`);
2022-04-11 17:09:17 -04:00
}
});
}
}
2022-04-11 17:09:17 -04:00
for (const { providerName, network, provider, tests } of testSets) {
for (const test of tests.blocks) {
retryIt(`fetches block by number: ${ providerName }.${ network }.${ test.number }`, async function() {
checkBlock(await provider.getBlock(test.number), test);
});
}
}
for (const { providerName, network, provider, tests } of testSets) {
for (const test of tests.blocks) {
if (skipGetBlockByBlockHash.indexOf(providerName) === -1) {
retryIt(`fetches block by hash: ${ providerName }.${ network }.${ sumhash(test.hash) }`, async function() {
checkBlock(await provider.getBlock(test.hash), test);
2022-04-11 17:09:17 -04:00
});
} else {
retryIt(`throws unsupported operation for fetching block by hash: ${ providerName }.${ network }.${ sumhash(test.hash) }`, async function() {
await assert.rejects(
provider.getBlock(test.hash),
(error) => {
return (error.code === "UNSUPPORTED_OPERATION" &&
error.operation === "getBlock(blockHash)");
}
);
2022-04-11 17:09:17 -04:00
});
}
}
}
for (const { providerName, network, provider, tests } of testSets) {
for (const test of tests.transactions) {
retryIt(`fetches transaction: ${ providerName }.${ network }.${ sumhash(test.hash) }`, async function() {
checkTransaction(await provider.getTransaction(test.hash), test);
});
}
}
for (const { providerName, network, provider, tests } of testSets) {
for (const test of tests.receipts) {
retryIt(`fetches transaction receipt: ${ providerName }.${ network }.${ sumhash(test.hash) }`, async function() {
checkTransactionReceipt(await provider.getTransactionReceipt(test.hash), test);
});
}
}
2022-04-11 17:09:17 -04:00
for (const providerName of providerNames) {
2022-04-11 17:09:17 -04:00
it(`fetches a pending block: ${ providerName }`, async function() {
this.timeout(15000);
const provider = getProvider(providerName, "homestead");
assert.ok(provider, "provider");
const block = await provider.getBlock("pending");
assert.ok(!!block, "block");
assert.equal(block.hash, null, "hash");
assert.ok(typeof(block.number) === "number", "number");
assert.ok(typeof(block.timestamp) === "number", "timestamp");
});
}
});