Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ rlp = { path = "../util/rlp" }
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
rand = "0.6.1"
rustc-hex = "1.0"
rustc-serialize = "0.3"
time = "0.1"
tokio-core = "0.1.17"
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
Expand Down
2 changes: 2 additions & 0 deletions rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ extern crate lazy_static;
extern crate log;
extern crate parking_lot;
extern crate primitives;
extern crate rand;
extern crate rlp;
extern crate rustc_hex;
extern crate rustc_serialize;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate time;
extern crate tokio_core;

#[macro_use]
Expand Down
263 changes: 258 additions & 5 deletions rpc/src/v1/impls/devel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,37 @@
use std::net::SocketAddr;
use std::ops::Deref;
use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
use std::vec::Vec;

use ccore::{DatabaseClient, MinerService, MiningBlockChainClient, COL_STATE};
use ccore::{
BlockId, DatabaseClient, EngineClient, EngineInfo, MinerService, MiningBlockChainClient, SignedTransaction,
COL_STATE,
};
use cjson::bytes::Bytes;
use ckey::{Address, KeyPair, Private};
use cnetwork::IntoSocketAddr;
use cstate::AssetSchemeAddress;
use csync::BlockSyncInfo;
use ctypes::transaction::{
Action, AssetMintOutput, AssetOutPoint, AssetTransferInput, AssetTransferOutput, Transaction,
};
use jsonrpc_core::Result;
use kvdb::KeyValueDB;
use primitives::H256;
use primitives::{H160, H256};
use rand::rngs::SmallRng;
use rand::{Rng, SeedableRng};
use rlp::UntrustedRlp;
use time::PreciseTime;

use super::super::errors;
use super::super::traits::Devel;
use super::super::types::{TPSTestOption, TPSTestSetting};

