Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.

Commit

Permalink
Problem: (Fix #1435) No standardized staking event
Browse files Browse the repository at this point in the history
Solution: Refactor staking related events to standardized events
  • Loading branch information
calvinlauyh committed Apr 20, 2020
1 parent 15530f4 commit 7f810cb
Show file tree
Hide file tree
Showing 13 changed files with 1,279 additions and 188 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
## v0.4.0

### Breaking changes
* *chain-abci* [1449](https://github.com/crypto-com/chain/pull/1449): introduce staking_change event, remove RewardsDistribution and SlashValidators event
* *client-rpc* [1443](https://github.com/crypto-com/chain/pull/1443): add progress, and multi-thread to sync api
* *chain-abci* [1239](https://github.com/crypto-com/chain/pull/1239): basic versioning
* *chain-abci* [1090](https://github.com/crypto-com/chain/pull/1090): upper bounds of reward parameters changed
Expand Down
173 changes: 106 additions & 67 deletions chain-abci/src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod commit;
mod end_block;
mod query;
mod rewards;
mod staking_event;
pub mod validate_tx;

use abci::*;
Expand All @@ -16,14 +17,15 @@ pub use self::app_init::check_validators;
pub use self::app_init::{
get_validator_key, init_app_hash, BufferType, ChainNodeApp, ChainNodeState,
};
use crate::app::staking_event::StakingEvent;
use crate::app::validate_tx::ResponseWithCodeAndLog;
use crate::enclave_bridge::EnclaveProxy;
use crate::staking::RewardsDistribution;
use crate::storage::{TxAction, TxEnclaveAction, TxPublicAction};
use chain_core::common::{TendermintEventKey, TendermintEventType, Timespec};
use chain_core::init::coin::Coin;
use chain_core::state::account::{PunishmentKind, StakedStateAddress};
use chain_core::state::account::PunishmentKind;
use chain_core::state::tendermint::{BlockHeight, TendermintValidatorAddress, TendermintVotePower};
use chain_core::tx::fee::Fee;
use chain_core::tx::TxAux;
use std::convert::{TryFrom, TryInto};

Expand Down Expand Up @@ -150,40 +152,39 @@ impl<T: EnclaveProxy> abci::Application for ChainNodeApp<T> {
&evidences,
);

let mut jailing_event = Event::new();
jailing_event.field_type = TendermintEventType::JailValidators.to_string();
let mut slashing_event = Event::new();
slashing_event.field_type = TendermintEventType::SlashValidators.to_string();
let mut response = ResponseBeginBlock::new();

let rewards_pool = &mut last_state.top_level.rewards_pool;
for (addr, amount, punishment_kind) in slashes.iter() {
rewards_pool.period_bonus = (rewards_pool.period_bonus + amount)
for (
addr,
bonded_slash_amount,
unbonded_slash_amount,
punishment_kind,
maybe_jailed_until,
) in slashes.iter()
{
// slashed_amount <= bonded + unbonded <= max supply
let slash_amount = (*bonded_slash_amount + *unbonded_slash_amount)
.expect("sum of bonded and unbonded slash amount exceed maximum coin");
rewards_pool.period_bonus = (rewards_pool.period_bonus + slash_amount)
.expect("rewards pool + fee greater than max coin?");

self.rewards_pool_updated = true;
let mut kvpair = KVPair::new();
kvpair.key = TendermintEventKey::Account.into();
kvpair.value = addr.to_string().into_bytes();

let event = StakingEvent::Slash(
addr,
*bonded_slash_amount,
*unbonded_slash_amount,
*punishment_kind,
);
response.events.push(event.into());

if *punishment_kind == PunishmentKind::ByzantineFault {
jailing_event.attributes.push(kvpair.clone());
let jailed_until =
maybe_jailed_until.expect("jailed until should exist when being jailed");
let event = StakingEvent::Jail(addr, jailed_until, *punishment_kind);
response.events.push(event.into());
}
slashing_event.attributes.push(kvpair);

let mut kvpair = KVPair::new();
kvpair.key = TendermintEventKey::Slash.into();
kvpair.value = amount.to_string().into_bytes();
slashing_event.attributes.push(kvpair);
}

let mut response = ResponseBeginBlock::new();

if !jailing_event.attributes.is_empty() {
response.events.push(jailing_event);
}

if !slashing_event.attributes.is_empty() {
response.events.push(slashing_event);
}

if let Some(last_commit_info) = req.last_commit_info.as_ref() {
Expand All @@ -203,9 +204,10 @@ impl<T: EnclaveProxy> abci::Application for ChainNodeApp<T> {
}

if let Some((distributed, minted)) = self.rewards_try_distribute() {
response
.events
.push(write_reward_event(distributed, minted));
let events = generate_reward_events(distributed, minted);
for event in events.iter() {
response.events.push(event.to_owned());
}
}

response
Expand All @@ -218,13 +220,18 @@ impl<T: EnclaveProxy> abci::Application for ChainNodeApp<T> {
let mut resp = ResponseDeliverTx::new();
let result = self.process_tx(req, BufferType::Consensus);
match result {
Ok((txaux, fee, maccount)) => {
Ok((txaux, tx_action)) => {
let fee_amount = tx_action.fee().to_coin();
let tx_events = generate_tx_events(&txaux, tx_action);

resp.set_code(0);
resp.events.push(write_tx_event(&txaux, fee, maccount));

for event in tx_events.iter() {
resp.events.push(event.to_owned());
}

self.delivered_txs.push(txaux);

let fee_amount = fee.to_coin();
if fee_amount > Coin::zero() {
let rewards_pool =
&mut self.last_state.as_mut().unwrap().top_level.rewards_pool;
Expand Down Expand Up @@ -291,47 +298,79 @@ fn abci_block_height(i: i64) -> Option<BlockHeight> {
result
}

fn write_reward_event(distributed: RewardsDistribution, minted: Coin) -> Event {
let mut event = Event::new();
event.field_type = TendermintEventType::RewardsDistribution.to_string();
fn generate_reward_events(distribution: RewardsDistribution, minted: Coin) -> Vec<Event> {
let mut events: Vec<Event> = Vec::new();

for reward in distribution.iter() {
let event = StakingEvent::Reward(&reward.0, reward.1).into();

let mut kvpair = KVPair::new();
kvpair.key = TendermintEventKey::RewardsDistribution.into();
kvpair.value = serde_json::to_string(&distributed)
.expect("encode rewards result failed")
events.push(event);
}

let mut reward_event = Event::new();
reward_event.field_type = TendermintEventType::Reward.to_string();

let mut minted_kvpair = KVPair::new();
minted_kvpair.key = TendermintEventKey::CoinMinted.into();
minted_kvpair.value = serde_json::to_string(&minted)
.expect("encode coin minted failed")
.as_bytes()
.to_owned();
event.attributes.push(kvpair);
reward_event.attributes.push(minted_kvpair);

let mut kvpair = KVPair::new();
kvpair.key = TendermintEventKey::CoinMinted.into();
kvpair.value = minted.to_string().as_bytes().to_owned();
event.attributes.push(kvpair);
events.push(reward_event);

event
events
}

fn write_tx_event(txaux: &TxAux, fee: Fee, maccount: Option<StakedStateAddress>) -> abci::Event {
let mut event = Event::new();
event.field_type = TendermintEventType::ValidTransactions.to_string();

// write fee into event
let mut kvpair_fee = abci::KVPair::new();
kvpair_fee.key = TendermintEventKey::Fee.into();
kvpair_fee.value = Vec::from(format!("{}", fee.to_coin()));
event.attributes.push(kvpair_fee);

if let Some(address) = maccount {
let mut kvpair = abci::KVPair::new();
kvpair.key = TendermintEventKey::Account.into();
kvpair.value = Vec::from(format!("{}", address));
event.attributes.push(kvpair);
fn generate_tx_events(txaux: &TxAux, tx_action: TxAction) -> Vec<abci::Event> {
let mut events = Vec::new();

let mut valid_txs_event = Event::new();
valid_txs_event.field_type = TendermintEventType::ValidTransactions.to_string();

let mut fee_kvpair = abci::KVPair::new();
let fee = tx_action.fee();
fee_kvpair.key = TendermintEventKey::Fee.into();
fee_kvpair.value = Vec::from(format!("{}", fee.to_coin()));
valid_txs_event.attributes.push(fee_kvpair);

let mut txid_kvpair = abci::KVPair::new();
txid_kvpair.key = TendermintEventKey::TxId.into();
txid_kvpair.value = Vec::from(hex::encode(txaux.tx_id()).as_bytes());
valid_txs_event.attributes.push(txid_kvpair);

events.push(valid_txs_event);

let maybe_tx_staking_event = generate_tx_staking_event(tx_action);
if let Some(tx_staking_event) = maybe_tx_staking_event {
events.push(tx_staking_event);
}

let mut kvpair = abci::KVPair::new();
kvpair.key = TendermintEventKey::TxId.into();
kvpair.value = Vec::from(hex::encode(txaux.tx_id()).as_bytes());
event.attributes.push(kvpair);
events
}

event
fn generate_tx_staking_event(tx_action: TxAction) -> Option<abci::Event> {
match tx_action {
TxAction::Enclave(tx_enclave_action) => match tx_enclave_action {
TxEnclaveAction::Transfer { .. } => None,
TxEnclaveAction::Deposit { deposit, .. } => {
Some(StakingEvent::Deposit(&deposit.0, deposit.1).into())
}
TxEnclaveAction::Withdraw { withdraw, .. } => {
Some(StakingEvent::Withdraw(&withdraw.0, withdraw.1).into())
}
},
TxAction::Public(tx_public_action) => match tx_public_action {
TxPublicAction::Unbond { unbond, .. } => {
Some(StakingEvent::Unbond(&unbond.0, unbond.1).into())
}
TxPublicAction::NodeJoin(staking_address, council_node) => {
Some(StakingEvent::NodeJoin(&staking_address, council_node).into())
}
TxPublicAction::Unjail(staking_address) => {
Some(StakingEvent::Unjail(&staking_address).into())
}
},
}
}
Loading

0 comments on commit 7f810cb

Please sign in to comment.