Skip to content

Instantly share code, notes, and snippets.

@allada
Created June 18, 2021 07:53
Show Gist options
  • Save allada/c197c18ef7c0f6f9c5b9d6ebce61e2c5 to your computer and use it in GitHub Desktop.
Save allada/c197c18ef7c0f6f9c5b9d6ebce61e2c5 to your computer and use it in GitHub Desktop.
Proof
const ethers = require('ethers');
const WebSocket = require('ws');
const endPoints = [
'ws://127.0.0.1:49011',
'ws://127.0.0.1:49012',
'ws://127.0.0.1:49013',
'ws://127.0.0.1:49014',
'ws://127.0.0.1:49015',
'ws://127.0.0.1:49016',
'ws://127.0.0.1:49017',
'ws://127.0.0.1:49018',
'ws://127.0.0.1:49019',
'ws://127.0.0.1:49020',
'ws://127.0.0.1:49021',
];
let providers = [];
function providerForBlock(blockNumber) {
if (!blockNumber) {
return providers[providers.length - 1];
}
let left = 0;
let right = providers.length - 1;
while (left <= right) {
const mid = Math.floor((right + left) / 2);
if (providers[mid].startBlock > blockNumber) {
right = mid - 1;
continue;
}
if (providers[mid].endBlock < blockNumber) {
left = mid + 1;
continue;
}
return providers[mid];
}
throw new Exception("Block not found in any providers: " + blockNumber);
}
async function getBlockRangeOfProvider(provider) {
function checkHeight(pos) {
return provider.getBalance('0x0000000000000000000000000000000000001004', pos);
}
const lastBlock = await provider.getBlockNumber();
let left = 0;
let right = lastBlock;
while (left <= right) {
const mid = Math.floor((right + left) / 2);
try {
await checkHeight(mid);
right = mid - 1;
} catch (e) {
left = mid + 1;
}
}
return [left, lastBlock];
}
async function main() {
providers = await Promise.all(endPoints.map(async (endPoint) => {
const provider = new ethers.providers.WebSocketProvider(endPoint);
const [startBlock, endBlock] = await getBlockRangeOfProvider(provider);
provider.startBlock = startBlock;
provider.endBlock = endBlock;
return provider;
}));
providers.sort((a, b) => a.startBlock - b.startBlock);
const wss = new WebSocket.Server({ port: 26656 });
console.log('Ready');
wss.on('connection', function connection(ws) {
ws.isAlive = true;
ws.on('pong', () => ws.isAlive = true);
async function incoming(message) {
const jsonData = JSON.parse(message);
// console.log('Request', jsonData);
let blockTag = null; // Latest.
switch (jsonData.method) {
case 'eth_chainId':
ws.send(JSON.stringify({
id: jsonData.id,
jsonrpc: "2.0",
result: "0x38" // 56
}));
return;
case 'eth_blockNumber':
case 'eth_getBlockTransactionCountByHash':
case 'eth_getBlockTransactionCountByNumber':
case 'eth_getUncleCountByBlockHash':
case 'eth_getUncleCountByBlockNumber':
case 'eth_getBlockByHash':
case 'eth_getBlockByNumber':
case 'eth_getTransactionByHash':
case 'eth_getTransactionByBlockHashAndIndex':
case 'eth_getTransactionByBlockNumberAndIndex':
case 'eth_getTransactionReceipt':
case 'eth_getUncleByBlockHashAndIndex':
case 'eth_getUncleByBlockNumberAndIndex':
case 'eth_getLogs':
// Latest block.
break;
case 'eth_getBalance':
case 'eth_getCode':
case 'eth_getTransactionCount':
case 'eth_getStorageAt':
case 'eth_call':
case 'eth_getTransactionCount':
case 'eth_estimateGas':
blockTag = jsonData.params[jsonData.params.length - 1];
if (blockTag === 'latest') {
blockTag = null;
break;
}
if (!blockTag.startsWith('0x')) {
throw new Exception('Expected blockTag to start with 0x');
}
blockTag = parseInt(blockTag, 16);
break;
}
const provider = providerForBlock(blockTag);
const response = await provider.send(
jsonData.method,
jsonData.params
);
const fullResponse = {
id: jsonData.id,
jsonrpc: "2.0",
result: response,
};
ws.send(JSON.stringify(fullResponse));
// console.log("Tag:", blockTag, "Response", fullResponse)
}
ws.on('message', async (m) => {
try {
await incoming(m);
} catch(e) {
try {
await incoming(m);
} catch (e) {
console.log(e);
}
}
});
});
const pingInterval = setInterval(() => {
wss.clients.forEach((ws) => {
if (ws.isAlive === false) {
return ws.terminate();
}
ws.isAlive = false;
ws.ping(function () {});
});
}, 30000);
wss.on('close', () => clearInterval(pingInterval));
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment