Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cli] add command to show tps for given epoch #1617

Merged
merged 10 commits into from
Nov 13, 2020
9 changes: 9 additions & 0 deletions chain/api/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use anyhow::Result;
use starcoin_crypto::HashValue;
use starcoin_state_api::{ChainState, ChainStateReader};
use starcoin_types::stress_test::TPS;
use starcoin_types::{
block::{Block, BlockHeader, BlockInfo, BlockNumber},
transaction::{Transaction, TransactionInfo},
Expand Down Expand Up @@ -42,6 +43,14 @@ pub trait ChainReader {
reverse: bool,
max_size: usize,
) -> Result<Vec<HashValue>>;
fn get_block_info_by_number(&self, number: BlockNumber) -> Result<Option<BlockInfo>>;
fn total_txns_in_blocks(
&self,
start_number: BlockNumber,
end_number: BlockNumber,
) -> Result<u64>;
/// Get tps for an epoch. The epoch includes the block given by `number`. If `number` is absent, return tps for the latest epoch
fn tps(&self, number: Option<BlockNumber>) -> Result<TPS>;
}

pub trait ChainWriter {
Expand Down
3 changes: 3 additions & 0 deletions chain/api/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use anyhow::Result;
use starcoin_crypto::HashValue;
use starcoin_service_registry::ServiceRequest;
use starcoin_types::stress_test::TPS;
use starcoin_types::{
block::{Block, BlockHeader, BlockInfo, BlockNumber, BlockState, BlockTemplate},
contract_event::ContractEvent,
Expand Down Expand Up @@ -49,6 +50,7 @@ pub enum ChainRequest {
max_size: usize,
},
GetBlocks(Vec<HashValue>),
TPS(Option<BlockNumber>),
}

impl ServiceRequest for ChainRequest {
Expand Down Expand Up @@ -78,4 +80,5 @@ pub enum ChainResponse {
EpochInfo(EpochInfo),
GlobalTime(GlobalTimeOnChain),
HashVec(Vec<HashValue>),
TPS(TPS),
}
12 changes: 12 additions & 0 deletions chain/api/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use starcoin_types::contract_event::{ContractEvent, ContractEventInfo};
use starcoin_types::filter::Filter;
use starcoin_types::peer_info::PeerId;
use starcoin_types::startup_info::ChainInfo;
use starcoin_types::stress_test::TPS;
use starcoin_types::transaction::{Transaction, TransactionInfo};
use starcoin_types::{
block::{Block, BlockHeader, BlockInfo, BlockNumber},
Expand Down Expand Up @@ -58,6 +59,7 @@ pub trait ReadableChainService {
reverse: bool,
max_size: usize,
) -> Result<Vec<HashValue>>;
fn tps(&self, number: Option<BlockNumber>) -> Result<TPS>;
}

/// Writeable block chain service trait
Expand Down Expand Up @@ -115,6 +117,7 @@ pub trait ChainAsyncService:
reverse: bool,
max_size: usize,
) -> Result<Vec<HashValue>>;
async fn tps(&self, number: Option<BlockNumber>) -> Result<TPS>;
}

#[async_trait::async_trait]
Expand Down Expand Up @@ -382,4 +385,13 @@ where
bail!("get_block_ids invalid response")
}
}

async fn tps(&self, number: Option<BlockNumber>) -> Result<TPS> {
let response = self.send(ChainRequest::TPS(number)).await??;
if let ChainResponse::TPS(tps) = response {
Ok(tps)
} else {
bail!("get tps error.")
}
}
}
6 changes: 6 additions & 0 deletions chain/service/src/chain_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use starcoin_service_registry::{
use starcoin_storage::{BlockStore, Storage, Store};
use starcoin_types::contract_event::ContractEventInfo;
use starcoin_types::filter::Filter;
use starcoin_types::stress_test::TPS;
use starcoin_types::system_events::NewHeadBlock;
use starcoin_types::{
block::{Block, BlockHeader, BlockInfo, BlockNumber, BlockState},
Expand Down Expand Up @@ -178,6 +179,7 @@ impl ServiceHandler<Self, ChainRequest> for ChainReaderService {
ChainRequest::GetBlocks(ids) => {
Ok(ChainResponse::BlockOptionVec(self.inner.get_blocks(ids)?))
}
ChainRequest::TPS(number) => Ok(ChainResponse::TPS(self.inner.tps(number)?)),
}
}
}
Expand Down Expand Up @@ -341,6 +343,10 @@ impl ReadableChainService for ChainReaderServiceInner {
) -> Result<Vec<HashValue>> {
self.master.get_block_ids(start_number, reverse, max_size)
}

