This repository has been archived by the owner on Sep 13, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf: use inner call instead of dispatcher
- Loading branch information
KaoImin
committed
Jul 21, 2020
1 parent
2ccdf1a
commit abbdfc2
Showing
29 changed files
with
695 additions
and
654 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
use asset::types::TransferPayload; | ||
|
||
use super::*; | ||
|
||
#[rustfmt::skip] | ||
/// Bench in Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz (8 x 2200) | ||
/// 100 txs bench_execute ... bench: 11,299,912 ns/iter (+/- 3,402,276) | ||
/// 1000 txs bench::bench_execute ... bench: 101,187,934 ns/iter (+/- 26,000,469) | ||
#[bench] | ||
fn bench_execute(b: &mut Bencher) { | ||
let payload = TransferPayload { | ||
asset_id: NATIVE_ASSET_ID.clone(), | ||
to: FEE_INLET_ACCOUNT.clone(), | ||
value: 1u64, | ||
}; | ||
|
||
let req = TransactionRequest { | ||
service_name: "asset".to_string(), | ||
method: "transfer".to_string(), | ||
payload: serde_json::to_string(&payload).unwrap(), | ||
}; | ||
|
||
benchmark!(req, 1_000, b); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
timestamp = 0 | ||
prevhash = "0x44915be5b6c20b0678cf05fcddbbaa832e25d7e6ac538784cd5c24de00d47472" | ||
|
||
[[services]] | ||
name = "asset" | ||
payload = ''' | ||
{ | ||
"id": "0xf56924db538e77bb5951eb5ff0d02b88983c49c45eea30e8ae3e7234b311436c", | ||
"name": "HuobiToken", | ||
"symbol": "HT", | ||
"supply": 320000011, | ||
"precision": 100000, | ||
"issuer": "0xcff1002107105460941f797828f468667aa1a2db", | ||
"fee_account": "0x503492f4bddc731a72b8caa806183f921c284f8e", | ||
"fee": 10, | ||
"admin": "0xcff1002107105460941f797828f468667aa1a2db", | ||
"relayable": true | ||
} | ||
''' | ||
|
||
# private key of this admin: | ||
# 2b672bb959fa7a852d7259b129b65aee9c83b39f427d6f7bded1f58c4c9310c2 | ||
[[services]] | ||
name = "governance" | ||
payload = ''' | ||
{ | ||
"info": { | ||
"admin": "0xcff1002107105460941f797828f468667aa1a2db", | ||
"tx_failure_fee": 10, | ||
"tx_floor_fee": 20, | ||
"profit_deduct_rate_per_million": 3, | ||
"tx_fee_discount": [ | ||
{ | ||
"threshold": 1000, | ||
"discount_percent": 90 | ||
}, | ||
{ | ||
"threshold": 10000, | ||
"discount_percent": 70 | ||
}, | ||
{ | ||
"threshold": 100000, | ||
"discount_percent": 50 | ||
} | ||
], | ||
"miner_benefit": 10 | ||
}, | ||
"tx_fee_inlet_address": "0x503492f4bddc731a72b8caa806183f921c284f8e", | ||
"miner_profit_outlet_address": "0xcff1002107105460941f797828f468667aa1a2db", | ||
"miner_charge_map": [] | ||
} | ||
''' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
mod types; | ||
|
||
use std::cell::RefCell; | ||
use std::convert::From; | ||
use std::rc::Rc; | ||
|
||
use bytes::Bytes; | ||
use derive_more::{Display, From}; | ||
|
||
use binding_macro::{genesis, hook_after, service, tx_hook_after, tx_hook_before}; | ||
use protocol::traits::{ExecutorParams, ServiceResponse, ServiceSDK, StoreMap}; | ||
use protocol::types::{Address, Hash, ServiceContext, ServiceContextParams}; | ||
|
||
use asset::types::TransferPayload; | ||
use asset::AssetService; | ||
use types::{GovernanceInfo, InitGenesisPayload}; | ||
|
||
const INFO_KEY: &str = "admin"; | ||
const TX_FEE_INLET_KEY: &str = "fee_address"; | ||
const MINER_PROFIT_OUTLET_KEY: &str = "miner_address"; | ||
static ADMISSION_TOKEN: Bytes = Bytes::from_static(b"governance"); | ||
|
||
lazy_static::lazy_static! { | ||
pub static ref NATIVE_ASSET_ID: Hash = Hash::from_hex("0xf56924db538e77bb5951eb5ff0d02b88983c49c45eea30e8ae3e7234b311436c").unwrap(); | ||
} | ||
|
||
pub struct GovernanceService<SDK> { | ||
sdk: SDK, | ||
profits: Box<dyn StoreMap<Address, u64>>, | ||
miners: Box<dyn StoreMap<Address, Address>>, | ||
|
||
asset: AssetService<SDK>, | ||
} | ||
|
||
#[service] | ||
impl<SDK: ServiceSDK> GovernanceService<SDK> { | ||
pub fn new(mut sdk: SDK, asset: AssetService<SDK>) -> Self { | ||
let profits: Box<dyn StoreMap<Address, u64>> = sdk.alloc_or_recover_map("profit"); | ||
let miners: Box<dyn StoreMap<Address, Address>> = sdk.alloc_or_recover_map("miner_address"); | ||
Self { | ||
sdk, | ||
profits, | ||
miners, | ||
asset, | ||
} | ||
} | ||
|
||
#[genesis] | ||
fn init_genesis(&mut self, payload: InitGenesisPayload) { | ||
assert!(self.profits.is_empty()); | ||
|
||
let mut info = payload.info; | ||
info.tx_fee_discount.sort(); | ||
self.sdk.set_value(INFO_KEY.to_string(), info); | ||
self.sdk | ||
.set_value(TX_FEE_INLET_KEY.to_string(), payload.tx_fee_inlet_address); | ||
self.sdk.set_value( | ||
MINER_PROFIT_OUTLET_KEY.to_string(), | ||
payload.miner_profit_outlet_address, | ||
); | ||
|
||
for miner in payload.miner_charge_map.into_iter() { | ||
self.miners | ||
.insert(miner.address, miner.miner_charge_address); | ||
} | ||
} | ||
|
||
#[tx_hook_before] | ||
fn pledge_fee(&mut self, ctx: ServiceContext) -> ServiceResponse<String> { | ||
let info = self | ||
.sdk | ||
.get_value::<_, GovernanceInfo>(&INFO_KEY.to_owned()); | ||
let tx_fee_inlet_address = self | ||
.sdk | ||
.get_value::<_, Address>(&TX_FEE_INLET_KEY.to_owned()); | ||
|
||
if info.is_none() || tx_fee_inlet_address.is_none() { | ||
return ServiceError::MissingInfo.into(); | ||
} | ||
|
||
let info = info.unwrap(); | ||
let tx_fee_inlet_address = tx_fee_inlet_address.unwrap(); | ||
|
||
// Pledge the tx failure fee before executed the transaction. | ||
let ret = self.asset.transfer(ctx, TransferPayload { | ||
asset_id: NATIVE_ASSET_ID.clone(), | ||
to: tx_fee_inlet_address, | ||
value: info.tx_failure_fee, | ||
}); | ||
|
||
if ret.is_error() { | ||
return ServiceResponse::from_error(ret.code, ret.error_message); | ||
} | ||
|
||
ServiceResponse::from_succeed("".to_owned()) | ||
} | ||
|
||
#[tx_hook_after] | ||
fn deduct_fee(&mut self, ctx: ServiceContext) -> ServiceResponse<String> { | ||
let tx_fee_inlet_address = self | ||
.sdk | ||
.get_value::<_, Address>(&TX_FEE_INLET_KEY.to_owned()); | ||
if tx_fee_inlet_address.is_none() { | ||
return ServiceError::MissingInfo.into(); | ||
} | ||
|
||
let tx_fee_inlet_address = tx_fee_inlet_address.unwrap(); | ||
|
||
let ret = self.asset.transfer(ctx, TransferPayload { | ||
asset_id: NATIVE_ASSET_ID.clone(), | ||
to: tx_fee_inlet_address, | ||
value: 1, | ||
}); | ||
|
||
if ret.is_error() { | ||
return ServiceResponse::from_error(ret.code, ret.error_message); | ||
} | ||
|
||
ServiceResponse::from_succeed("".to_owned()) | ||
} | ||
|
||
#[hook_after] | ||
fn handle_miner_profit(&mut self, params: &ExecutorParams) { | ||
let info = self | ||
.sdk | ||
.get_value::<_, GovernanceInfo>(&INFO_KEY.to_owned()); | ||
|
||
let sender_address = self | ||
.sdk | ||
.get_value::<_, Address>(&MINER_PROFIT_OUTLET_KEY.to_owned()); | ||
|
||
if info.is_none() || sender_address.is_none() { | ||
return; | ||
} | ||
|
||
let info = info.unwrap(); | ||
let sender_address = sender_address.unwrap(); | ||
|
||
let ctx_params = ServiceContextParams { | ||
tx_hash: None, | ||
nonce: None, | ||
cycles_limit: params.cycles_limit, | ||
cycles_price: 1, | ||
cycles_used: Rc::new(RefCell::new(0)), | ||
caller: sender_address, | ||
height: params.height, | ||
service_name: String::new(), | ||
service_method: String::new(), | ||
service_payload: String::new(), | ||
extra: Some(ADMISSION_TOKEN.clone()), | ||
timestamp: params.timestamp, | ||
events: Rc::new(RefCell::new(vec![])), | ||
}; | ||
|
||
let recipient_addr = if let Some(addr) = self.miners.get(¶ms.proposer) { | ||
addr | ||
} else { | ||
params.proposer.clone() | ||
}; | ||
|
||
let payload = TransferPayload { | ||
asset_id: NATIVE_ASSET_ID.clone(), | ||
to: recipient_addr, | ||
value: info.miner_benefit, | ||
}; | ||
|
||
let _ = self | ||
.asset | ||
.transfer(ServiceContext::new(ctx_params), payload); | ||
} | ||
} | ||
|
||
#[derive(Debug, Display, From)] | ||
pub enum ServiceError { | ||
NonAuthorized, | ||
|
||
#[display(fmt = "Can not get governance info")] | ||
MissingInfo, | ||
|
||
#[display(fmt = "calc overflow")] | ||
Overflow, | ||
|
||
#[display(fmt = "query balance failed")] | ||
QueryBalance, | ||
|
||
#[display(fmt = "Parsing payload to json failed {:?}", _0)] | ||
JsonParse(serde_json::Error), | ||
} | ||
|
||
impl ServiceError { | ||
fn code(&self) -> u64 { | ||
match self { | ||
ServiceError::NonAuthorized => 101, | ||
ServiceError::JsonParse(_) => 102, | ||
ServiceError::MissingInfo => 103, | ||
ServiceError::Overflow => 104, | ||
ServiceError::QueryBalance => 105, | ||
} | ||
} | ||
} | ||
|
||
impl<T: Default> From<ServiceError> for ServiceResponse<T> { | ||
fn from(err: ServiceError) -> ServiceResponse<T> { | ||
ServiceResponse::from_error(err.code(), err.to_string()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use std::cmp::Ordering; | ||
|
||
use muta_codec_derive::RlpFixedCodec; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use protocol::fixed_codec::{FixedCodec, FixedCodecError}; | ||
use protocol::types::{Address, Bytes}; | ||
use protocol::ProtocolResult; | ||
|
||
#[derive(RlpFixedCodec, Deserialize, Serialize, Clone, Debug)] | ||
pub struct InitGenesisPayload { | ||
pub info: GovernanceInfo, | ||
pub tx_fee_inlet_address: Address, | ||
pub miner_profit_outlet_address: Address, | ||
pub miner_charge_map: Vec<MinerChargeConfig>, | ||
} | ||
|
||
#[derive(RlpFixedCodec, Deserialize, Serialize, Clone, Debug)] | ||
pub struct MinerChargeConfig { | ||
pub address: Address, | ||
pub miner_charge_address: Address, | ||
} | ||
|
||
#[derive(RlpFixedCodec, Deserialize, Serialize, Clone, Debug, Default)] | ||
pub struct GovernanceInfo { | ||
pub admin: Address, | ||
pub tx_failure_fee: u64, | ||
pub tx_floor_fee: u64, | ||
pub profit_deduct_rate_per_million: u64, | ||
pub tx_fee_discount: Vec<DiscountLevel>, | ||
pub miner_benefit: u64, | ||
} | ||
|
||
#[derive(RlpFixedCodec, Deserialize, Serialize, Clone, Debug, Default, PartialEq, Eq)] | ||
pub struct DiscountLevel { | ||
pub threshold: u64, | ||
pub discount_percent: u64, | ||
} | ||
|
||
impl PartialOrd for DiscountLevel { | ||
fn partial_cmp(&self, other: &DiscountLevel) -> Option<Ordering> { | ||
self.threshold.partial_cmp(&other.threshold) | ||
} | ||
} | ||
|
||
impl Ord for DiscountLevel { | ||
fn cmp(&self, other: &DiscountLevel) -> Ordering { | ||
self.threshold.cmp(&other.threshold) | ||
} | ||
} | ||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)] | ||
pub struct RecordProfitEvent { | ||
pub owner: Address, | ||
pub amount: u64, | ||
} | ||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)] | ||
pub struct AccumulateProfitPayload { | ||
pub address: Address, | ||
pub accumulated_profit: u64, | ||
} | ||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)] | ||
pub struct HookTransferFromPayload { | ||
pub sender: Address, | ||
pub recipient: Address, | ||
pub value: u64, | ||
pub memo: String, | ||
} |
Oops, something went wrong.