From 74078e1dc4ded63b23aee056a27a2aebbdfa9510 Mon Sep 17 00:00:00 2001 From: buddho Date: Fri, 19 Jul 2024 10:20:53 +0800 Subject: [PATCH] consensus/parlia: add GetJustifiedNumber and GetFinalizedNumber (#2591) --- cmd/jsutils/README.md | 2 +- cmd/jsutils/get_perf.js | 12 +++++++- consensus/parlia/api.go | 65 ++++++++++++++++++++++++++++++++--------- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/cmd/jsutils/README.md b/cmd/jsutils/README.md index 6c0ed5aa7..95a9afee2 100644 --- a/cmd/jsutils/README.md +++ b/cmd/jsutils/README.md @@ -33,7 +33,7 @@ node get_perf.js --rpc ${url} --startNum ${start} --endNum ${end} output as following ```bash Get the performance between [ 19470 , 19670 ) -txCountPerBlock = 3142.81 txCountTotal = 628562 BlockCount = 200 avgBlockTime = 3.005 inturnBlocksRatio = 0.975 +txCountPerBlock = 3142.81 txCountTotal = 628562 BlockCount = 200 avgBlockTime = 3.005 inturnBlocksRatio = 0.975 justifiedBlocksRatio = 0.98 txCountPerSecond = 1045.8602329450914 avgGasUsedPerBlock = 250.02062627 avgGasUsedPerSecond = 83.20153952412646 ``` diff --git a/cmd/jsutils/get_perf.js b/cmd/jsutils/get_perf.js index 83f90a33e..da0aff0e7 100644 --- a/cmd/jsutils/get_perf.js +++ b/cmd/jsutils/get_perf.js @@ -12,6 +12,7 @@ const main = async () => { let txCountTotal = 0; let gasUsedTotal = 0; let inturnBlocks = 0; + let justifiedBlocks = 0; for (let i = program.startNum; i < program.endNum; i++) { let txCount = await provider.send("eth_getBlockTransactionCountByNumber", [ ethers.toQuantity(i)]); @@ -26,6 +27,14 @@ const main = async () => { inturnBlocks += 1 } let timestamp = eval(eval(header.timestamp).toString(10)) + + let justifiedNumber = await provider.send("parlia_getJustifiedNumber", [ + ethers.toQuantity(i)]); + if (justifiedNumber + 1 == i) { + justifiedBlocks += 1 + } else { + console.log("justified unexpected", "BlockNumber =", i,"justifiedNumber",justifiedNumber) + } console.log("BlockNumber =", i, "mod =", i%4, "miner =", header.miner , "difficulty =", difficulty, "txCount =", ethers.toNumber(txCount), "gasUsed", gasUsed, "timestamp", timestamp) } @@ -41,13 +50,14 @@ const main = async () => { let timeCost = endTime - startTime 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); + console.log("txCountPerBlock =", txCountPerBlock, "txCountTotal =", txCountTotal, "BlockCount =", blockCount, "avgBlockTime =", avgBlockTime, "inturnBlocksRatio =", inturnBlocksRatio, "justifiedBlocksRatio =", justifiedBlocksRatio); console.log("txCountPerSecond =", tps, "avgGasUsedPerBlock =", avgGasUsedPerBlock, "avgGasUsedPerSecond =", avgGasUsedPerSecond); }; diff --git a/consensus/parlia/api.go b/consensus/parlia/api.go index 77d58ac6b..0527a1c6a 100644 --- a/consensus/parlia/api.go +++ b/consensus/parlia/api.go @@ -31,13 +31,7 @@ type API struct { // GetSnapshot retrieves the state snapshot at a given block. func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) { - // Retrieve the requested block number (or current if none requested) - var header *types.Header - if number == nil || *number == rpc.LatestBlockNumber { - header = api.chain.CurrentHeader() - } else { - header = api.chain.GetHeaderByNumber(uint64(number.Int64())) - } + header := api.getHeader(number) // Ensure we have an actually valid block and return its snapshot if header == nil { return nil, errUnknownBlock @@ -56,13 +50,7 @@ func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) { // GetValidators retrieves the list of validators at the specified block. func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) { - // Retrieve the requested block number (or current if none requested) - var header *types.Header - if number == nil || *number == rpc.LatestBlockNumber { - header = api.chain.CurrentHeader() - } else { - header = api.chain.GetHeaderByNumber(uint64(number.Int64())) - } + header := api.getHeader(number) // Ensure we have an actually valid block and return the validators from its snapshot if header == nil { return nil, errUnknownBlock @@ -86,3 +74,52 @@ func (api *API) GetValidatorsAtHash(hash common.Hash) ([]common.Address, error) } return snap.validators(), nil } + +func (api *API) GetJustifiedNumber(number *rpc.BlockNumber) (uint64, error) { + header := api.getHeader(number) + // Ensure we have an actually valid block and return the validators from its snapshot + if header == nil { + return 0, errUnknownBlock + } + snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) + if err != nil || snap.Attestation == nil { + return 0, err + } + return snap.Attestation.TargetNumber, nil +} + +func (api *API) GetFinalizedNumber(number *rpc.BlockNumber) (uint64, error) { + header := api.getHeader(number) + // Ensure we have an actually valid block and return the validators from its snapshot + if header == nil { + return 0, errUnknownBlock + } + snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil) + if err != nil || snap.Attestation == nil { + return 0, err + } + return snap.Attestation.SourceNumber, nil +} + +func (api *API) getHeader(number *rpc.BlockNumber) (header *types.Header) { + currentHeader := api.chain.CurrentHeader() + + if number == nil || *number == rpc.LatestBlockNumber { + header = currentHeader // current if none requested + } else if *number == rpc.SafeBlockNumber { + justifiedNumber, _, err := api.parlia.GetJustifiedNumberAndHash(api.chain, []*types.Header{currentHeader}) + if err != nil { + return nil + } + header = api.chain.GetHeaderByNumber(justifiedNumber) + } else if *number == rpc.FinalizedBlockNumber { + header = api.parlia.GetFinalizedHeader(api.chain, currentHeader) + } else if *number == rpc.PendingBlockNumber { + return nil // no pending blocks on bsc + } else if *number == rpc.EarliestBlockNumber { + header = api.chain.GetHeaderByNumber(0) + } else { + header = api.chain.GetHeaderByNumber(uint64(number.Int64())) + } + return +}