fn tps(&self, number: Option<BlockNumber>) -> Result<TPS> {
self.master.tps(number)
}
}

#[cfg(test)]
Expand Down
59 changes: 59 additions & 0 deletions chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use starcoin_types::{
},
contract_event::ContractEvent,
error::BlockExecutorError,
stress_test::TPS,
transaction::{SignedUserTransaction, Transaction, TransactionInfo},
U256,
};
Expand Down Expand Up @@ -511,6 +512,64 @@ impl ChainReader for BlockChain {
self.block_accumulator
.get_leaves(start_number, reverse, max_size)
}

fn get_block_info_by_number(&self, number: BlockNumber) -> Result<Option<BlockInfo>> {
let block = self
.get_block_by_number(number)?
.ok_or_else(|| format_err!("Can not find block by number {}", number))?;

self.get_block_info(Some(block.id()))
}

fn total_txns_in_blocks(
&self,
start_number: BlockNumber,
end_number: BlockNumber,
) -> Result<u64> {
let txn_num_in_start_block = self
.get_block_info_by_number(start_number)?
.ok_or_else(|| format_err!("Can not find block info by number {}", start_number))?
.get_txn_accumulator_info()
.num_leaves;
let txn_num_in_end_block = self
.get_block_info_by_number(end_number)?
.ok_or_else(|| format_err!("Can not find block info by number {}", end_number))?
.get_txn_accumulator_info()
.num_leaves;

Ok(txn_num_in_end_block - txn_num_in_start_block)
}

/// Get tps for an epoch, the epoch includes the block given by `number`.
/// If `number` is absent, return tps for the latest epoch
fn tps(&self, number: Option<BlockNumber>) -> Result<TPS> {
let epoch_info = self.get_epoch_info_by_number(number)?;
let start_block_number = epoch_info.start_block_number();
let end_block_number = epoch_info.end_block_number();
let current_block_number = self.current_header().number();
let start_block_time = self
.get_header_by_number(start_block_number)?
.ok_or_else(|| {
format_err!("Can not find block header by number {}", start_block_number)
})?
.timestamp();
let result = if end_block_number < current_block_number {
let end_block_time = self
.get_header_by_number(end_block_number)?
.ok_or_else(|| {
format_err!("Can not find block header by number {}", end_block_number)
})?
.timestamp();
let duration = (end_block_time - start_block_time) / 1000;
let total_txns = self.total_txns_in_blocks(start_block_number, end_block_number)?;
TPS::new(total_txns, duration, total_txns / duration)
} else {
let duration = (self.current_header().timestamp() - start_block_time) / 1000;
let total_txns = self.total_txns_in_blocks(start_block_number, current_block_number)?;
TPS::new(total_txns, duration, total_txns / duration)
};
Ok(result)
}
}

impl BlockChain {
Expand Down
2 changes: 2 additions & 0 deletions cmd/starcoin/src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod get_txn_cmd;
mod get_txn_info_cmd;
mod list_block_cmd;
mod show_cmd;
mod tps;

pub use epoch_info::*;
pub use get_block_by_number_cmd::*;
Expand All @@ -24,3 +25,4 @@ pub use get_txn_cmd::*;
pub use get_txn_info_cmd::*;
pub use list_block_cmd::*;
pub use show_cmd::*;
pub use tps::*;
40 changes: 40 additions & 0 deletions cmd/starcoin/src/chain/tps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) The Starcoin Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::cli_state::CliState;
use crate::StarcoinOpt;
use anyhow::Result;
use scmd::{CommandAction, ExecContext};
use starcoin_types::block::BlockNumber;
use starcoin_types::stress_test::TPS;
use structopt::StructOpt;

/// Get tps for an epoch.
#[derive(Debug, StructOpt)]
#[structopt(name = "tps")]
pub struct TPSOpt {
#[structopt(
name = "number",
long,
short = "n",
help = "block number, if absent return tps for the latest epoch"
)]
number: Option<BlockNumber>,
}

