From b61128bd7b3f01c47db7e536e419567687167946 Mon Sep 17 00:00:00 2001 From: zzzckck <152148891+zzzckck@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:48:33 +0800 Subject: [PATCH] utils: add GetTopAddr to analyse large traffic (#2629) --- cmd/jsutils/getchainstatus.js | 164 +++++++++++++++++++++++++++++ cmd/jsutils/gettxcount.js | 41 -------- cmd/jsutils/getvalidatorversion.js | 38 ------- 3 files changed, 164 insertions(+), 79 deletions(-) create mode 100644 cmd/jsutils/getchainstatus.js delete mode 100644 cmd/jsutils/gettxcount.js delete mode 100644 cmd/jsutils/getvalidatorversion.js diff --git a/cmd/jsutils/getchainstatus.js b/cmd/jsutils/getchainstatus.js new file mode 100644 index 000000000..db5e25cf4 --- /dev/null +++ b/cmd/jsutils/getchainstatus.js @@ -0,0 +1,164 @@ +import { ethers } from "ethers"; +import program from "commander"; + +// Global Options: +program.option("--rpc ", "Rpc"); +// GetTxCount Options: +program.option("--startNum ", "start num") +program.option("--endNum ", "end num") +program.option("--miner ", "miner", "") +// GetVersion Options: +program.option("--num ", "validator num", 21) +// GetTopAddr Options: +program.option("--topNum ", "top num of address to be displayed", 20) + +program.parse(process.argv); + +const provider = new ethers.JsonRpcProvider(program.rpc) + +function printUsage() { + console.log("Usage:"); + console.log(" node getchainstatus.js --help"); + console.log(" node getchainstatus.js [subcommand] [options]"); + console.log("\nSubcommands:"); + console.log(" GetTxCount: find the block with max tx size of a range"); + console.log(" GetVersion: dump validators' binary version, based on Header.Extra"); + console.log(" GetTopAddr: get hottest $topNum target address within a block range"); + console.log("\nOptions:"); + console.log(" --rpc specify the url of RPC endpoint"); + console.log(" --startNum the start block number, for command GetTxCount"); + console.log(" --endNum the end block number, for command GetTxCount"); + console.log(" --miner the miner address, for command GetTxCount"); + console.log(" --num the number of blocks to be checked, for command GetVersion"); + console.log(" --topNum the topNum of blocks to be checked, for command GetVersion"); + console.log("\nExample:"); + // mainnet https://bsc-mainnet.nodereal.io/v1/454e504917db4f82b756bd0cf6317dce + console.log(" node getchainstatus.js GetTxCount --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000005") + console.log(" node getchainstatus.js GetVersion --rpc https://bsc-testnet-dataseed.bnbchain.org --num 21") + console.log(" node getchainstatus.js GetTopAddr --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010 --topNum 10") +} + +// 1.cmd: "GetTxCount", usage: +// node getchainstatus.js GetTxCount --rpc https://bsc-testnet-dataseed.bnbchain.org \ +// --startNum 40000001 --endNum 40000005 \ +// --miner(optional): specified: find the max txCounter from the specified validator, +// not specified: find the max txCounter from all validators +async function getTxCount() { + let txCount = 0; + let num = 0; + console.log("Find the max txs count between", program.startNum, "and", program.endNum); + for (let i = program.startNum; i < program.endNum; i++) { + if (program.miner !== "") { + let blockData = await provider.getBlock(Number(i)) + if (program.miner !== blockData.miner) { + continue + } + } + let x = await provider.send("eth_getBlockTransactionCountByNumber", [ + ethers.toQuantity(i)]); + let a = ethers.toNumber(x) + if (a > txCount) { + num = i; + txCount = a; + } + } + console.log("BlockNum = ", num, "TxCount =", txCount); +} + +// 2.cmd: "GetVersion", usage: +// node getchainstatus.js GetVersion \ +// --rpc https://bsc-testnet-dataseed.bnbchain.org \ +// --num(optional): defualt 21, the number of blocks that will be checked +async function getBinaryVersion() { + const blockNum = await provider.getBlockNumber(); + console.log(blockNum); + for (let i = 0; i < program.num; i++) { + let blockData = await provider.getBlock(blockNum - i); + // 1.get Geth client version + let major = ethers.toNumber(ethers.dataSlice(blockData.extraData, 2, 3)) + let minor = ethers.toNumber(ethers.dataSlice(blockData.extraData, 3, 4)) + let patch = ethers.toNumber(ethers.dataSlice(blockData.extraData, 4, 5)) + + // 2.get minimum txGasPrice based on the last non-zero-gasprice transaction + let lastGasPrice = 0 + for (let txIndex = blockData.transactions.length - 1; txIndex >= 0; txIndex--) { + let txHash = blockData.transactions[txIndex] + let txData = await provider.getTransaction(txHash); + if (txData.gasPrice == 0) { + continue + } + lastGasPrice = txData.gasPrice + break + } + console.log(blockData.miner, "version =", major + "." + minor + "." + patch, " MinGasPrice = " + lastGasPrice) + } +}; + +// 3.cmd: "GetTopAddr", usage: +// node getchainstatus.js GetTopAddr \ +// --rpc https://bsc-testnet-dataseed.bnbchain.org \ +// --startNum 40000001 --endNum 40000005 \ +// --topNum(optional): the top num of address to be displayed, default 20 +function getTopKElements(map, k) { + let entries = Array.from(map.entries()); + entries.sort((a, b) => b[1] - a[1]); + return entries.slice(0, k); +} + +async function getTopAddr() { + let countMap = new Map(); + let totalTxs = 0 + console.log("Find the top target address, between", program.startNum, "and", program.endNum); + for (let i = program.startNum; i <= program.endNum; i++) { + let blockData = await provider.getBlock(Number(i), true) + totalTxs += blockData.transactions.length + for (let txIndex = blockData.transactions.length - 1; txIndex >= 0; txIndex--) { + let txData = await blockData.getTransaction(txIndex) + if (txData.to == null) { + console.log("Contract creation,txHash:", txData.hash) + continue + } + let toAddr = txData.to; + if (countMap.has(toAddr)) { + countMap.set(toAddr, countMap.get(toAddr) + 1); + } else { + countMap.set(toAddr, 1); + } + } + console.log("progress:", (program.endNum-i), "blocks left", "totalTxs", totalTxs) + } + let tops = getTopKElements(countMap, program.topNum) + tops.forEach((value, key) => { + // value: [ '0x40661F989826CC641Ce1601526Bb16a4221412c8', 71 ] + console.log(key+":", value[0], " ", value[1], " ", ((value[1]*100)/totalTxs).toFixed(2)+"%"); + }); +}; + +const main = async () => { + if (process.argv.length <= 2) { + console.error('invalid process.argv.length', process.argv.length); + printUsage() + return + } + const cmd = process.argv[2] + if (cmd === "--help") { + printUsage() + return + } + if (cmd === "GetTxCount") { + await getTxCount() + } else if (cmd === "GetVersion") { + await getBinaryVersion() + } else if (cmd === "GetTopAddr") { + await getTopAddr() + } else { + console.log("unsupported cmd", cmd); + printUsage() + } +} + +main().then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); \ No newline at end of file diff --git a/cmd/jsutils/gettxcount.js b/cmd/jsutils/gettxcount.js deleted file mode 100644 index 8bc7f2bdd..000000000 --- a/cmd/jsutils/gettxcount.js +++ /dev/null @@ -1,41 +0,0 @@ -import { ethers } from "ethers"; -import program from "commander"; - -program.option("--rpc ", "Rpc"); -program.option("--startNum ", "start num") -program.option("--endNum ", "end num") -// --miner: -// specified: find the max txCounter from the specified validator -// not specified: find the max txCounter from all validators -program.option("--miner ", "miner", "") -program.parse(process.argv); - -const provider = new ethers.JsonRpcProvider(program.rpc) - -const main = async () => { - let txCount = 0; - let num = 0; - console.log("Find the max txs count between", program.startNum, "and", program.endNum); - for (let i = program.startNum; i < program.endNum; i++) { - if (program.miner !== "") { - let blockData = await provider.getBlock(Number(i)) - if (program.miner !== blockData.miner) { - continue - } - } - let x = await provider.send("eth_getBlockTransactionCountByNumber", [ - ethers.toQuantity(i)]); - let a = ethers.toNumber(x) - if (a > txCount) { - num = i; - txCount = a; - } - } - console.log("BlockNum = ", num, "TxCount =", txCount); -}; - -main().then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); \ No newline at end of file diff --git a/cmd/jsutils/getvalidatorversion.js b/cmd/jsutils/getvalidatorversion.js deleted file mode 100644 index 495b913f4..000000000 --- a/cmd/jsutils/getvalidatorversion.js +++ /dev/null @@ -1,38 +0,0 @@ -import { ethers } from "ethers"; -import program from "commander"; - -program.option("--Rpc ", "Rpc"); -program.option("--Num ", "validator num", 21) -program.parse(process.argv); - -const provider = new ethers.JsonRpcProvider(program.Rpc); - -const main = async () => { - const blockNum = await provider.getBlockNumber(); - console.log(blockNum); - for (let i = 0; i < program.Num; i++) { - let blockData = await provider.getBlock(blockNum - i); - // 1.get Geth client version - let major = ethers.toNumber(ethers.dataSlice(blockData.extraData, 2, 3)) - let minor = ethers.toNumber(ethers.dataSlice(blockData.extraData, 3, 4)) - let patch = ethers.toNumber(ethers.dataSlice(blockData.extraData, 4, 5)) - - // 2.get minimum txGasPrice based on the last non-zero-gasprice transaction - let lastGasPrice = 0 - for (let txIndex = blockData.transactions.length - 1; txIndex >= 0; txIndex--) { - let txHash = blockData.transactions[txIndex] - let txData = await provider.getTransaction(txHash); - if (txData.gasPrice == 0) { - continue - } - lastGasPrice = txData.gasPrice - break - } - console.log(blockData.miner, "version =", major + "." + minor + "." + patch, " MinGasPrice = " + lastGasPrice) - } -}; -main().then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); \ No newline at end of file