Created
June 18, 2021 07:53
-
-
Save allada/c197c18ef7c0f6f9c5b9d6ebce61e2c5 to your computer and use it in GitHub Desktop.
Proof
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
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