pub struct DevelClient<C, M, B>
where
C: DatabaseClient + MiningBlockChainClient,
C: DatabaseClient + EngineInfo + EngineClient + MiningBlockChainClient,
M: MinerService,
B: BlockSyncInfo, {
client: Arc<C>,
Expand All @@ -44,7 +58,7 @@ where

impl<C, M, B> DevelClient<C, M, B>
where
C: DatabaseClient + MiningBlockChainClient,
C: DatabaseClient + EngineInfo + EngineClient + MiningBlockChainClient,
M: MinerService,
B: BlockSyncInfo,
{
Expand All @@ -61,7 +75,7 @@ where

impl<C, M, B> Devel for DevelClient<C, M, B>
where
C: DatabaseClient + MiningBlockChainClient + 'static,
C: DatabaseClient + EngineInfo + EngineClient + MiningBlockChainClient + 'static,
M: MinerService + 'static,
B: BlockSyncInfo + 'static,
{
Expand Down Expand Up @@ -97,4 +111,243 @@ where
Ok(Vec::new())
}
}

fn test_tps(&self, setting: TPSTestSetting) -> Result<f64> {
let mint_fee = self.client.common_params().min_asset_mint_cost;
let transfer_fee = self.client.common_params().min_asset_transfer_cost;
let pay_fee = self.client.common_params().min_pay_transaction_cost;
let network_id = self.client.common_params().network_id;
let shard_id = 0;

// NOTE: Assuming solo network
let genesis_secret: Private = "ede1d4ccb4ec9a8bbbae9a13db3f4a7b56ea04189be86ac3a6a439d9a0a1addd".into();
let genesis_keypair = KeyPair::from_private(genesis_secret).map_err(errors::transaction_core)?;

let base_seq = self.client.seq(&genesis_keypair.address(), BlockId::Latest).unwrap();
let lock_script_hash_empty_sig = H160::from("b042ad154a3359d276835c903587ebafefea22af");

// Helper macros
macro_rules! pay_tx {
($seq:expr, $address:expr) => {
pay_tx!($seq, $address, 1)
};
($seq:expr, $address:expr, $quantity: expr) => {
Transaction {
seq: $seq,
fee: pay_fee,
network_id,
action: Action::Pay {
receiver: $address,
quantity: $quantity,
},
}
};
}

macro_rules! mint_tx {
($seq:expr, $supply:expr) => {
Transaction {
seq: $seq,
fee: mint_fee,
network_id,
action: Action::MintAsset {
network_id,
shard_id,
metadata: format!("{:?}", Instant::now()),
approver: None,
administrator: None,
allowed_script_hashes: vec![],
output: Box::new(AssetMintOutput {
lock_script_hash: lock_script_hash_empty_sig,
parameters: vec![],
supply: Some($supply),
}),
approvals: vec![],
},
}
};
}

macro_rules! transfer_tx {
($seq:expr, $inputs:expr, $outputs:expr) => {
Transaction {
seq: $seq,
fee: transfer_fee,
network_id,
action: Action::TransferAsset {
network_id,
burns: vec![],
inputs: $inputs,
outputs: $outputs,
orders: vec![],
metadata: "".to_string(),
approvals: vec![],
},
}
};
}

macro_rules! transfer_input {
($hash:expr, $index:expr, $asset_type:expr, $quantity:expr) => {
AssetTransferInput {
prev_out: AssetOutPoint {
tracker: $hash,
index: $index,
asset_type: $asset_type,
quantity: $quantity,
},
timelock: None,
lock_script: vec![0x30, 0x01],
unlock_script: vec![],
}
};
}

macro_rules! transfer_output {
($asset_type:expr, $quantity:expr) => {
AssetTransferOutput {
lock_script_hash: lock_script_hash_empty_sig,
parameters: vec![],
asset_type: $asset_type,
quantity: $quantity,
}
};
}

// Helper functions
fn sign_tx(tx: Transaction, key_pair: &KeyPair) -> SignedTransaction {
SignedTransaction::new_with_sign(tx, key_pair.private())
}

fn send_tx<C, M>(tx: Transaction, client: &C, key_pair: &KeyPair, miner: &M) -> Result<H256>
where
C: MiningBlockChainClient,
M: MinerService, {
let signed = SignedTransaction::new_with_sign(tx, key_pair.private());
let hash = signed.hash();
miner.import_own_transaction(client, signed).map_err(errors::transaction_core)?;
Ok(hash)
}

fn asset_type(tx: &Transaction, shard_id: u16) -> H256 {
AssetSchemeAddress::new(tx.tracker().unwrap(), shard_id).into()
}

fn tps(count: u64, start_time: PreciseTime, end_time: PreciseTime) -> f64 {
f64::from(count as u32) * 1000.0_f64 / f64::from(start_time.to(end_time).num_milliseconds() as i32)
}

// Main
let count = setting.count;
let mut rng = SmallRng::seed_from_u64(setting.seed);
let transactions = match setting.option {
TPSTestOption::PayOnly => {
let mut transactions = Vec::with_capacity(count as usize);
for i in 0..count {
let address = Address::random();
let tx = sign_tx(pay_tx!(base_seq + i, address), &genesis_keypair);
transactions.push(tx);
}
transactions
}
TPSTestOption::TransferSingle => {
let mint_tx = mint_tx!(base_seq, 1);
let asset_type = asset_type(&mint_tx, shard_id);
let mut previous_tracker = mint_tx.tracker().unwrap();
send_tx(mint_tx, &*self.client, &genesis_keypair, &*self.miner)?;

let mut transactions = Vec::with_capacity(count as usize);
for i in 0..count {
let transfer_tx = transfer_tx!(
base_seq + i + 1,
vec![transfer_input!(previous_tracker, 0, asset_type, 1)],
vec![transfer_output!(asset_type, 1)]
);
previous_tracker = transfer_tx.tracker().unwrap();
let tx = sign_tx(transfer_tx, &genesis_keypair);
transactions.push(tx);
}
transactions
}
TPSTestOption::TransferMultiple => {
let number_of_in_out: usize = 10;
let mint_tx = mint_tx!(base_seq, number_of_in_out as u64);
let asset_type = asset_type(&mint_tx, shard_id);
let mut previous_tracker = mint_tx.tracker().unwrap();
send_tx(mint_tx, &*self.client, &genesis_keypair, &*self.miner)?;

fn create_inputs(
transaction_hash: H256,
asset_type: H256,
total_amount: u64,
count: usize,
) -> Vec<AssetTransferInput> {
let mut inputs = Vec::new();
let amount = total_amount / (count as u64);
for i in 0..(count as usize) {
let input = transfer_input!(transaction_hash, i, asset_type, amount);
inputs.push(input);
}
inputs
}

let mut transactions = Vec::with_capacity(count as usize);
for i in 0..count {
let num_input = 1 + 9 * (i > 0) as usize;
let inputs = create_inputs(previous_tracker, asset_type, number_of_in_out as u64, num_input);
let outputs = vec![transfer_output!(asset_type, 1); number_of_in_out];

let transfer_tx = transfer_tx!(base_seq + i + 1, inputs, outputs);
previous_tracker = transfer_tx.tracker().unwrap();
transactions.push(sign_tx(transfer_tx, &genesis_keypair));
}
transactions
}
TPSTestOption::PayOrTransfer => {
let mint_tx = mint_tx!(base_seq, 1);
let asset_type = asset_type(&mint_tx, shard_id);
let mut previous_tracker = mint_tx.tracker().unwrap();
send_tx(mint_tx, &*self.client, &genesis_keypair, &*self.miner)?;

let mut transactions = Vec::with_capacity(count as usize);
for i in 0..count {
// 0. Payment
let tx = if rng.gen::<bool>() {
let address = Address::random();
pay_tx!(base_seq + i + 1, address)
}
// 1. Transfer
else {
let transfer_tx = transfer_tx!(
base_seq + i + 1,
vec![transfer_input!(previous_tracker, 0, asset_type, 1)],
vec![transfer_output!(asset_type, 1)]
);
previous_tracker = transfer_tx.tracker().unwrap();
transfer_tx
};
let tx = sign_tx(tx, &genesis_keypair);
transactions.push(tx);
}
transactions
}
};

let last_hash = transactions.last().unwrap().hash();
let mut start_time = None;

for tx in transactions.into_iter().rev() {
if tx.seq == base_seq {
start_time = Some(PreciseTime::now());
}
self.miner.import_own_transaction(&*self.client, tx).map_err(errors::transaction_core)?;
}
while !self.client.is_pending_queue_empty() {
thread::sleep(Duration::from_millis(50));
}
while self.client.parcel_invoice(&last_hash.into()).is_none() {}

let end_time = PreciseTime::now();
Ok(tps(count, start_time.unwrap(), end_time))
}
}
5 changes: 5 additions & 0 deletions rpc/src/v1/traits/devel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use cjson::bytes::Bytes;
use jsonrpc_core::Result;
use primitives::H256;

use super::super::types::TPSTestSetting;

build_rpc_trait! {
pub trait Devel {
# [rpc(name = "devel_getStateTrieKeys")]
Expand All @@ -36,5 +38,8 @@ build_rpc_trait! {

# [rpc(name = "devel_getBlockSyncPeers")]
fn get_block_sync_peers(&self) -> Result<Vec<SocketAddr>>;

# [rpc(name = "devel_testTPS")]
fn test_tps(&self, TPSTestSetting) -> Result<f64>;
}
}
Loading