diff --git a/cmd/jsutils/.prettierrc b/cmd/jsutils/.prettierrc new file mode 100644 index 0000000000..b04668ccc6 --- /dev/null +++ b/cmd/jsutils/.prettierrc @@ -0,0 +1,10 @@ +{ + "semi": true, + "tabWidth": 4, + "printWidth": 160, + "singleQuote": false, + "trailingComma": "es5", + "bracketSpacing": true, + "arrowParens": "avoid", + "endOfLine": "lf" +} \ No newline at end of file diff --git a/cmd/jsutils/getchainstatus.js b/cmd/jsutils/getchainstatus.js index 672041a3f8..88de6e5a07 100644 --- a/cmd/jsutils/getchainstatus.js +++ b/cmd/jsutils/getchainstatus.js @@ -2,14 +2,14 @@ import { ethers } from "ethers"; import program from "commander"; program.option("--rpc ", "Rpc"); -program.option("--startNum ", "start num") -program.option("--endNum ", "end num") -program.option("--miner ", "miner", "") -program.option("--num ", "validator num", 21) -program.option("--turnLength ", "the consecutive block length", 4) -program.option("--topNum ", "top num of address to be displayed", 20) -program.option("--blockNum ", "block num", 0) -program.option("-h, --help", "") +program.option("--startNum ", "start num"); +program.option("--endNum ", "end num"); +program.option("--miner ", "miner", ""); +program.option("--num ", "validator num", 21); +program.option("--turnLength ", "the consecutive block length", 4); +program.option("--topNum ", "top num of address to be displayed", 20); +program.option("--blockNum ", "block num", 0); +program.option("-h, --help", ""); function printUsage() { console.log("Usage:"); @@ -35,26 +35,26 @@ function printUsage() { console.log(" --blockNum the block number to be checked"); console.log("\nExample:"); // mainnet https://bsc-mainnet.nodereal.io/v1/454e504917db4f82b756bd0cf6317dce - console.log(" node getchainstatus.js GetMaxTxCountInBlockRange --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000005") - console.log(" node getchainstatus.js GetBinaryVersion --rpc https://bsc-testnet-dataseed.bnbchain.org --num 21 --turnLength 4") - console.log(" node getchainstatus.js GetTopAddr --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010 --topNum 10") - console.log(" node getchainstatus.js GetSlashCount --rpc https://bsc-testnet-dataseed.bnbchain.org --blockNum 40000001") // default: latest block - console.log(" node getchainstatus.js GetPerformanceData --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010") - console.log(" node getchainstatus.js GetBlobTxs --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010") - console.log(" node getchainstatus.js GetFaucetStatus --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010") - console.log(" node getchainstatus.js GetKeyParameters --rpc https://bsc-testnet-dataseed.bnbchain.org") // default: latest block - console.log(" node getchainstatus.js GetEip7623 --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010") - console.log(" node getchainstatus.js GetMevStatus --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010") + console.log(" node getchainstatus.js GetMaxTxCountInBlockRange --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000005"); + console.log(" node getchainstatus.js GetBinaryVersion --rpc https://bsc-testnet-dataseed.bnbchain.org --num 21 --turnLength 4"); + console.log(" node getchainstatus.js GetTopAddr --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010 --topNum 10"); + console.log(" node getchainstatus.js GetSlashCount --rpc https://bsc-testnet-dataseed.bnbchain.org --blockNum 40000001"); // default: latest block + console.log(" node getchainstatus.js GetPerformanceData --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010"); + console.log(" node getchainstatus.js GetBlobTxs --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010"); + console.log(" node getchainstatus.js GetFaucetStatus --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010"); + console.log(" node getchainstatus.js GetKeyParameters --rpc https://bsc-testnet-dataseed.bnbchain.org"); // default: latest block + console.log(" node getchainstatus.js GetEip7623 --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010"); + console.log(" node getchainstatus.js GetMevStatus --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010"); } program.usage = printUsage; program.parse(process.argv); -const provider = new ethers.JsonRpcProvider(program.rpc) +const provider = new ethers.JsonRpcProvider(program.rpc); -const addrValidatorSet = '0x0000000000000000000000000000000000001000'; -const addrSlash = '0x0000000000000000000000000000000000001001'; -const addrStakeHub = '0x0000000000000000000000000000000000002002'; +const addrValidatorSet = "0x0000000000000000000000000000000000001000"; +const addrSlash = "0x0000000000000000000000000000000000001001"; +const addrStakeHub = "0x0000000000000000000000000000000000002002"; const validatorSetAbi = [ "function validatorExtraSet(uint256 offset) external view returns (uint256, bool, bytes)", @@ -62,34 +62,32 @@ const validatorSetAbi = [ "function numOfCabinets() external view returns (uint256)", "function maxNumOfCandidates() external view returns (uint256)", "function maxNumOfWorkingCandidates() external view returns (uint256)", - "function maxNumOfMaintaining() external view returns (uint256)", // default 3 + "function maxNumOfMaintaining() external view returns (uint256)", // default 3 "function turnLength() external view returns (uint256)", "function systemRewardAntiMEVRatio() external view returns (uint256)", - "function maintainSlashScale() external view returns (uint256)", // default 2, valid: 1->9 - "function burnRatio() external view returns (uint256)", // default: 10% - "function systemRewardBaseRatio() external view returns (uint256)" // default: 1/16 -] -const slashAbi = [ - "function getSlashIndicator(address validatorAddr) external view returns (uint256, uint256)" -] + "function maintainSlashScale() external view returns (uint256)", // default 2, valid: 1->9 + "function burnRatio() external view returns (uint256)", // default: 10% + "function systemRewardBaseRatio() external view returns (uint256)", // default: 1/16 +]; +const slashAbi = ["function getSlashIndicator(address validatorAddr) external view returns (uint256, uint256)"]; // https://github.com/bnb-chain/bsc-genesis-contract/blob/master/contracts/StakeHub.sol const stakeHubAbi = [ "function getValidatorElectionInfo(uint256 offset, uint256 limit) external view returns (address[], uint256[], bytes[], uint256)", "function getValidatorDescription(address validatorAddr) external view returns (tuple(string, string, string, string))", "function consensusToOperator(address consensusAddr) public view returns (address)", - "function minSelfDelegationBNB() public view returns (uint256)", // default 2000, valid: 1000 -> 100,000 - "function maxElectedValidators() public view returns (uint256)", // valid: 1 -> 500 - "function unbondPeriod() public view returns (uint256)", // default 7days, valid: 3days ->30days - "function downtimeSlashAmount() public view returns (uint256)", // default 10BNB, valid: 5 -> felonySlashAmount - "function felonySlashAmount() public view returns (uint256)", // default 200BNB, valid: > max(100, downtimeSlashAmount) - "function downtimeJailTime() public view returns (uint256)", // default 2days, - "function felonyJailTime() public view returns (uint256)" // default 30days, -] + "function minSelfDelegationBNB() public view returns (uint256)", // default 2000, valid: 1000 -> 100,000 + "function maxElectedValidators() public view returns (uint256)", // valid: 1 -> 500 + "function unbondPeriod() public view returns (uint256)", // default 7days, valid: 3days ->30days + "function downtimeSlashAmount() public view returns (uint256)", // default 10BNB, valid: 5 -> felonySlashAmount + "function felonySlashAmount() public view returns (uint256)", // default 200BNB, valid: > max(100, downtimeSlashAmount) + "function downtimeJailTime() public view returns (uint256)", // default 2days, + "function felonyJailTime() public view returns (uint256)", // default 30days, +]; const validatorSet = new ethers.Contract(addrValidatorSet, validatorSetAbi, provider); -const slashIndicator = new ethers.Contract(addrSlash, slashAbi, provider) -const stakeHub = new ethers.Contract(addrStakeHub, stakeHubAbi, provider) +const slashIndicator = new ethers.Contract(addrSlash, slashAbi, provider); +const stakeHub = new ethers.Contract(addrStakeHub, stakeHubAbi, provider); const validatorMap = new Map([ // BSC mainnet @@ -103,65 +101,65 @@ const validatorMap = new Map([ ["0xF8de5e61322302b2c6e0a525cC842F10332811bf", "Namelix"], ["0xCcB42A9b8d6C46468900527Bc741938E78AB4577", "Turing"], ["0x9f1b7FAE54BE07F4FEE34Eb1aaCb39A1F7B6FC92", "TWStaking"], - ["0x7E1FdF03Eb3aC35BF0256694D7fBe6B6d7b3E0c8","LegendIII"], - ["0x7b501c7944185130DD4aD73293e8Aa84eFfDcee7","MathW"], - ["0x58567F7A51a58708C8B40ec592A38bA64C0697De","Legend"], - ["0x460A252B4fEEFA821d3351731220627D7B7d1F3d","Defibit"], - ["0x8A239732871AdC8829EA2f47e94087C5FBad47b6","The48Club"], - ["0xD3b0d838cCCEAe7ebF1781D11D1bB741DB7Fe1A7","BNBEve"], - ["0xF8B99643fAfC79d9404DE68E48C4D49a3936f787","Avengers"], - ["0x4e5acf9684652BEa56F2f01b7101a225Ee33d23f","HashKey"], - ["0x9bb56C2B4DBE5a06d79911C9899B6f817696ACFc","Feynman"], - ["0xbdcc079BBb23C1D9a6F36AA31309676C258aBAC7","Fuji"], - ["0x38944092685a336CB6B9ea58836436709a2adC89","Shannon"], - ["0xfC1004C0f296Ec3Df4F6762E9EabfcF20EB304a2","Aoraki"], - ["0xa0884bb00E5F23fE2427f0E5eC9E51F812848563","Coda"], - ["0xe7776De78740f28a96412eE5cbbB8f90896b11A5","Ankr"], - ["0xA2D969E82524001Cb6a2357dBF5922B04aD2FCD8","Pexmons"], - ["0x5cf810AB8C718ac065b45f892A5BAdAB2B2946B9","Zen"], - ["0x4d15D9BCd0c2f33E7510c0de8b42697CA558234a","LegendVII"], - ["0x1579ca96EBd49A0B173f86C372436ab1AD393380","LegendV"], - ["0xd1F72d433f362922f6565FC77c25e095B29141c8","LegendVI"], - ["0xf9814D93b4d904AaA855cBD4266D6Eb0Ec1Aa478","Legend8"], - ["0x025a4e09Ea947b8d695f53ddFDD48ddB8F9B06b7","Ciscox"], - ["0xE9436F6F30b4B01b57F2780B2898f3820EbD7B98","LegendIV"], - ["0xC2d534F079444E6E7Ff9DabB3FD8a26c607932c8","Axion"], - ["0x9F7110Ba7EdFda83Fc71BeA6BA3c0591117b440D","LegendIX"], - ["0xB997Bf1E3b96919fBA592c1F61CE507E165Ec030","Seoraksan"], - ["0x286C1b674d48cFF67b4096b6c1dc22e769581E91","Sigm8"], - ["0x73A26778ef9509a6E94b55310eE7233795a9EB25","Coinlix"], - ["0x18c44f4FBEde9826C7f257d500A65a3D5A8edebc","Nozti"], - ["0xA100FCd08cE722Dc68Ddc3b54237070Cb186f118","Tiollo"], - ["0x0F28847cfdbf7508B13Ebb9cEb94B2f1B32E9503","Raptas"], - ["0xfD85346c8C991baC16b9c9157e6bdfDACE1cD7d7","Glorin"], - ["0x978F05CED39A4EaFa6E8FD045Fe2dd6Da836c7DF","NovaX"], - ["0xd849d1dF66bFF1c2739B4399425755C2E0fAbbAb","Nexa"], - ["0xA015d9e9206859c13201BB3D6B324d6634276534","Star"], - ["0x5ADde0151BfAB27f329e5112c1AeDeed7f0D3692","Veri"], + ["0x7E1FdF03Eb3aC35BF0256694D7fBe6B6d7b3E0c8", "LegendIII"], + ["0x7b501c7944185130DD4aD73293e8Aa84eFfDcee7", "MathW"], + ["0x58567F7A51a58708C8B40ec592A38bA64C0697De", "Legend"], + ["0x460A252B4fEEFA821d3351731220627D7B7d1F3d", "Defibit"], + ["0x8A239732871AdC8829EA2f47e94087C5FBad47b6", "The48Club"], + ["0xD3b0d838cCCEAe7ebF1781D11D1bB741DB7Fe1A7", "BNBEve"], + ["0xF8B99643fAfC79d9404DE68E48C4D49a3936f787", "Avengers"], + ["0x4e5acf9684652BEa56F2f01b7101a225Ee33d23f", "HashKey"], + ["0x9bb56C2B4DBE5a06d79911C9899B6f817696ACFc", "Feynman"], + ["0xbdcc079BBb23C1D9a6F36AA31309676C258aBAC7", "Fuji"], + ["0x38944092685a336CB6B9ea58836436709a2adC89", "Shannon"], + ["0xfC1004C0f296Ec3Df4F6762E9EabfcF20EB304a2", "Aoraki"], + ["0xa0884bb00E5F23fE2427f0E5eC9E51F812848563", "Coda"], + ["0xe7776De78740f28a96412eE5cbbB8f90896b11A5", "Ankr"], + ["0xA2D969E82524001Cb6a2357dBF5922B04aD2FCD8", "Pexmons"], + ["0x5cf810AB8C718ac065b45f892A5BAdAB2B2946B9", "Zen"], + ["0x4d15D9BCd0c2f33E7510c0de8b42697CA558234a", "LegendVII"], + ["0x1579ca96EBd49A0B173f86C372436ab1AD393380", "LegendV"], + ["0xd1F72d433f362922f6565FC77c25e095B29141c8", "LegendVI"], + ["0xf9814D93b4d904AaA855cBD4266D6Eb0Ec1Aa478", "Legend8"], + ["0x025a4e09Ea947b8d695f53ddFDD48ddB8F9B06b7", "Ciscox"], + ["0xE9436F6F30b4B01b57F2780B2898f3820EbD7B98", "LegendIV"], + ["0xC2d534F079444E6E7Ff9DabB3FD8a26c607932c8", "Axion"], + ["0x9F7110Ba7EdFda83Fc71BeA6BA3c0591117b440D", "LegendIX"], + ["0xB997Bf1E3b96919fBA592c1F61CE507E165Ec030", "Seoraksan"], + ["0x286C1b674d48cFF67b4096b6c1dc22e769581E91", "Sigm8"], + ["0x73A26778ef9509a6E94b55310eE7233795a9EB25", "Coinlix"], + ["0x18c44f4FBEde9826C7f257d500A65a3D5A8edebc", "Nozti"], + ["0xA100FCd08cE722Dc68Ddc3b54237070Cb186f118", "Tiollo"], + ["0x0F28847cfdbf7508B13Ebb9cEb94B2f1B32E9503", "Raptas"], + ["0xfD85346c8C991baC16b9c9157e6bdfDACE1cD7d7", "Glorin"], + ["0x978F05CED39A4EaFa6E8FD045Fe2dd6Da836c7DF", "NovaX"], + ["0xd849d1dF66bFF1c2739B4399425755C2E0fAbbAb", "Nexa"], + ["0xA015d9e9206859c13201BB3D6B324d6634276534", "Star"], + ["0x5ADde0151BfAB27f329e5112c1AeDeed7f0D3692", "Veri"], // Chapel - ["0x08265dA01E1A65d62b903c7B34c08cB389bF3D99","Ararat"], - ["0x7f5f2cF1aec83bF0c74DF566a41aa7ed65EA84Ea","Kita"], - ["0x53387F3321FD69d1E030BB921230dFb188826AFF","Fuji"], - ["0x76D76ee8823dE52A1A431884c2ca930C5e72bff3","Seoraksan"], - ["0xd447b49CD040D20BC21e49ffEa6487F5638e4346","Everest"], - ["0x1a3d9D7A717D64e6088aC937d5aAcDD3E20ca963","Elbrus"], - ["0x40D3256EB0BaBE89f0ea54EDAa398513136612f5","Bloxroute"], - ["0xF9a1Db0d6f22Bd78ffAECCbc8F47c83Df9FBdbCf","Test"], - ["0xB4cd0dCF71381b452A92A359BbE7146e8825Ce46","BSCLista"], - ["0xD7b26968D8AD24f433d422b18A11a6580654Af13","TNkgnL4"], - ["0xFDA4C7E5C6005511236E24f3d5eBFd65Ffa10AED","MyHave"], - ["0x73f86c0628e04A69dcb61944F0df5DE115bA3FD8","InfStones"], - ["0xcAc5E4158fAb2eB95aA5D9c8DdfC9DF7208fDc58","My5eVal"], - ["0x96f6a2A267C726973e40cCCBB956f1716Bac7dc0","ForDc0"], - ["0x15a13e315CbfB9398A26D77a299963BF034c28F8","Blxr"], - ["0x1d622CAcd06c0eafd0a8a4C66754C96Db50cE14C","Val9B"], - ["0xd6BD505f4CFc19203875A92B897B07DE13d118ce","Panipuri"], - ["0x9532223eAa6Eb6939A00C0A39A054d93b5cCf4Af","TrustT"], - ["0xB19b6057245002442123371494372719d2Beb83D","Vtwval"], - ["0x5530Bac059E50821E7146D951e56FC7500bda007","LedgrTrus"], - ["0xEe22F03961b407bCBae66499a029Be4cA0AF4ab4","AB4"], - ["0x1AE5f5C3Cb452E042b0B7b9DC60596C9CD84BaF6","Jake"], - ["0xfA4d592F9B152f7a10B5DE9bE24C27a74BCE431A","MyTWFMM"] + ["0x08265dA01E1A65d62b903c7B34c08cB389bF3D99", "Ararat"], + ["0x7f5f2cF1aec83bF0c74DF566a41aa7ed65EA84Ea", "Kita"], + ["0x53387F3321FD69d1E030BB921230dFb188826AFF", "Fuji"], + ["0x76D76ee8823dE52A1A431884c2ca930C5e72bff3", "Seoraksan"], + ["0xd447b49CD040D20BC21e49ffEa6487F5638e4346", "Everest"], + ["0x1a3d9D7A717D64e6088aC937d5aAcDD3E20ca963", "Elbrus"], + ["0x40D3256EB0BaBE89f0ea54EDAa398513136612f5", "Bloxroute"], + ["0xF9a1Db0d6f22Bd78ffAECCbc8F47c83Df9FBdbCf", "Test"], + ["0xB4cd0dCF71381b452A92A359BbE7146e8825Ce46", "BSCLista"], + ["0xD7b26968D8AD24f433d422b18A11a6580654Af13", "TNkgnL4"], + ["0xFDA4C7E5C6005511236E24f3d5eBFd65Ffa10AED", "MyHave"], + ["0x73f86c0628e04A69dcb61944F0df5DE115bA3FD8", "InfStones"], + ["0xcAc5E4158fAb2eB95aA5D9c8DdfC9DF7208fDc58", "My5eVal"], + ["0x96f6a2A267C726973e40cCCBB956f1716Bac7dc0", "ForDc0"], + ["0x15a13e315CbfB9398A26D77a299963BF034c28F8", "Blxr"], + ["0x1d622CAcd06c0eafd0a8a4C66754C96Db50cE14C", "Val9B"], + ["0xd6BD505f4CFc19203875A92B897B07DE13d118ce", "Panipuri"], + ["0x9532223eAa6Eb6939A00C0A39A054d93b5cCf4Af", "TrustT"], + ["0xB19b6057245002442123371494372719d2Beb83D", "Vtwval"], + ["0x5530Bac059E50821E7146D951e56FC7500bda007", "LedgrTrus"], + ["0xEe22F03961b407bCBae66499a029Be4cA0AF4ab4", "AB4"], + ["0x1AE5f5C3Cb452E042b0B7b9DC60596C9CD84BaF6", "Jake"], + ["0xfA4d592F9B152f7a10B5DE9bE24C27a74BCE431A", "MyTWFMM"], ]); const builderMap = new Map([ @@ -195,27 +193,26 @@ const builderMap = new Map([ ["0x76736159984AE865a9b9Cc0Df61484A49dA68191", "puissant eu"], ["0x5054b21D8baea3d602dca8761B235ee10bc0231E", "puissant us"], // Chapel - ]); +]); // 1.cmd: "GetMaxTxCountInBlockRange", usage: // node getchainstatus.js GetMaxTxCountInBlockRange --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 getMaxTxCountInBlockRange() { +async function getMaxTxCountInBlockRange() { 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)) + let blockData = await provider.getBlock(Number(i)); if (program.miner !== blockData.miner) { - continue + continue; } } - let x = await provider.send("eth_getBlockTransactionCountByNumber", [ - ethers.toQuantity(i)]); - let a = ethers.toNumber(x) + let x = await provider.send("eth_getBlockTransactionCountByNumber", [ethers.toQuantity(i)]); + let a = ethers.toNumber(x); if (a > txCount) { num = i; txCount = a; @@ -229,31 +226,31 @@ async function getMaxTxCountInBlockRange() { // --rpc https://bsc-testnet-dataseed.bnbchain.org \ // --num(optional): default 21, the number of blocks that will be checked // --turnLength(optional): default 4, the consecutive block length -async function getBinaryVersion() { +async function getBinaryVersion() { const blockNum = await provider.getBlockNumber(); - let turnLength = program.turnLength + let turnLength = program.turnLength; for (let i = 0; i < program.num; i++) { - let blockData = await provider.getBlock(blockNum - i*turnLength); + let blockData = await provider.getBlock(blockNum - i * turnLength); // 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)) + 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); + 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 + continue; } - lastGasPrice = txData.gasPrice - break + lastGasPrice = txData.gasPrice; + break; } - var moniker = await getValidatorMoniker(blockData.miner, blockNum) - console.log(blockNum - i*turnLength, blockData.miner, "version =", major + "." + minor + "." + patch, " MinGasPrice = " + lastGasPrice, moniker) + var moniker = await getValidatorMoniker(blockData.miner, blockNum); + console.log(blockNum - i * turnLength, blockData.miner, "version =", major + "." + minor + "." + patch, " MinGasPrice = " + lastGasPrice, moniker); } -}; +} // 3.cmd: "GetTopAddr", usage: // node getchainstatus.js GetTopAddr \ @@ -266,18 +263,18 @@ function getTopKElements(map, k) { return entries.slice(0, k); } -async function getTopAddr() { +async function getTopAddr() { let countMap = new Map(); - let totalTxs = 0 + 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) + 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 + console.log("Contract creation,txHash:", txData.hash); + continue; } let toAddr = txData.to; if (countMap.has(toAddr)) { @@ -286,14 +283,14 @@ async function getTopAddr() { countMap.set(toAddr, 1); } } - console.log("progress:", (program.endNum-i), "blocks left", "totalTxs", totalTxs) + console.log("progress:", program.endNum - i, "blocks left", "totalTxs", totalTxs); } - let tops = getTopKElements(countMap, program.topNum) + 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)+"%"); - }); -}; + console.log(key + ":", value[0], " ", value[1], " ", ((value[1] * 100) / totalTxs).toFixed(2) + "%"); + }); +} // 4.cmd: "GetSlashCount", usage: // node getchainstatus.js GetSlashCount \ @@ -301,118 +298,142 @@ async function getTopAddr() { // --blockNum(optional): the block num which is based for the slash state, default: latest block async function getValidatorMoniker(consensusAddr, blockNum) { if (validatorMap.has(consensusAddr)) { - return validatorMap.get(consensusAddr) + return validatorMap.get(consensusAddr); } - let opAddr = await stakeHub.consensusToOperator(consensusAddr, {blockTag:blockNum}) - let desc = await stakeHub.getValidatorDescription(opAddr, {blockTag:blockNum}) - let moniker = desc[0] - console.log(consensusAddr, moniker) - return moniker + let opAddr = await stakeHub.consensusToOperator(consensusAddr, { blockTag: blockNum }); + let desc = await stakeHub.getValidatorDescription(opAddr, { blockTag: blockNum }); + let moniker = desc[0]; + console.log(consensusAddr, moniker); + return moniker; } -async function getSlashCount() { - let blockNum = ethers.getNumber(program.blockNum) - if (blockNum === 0) { - blockNum = await provider.getBlockNumber() - } - let slashScale = await validatorSet.maintainSlashScale({blockTag:blockNum}) - let maxElected = await stakeHub.maxElectedValidators({blockTag:blockNum}) - const maintainThreshold = BigInt(50) // governable, hardcode to avoid one RPC call - const felonyThreshold = BigInt(150) // governable, hardcode to avoid one RPC call - - let block = await provider.getBlock(blockNum) - console.log("At block", blockNum, "time", block.date) - const data = await validatorSet.getLivingValidators({blockTag:blockNum}) - let totalSlash = 0 - for (let i = 0; i < data[0].length; i++) { - let addr = data[0][i]; - var moniker = await getValidatorMoniker(addr, blockNum) - let info = await slashIndicator.getSlashIndicator(addr, {blockTag:blockNum}) - let slashHeight = ethers.toNumber(info[0]) - let slashCount = ethers.toNumber(info[1]) - totalSlash += slashCount - console.log("Slash:", slashCount, addr, moniker, slashHeight) - if (slashCount >= maintainThreshold) { - let validatorExtra = await validatorSet.validatorExtraSet(i, {blockTag:blockNum}) - let enterMaintenanceHeight = validatorExtra[0] - let isMaintaining = validatorExtra[1] - // let voteAddress = validatorExtra[2] - if (isMaintaining) { - let jailHeight = (felonyThreshold - BigInt(slashCount)) * slashScale * maxElected + BigInt(enterMaintenanceHeight) - console.log(" in maintenance mode since", enterMaintenanceHeight, "will jail after", ethers.toNumber(jailHeight)) - } else { - console.log(" exited maintenance mode") - } +async function getSlashCount() { + let blockNum = ethers.getNumber(program.blockNum); + if (blockNum === 0) { + blockNum = await provider.getBlockNumber(); + } + let slashScale = await validatorSet.maintainSlashScale({ blockTag: blockNum }); + let maxElected = await stakeHub.maxElectedValidators({ blockTag: blockNum }); + const maintainThreshold = BigInt(50); // governable, hardcode to avoid one RPC call + const felonyThreshold = BigInt(150); // governable, hardcode to avoid one RPC call + + let block = await provider.getBlock(blockNum); + console.log("At block", blockNum, "time", block.date); + const data = await validatorSet.getLivingValidators({ blockTag: blockNum }); + let totalSlash = 0; + for (let i = 0; i < data[0].length; i++) { + let addr = data[0][i]; + var moniker = await getValidatorMoniker(addr, blockNum); + let info = await slashIndicator.getSlashIndicator(addr, { blockTag: blockNum }); + let slashHeight = ethers.toNumber(info[0]); + let slashCount = ethers.toNumber(info[1]); + totalSlash += slashCount; + console.log("Slash:", slashCount, addr, moniker, slashHeight); + if (slashCount >= maintainThreshold) { + let validatorExtra = await validatorSet.validatorExtraSet(i, { blockTag: blockNum }); + let enterMaintenanceHeight = validatorExtra[0]; + let isMaintaining = validatorExtra[1]; + // let voteAddress = validatorExtra[2] + if (isMaintaining) { + let jailHeight = (felonyThreshold - BigInt(slashCount)) * slashScale * maxElected + BigInt(enterMaintenanceHeight); + console.log(" in maintenance mode since", enterMaintenanceHeight, "will jail after", ethers.toNumber(jailHeight)); + } else { + console.log(" exited maintenance mode"); } } - console.log("Total slash count", totalSlash) -}; + } + console.log("Total slash count", totalSlash); +} // 5.cmd: "getPerformanceData", usage: // node getchainstatus.js getPerformanceData \ // --rpc https://bsc-testnet-dataseed.bnbchain.org \ // --startNum 40000001 --endNum 40000005 -async function getPerformanceData() { +async function getPerformanceData() { let txCountTotal = 0; let gasUsedTotal = 0; let inturnBlocks = 0; let justifiedBlocks = 0; let turnLength = 1; let parliaEnabled = true; - try { + try { turnLength = await provider.send("parlia_getTurnLength", [ethers.toQuantity(program.startNum)]); } catch (error) { // the "parlia" module was not enabled for RPC call - parliaEnabled = false + parliaEnabled = false; console.log("parlia RPC modudle is not enabled\n", error); } for (let i = program.startNum; i < program.endNum; i++) { - let txCount = await provider.send("eth_getBlockTransactionCountByNumber", [ - ethers.toQuantity(i)]); - txCountTotal += ethers.toNumber(txCount) - - let header = await provider.send("eth_getHeaderByNumber", [ - ethers.toQuantity(i)]); - let gasUsed = eval(eval(header.gasUsed).toString(10)) - gasUsedTotal += gasUsed - let difficulty = eval(eval(header.difficulty).toString(10)) + let txCount = await provider.send("eth_getBlockTransactionCountByNumber", [ethers.toQuantity(i)]); + txCountTotal += ethers.toNumber(txCount); + + let header = await provider.send("eth_getHeaderByNumber", [ethers.toQuantity(i)]); + let gasUsed = eval(eval(header.gasUsed).toString(10)); + gasUsedTotal += gasUsed; + let difficulty = eval(eval(header.difficulty).toString(10)); if (difficulty == 2) { - inturnBlocks += 1 + inturnBlocks += 1; } - let timestamp = eval(eval(header.milliTimestamp).toString(10)) + let timestamp = eval(eval(header.milliTimestamp).toString(10)); if (parliaEnabled) { let justifiedNumber = await provider.send("parlia_getJustifiedNumber", [ethers.toQuantity(i)]); if (justifiedNumber + 1 == i) { - justifiedBlocks += 1 + justifiedBlocks += 1; } else { - console.log("justified unexpected", "BlockNumber =", i,"justifiedNumber",justifiedNumber) + console.log("justified unexpected", "BlockNumber =", i, "justifiedNumber", justifiedNumber); } } - console.log("BlockNumber =", i, "mod =", i%turnLength, "miner =", header.miner , "difficulty =", difficulty, "txCount =", ethers.toNumber(txCount), "gasUsed", gasUsed, "timestamp", timestamp) - } - let blockCount = program.endNum - program.startNum - let txCountPerBlock = txCountTotal/blockCount - - let startHeader = await provider.send("eth_getHeaderByNumber", [ - ethers.toQuantity(program.startNum)]); - let startTime = eval(eval(startHeader.milliTimestamp).toString(10)) - let endHeader = await provider.send("eth_getHeaderByNumber", [ - ethers.toQuantity(program.endNum)]); - let endTime = eval(eval(endHeader.milliTimestamp).toString(10)) - let timeCost = (endTime - startTime)/1000 - let avgBlockTime = timeCost/blockCount - let inturnBlocksRatio = inturnBlocks/blockCount - let justifiedBlocksRatio = justifiedBlocks/blockCount - let tps = txCountTotal/timeCost - let M = 1000000 - let avgGasUsedPerBlock = gasUsedTotal/blockCount/M - let avgGasUsedPerSecond = gasUsedTotal/timeCost/M + console.log( + "BlockNumber =", + i, + "mod =", + i % turnLength, + "miner =", + header.miner, + "difficulty =", + difficulty, + "txCount =", + ethers.toNumber(txCount), + "gasUsed", + gasUsed, + "timestamp", + timestamp + ); + } + let blockCount = program.endNum - program.startNum; + let txCountPerBlock = txCountTotal / blockCount; + + let startHeader = await provider.send("eth_getHeaderByNumber", [ethers.toQuantity(program.startNum)]); + let startTime = eval(eval(startHeader.milliTimestamp).toString(10)); + let endHeader = await provider.send("eth_getHeaderByNumber", [ethers.toQuantity(program.endNum)]); + let endTime = eval(eval(endHeader.milliTimestamp).toString(10)); + let timeCost = (endTime - startTime) / 1000; + let avgBlockTime = timeCost / blockCount; + let inturnBlocksRatio = inturnBlocks / blockCount; + let justifiedBlocksRatio = justifiedBlocks / blockCount; + let tps = txCountTotal / timeCost; + let M = 1000000; + let avgGasUsedPerBlock = gasUsedTotal / blockCount / M; + let avgGasUsedPerSecond = gasUsedTotal / timeCost / M; console.log("Get the performance between [", program.startNum, ",", program.endNum, ")"); - console.log("txCountPerBlock =", txCountPerBlock, "txCountTotal =", txCountTotal, "BlockCount =", blockCount, "avgBlockTime =", avgBlockTime, "inturnBlocksRatio =", inturnBlocksRatio, "justifiedBlocksRatio =", justifiedBlocksRatio); + console.log( + "txCountPerBlock =", + txCountPerBlock, + "txCountTotal =", + txCountTotal, + "BlockCount =", + blockCount, + "avgBlockTime =", + avgBlockTime, + "inturnBlocksRatio =", + inturnBlocksRatio, + "justifiedBlocksRatio =", + justifiedBlocksRatio + ); console.log("txCountPerSecond =", tps, "avgGasUsedPerBlock =", avgGasUsedPerBlock, "avgGasUsedPerSecond =", avgGasUsedPerSecond); -}; +} // 6.cmd: "GetBlobTxs", usage: // node getchainstatus.js GetBlobTxs \ @@ -420,147 +441,154 @@ async function getPerformanceData() { // --startNum 40000001 --endNum 40000005 // depends on ethjs v6.11.0+ for 4844, https://github.com/ethers-io/ethers.js/releases/tag/v6.11.0 // BSC testnet enabled 4844 on block: 39539137 -async function getBlobTxs() { - var startBlock = parseInt(program.startNum) - var endBlock = parseInt(program.endNum) +async function getBlobTxs() { + var startBlock = parseInt(program.startNum); + var endBlock = parseInt(program.endNum); if (isNaN(endBlock) || isNaN(startBlock) || startBlock == 0) { - console.error("invalid input, --startNum", program.startNum, "--end", program.endNum) - return + console.error("invalid input, --startNum", program.startNum, "--end", program.endNum); + return; } // if --endNum is not specified, set it to the latest block number. if (endBlock == 0) { endBlock = await provider.getBlockNumber(); } if (startBlock > endBlock) { - console.error("invalid input, startBlock:",startBlock, " endBlock:", endBlock); - return + console.error("invalid input, startBlock:", startBlock, " endBlock:", endBlock); + return; } for (let i = startBlock; i <= endBlock; i++) { let blockData = await provider.getBlock(i); - console.log("startBlock:",startBlock, "endBlock:", endBlock, "curBlock", i, "blobGasUsed", blockData.blobGasUsed); + console.log("startBlock:", startBlock, "endBlock:", endBlock, "curBlock", i, "blobGasUsed", blockData.blobGasUsed); if (blockData.blobGasUsed == 0) { - continue + continue; } - for (let txIndex = 0; txIndex<= blockData.transactions.length - 1; txIndex++) { - let txHash = blockData.transactions[txIndex] - let txData = await provider.getTransaction(txHash); + for (let txIndex = 0; txIndex <= blockData.transactions.length - 1; txIndex++) { + let txHash = blockData.transactions[txIndex]; + let txData = await provider.getTransaction(txHash); if (txData.type == 3) { - console.log("BlobTx in block:",i, " txIndex:", txIndex, " txHash:", txHash); + console.log("BlobTx in block:", i, " txIndex:", txIndex, " txHash:", txHash); } } } -}; +} // 7.cmd: "GetFaucetStatus", usage: // node getchainstatus.js GetFaucetStatus \ // --rpc https://bsc-testnet-dataseed.bnbchain.org \ // --startNum 40000001 --endNum 40000005 -async function getFaucetStatus() { - var startBlock = parseInt(program.startNum) - var endBlock = parseInt(program.endNum) +async function getFaucetStatus() { + var startBlock = parseInt(program.startNum); + var endBlock = parseInt(program.endNum); if (isNaN(endBlock) || isNaN(startBlock) || startBlock == 0) { - console.error("invalid input, --startNum", program.startNum, "--end", program.endNum) - return + console.error("invalid input, --startNum", program.startNum, "--end", program.endNum); + return; } // if --endNum is not specified, set it to the latest block number. if (endBlock == 0) { endBlock = await provider.getBlockNumber(); } if (startBlock > endBlock) { - console.error("invalid input, startBlock:",startBlock, " endBlock:", endBlock); - return + console.error("invalid input, startBlock:", startBlock, " endBlock:", endBlock); + return; } - let startBalance = await provider.getBalance("0xaa25Aa7a19f9c426E07dee59b12f944f4d9f1DD3", startBlock) - let endBalance = await provider.getBalance("0xaa25Aa7a19f9c426E07dee59b12f944f4d9f1DD3", endBlock) - const faucetAmount = BigInt(0.3 * 10**18); // Convert 0.3 ether to wei as a BigInt + let startBalance = await provider.getBalance("0xaa25Aa7a19f9c426E07dee59b12f944f4d9f1DD3", startBlock); + let endBalance = await provider.getBalance("0xaa25Aa7a19f9c426E07dee59b12f944f4d9f1DD3", endBlock); + const faucetAmount = BigInt(0.3 * 10 ** 18); // Convert 0.3 ether to wei as a BigInt const numFaucetRequest = (startBalance - endBalance) / faucetAmount; // Convert BigInt to ether - const startBalanceEth = Number(startBalance) / 10**18; - const endBalanceEth = Number(endBalance) / 10**18; + const startBalanceEth = Number(startBalance) / 10 ** 18; + const endBalanceEth = Number(endBalance) / 10 ** 18; console.log(`Start Balance: ${startBalanceEth} ETH`); console.log(`End Balance: ${endBalanceEth} ETH`); - console.log("successful faucet request: ",numFaucetRequest); -}; - + console.log("successful faucet request: ", numFaucetRequest); +} // 8.cmd: "GetKeyParameters", usage: // node getchainstatus.js GetKeyParameters \ // --rpc https://bsc-testnet-dataseed.bnbchain.org \ // --blockNum(optional): the block num which is based for the slash state, default: latest block -async function getKeyParameters() { - let blockNum = ethers.getNumber(program.blockNum) +async function getKeyParameters() { + let blockNum = ethers.getNumber(program.blockNum); if (blockNum === 0) { - blockNum = await provider.getBlockNumber() + blockNum = await provider.getBlockNumber(); } - let block = await provider.getBlock(blockNum) - console.log("At block", blockNum, "time", block.date) + let block = await provider.getBlock(blockNum); + console.log("At block", blockNum, "time", block.date); // part 1: validatorset - let numOfCabinets = await validatorSet.numOfCabinets({blockTag:blockNum}) - if (numOfCabinets == 0) { numOfCabinets = 21 } + let numOfCabinets = await validatorSet.numOfCabinets({ blockTag: blockNum }); + if (numOfCabinets == 0) { + numOfCabinets = 21; + } // let maxNumOfCandidates = await validatorSet.maxNumOfCandidates({blockTag:blockNum}) // deprecated // let turnLength = await validatorSet.turnLength({blockTag:blockNum}) - let maxNumOfWorkingCandidates = await validatorSet.maxNumOfWorkingCandidates({blockTag:blockNum}) - let maintainSlashScale = await validatorSet.maintainSlashScale({blockTag:blockNum}) - console.log("numOfCabinets", Number(numOfCabinets), "maxNumOfWorkingCandidates", Number(maxNumOfWorkingCandidates), - "maintainSlashScale", maintainSlashScale) + let maxNumOfWorkingCandidates = await validatorSet.maxNumOfWorkingCandidates({ blockTag: blockNum }); + let maintainSlashScale = await validatorSet.maintainSlashScale({ blockTag: blockNum }); + console.log( + "numOfCabinets", + Number(numOfCabinets), + "maxNumOfWorkingCandidates", + Number(maxNumOfWorkingCandidates), + "maintainSlashScale", + maintainSlashScale + ); // part 2: staking // let minSelfDelegationBNB = await stakeHub.minSelfDelegationBNB({blockTag:blockNum})/BigInt(10**18) - let maxElectedValidators = await stakeHub.maxElectedValidators({blockTag:blockNum}) - let validatorElectionInfo = await stakeHub.getValidatorElectionInfo(0,0,{blockTag:blockNum}) - let consensusAddrs = validatorElectionInfo[0] - let votingPowers = validatorElectionInfo[1] - let voteAddrs = validatorElectionInfo[2] - let totalLength = validatorElectionInfo[3] - console.log("maxElectedValidators", Number(maxElectedValidators), "Registered", Number(totalLength)) - let validatorTable = [] + let maxElectedValidators = await stakeHub.maxElectedValidators({ blockTag: blockNum }); + let validatorElectionInfo = await stakeHub.getValidatorElectionInfo(0, 0, { blockTag: blockNum }); + let consensusAddrs = validatorElectionInfo[0]; + let votingPowers = validatorElectionInfo[1]; + let voteAddrs = validatorElectionInfo[2]; + let totalLength = validatorElectionInfo[3]; + console.log("maxElectedValidators", Number(maxElectedValidators), "Registered", Number(totalLength)); + let validatorTable = []; for (let i = 0; i < totalLength; i++) { validatorTable.push({ - addr: consensusAddrs[i], - votingPower: Number(votingPowers[i]/BigInt(10**18)), - voteAddr: voteAddrs[i], - moniker: await getValidatorMoniker(consensusAddrs[i], blockNum) - }) + addr: consensusAddrs[i], + votingPower: Number(votingPowers[i] / BigInt(10 ** 18)), + voteAddr: voteAddrs[i], + moniker: await getValidatorMoniker(consensusAddrs[i], blockNum), + }); } validatorTable.sort((a, b) => b.votingPower - a.votingPower); - console.table(validatorTable) + console.table(validatorTable); } // 9.cmd: "getEip7623", usage: // node getEip7623.js GetEip7623 \ // --rpc https://bsc-testnet-dataseed.bnbchain.org \ // --startNum 40000001 --endNum 40000005 -async function getEip7623() { - var startBlock = parseInt(program.startNum) - var endBlock = parseInt(program.endNum) +async function getEip7623() { + var startBlock = parseInt(program.startNum); + var endBlock = parseInt(program.endNum); if (isNaN(endBlock) || isNaN(startBlock) || startBlock === 0) { - console.error("invalid input, --startNum", program.startNum, "--end", program.endNum) - return + console.error("invalid input, --startNum", program.startNum, "--end", program.endNum); + return; } // if --endNum is not specified, set it to the latest block number. if (endBlock === 0) { endBlock = await provider.getBlockNumber(); } if (startBlock > endBlock) { - console.error("invalid input, startBlock:",startBlock, " endBlock:", endBlock); - return + console.error("invalid input, startBlock:", startBlock, " endBlock:", endBlock); + return; } const startTime = Date.now(); - const TOTAL_COST_FLOOR_PER_TOKEN = 10 - const intrinsicGas = 21000 + const TOTAL_COST_FLOOR_PER_TOKEN = 10; + const intrinsicGas = 21000; for (let blockNumber = startBlock; blockNumber <= endBlock; blockNumber++) { const block = await provider.getBlock(blockNumber, true); for (let txHash of block.transactions) { - let tx = block.getPrefetchedTransaction(txHash) + let tx = block.getPrefetchedTransaction(txHash); const receipt = await provider.getTransactionReceipt(tx.hash); let tokens_in_calldata = -4; // means '0x' let calldata = tx.data; @@ -572,9 +600,9 @@ async function getEip7623() { tokens_in_calldata = tokens_in_calldata + 4; } } - let want = TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata + intrinsicGas + let want = TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata + intrinsicGas; if (want > receipt.gasUsed) { - console.log("Cost more gas, blockNum:", tx.blockNumber, "txHash", tx.hash, " gasUsed", receipt.gasUsed.toString(), " New GasUsed", want) + console.log("Cost more gas, blockNum:", tx.blockNumber, "txHash", tx.hash, " gasUsed", receipt.gasUsed.toString(), " New GasUsed", want); } } } @@ -584,109 +612,170 @@ async function getEip7623() { } // 10.cmd: "getMevStatus", usage: -// node getchainstatus.js GetMeVStatus \ +// node getchainstatus.js GetMevStatus \ // --rpc https://bsc-testnet-dataseed.bnbchain.org \ -// --startNum 40000001 --endNum 40000005 +// --startNum(optional): default to last 100 blocks, the start block number to analyze +// --endNum(optional): default to latest block, the end block number to analyze +// +// Description: +// Analyzes MEV (Maximal Extractable Value) blocks in a given range and displays: +// 1. Block-by-block information including: +// - Block number +// - Miner name (from validator set) +// - Builder information (if MEV block) or "local" (if non-MEV block) +// 2. Statistics summary including: +// - Block range analyzed +// - Total number of blocks +// - Distribution of blocks by builder type (local, blockrazor, puissant, blockroute, txboost) +// - Percentage of each builder type +// +// Example: +// # Analyze last 100 blocks (default) +// node getchainstatus.js GetMevStatus --rpc https://bsc-testnet-dataseed.bnbchain.org +// +// # Analyze specific range +// node getchainstatus.js GetMevStatus --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000005 +// +// # Analyze from specific block to latest +// node getchainstatus.js GetMevStatus --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 async function getMevStatus() { - let localCount = 0 - let blockrazorCount = 0 - let puissantCount = 0 - let blockrouteCount = 0 - let txboostCount = 0 - var startBlock = parseInt(program.startNum) - var endBlock = parseInt(program.endNum) - if (isNaN(endBlock) || isNaN(startBlock) || startBlock == 0) { - console.error("invalid input, --startNum", program.startNum, "--end", program.endNum) - return + let counts = { + local: 0, + blockrazor: 0, + puissant: 0, + blockroute: 0, + txboost: 0, + }; + + // Get the latest block number + const latestBlock = await provider.getBlockNumber(); + + // If startNum is not specified or is 0, use last 100 blocks + let startBlock = parseInt(program.startNum, 10); + if (isNaN(startBlock) || startBlock === 0) { + startBlock = Math.max(1, latestBlock - 99); // Ensure we don't go below block 1 } - // if --endNum is not specified, set it to the latest block number. - if (endBlock == 0) { - endBlock = await provider.getBlockNumber(); + + // If endNum is not specified or is 0, use the latest block number + let endBlock = parseInt(program.endNum, 10); + if (isNaN(endBlock) || endBlock === 0) { + endBlock = latestBlock; } + if (startBlock > endBlock) { - console.error("invalid input, startBlock:", startBlock, " endBlock:", endBlock); - return + console.error("Invalid input, startBlock:", startBlock, " endBlock:", endBlock); + return; } - + + const blockPromises = []; for (let i = startBlock; i <= endBlock; i++) { - let blockData = await provider.getBlock(i); - let miner = validatorMap.get(blockData.miner) - const payBidTxReverseIdxMax = 3 - let mevBlock = false - for (let idx = 0; idx <= payBidTxReverseIdxMax && blockData.transactions.length - 1 - idx >= 0; idx++) { - var txIndex = blockData.transactions.length - 1 - idx - let txHash = blockData.transactions[txIndex] - let txData = await provider.getTransaction(txHash); - if (builderMap.has(txData.to)) { - let builder = builderMap.get(txData.to) - if (builder.search("blockrazor") != -1) { - blockrazorCount++ - } else if (builder.search("puissant") != -1) { - puissantCount++ - } else if (builder.search("blockroute") != -1) { - blockrouteCount++ - } else if (builder.search("txboost") != -1) { - txboostCount++ - } - mevBlock = true - console.log("blockNum:", i, " miner:", miner, " builder:("+builderMap.get(txData.to)+")", txData.to); - break - } - } - if (!mevBlock) { - localCount++ - console.log("blockNum:", i, " miner:", miner, " builder:local"); - } - } - console.log("Get Mev Status between [", program.startNum, ",", program.endNum, "]"); - let total = program.endNum - program.startNum + 1 - console.log("total =", total) - console.log("local =", localCount, " ratio =", (localCount / total).toFixed(2)) - console.log("blockrazor =", blockrazorCount, " ratio =", (blockrazorCount / total).toFixed(2)) - console.log("puissant =", puissantCount, " ratio =", (puissantCount / total).toFixed(2)) - console.log("blockroute =", blockrouteCount, " ratio =", (blockrouteCount / total).toFixed(2)) - console.log("txboost =", txboostCount, " ratio =", (txboostCount / total).toFixed(2)) - }; + blockPromises.push(provider.getBlock(i)); + } + + const blocks = await Promise.all(blockPromises); + + // Calculate max lengths for alignment with default values + let maxMinerLength = 10; // Default length + let maxBuilderLength = 20; // Default length + + if (validatorMap.size > 0) { + const minerLengths = Array.from(validatorMap.values()).map(m => m.length); + maxMinerLength = Math.max(...minerLengths); + } + + if (builderMap.size > 0) { + const builderLengths = Array.from(builderMap.values()).map(b => b.length); + maxBuilderLength = Math.max(...builderLengths); + } + + for (const blockData of blocks) { + const miner = validatorMap.get(blockData.miner) || "Unknown"; + const transactions = blockData.transactions.slice(-4); // Last 4 transactions + const txPromises = transactions.map(txHash => provider.getTransaction(txHash)); + + const txResults = await Promise.all(txPromises); + let mevBlock = false; + + for (const txData of txResults) { + if (builderMap.has(txData.to)) { + const builder = builderMap.get(txData.to); + const builderKey = Object.keys(counts).find(key => builder.includes(key)); + + if (builderKey) { + counts[builderKey]++; + } + + mevBlock = true; + console.log( + `blockNum: ${blockData.number.toString().padStart(8)} ` + + `miner: ${miner.padEnd(maxMinerLength)} ` + + `builder: (${builder.padEnd(maxBuilderLength)}) ${txData.to}` + ); + break; + } + } + + if (!mevBlock) { + counts.local++; + console.log( + `blockNum: ${blockData.number.toString().padStart(8)} ` + + `miner: ${miner.padEnd(maxMinerLength)} ` + + `builder: local` + ); + } + } + + const total = endBlock - startBlock + 1; + console.log("\nMEV Statistics:"); + console.log(`Range: [${startBlock}, ${endBlock}]`); + console.log(`Total Blocks: ${total}`); + console.log("\nBuilder Distribution:"); + Object.entries(counts).forEach(([key, value]) => { + const ratio = (value *100 / total).toFixed(2); + console.log(`${key.padEnd(10)}: ${value.toString().padStart(3)} blocks (${ratio}%)`); + }); +} const main = async () => { if (process.argv.length <= 2) { - console.error('invalid process.argv.length', process.argv.length); - printUsage() - return + console.error("invalid process.argv.length", process.argv.length); + printUsage(); + return; } - const cmd = process.argv[2] + const cmd = process.argv[2]; if (cmd == "-h" || cmd == "--help") { - printUsage() - return + printUsage(); + return; } if (cmd === "GetMaxTxCountInBlockRange") { - await getMaxTxCountInBlockRange() + await getMaxTxCountInBlockRange(); } else if (cmd === "GetBinaryVersion") { - await getBinaryVersion() + await getBinaryVersion(); } else if (cmd === "GetTopAddr") { - await getTopAddr() + await getTopAddr(); } else if (cmd === "GetSlashCount") { - await getSlashCount() + await getSlashCount(); } else if (cmd === "GetPerformanceData") { - await getPerformanceData() + await getPerformanceData(); } else if (cmd === "GetBlobTxs") { - await getBlobTxs() + await getBlobTxs(); } else if (cmd === "GetFaucetStatus") { - await getFaucetStatus() + await getFaucetStatus(); } else if (cmd === "GetKeyParameters") { - await getKeyParameters() - } else if (cmd === "GetEip7623"){ - await getEip7623() - } else if (cmd === "GetMevStatus"){ - await getMevStatus() + await getKeyParameters(); + } else if (cmd === "GetEip7623") { + await getEip7623(); + } else if (cmd === "GetMevStatus") { + await getMevStatus(); } else { console.log("unsupported cmd", cmd); - printUsage() + printUsage(); } -} +}; -main().then(() => process.exit(0)) - .catch((error) => { +main() + .then(() => process.exit(0)) + .catch(error => { console.error(error); process.exit(1); - }); \ No newline at end of file + }); diff --git a/cmd/jsutils/package.json b/cmd/jsutils/package.json index 68a76c9aa4..2758252804 100644 --- a/cmd/jsutils/package.json +++ b/cmd/jsutils/package.json @@ -6,11 +6,15 @@ "main": "index.js", "scripts": { "startMainnet": "node getvalidatorversion.js --Rpc https://bsc-dataseed.bnbchain.org --Num 21", - "startTestnet": "node getvalidatorversion.js --Rpc https://bsc-testnet-dataseed.bnbchain.org --Num 7" + "startTestnet": "node getvalidatorversion.js --Rpc https://bsc-testnet-dataseed.bnbchain.org --Num 7", + "format": "prettier --write \"**/*.{js,jsx,ts,tsx}\"" }, "dependencies": { "commander": "^3.0.1", "ethers": "^6.2.3" }, - "author": "BNB Chain" + "author": "BNB Chain", + "devDependencies": { + "prettier": "^3.5.3" + } } diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index f42317b441..b5612fe5bc 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -152,10 +152,7 @@ func (f *chainFreezer) freezeThreshold(db ethdb.Reader) (uint64, error) { if final == 0 && headLimit == 0 { return 0, errors.New("freezing threshold is not available") } - if final > headLimit { - return final, nil - } - return headLimit, nil + return max(final, headLimit), nil } // freeze is a background thread that periodically checks the blockchain for any diff --git a/core/txpool/blobpool/priority.go b/core/txpool/blobpool/priority.go index 7ae7f92def..457e4c20bf 100644 --- a/core/txpool/blobpool/priority.go +++ b/core/txpool/blobpool/priority.go @@ -36,10 +36,7 @@ func evictionPriority(basefeeJumps float64, txBasefeeJumps, blobfeeJumps, txBlob basefeePriority = evictionPriority1D(basefeeJumps, txBasefeeJumps) blobfeePriority = evictionPriority1D(blobfeeJumps, txBlobfeeJumps) ) - if basefeePriority < blobfeePriority { - return basefeePriority - } - return blobfeePriority + return min(basefeePriority, blobfeePriority) } // evictionPriority1D calculates the eviction priority based on the algorithm diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index 28746042cf..df13d4c8ae 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -73,10 +73,7 @@ func memoryCall(stack *Stack) (uint64, bool) { if overflow { return 0, true } - if x > y { - return x, false - } - return y, false + return max(x, y), false } func memoryDelegateCall(stack *Stack) (uint64, bool) { @@ -88,10 +85,7 @@ func memoryDelegateCall(stack *Stack) (uint64, bool) { if overflow { return 0, true } - if x > y { - return x, false - } - return y, false + return max(x, y), false } func memoryStaticCall(stack *Stack) (uint64, bool) { @@ -103,10 +97,7 @@ func memoryStaticCall(stack *Stack) (uint64, bool) { if overflow { return 0, true } - if x > y { - return x, false - } - return y, false + return max(x, y), false } func memoryReturn(stack *Stack) (uint64, bool) { diff --git a/eth/protocols/bsc/peer.go b/eth/protocols/bsc/peer.go index c3052e36ec..c6c09026e8 100644 --- a/eth/protocols/bsc/peer.go +++ b/eth/protocols/bsc/peer.go @@ -28,14 +28,6 @@ const ( secondsPerPeriod = float64(30) ) -// max is a helper function which returns the larger of the two given integers. -func max(a, b int) int { - if a > b { - return a - } - return b -} - // Peer is a collection of relevant information we have about a `bsc` peer. type Peer struct { id string // Unique ID for the peer, cached diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 53f38938bb..cd3f26c473 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -54,14 +54,6 @@ import ( "github.com/holiman/uint256" ) -// max is a helper function which returns the larger of the two given integers. -func max(a, b int64) int64 { - if a > b { - return a - } - return b -} - const UnHealthyTimeout = 5 * time.Second // estimateGasErrorRatio is the amount of overestimation eth_estimateGas is diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 3ad368ec50..f901732d78 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -19,7 +19,7 @@ package web3ext var Modules = map[string]string{ "admin": AdminJs, - "clique": CliqueJs, + "parlia": ParliaJs, "debug": DebugJs, "eth": EthJs, "miner": MinerJs, @@ -29,60 +29,46 @@ var Modules = map[string]string{ "dev": DevJs, } -const CliqueJs = ` +const ParliaJs = ` web3._extend({ - property: 'clique', + property: 'parlia', methods: [ new web3._extend.Method({ name: 'getSnapshot', - call: 'clique_getSnapshot', + call: 'parlia_getSnapshot', params: 1, inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] }), new web3._extend.Method({ name: 'getSnapshotAtHash', - call: 'clique_getSnapshotAtHash', + call: 'parlia_getSnapshotAtHash', params: 1 }), new web3._extend.Method({ - name: 'getSigners', - call: 'clique_getSigners', + name: 'getValidators', + call: 'parlia_getValidators', params: 1, inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] }), new web3._extend.Method({ - name: 'getSignersAtHash', - call: 'clique_getSignersAtHash', + name: 'getValidatorsAtHash', + call: 'parlia_getValidatorsAtHash', params: 1 }), new web3._extend.Method({ - name: 'propose', - call: 'clique_propose', - params: 2 - }), - new web3._extend.Method({ - name: 'discard', - call: 'clique_discard', - params: 1 - }), - new web3._extend.Method({ - name: 'status', - call: 'clique_status', - params: 0 + name: 'getJustifiedNumber', + call: 'parlia_getJustifiedNumber', + params: 1, + inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] }), new web3._extend.Method({ - name: 'getSigner', - call: 'clique_getSigner', + name: 'getFinalizedNumber', + call: 'parlia_getFinalizedNumber', params: 1, - inputFormatter: [null] + inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter] }), ], - properties: [ - new web3._extend.Property({ - name: 'proposals', - getter: 'clique_proposals' - }), - ] + properties: [] }); ` diff --git a/miner/bid_simulator.go b/miner/bid_simulator.go index 999efe06a8..8068fd6261 100644 --- a/miner/bid_simulator.go +++ b/miner/bid_simulator.go @@ -31,11 +31,6 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -const ( - // maxBidPerBuilderPerBlock is the max bid number per builder - maxBidPerBuilderPerBlock = 3 -) - var ( bidSimTimer = metrics.NewRegisteredTimer("bid/sim/duration", nil) ) @@ -118,6 +113,8 @@ type bidSimulator struct { simBidMu sync.RWMutex simulatingBid map[common.Hash]*BidRuntime // prevBlockHash -> bidRuntime, in the process of simulation + + maxBidsPerBuilder uint32 // Maximum number of bids allowed per builder per block } func newBidSimulator( @@ -129,24 +126,31 @@ func newBidSimulator( engine consensus.Engine, bidWorker bidWorker, ) *bidSimulator { + // Set default value + maxBids := uint32(3) + if config.MaxBidsPerBuilder > 0 { + maxBids = config.MaxBidsPerBuilder + } + b := &bidSimulator{ - config: config, - delayLeftOver: delayLeftOver, - minGasPrice: minGasPrice, - chain: eth.BlockChain(), - txpool: eth.TxPool(), - chainConfig: chainConfig, - engine: engine, - bidWorker: bidWorker, - exitCh: make(chan struct{}), - chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), - builders: make(map[common.Address]*builderclient.Client), - simBidCh: make(chan *simBidReq), - newBidCh: make(chan newBidPackage, 100), - pending: make(map[uint64]map[common.Address]map[common.Hash]struct{}), - bestBid: make(map[common.Hash]*BidRuntime), - bestBidToRun: make(map[common.Hash]*types.Bid), - simulatingBid: make(map[common.Hash]*BidRuntime), + config: config, + delayLeftOver: delayLeftOver, + minGasPrice: minGasPrice, + chain: eth.BlockChain(), + txpool: eth.TxPool(), + chainConfig: chainConfig, + engine: engine, + bidWorker: bidWorker, + maxBidsPerBuilder: maxBids, + exitCh: make(chan struct{}), + chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), + builders: make(map[common.Address]*builderclient.Client), + simBidCh: make(chan *simBidReq), + newBidCh: make(chan newBidPackage, 100), + pending: make(map[uint64]map[common.Address]map[common.Hash]struct{}), + bestBid: make(map[common.Hash]*BidRuntime), + bestBidToRun: make(map[common.Hash]*types.Bid), + simulatingBid: make(map[common.Hash]*BidRuntime), } b.chainHeadSub = b.chain.SubscribeChainHeadEvent(b.chainHeadCh) @@ -577,8 +581,8 @@ func (b *bidSimulator) CheckPending(blockNumber uint64, builder common.Address, return errors.New("bid already exists") } - if len(b.pending[blockNumber][builder]) >= maxBidPerBuilderPerBlock { - return errors.New("too many bids") + if len(b.pending[blockNumber][builder]) >= int(b.maxBidsPerBuilder) { + return fmt.Errorf("too many bids: exceeded limit of %d bids per builder per block", b.maxBidsPerBuilder) } return nil diff --git a/miner/minerconfig/config.go b/miner/minerconfig/config.go index 31bf5499cc..00dc7b6b88 100644 --- a/miner/minerconfig/config.go +++ b/miner/minerconfig/config.go @@ -76,6 +76,7 @@ type MevConfig struct { ValidatorCommission uint64 // 100 means the validator claims 1% from block reward BidSimulationLeftOver time.Duration NoInterruptLeftOver time.Duration + MaxBidsPerBuilder uint32 // Maximum number of bids allowed per builder per block } var DefaultMevConfig = MevConfig{ @@ -86,4 +87,5 @@ var DefaultMevConfig = MevConfig{ ValidatorCommission: 100, BidSimulationLeftOver: 50 * time.Millisecond, NoInterruptLeftOver: 400 * time.Millisecond, + MaxBidsPerBuilder: 3, } diff --git a/p2p/nat/stun_test.go b/p2p/nat/stun_test.go index b5f429986c..6bcaf45f9f 100644 --- a/p2p/nat/stun_test.go +++ b/p2p/nat/stun_test.go @@ -18,17 +18,8 @@ package nat import ( "testing" - - "github.com/stretchr/testify/assert" ) -func TestNatStun(t *testing.T) { - nat, err := newSTUN("") - assert.NoError(t, err) - _, err = nat.ExternalIP() - assert.NoError(t, err) -} - func TestUnreachedNatServer(t *testing.T) { stun := &stun{ serverList: []string{"198.51.100.2:1234", "198.51.100.5"},