pub struct TPSCommand;

impl CommandAction for TPSCommand {
type State = CliState;
type GlobalOpt = StarcoinOpt;
type Opt = TPSOpt;
type ReturnItem = TPS;

fn run(
&self,
ctx: &ExecContext<Self::State, Self::GlobalOpt, Self::Opt>,
) -> Result<Self::ReturnItem> {
let client = ctx.state().client();
client.tps(ctx.opt().number)
}
}
3 changes: 2 additions & 1 deletion cmd/starcoin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ pub fn add_command(
.subcommand(chain::GetEventsCommand)
.subcommand(chain::GetBlockCommand)
.subcommand(chain::EpochInfoCommand)
.subcommand(chain::GetEpochInfoByNumberCommand),
.subcommand(chain::GetEpochInfoByNumberCommand)
.subcommand(chain::TPSCommand),
)
.command(
Command::with_name("dev")
Expand Down
5 changes: 5 additions & 0 deletions rpc/api/src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use starcoin_crypto::HashValue;
use starcoin_types::block::{Block, BlockNumber};
use starcoin_types::contract_event::ContractEvent;
use starcoin_types::startup_info::ChainInfo;
use starcoin_types::stress_test::TPS;
use starcoin_types::transaction::{Transaction, TransactionInfo};
use starcoin_vm_types::on_chain_resource::{EpochInfo, GlobalTimeOnChain};

Expand Down Expand Up @@ -75,4 +76,8 @@ pub trait ChainApi {
/// Get chain blocks by number
#[rpc(name = "chain.get_block_by_uncle")]
fn get_block_by_uncle(&self, uncle_id: HashValue) -> FutureResult<Option<Block>>;

/// Get tps by block number.
#[rpc(name = "chain.tps")]
fn tps(&self, number: Option<BlockNumber>) -> FutureResult<TPS>;
}
6 changes: 6 additions & 0 deletions rpc/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use starcoin_types::startup_info::ChainInfo;
use starcoin_types::transaction::{
RawUserTransaction, SignedUserTransaction, Transaction, TransactionInfo, TransactionOutput,
};
use starcoin_types::stress_test::TPS;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;
Expand Down Expand Up @@ -477,6 +478,11 @@ impl RpcClient {
.map_err(map_err)
}

pub fn tps(&self, number: Option<BlockNumber>) -> anyhow::Result<TPS> {
self.call_rpc_blocking(|inner| async move { inner.chain_client.tps(number).compat().await })
.map_err(map_err)
}

pub fn get_global_time_by_number(
&self,
number: BlockNumber,
Expand Down
8 changes: 8 additions & 0 deletions rpc/server/src/module/chain_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use starcoin_traits::ChainAsyncService;
use starcoin_types::block::{Block, BlockNumber};
use starcoin_types::contract_event::ContractEvent;
use starcoin_types::startup_info::ChainInfo;
use starcoin_types::stress_test::TPS;
use starcoin_types::transaction::{Transaction, TransactionInfo};
use starcoin_vm_types::on_chain_resource::{EpochInfo, GlobalTimeOnChain};
use std::convert::TryInto;
Expand Down Expand Up @@ -187,4 +188,11 @@ where

Box::new(fut.boxed().compat())
}

fn tps(&self, number: Option<BlockNumber>) -> FutureResult<TPS> {
let service = self.service.clone();
let fut = async move { service.tps(number).await };

Box::new(fut.boxed().map_err(map_err).compat())
}
}
2 changes: 2 additions & 0 deletions types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,5 @@ pub static PROTOCOLS: Lazy<Vec<Cow<'static, [u8]>>> = Lazy::new(|| {
BLOCK_PROTOCOL_NAME.into(),
]
});

pub mod stress_test;
18 changes: 18 additions & 0 deletions types/src/stress_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use serde::{Deserialize, Serialize};

#[derive(Eq, PartialEq, Deserialize, Serialize, Clone, Debug)]
pub struct TPS {
total_txns: u64,
duration: u64,
tps: u64,
}

impl TPS {
pub fn new(total_txns: u64, duration: u64, tps: u64) -> Self {
Self {
total_txns,
duration,
tps,
}
}
}