diff --git a/core/res/solo.json b/core/res/solo.json index 7f05dee7c6..91bdbb74ae 100644 --- a/core/res/solo.json +++ b/core/res/solo.json @@ -3,7 +3,6 @@ "engine": { "solo": { "params": { - "hit": {}, "genesisStakes": { "tccqxphelyu2n73ekpewrsyj0256wjhn2aqds9xrrrg": 70000, "tccq9qvruafmf9vegjhkl0ruunkwp0d4lc8fgxknzh5": 20000, diff --git a/core/src/block.rs b/core/src/block.rs index 865486128d..39eec848af 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -22,7 +22,7 @@ use crate::stake; use crate::transaction::{UnverifiedTransaction, VerifiedTransaction}; use ccrypto::BLAKE_NULL_RLP; use ckey::Address; -use cstate::{FindActionHandler, StateDB, StateError, StateWithCache, TopLevelState}; +use cstate::{FindStakeHandler, StateDB, StateError, StateWithCache, TopLevelState}; use ctypes::errors::HistoryError; use ctypes::header::{Header, Seal}; use ctypes::util::unexpected::Mismatch; @@ -147,7 +147,7 @@ impl<'x> OpenBlock<'x> { } /// Push a transaction into the block. - pub fn push_transaction( + pub fn push_transaction( &mut self, tx: VerifiedTransaction, h: Option, @@ -188,7 +188,7 @@ impl<'x> OpenBlock<'x> { } /// Push transactions onto the block. - pub fn push_transactions( + pub fn push_transactions( &mut self, transactions: &[VerifiedTransaction], client: &C, @@ -215,13 +215,6 @@ impl<'x> OpenBlock<'x> { warn!("Encountered error on closing the block: {}", e); return Err(e) } - let header = self.block.header().clone(); - for handler in self.engine.action_handlers() { - handler.on_close_block(self.block.state_mut(), &header).map_err(|e| { - warn!("Encountered error in {}::on_close_block", handler.name()); - e - })?; - } let state_root = self.block.state.commit().map_err(|e| { warn!("Encountered error on state commit: {}", e); e @@ -359,7 +352,7 @@ impl<'x> IsBlock for ClosedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact( +pub fn enact( header: &Header, transactions: &[VerifiedTransaction], engine: &dyn CodeChainEngine, diff --git a/core/src/client/client.rs b/core/src/client/client.rs index e3aa8591a8..e1539b0b54 100644 --- a/core/src/client/client.rs +++ b/core/src/client/client.rs @@ -37,7 +37,7 @@ use crate::MemPoolMinFees; use cdb::{new_journaldb, Algorithm, AsHashDB}; use cio::IoChannel; use ckey::{Address, NetworkId, PlatformAddress}; -use cstate::{ActionHandler, FindActionHandler, StateDB, StateResult, TopLevelState, TopStateView}; +use cstate::{FindStakeHandler, StakeHandler, StateDB, StateResult, TopLevelState, TopStateView}; use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken}; use ctypes::header::Header; use ctypes::transaction::ShardTransaction; @@ -705,9 +705,9 @@ impl MiningBlockChainClient for Client { } } -impl FindActionHandler for Client { - fn find_action_handler_for(&self, id: u64) -> Option<&dyn ActionHandler> { - self.engine.find_action_handler_for(id) +impl FindStakeHandler for Client { + fn stake_handler(&self) -> Option<&dyn StakeHandler> { + self.engine.stake_handler() } } diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index 6c801de022..1560b18cce 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -38,7 +38,7 @@ use crate::transaction::{LocalizedTransaction, PendingVerifiedTransactions, Veri use crate::types::{BlockId, BlockStatus, TransactionId, VerificationQueueInfo as BlockQueueInfo}; use cdb::DatabaseError; use ckey::{Address, NetworkId, PlatformAddress}; -use cstate::{FindActionHandler, StateResult, TopLevelState, TopStateView}; +use cstate::{FindStakeHandler, StateResult, TopLevelState, TopStateView}; use ctypes::header::Header; use ctypes::transaction::ShardTransaction; use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, TxHash}; @@ -247,7 +247,7 @@ pub trait BlockProducer { } /// Extended client interface used for mining -pub trait MiningBlockChainClient: BlockChainClient + BlockProducer + FindActionHandler { +pub trait MiningBlockChainClient: BlockChainClient + BlockProducer + FindStakeHandler { /// Returns malicious users who sent failing transactions. fn get_malicious_users(&self) -> Vec
; diff --git a/core/src/client/test_client.rs b/core/src/client/test_client.rs index ff0c05f71e..49bbe7c197 100644 --- a/core/src/client/test_client.rs +++ b/core/src/client/test_client.rs @@ -51,7 +51,7 @@ use ckey::{ Generator, KeyPairTrait, NetworkId, PlatformAddress, Random, }; use cstate::tests::helpers::empty_top_state_with_metadata; -use cstate::{FindActionHandler, StateDB, TopLevelState}; +use cstate::{FindStakeHandler, StateDB, TopLevelState}; use ctimer::{TimeoutHandler, TimerToken}; use ctypes::header::Header; use ctypes::transaction::{Action, Transaction}; @@ -578,7 +578,7 @@ impl TimeoutHandler for TestBlockChainClient { fn on_timeout(&self, _token: TimerToken) {} } -impl FindActionHandler for TestBlockChainClient {} +impl FindStakeHandler for TestBlockChainClient {} impl super::EngineClient for TestBlockChainClient { fn update_sealing(&self, parent_block: BlockId, allow_empty_block: bool) { diff --git a/core/src/consensus/mod.rs b/core/src/consensus/mod.rs index 5e42e06b07..405601387c 100644 --- a/core/src/consensus/mod.rs +++ b/core/src/consensus/mod.rs @@ -41,7 +41,7 @@ use crate::views::HeaderView; use crate::Client; use ckey::{Address, Signature}; use cnetwork::NetworkService; -use cstate::{ActionHandler, StateDB, StateResult}; +use cstate::{StakeHandler, StateDB, StateResult}; use ctypes::errors::SyntaxError; use ctypes::transaction::Action; use ctypes::util::unexpected::{Mismatch, OutOfBounds}; @@ -233,12 +233,8 @@ pub trait ConsensusEngine: Sync + Send { true } - fn action_handlers(&self) -> &[Arc] { - &[] - } - - fn find_action_handler_for(&self, id: u64) -> Option<&dyn ActionHandler> { - self.action_handlers().iter().find(|handler| handler.handler_id() == id).map(AsRef::as_ref) + fn stake_handler(&self) -> Option<&dyn StakeHandler> { + None } fn possible_authors(&self, block_number: Option) -> Result>, EngineError>; @@ -327,13 +323,12 @@ pub trait CodeChainEngine: ConsensusEngine { common_params: &CommonParams, ) -> Result<(), Error> { if let Action::Custom { - handler_id, bytes, + .. } = &tx.transaction().action { - let handler = self - .find_action_handler_for(*handler_id) - .ok_or_else(|| SyntaxError::InvalidCustomAction(format!("{} is an invalid handler id", handler_id)))?; + let handler = + self.stake_handler().ok_or_else(|| SyntaxError::InvalidCustomAction("no valid handler".to_string()))?; handler.verify(bytes, common_params)?; } self.machine().verify_transaction_with_params(tx, common_params) diff --git a/core/src/consensus/solo/mod.rs b/core/src/consensus/solo/mod.rs index c9b2ea5e43..a9b122d1eb 100644 --- a/core/src/consensus/solo/mod.rs +++ b/core/src/consensus/solo/mod.rs @@ -26,37 +26,33 @@ use crate::codechain_machine::CodeChainMachine; use crate::consensus::{EngineError, EngineType}; use crate::error::Error; use ckey::Address; -use cstate::{ActionHandler, HitHandler}; +use cstate::{StakeHandler, StateDB, StateResult, StateWithCache, TopLevelState}; use ctypes::{BlockHash, Header}; use parking_lot::RwLock; +use primitives::H256; +use std::collections::HashMap; use std::sync::{Arc, Weak}; /// A consensus engine which does not provide any consensus mechanism. pub struct Solo { client: RwLock>>, machine: CodeChainMachine, - action_handlers: Vec>, snapshot_notify_sender: Arc>>, + genesis_stakes: HashMap, + stake: stake::Stake, } impl Solo { /// Returns new instance of Solo over the given state machine. pub fn new(params: SoloParams, machine: CodeChainMachine) -> Self { - let mut action_handlers: Vec> = Vec::new(); - if params.enable_hit_handler { - action_handlers.push(Arc::new(HitHandler::new())); - } - action_handlers.push(Arc::new(stake::Stake::new( - params.genesis_stakes, - Default::default(), - Default::default(), - ))); + let genesis_stakes = params.genesis_stakes; Solo { client: Default::default(), machine, - action_handlers, snapshot_notify_sender: Arc::new(RwLock::new(None)), + genesis_stakes, + stake: stake::Stake::default(), } } @@ -130,13 +126,19 @@ impl ConsensusEngine for Solo { } } - fn action_handlers(&self) -> &[Arc] { - &self.action_handlers + fn stake_handler(&self) -> Option<&dyn StakeHandler> { + Some(&self.stake) } fn possible_authors(&self, _block_number: Option) -> Result>, EngineError> { Ok(None) } + + fn initialize_genesis_state(&self, db: StateDB, root: H256) -> StateResult<(StateDB, H256)> { + let mut top_level = TopLevelState::from_existing(db, root)?; + stake::init(&mut top_level, self.genesis_stakes.clone(), Default::default(), Default::default())?; + Ok(top_level.commit_and_into_db()?) + } } #[cfg(test)] diff --git a/core/src/consensus/solo/params.rs b/core/src/consensus/solo/params.rs index 01bca6eb45..8ea3f4d026 100644 --- a/core/src/consensus/solo/params.rs +++ b/core/src/consensus/solo/params.rs @@ -20,16 +20,13 @@ use std::collections::HashMap; /// Params for a null engine. #[derive(Clone, Default)] pub struct SoloParams { - pub enable_hit_handler: bool, pub genesis_stakes: HashMap, } impl From for SoloParams { fn from(p: cjson::scheme::SoloParams) -> Self { SoloParams { - enable_hit_handler: p.action_handlers.hit.is_some(), genesis_stakes: p - .action_handlers .genesis_stakes .unwrap_or_default() .into_iter() diff --git a/core/src/consensus/stake/action_data.rs b/core/src/consensus/stake/action_data.rs index 44005352c5..67b9ce35e6 100644 --- a/core/src/consensus/stake/action_data.rs +++ b/core/src/consensus/stake/action_data.rs @@ -14,9 +14,8 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use super::CUSTOM_ACTION_HANDLER_ID; use ckey::{public_to_address, Address, Ed25519Public as Public}; -use cstate::{ActionData, ActionDataKeyBuilder, StateResult, TopLevelState, TopState, TopStateView}; +use cstate::{ActionData, StakeKeyBuilder, StateResult, TopLevelState, TopState, TopStateView}; use ctypes::errors::RuntimeError; use ctypes::{CompactValidatorEntry, CompactValidatorSet}; use primitives::{Bytes, H256}; @@ -29,25 +28,20 @@ use std::ops::Deref; use std::vec; pub fn get_account_key(address: &Address) -> H256 { - ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 2).append(&"Account").append(address).into_key() + StakeKeyBuilder::new(2).append(&"Account").append(address).into_key() } lazy_static! { - pub static ref STAKEHOLDER_ADDRESSES_KEY: H256 = - ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 1).append(&"StakeholderAddresses").into_key(); - pub static ref CANDIDATES_KEY: H256 = - ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 1).append(&"Candidates").into_key(); - pub static ref JAIL_KEY: H256 = ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 1).append(&"Jail").into_key(); - pub static ref BANNED_KEY: H256 = - ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 1).append(&"Banned").into_key(); - pub static ref NEXT_VALIDATORS_KEY: H256 = - ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 1).append(&"Validators").into_key(); - pub static ref CURRENT_VALIDATORS_KEY: H256 = - ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 1).append(&"CurrentValidators").into_key(); + pub static ref STAKEHOLDER_ADDRESSES_KEY: H256 = StakeKeyBuilder::new(1).append(&"StakeholderAddresses").into_key(); + pub static ref CANDIDATES_KEY: H256 = StakeKeyBuilder::new(1).append(&"Candidates").into_key(); + pub static ref JAIL_KEY: H256 = StakeKeyBuilder::new(1).append(&"Jail").into_key(); + pub static ref BANNED_KEY: H256 = StakeKeyBuilder::new(1).append(&"Banned").into_key(); + pub static ref NEXT_VALIDATORS_KEY: H256 = StakeKeyBuilder::new(1).append(&"Validators").into_key(); + pub static ref CURRENT_VALIDATORS_KEY: H256 = StakeKeyBuilder::new(1).append(&"CurrentValidators").into_key(); } pub fn get_delegation_key(address: &Address) -> H256 { - ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 2).append(&"Delegation").append(address).into_key() + StakeKeyBuilder::new(2).append(&"Delegation").append(address).into_key() } pub type StakeQuantity = u64; diff --git a/core/src/consensus/stake/actions.rs b/core/src/consensus/stake/actions.rs index 7c1f7ae817..168fd9aecc 100644 --- a/core/src/consensus/stake/actions.rs +++ b/core/src/consensus/stake/actions.rs @@ -26,7 +26,7 @@ use std::sync::Arc; #[derive(Clone, Copy)] #[repr(u8)] -enum ActionTag { +enum StakeActionTag { TransferCCS = 1, DelegateCCS = 2, Revoke = 3, @@ -36,23 +36,23 @@ enum ActionTag { ChangeParams = 0xFF, } -impl Encodable for ActionTag { +impl Encodable for StakeActionTag { fn rlp_append(&self, s: &mut RlpStream) { s.append_single_value(&(*self as u8)); } } -impl Decodable for ActionTag { +impl Decodable for StakeActionTag { fn decode(rlp: &Rlp) -> Result { let tag = rlp.as_val()?; match tag { - 1u8 => Ok(ActionTag::TransferCCS), - 2 => Ok(ActionTag::DelegateCCS), - 3 => Ok(ActionTag::Revoke), - 4 => Ok(ActionTag::SelfNominate), - 5 => Ok(ActionTag::ReportDoubleVote), - 6 => Ok(ActionTag::Redelegate), - 0xFF => Ok(ActionTag::ChangeParams), + 1u8 => Ok(StakeActionTag::TransferCCS), + 2 => Ok(StakeActionTag::DelegateCCS), + 3 => Ok(StakeActionTag::Revoke), + 4 => Ok(StakeActionTag::SelfNominate), + 5 => Ok(StakeActionTag::ReportDoubleVote), + 6 => Ok(StakeActionTag::Redelegate), + 0xFF => Ok(StakeActionTag::ChangeParams), _ => Err(DecoderError::Custom("Unexpected ActionTag Value")), } } @@ -75,7 +75,7 @@ impl Approval { } #[derive(Debug, PartialEq)] -pub enum Action { +pub enum StakeAction { TransferCCS { address: Address, quantity: u64, @@ -102,14 +102,13 @@ pub enum Action { params: Box, approvals: Vec, }, - // TODO: ConsensusMessage is tied to the Tendermint ReportDoubleVote { - message1: Box, - message2: Box, + message1: Bytes, + message2: Bytes, }, } -impl Action { +impl StakeAction { pub fn verify( &self, current_params: &CommonParams, @@ -117,19 +116,19 @@ impl Action { validators: Option>, ) -> Result<(), SyntaxError> { match self { - Action::TransferCCS { + StakeAction::TransferCCS { .. } => {} - Action::DelegateCCS { + StakeAction::DelegateCCS { .. } => {} - Action::Revoke { + StakeAction::Revoke { .. } => {} - Action::Redelegate { + StakeAction::Redelegate { .. } => {} - Action::SelfNominate { + StakeAction::SelfNominate { metadata, .. } => { @@ -140,13 +139,13 @@ impl Action { ))) } } - Action::ChangeParams { + StakeAction::ChangeParams { metadata_seq, params, approvals, } => { params.verify_change(current_params).map_err(SyntaxError::InvalidCustomAction)?; - let action = Action::ChangeParams { + let action = StakeAction::ChangeParams { metadata_seq: *metadata_seq, params: params.clone(), approvals: vec![], @@ -163,13 +162,17 @@ impl Action { } } } - Action::ReportDoubleVote { + StakeAction::ReportDoubleVote { message1, message2, } => { if message1 == message2 { return Err(SyntaxError::InvalidCustomAction(String::from("Messages are duplicated"))) } + let message1: ConsensusMessage = + rlp::decode(&message1).map_err(|err| SyntaxError::InvalidCustomAction(err.to_string()))?; + let message2: ConsensusMessage = + rlp::decode(&message2).map_err(|err| SyntaxError::InvalidCustomAction(err.to_string()))?; if message1.round() != message2.round() { return Err(SyntaxError::InvalidCustomAction(String::from( "The messages are from two different voting rounds", @@ -220,75 +223,72 @@ impl Action { } } -impl Encodable for Action { +impl Encodable for StakeAction { fn rlp_append(&self, s: &mut RlpStream) { match self { - Action::TransferCCS { + StakeAction::TransferCCS { address, quantity, } => { - s.begin_list(3).append(&ActionTag::TransferCCS).append(address).append(quantity); + s.begin_list(3).append(&StakeActionTag::TransferCCS).append(address).append(quantity); } - Action::DelegateCCS { + StakeAction::DelegateCCS { address, quantity, } => { - s.begin_list(3).append(&ActionTag::DelegateCCS).append(address).append(quantity); + s.begin_list(3).append(&StakeActionTag::DelegateCCS).append(address).append(quantity); } - Action::Revoke { + StakeAction::Revoke { address, quantity, } => { - s.begin_list(3).append(&ActionTag::Revoke).append(address).append(quantity); + s.begin_list(3).append(&StakeActionTag::Revoke).append(address).append(quantity); } - Action::Redelegate { + StakeAction::Redelegate { prev_delegatee, next_delegatee, quantity, } => { s.begin_list(4) - .append(&ActionTag::Redelegate) + .append(&StakeActionTag::Redelegate) .append(prev_delegatee) .append(next_delegatee) .append(quantity); } - Action::SelfNominate { + StakeAction::SelfNominate { deposit, metadata, } => { - s.begin_list(3).append(&ActionTag::SelfNominate).append(deposit).append(metadata); + s.begin_list(3).append(&StakeActionTag::SelfNominate).append(deposit).append(metadata); } - Action::ChangeParams { + StakeAction::ChangeParams { metadata_seq, params, approvals, } => { s.begin_list(3 + approvals.len()) - .append(&ActionTag::ChangeParams) + .append(&StakeActionTag::ChangeParams) .append(metadata_seq) .append(&**params); for approval in approvals { s.append(approval); } } - Action::ReportDoubleVote { + StakeAction::ReportDoubleVote { message1, message2, } => { - s.begin_list(3) - .append(&ActionTag::ReportDoubleVote) - .append(message1.as_ref()) - .append(message2.as_ref()); + s.begin_list(3).append(&StakeActionTag::ReportDoubleVote).append(message1).append(message2); } }; } } -impl Decodable for Action { +impl Decodable for StakeAction { fn decode(rlp: &Rlp<'_>) -> Result { let tag = rlp.val_at(0)?; match tag { - ActionTag::TransferCCS => { + StakeActionTag::TransferCCS => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpInvalidLength { @@ -296,12 +296,12 @@ impl Decodable for Action { got: item_count, }) } - Ok(Action::TransferCCS { + Ok(StakeAction::TransferCCS { address: rlp.val_at(1)?, quantity: rlp.val_at(2)?, }) } - ActionTag::DelegateCCS => { + StakeActionTag::DelegateCCS => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpInvalidLength { @@ -309,12 +309,12 @@ impl Decodable for Action { got: item_count, }) } - Ok(Action::DelegateCCS { + Ok(StakeAction::DelegateCCS { address: rlp.val_at(1)?, quantity: rlp.val_at(2)?, }) } - ActionTag::Revoke => { + StakeActionTag::Revoke => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpInvalidLength { @@ -322,12 +322,12 @@ impl Decodable for Action { got: item_count, }) } - Ok(Action::Revoke { + Ok(StakeAction::Revoke { address: rlp.val_at(1)?, quantity: rlp.val_at(2)?, }) } - ActionTag::Redelegate => { + StakeActionTag::Redelegate => { let item_count = rlp.item_count()?; if item_count != 4 { return Err(DecoderError::RlpInvalidLength { @@ -335,13 +335,13 @@ impl Decodable for Action { got: item_count, }) } - Ok(Action::Redelegate { + Ok(StakeAction::Redelegate { prev_delegatee: rlp.val_at(1)?, next_delegatee: rlp.val_at(2)?, quantity: rlp.val_at(3)?, }) } - ActionTag::SelfNominate => { + StakeActionTag::SelfNominate => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpInvalidLength { @@ -349,12 +349,12 @@ impl Decodable for Action { got: item_count, }) } - Ok(Action::SelfNominate { + Ok(StakeAction::SelfNominate { deposit: rlp.val_at(1)?, metadata: rlp.val_at(2)?, }) } - ActionTag::ChangeParams => { + StakeActionTag::ChangeParams => { let item_count = rlp.item_count()?; if item_count < 4 { return Err(DecoderError::RlpIncorrectListLen { @@ -365,13 +365,13 @@ impl Decodable for Action { let metadata_seq = rlp.val_at(1)?; let params = Box::new(rlp.val_at(2)?); let approvals = (3..item_count).map(|i| rlp.val_at(i)).collect::>()?; - Ok(Action::ChangeParams { + Ok(StakeAction::ChangeParams { metadata_seq, params, approvals, }) } - ActionTag::ReportDoubleVote => { + StakeActionTag::ReportDoubleVote => { let item_count = rlp.item_count()?; if item_count != 3 { return Err(DecoderError::RlpIncorrectListLen { @@ -379,9 +379,9 @@ impl Decodable for Action { got: item_count, }) } - let message1 = Box::new(rlp.val_at(1)?); - let message2 = Box::new(rlp.val_at(2)?); - Ok(Action::ReportDoubleVote { + let message1 = rlp.val_at(1)?; + let message2 = rlp.val_at(2)?; + Ok(StakeAction::ReportDoubleVote { message1, message2, }) @@ -401,7 +401,7 @@ mod tests { #[test] fn decode_fail_if_change_params_have_no_signatures() { - let action = Action::ChangeParams { + let action = StakeAction::ChangeParams { metadata_seq: 3, params: CommonParams::default_for_test().into(), approvals: vec![], @@ -411,13 +411,13 @@ mod tests { expected: 4, got: 3, }), - Rlp::new(&rlp::encode(&action)).as_val::() + Rlp::new(&rlp::encode(&action)).as_val::() ); } #[test] fn rlp_of_change_params() { - rlp_encode_and_decode_test!(Action::ChangeParams { + rlp_encode_and_decode_test!(StakeAction::ChangeParams { metadata_seq: 3, params: CommonParams::default_for_test().into(), approvals: vec![ @@ -497,9 +497,9 @@ mod tests { create_consensus_message(message_info1, &test_client, vote_step_twister, block_hash_twister); let consensus_message2 = create_consensus_message(message_info2, &test_client, vote_step_twister, block_hash_twister); - let action = Action::ReportDoubleVote { - message1: Box::new(consensus_message1), - message2: Box::new(consensus_message2), + let action = StakeAction::ReportDoubleVote { + message1: consensus_message1.rlp_bytes(), + message2: consensus_message2.rlp_bytes(), }; let arced_client: Arc = Arc::new(test_client); validator_set.register_client(Arc::downgrade(&arced_client)); diff --git a/core/src/consensus/stake/mod.rs b/core/src/consensus/stake/mod.rs index 17e36d4546..623f35b823 100644 --- a/core/src/consensus/stake/mod.rs +++ b/core/src/consensus/stake/mod.rs @@ -19,10 +19,10 @@ mod actions; use crate::client::ConsensusClient; use ckey::{public_to_address, Address, Ed25519Public as Public}; -use cstate::{ActionHandler, StateResult, TopLevelState, TopState, TopStateView}; +use cstate::{StakeHandler, StateResult, TopLevelState, TopState, TopStateView}; use ctypes::errors::{RuntimeError, SyntaxError}; use ctypes::util::unexpected::Mismatch; -use ctypes::{CommonParams, Header}; +use ctypes::CommonParams; use parking_lot::RwLock; use primitives::Bytes; use rlp::{Decodable, Rlp}; @@ -31,124 +31,27 @@ use std::sync::{Arc, Weak}; pub use self::action_data::{Banned, Candidates, CurrentValidators, Jail, NextValidators, Validator}; use self::action_data::{Delegation, ReleaseResult, StakeAccount, Stakeholders}; -pub use self::actions::{Action, Approval}; +pub use self::actions::{Approval, StakeAction}; use super::tendermint::Deposit; use super::ValidatorSet; +use crate::consensus::ConsensusMessage; pub const CUSTOM_ACTION_HANDLER_ID: u64 = 2; +#[derive(Default)] pub struct Stake { - genesis_stakes: HashMap, - genesis_candidates: HashMap, - genesis_delegations: HashMap>, client: RwLock>>, validators: RwLock>>, } impl Stake { - pub fn new( - genesis_stakes: HashMap, - genesis_candidates: HashMap, - genesis_delegations: HashMap>, - ) -> Stake { - Stake { - genesis_stakes, - genesis_candidates, - genesis_delegations, - client: Default::default(), - validators: Default::default(), - } - } pub fn register_resources(&self, client: Weak, validators: Weak) { *self.client.write() = Some(Weak::clone(&client)); *self.validators.write() = Some(Weak::clone(&validators)); } } -impl ActionHandler for Stake { - fn name(&self) -> &'static str { - "stake handler" - } - - fn handler_id(&self) -> u64 { - CUSTOM_ACTION_HANDLER_ID - } - - fn init(&self, state: &mut TopLevelState) -> StateResult<()> { - let mut genesis_stakes = self.genesis_stakes.clone(); - for (delegator, delegation) in &self.genesis_delegations { - let stake = genesis_stakes.entry(*delegator).or_default(); - let total_delegation = delegation.values().sum(); - if *stake < total_delegation { - cerror!(STATE, "{} has insufficient stakes to delegate", delegator); - return Err(RuntimeError::InsufficientStakes(Mismatch { - expected: total_delegation, - found: *stake, - }) - .into()) - } - for delegatee in delegation.keys() { - if !self.genesis_candidates.contains_key(delegatee) { - return Err( - RuntimeError::FailedToHandleCustomAction("Can delegate to who is a candidate".into()).into() - ) - } - } - *stake -= total_delegation; - } - - let mut stakeholders = Stakeholders::load_from_state(state)?; - for (address, amount) in &genesis_stakes { - let account = StakeAccount { - address, - balance: *amount, - }; - account.save_to_state(state)?; - stakeholders.update_by_increased_balance(&account); - } - stakeholders.save_to_state(state)?; - - for (address, deposit) in &self.genesis_candidates { - let balance = state.balance(address).unwrap_or_default(); - if balance < deposit.deposit { - cerror!(STATE, "{} has insufficient balance to become the candidate", address); - return Err(RuntimeError::InsufficientBalance { - address: *address, - balance, - cost: deposit.deposit, - } - .into()) - } - state.sub_balance(address, deposit.deposit).unwrap(); - } - - let mut candidates = Candidates::default(); - { - let mut values: Vec<_> = self.genesis_candidates.values().collect(); - values.sort_unstable(); // The insertion order of candidates is important. - - for candidate in values { - candidates.add_deposit( - &candidate.pubkey, - candidate.deposit, - candidate.nomination_ends_at, - candidate.metadata.clone(), - ); - } - } - candidates.save_to_state(state)?; - - for (delegator, delegations) in &self.genesis_delegations { - let mut delegation = Delegation::load_from_state(state, &delegator)?; - for (delegatee, amount) in delegations { - delegation.add_quantity(*delegatee, *amount)?; - } - delegation.save_to_state(state)?; - } - - Ok(()) - } - +impl StakeHandler for Stake { fn execute( &self, bytes: &[u8], @@ -156,26 +59,26 @@ impl ActionHandler for Stake { sender_address: &Address, sender_public: &Public, ) -> StateResult<()> { - let action = Action::decode(&Rlp::new(bytes)).expect("Verification passed"); + let action = StakeAction::decode(&Rlp::new(bytes)).expect("Verification passed"); match action { - Action::TransferCCS { + StakeAction::TransferCCS { address, quantity, } => transfer_ccs(state, sender_address, &address, quantity), - Action::DelegateCCS { + StakeAction::DelegateCCS { address, quantity, } => delegate_ccs(state, sender_address, &address, quantity), - Action::Revoke { + StakeAction::Revoke { address, quantity, } => revoke(state, sender_address, &address, quantity), - Action::Redelegate { + StakeAction::Redelegate { prev_delegatee, next_delegatee, quantity, } => redelegate(state, sender_address, &prev_delegatee, &next_delegatee, quantity), - Action::SelfNominate { + StakeAction::SelfNominate { deposit, metadata, } => { @@ -188,15 +91,17 @@ impl ActionHandler for Stake { }; self_nominate(state, sender_address, sender_public, deposit, current_term, nomination_ends_at, metadata) } - Action::ChangeParams { + StakeAction::ChangeParams { metadata_seq, params, approvals, } => change_params(state, metadata_seq, *params, &approvals), - Action::ReportDoubleVote { + StakeAction::ReportDoubleVote { message1, .. } => { + let message1: ConsensusMessage = + rlp::decode(&message1).map_err(|err| RuntimeError::FailedToHandleCustomAction(err.to_string()))?; let validator_set = self.validators.read().as_ref().and_then(Weak::upgrade).expect("ValidatorSet must be initialized"); let client = self.client.read().as_ref().and_then(Weak::upgrade).expect("Client must be initialized"); @@ -211,15 +116,11 @@ impl ActionHandler for Stake { fn verify(&self, bytes: &[u8], current_params: &CommonParams) -> Result<(), SyntaxError> { let action = - Action::decode(&Rlp::new(bytes)).map_err(|err| SyntaxError::InvalidCustomAction(err.to_string()))?; + StakeAction::decode(&Rlp::new(bytes)).map_err(|err| SyntaxError::InvalidCustomAction(err.to_string()))?; let client: Option> = self.client.read().as_ref().and_then(Weak::upgrade); let validators: Option> = self.validators.read().as_ref().and_then(Weak::upgrade); action.verify(current_params, client, validators) } - - fn on_close_block(&self, _state: &mut TopLevelState, _header: &Header) -> StateResult<()> { - Ok(()) - } } fn transfer_ccs(state: &mut TopLevelState, sender: &Address, receiver: &Address, quantity: u64) -> StateResult<()> { @@ -556,6 +457,84 @@ fn revert_delegations(state: &mut TopLevelState, reverted_delegatees: &[Address] Ok(()) } +pub(super) fn init( + state: &mut TopLevelState, + genesis_stakes: HashMap, + genesis_candidates: HashMap, + genesis_delegations: HashMap>, +) -> StateResult<()> { + let mut genesis_stakes = genesis_stakes; + for (delegator, delegation) in &genesis_delegations { + let stake = genesis_stakes.entry(*delegator).or_default(); + let total_delegation = delegation.values().sum(); + if *stake < total_delegation { + cerror!(STATE, "{} has insufficient stakes to delegate", delegator); + return Err(RuntimeError::InsufficientStakes(Mismatch { + expected: total_delegation, + found: *stake, + }) + .into()) + } + for delegatee in delegation.keys() { + if !genesis_candidates.contains_key(delegatee) { + return Err(RuntimeError::FailedToHandleCustomAction("Can delegate to who is a candidate".into()).into()) + } + } + *stake -= total_delegation; + } + + let mut stakeholders = Stakeholders::load_from_state(state)?; + for (address, amount) in &genesis_stakes { + let account = StakeAccount { + address, + balance: *amount, + }; + account.save_to_state(state)?; + stakeholders.update_by_increased_balance(&account); + } + stakeholders.save_to_state(state)?; + + for (address, deposit) in &genesis_candidates { + let balance = state.balance(address).unwrap_or_default(); + if balance < deposit.deposit { + cerror!(STATE, "{} has insufficient balance to become the candidate", address); + return Err(RuntimeError::InsufficientBalance { + address: *address, + balance, + cost: deposit.deposit, + } + .into()) + } + state.sub_balance(address, deposit.deposit).unwrap(); + } + + let mut candidates = Candidates::default(); + { + let mut values: Vec<_> = genesis_candidates.values().collect(); + values.sort_unstable(); // The insertion order of candidates is important. + + for candidate in values { + candidates.add_deposit( + &candidate.pubkey, + candidate.deposit, + candidate.nomination_ends_at, + candidate.metadata.clone(), + ); + } + } + candidates.save_to_state(state)?; + + for (delegator, delegations) in &genesis_delegations { + let mut delegation = Delegation::load_from_state(state, &delegator)?; + for (delegatee, amount) in delegations { + delegation.add_quantity(*delegatee, *amount)?; + } + delegation.save_to_state(state)?; + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::action_data::get_account_key; @@ -581,12 +560,12 @@ mod tests { let address2 = Address::random(); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(address1, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); let account1 = StakeAccount::load_from_state(&state, &address1).unwrap(); assert_eq!(account1.balance, 100); @@ -606,12 +585,12 @@ mod tests { let address2 = Address::random(); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(address1, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); let result = transfer_ccs(&mut state, &address1, &address2, 10); assert_eq!(result, Ok(())); @@ -634,12 +613,12 @@ mod tests { let address2 = Address::random(); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(address1, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); let result = transfer_ccs(&mut state, &address1, &address2, 100); assert_eq!(result, Ok(())); @@ -665,20 +644,20 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegatee, 100); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &delegatee, &delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: delegatee, quantity: 40, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert_eq!(result, Ok(())); let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); @@ -708,20 +687,20 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegatee, 100); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &delegatee, &delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: delegatee, quantity: 100, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert_eq!(result, Ok(())); let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); @@ -752,19 +731,19 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegatee, 100); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: delegatee, quantity: 40, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_err()); } @@ -776,20 +755,20 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegatee, 100); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &delegatee, &delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: delegatee, quantity: 200, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_err()); } @@ -801,26 +780,26 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegatee, 100); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &delegatee, &delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: delegatee, quantity: 50, }; - stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); + Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); - let action = Action::TransferCCS { + let action = StakeAction::TransferCCS { address: delegatee, quantity: 50, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_ok()); } @@ -832,26 +811,26 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegatee, 100); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &delegatee, &delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: delegatee, quantity: 50, }; - stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); + Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); - let action = Action::TransferCCS { + let action = StakeAction::TransferCCS { address: delegatee, quantity: 100, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_err()); } @@ -863,27 +842,27 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegatee, 100); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &delegatee, &delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: delegatee, quantity: 50, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_ok()); - let action = Action::Revoke { + let action = StakeAction::Revoke { address: delegatee, quantity: 20, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert_eq!(Ok(()), result); let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); @@ -901,27 +880,27 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegatee, 100); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &delegatee, &delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: delegatee, quantity: 50, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_ok()); - let action = Action::Revoke { + let action = StakeAction::Revoke { address: delegatee, quantity: 70, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_err()); let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); @@ -939,27 +918,27 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegatee, 100); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &delegatee, &delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: delegatee, quantity: 50, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_ok()); - let action = Action::Revoke { + let action = StakeAction::Revoke { address: delegatee, quantity: 50, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert_eq!(Ok(()), result); let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); @@ -977,28 +956,28 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &prev_delegatee, &prev_delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); self_nominate(&mut state, &next_delegatee, &next_delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: prev_delegatee, quantity: 50, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_ok()); - let action = Action::Redelegate { + let action = StakeAction::Redelegate { prev_delegatee, next_delegatee, quantity: 20, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert_eq!(Ok(()), result); let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); @@ -1019,28 +998,28 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &prev_delegatee, &prev_delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); self_nominate(&mut state, &next_delegatee, &next_delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: prev_delegatee, quantity: 50, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_ok()); - let action = Action::Redelegate { + let action = StakeAction::Redelegate { prev_delegatee, next_delegatee, quantity: 70, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_err()); let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); @@ -1061,28 +1040,28 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &prev_delegatee, &prev_delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); self_nominate(&mut state, &next_delegatee, &next_delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: prev_delegatee, quantity: 50, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_ok()); - let action = Action::Redelegate { + let action = StakeAction::Redelegate { prev_delegatee, next_delegatee, quantity: 50, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert_eq!(Ok(()), result); let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); @@ -1103,28 +1082,28 @@ mod tests { let delegator = public_to_address(&delegator_pubkey); let mut state = helpers::get_temp_state(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &prev_delegatee, &prev_delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: prev_delegatee, quantity: 40, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_ok()); - let action = Action::Redelegate { + let action = StakeAction::Redelegate { prev_delegatee, next_delegatee, quantity: 50, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_err()); } @@ -1142,25 +1121,25 @@ mod tests { let mut state = helpers::get_temp_state(); state.add_balance(&criminal, 1000).unwrap(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &prev_delegatee, &prev_delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); self_nominate(&mut state, &criminal, &criminal_pubkey, 100, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: criminal, quantity: 40, }; - stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); - let action = Action::DelegateCCS { + Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); + let action = StakeAction::DelegateCCS { address: prev_delegatee, quantity: 40, }; - stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); + Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); let candidates = Candidates::load_from_state(&state).unwrap(); assert_eq!(candidates.len(), 2); @@ -1173,12 +1152,12 @@ mod tests { let candidates = Candidates::load_from_state(&state).unwrap(); assert_eq!(candidates.len(), 1); - let action = Action::Redelegate { + let action = StakeAction::Redelegate { prev_delegatee, next_delegatee: criminal, quantity: 40, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_err()); } @@ -1194,22 +1173,22 @@ mod tests { let mut state = helpers::get_temp_state(); state.add_balance(&jail_address, 1000).unwrap(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); self_nominate(&mut state, &prev_delegatee, &prev_delegatee_pubkey, 0, 0, 10, b"".to_vec()).unwrap(); let deposit = 200; self_nominate(&mut state, &jail_address, &jail_pubkey, deposit, 0, 5, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: prev_delegatee, quantity: 40, }; - stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); + Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); let candidates = Candidates::load_from_state(&state).unwrap(); assert_eq!(candidates.len(), 2); @@ -1222,12 +1201,12 @@ mod tests { let candidates = Candidates::load_from_state(&state).unwrap(); assert_eq!(candidates.len(), 1); - let action = Action::Redelegate { + let action = StakeAction::Redelegate { prev_delegatee, next_delegatee: jail_address, quantity: 40, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_err()); } @@ -1239,10 +1218,9 @@ mod tests { let mut state = helpers::get_temp_state(); state.add_balance(&address, 1000).unwrap(); - let stake = Stake::new(Default::default(), Default::default(), Default::default()); - stake.init(&mut state).unwrap(); + super::init(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() let result = self_nominate(&mut state, &address, &address_pubkey, 0, 0, 5, b"metadata1".to_vec()); assert_eq!(result, Ok(())); @@ -1299,10 +1277,9 @@ mod tests { let mut state = helpers::get_temp_state(); state.add_balance(&address, 1000).unwrap(); - let stake = Stake::new(Default::default(), Default::default(), Default::default()); - stake.init(&mut state).unwrap(); + super::init(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() let result = self_nominate(&mut state, &address, &address_pubkey, 2000, 0, 5, b"".to_vec()); assert!(result.is_err(), "Cannot self-nominate without a sufficient balance"); } @@ -1324,10 +1301,9 @@ mod tests { increase_term_id_until(&mut state, 29); state.add_balance(&address, 1000).unwrap(); - let stake = Stake::new(Default::default(), Default::default(), Default::default()); - stake.init(&mut state).unwrap(); + super::init(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() self_nominate(&mut state, &address, &address_pubkey, 200, 0, 30, b"".to_vec()).unwrap(); let result = on_term_close(&mut state, pseudo_term_to_block_num_calculator(29), &[]); @@ -1365,21 +1341,21 @@ mod tests { increase_term_id_until(&mut state, 29); state.add_balance(&address, 1000).unwrap(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() self_nominate(&mut state, &address, &address_pubkey, 0, 0, 30, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address, quantity: 40, }; - stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); + Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); let result = on_term_close(&mut state, pseudo_term_to_block_num_calculator(29), &[]); assert_eq!(result, Ok(())); @@ -1406,10 +1382,9 @@ mod tests { let mut state = helpers::get_temp_state(); state.add_balance(&address, 1000).unwrap(); - let stake = Stake::new(Default::default(), Default::default(), Default::default()); - stake.init(&mut state).unwrap(); + super::init(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() let deposit = 200; self_nominate(&mut state, &address, &address_pubkey, deposit, 0, 5, b"".to_vec()).unwrap(); @@ -1444,10 +1419,9 @@ mod tests { let mut state = metadata_for_election(); state.add_balance(&address, 1000).unwrap(); - let stake = Stake::new(Default::default(), Default::default(), Default::default()); - stake.init(&mut state).unwrap(); + super::init(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() let deposit = 200; let nominate_expire = 5; let custody_until = 10; @@ -1483,10 +1457,9 @@ mod tests { let mut state = metadata_for_election(); state.add_balance(&address, 1000).unwrap(); - let stake = Stake::new(Default::default(), Default::default(), Default::default()); - stake.init(&mut state).unwrap(); + super::init(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() let deposit = 200; let nominate_expire = 5; let custody_until = 10; @@ -1537,10 +1510,9 @@ mod tests { let mut state = metadata_for_election(); state.add_balance(&address, 1000).unwrap(); - let stake = Stake::new(Default::default(), Default::default(), Default::default()); - stake.init(&mut state).unwrap(); + super::init(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() let deposit = 200; let nominate_expire = 5; let custody_until = 10; @@ -1579,14 +1551,14 @@ mod tests { let mut state = metadata_for_election(); state.add_balance(&address, 1000).unwrap(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() let deposit = 200; let nominate_expire = 5; let custody_until = 10; @@ -1595,21 +1567,21 @@ mod tests { jail(&mut state, &[address], custody_until, released_at).unwrap(); for current_term in 0..=released_at { - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address, quantity: 1, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert_ne!(Ok(()), result); on_term_close(&mut state, pseudo_term_to_block_num_calculator(current_term), &[]).unwrap(); } - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address, quantity: 1, }; - let result = stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); + let result = Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey); assert!(result.is_err()); } @@ -1623,25 +1595,25 @@ mod tests { let mut state = metadata_for_election(); state.add_balance(&address, 1000).unwrap(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() let deposit = 200; let nominate_expire = 5; let custody_until = 10; let released_at = 20; self_nominate(&mut state, &address, &address_pubkey, deposit, 0, nominate_expire, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address, quantity: 40, }; - stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); + Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); jail(&mut state, &[address], custody_until, released_at).unwrap(); @@ -1666,24 +1638,24 @@ mod tests { let mut state = metadata_for_election(); state.add_balance(&address, 1000).unwrap(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - // TODO: change with stake.execute() + // TODO: change with stake::execute() let nominate_expire = 5; let custody_until = 10; let released_at = 20; self_nominate(&mut state, &address, &address_pubkey, 0, 0, nominate_expire, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address, quantity: 40, }; - stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); + Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); jail(&mut state, &[address], custody_until, released_at).unwrap(); @@ -1722,20 +1694,20 @@ mod tests { let mut state = helpers::get_temp_state(); state.add_balance(&criminal, 1000).unwrap(); - let stake = { + let genesis_stakes = { let mut genesis_stakes = HashMap::new(); genesis_stakes.insert(delegator, 100); - Stake::new(genesis_stakes, Default::default(), Default::default()) + genesis_stakes }; - stake.init(&mut state).unwrap(); + super::init(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); let deposit = 100; self_nominate(&mut state, &criminal, &criminal_pubkey, deposit, 0, 10, b"".to_vec()).unwrap(); - let action = Action::DelegateCCS { + let action = StakeAction::DelegateCCS { address: criminal, quantity: 40, }; - stake.execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); + Stake::default().execute(&action.rlp_bytes(), &mut state, &delegator, &delegator_pubkey).unwrap(); assert_eq!(Ok(()), ban(&mut state, &informant, criminal)); @@ -1762,8 +1734,7 @@ mod tests { let criminal = public_to_address(&criminal_pubkey); let mut state = helpers::get_temp_state(); - let stake = Stake::new(Default::default(), Default::default(), Default::default()); - stake.init(&mut state).unwrap(); + super::init(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); assert_eq!(Ok(()), state.add_balance(&criminal, 100)); let deposit = 10; diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index c8c66dd956..3c061a6bfe 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -33,7 +33,7 @@ use crate::BlockId; use ckey::{public_to_address, Address}; use cnetwork::NetworkService; use crossbeam_channel as crossbeam; -use cstate::{ActionHandler, StateDB, StateResult, StateWithCache, TopLevelState, TopState, TopStateView}; +use cstate::{StakeHandler, StateDB, StateResult, StateWithCache, TopLevelState, TopState, TopStateView}; use ctypes::{BlockHash, Header}; use primitives::H256; use std::collections::HashSet; @@ -243,8 +243,8 @@ impl ConsensusEngine for Tendermint { parent_hash_of_new_header == prev_best_hash || grandparent_hash_of_new_header == prev_best_hash } - fn action_handlers(&self) -> &[Arc] { - &self.action_handlers + fn stake_handler(&self) -> Option<&dyn StakeHandler> { + Some(&*self.stake) } fn possible_authors(&self, block_number: Option) -> Result>, EngineError> { @@ -266,6 +266,13 @@ impl ConsensusEngine for Tendermint { fn initialize_genesis_state(&self, db: StateDB, root: H256) -> StateResult<(StateDB, H256)> { let mut state = TopLevelState::from_existing(db, root)?; + stake::init( + &mut state, + self.genesis_stakes.clone(), + self.genesis_candidates.clone(), + self.genesis_delegations.clone(), + )?; + NextValidators::elect(&state)?.save_to_state(&mut state)?; Ok(state.commit_and_into_db()?) } diff --git a/core/src/consensus/tendermint/mod.rs b/core/src/consensus/tendermint/mod.rs index eba53d92e3..ced8e597fb 100644 --- a/core/src/consensus/tendermint/mod.rs +++ b/core/src/consensus/tendermint/mod.rs @@ -35,10 +35,11 @@ use crate::codechain_machine::CodeChainMachine; use crate::consensus::DynamicValidator; use crate::snapshot_notify::NotifySender as SnapshotNotifySender; use crate::ChainNotify; +use ckey::Address; use crossbeam_channel as crossbeam; -use cstate::ActionHandler; use ctimer::TimerToken; use parking_lot::RwLock; +use std::collections::HashMap; use std::sync::atomic::AtomicBool; use std::sync::{Arc, Weak}; use std::thread::JoinHandle; @@ -66,13 +67,15 @@ pub struct Tendermint { validators: Arc, /// codechain machine descriptor machine: Arc, - /// Action handlers for this consensus method - action_handlers: Vec>, /// stake object to register client data later stake: Arc, /// Chain notify chain_notify: Arc, has_signer: AtomicBool, + /// Tokens distributed at genesis. + genesis_stakes: HashMap, + genesis_candidates: HashMap, + genesis_delegations: HashMap>, } impl Drop for Tendermint { @@ -88,11 +91,10 @@ impl Tendermint { /// Create a new instance of Tendermint engine pub fn new(our_params: TendermintParams, machine: CodeChainMachine) -> Arc { let validators = Arc::new(DynamicValidator::default()); - let stake = Arc::new(stake::Stake::new( - our_params.genesis_stakes, - our_params.genesis_candidates, - our_params.genesis_delegations, - )); + let stake = Arc::new(stake::Stake::default()); + let genesis_stakes = our_params.genesis_stakes; + let genesis_candidates = our_params.genesis_candidates; + let genesis_delegations = our_params.genesis_delegations; let timeouts = our_params.timeouts; let machine = Arc::new(machine); @@ -104,7 +106,6 @@ impl Tendermint { inner, quit_tendermint, ) = worker::spawn(Arc::clone(&validators)); - let action_handlers: Vec> = vec![stake.clone()]; let chain_notify = Arc::new(TendermintChainNotify::new(inner.clone())); Arc::new(Tendermint { @@ -118,10 +119,12 @@ impl Tendermint { inner, validators, machine, - action_handlers, stake, chain_notify, has_signer: false.into(), + genesis_stakes, + genesis_candidates, + genesis_delegations, }) } @@ -134,7 +137,7 @@ const SEAL_FIELDS: usize = 4; #[cfg(test)] mod tests { - use ckey::{Address, Ed25519Private as Private}; + use ckey::Ed25519Private as Private; use ctypes::Header; use super::super::BitSet; diff --git a/core/src/consensus/tendermint/params.rs b/core/src/consensus/tendermint/params.rs index 5a048eee2d..31b9917153 100644 --- a/core/src/consensus/tendermint/params.rs +++ b/core/src/consensus/tendermint/params.rs @@ -31,7 +31,7 @@ pub struct TendermintParams { pub genesis_delegations: HashMap>, } -#[derive(Eq, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] pub struct Deposit { pub pubkey: Public, pub deposit: u64, diff --git a/core/src/consensus/tendermint/vote_collector.rs b/core/src/consensus/tendermint/vote_collector.rs index 31470cc12c..595084de31 100644 --- a/core/src/consensus/tendermint/vote_collector.rs +++ b/core/src/consensus/tendermint/vote_collector.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use super::stake::Action; +use super::stake::StakeAction; use super::{ConsensusMessage, VoteStep}; use crate::consensus::BitSet; use ckey::Signature; @@ -44,10 +44,10 @@ pub struct DoubleVote { } impl DoubleVote { - pub fn to_action(&self) -> Action { - Action::ReportDoubleVote { - message1: Box::new(self.vote_one.clone()), - message2: Box::new(self.vote_two.clone()), + pub fn to_action(&self) -> StakeAction { + StakeAction::ReportDoubleVote { + message1: self.vote_one.rlp_bytes(), + message2: self.vote_two.rlp_bytes(), } } } diff --git a/core/src/miner/miner.rs b/core/src/miner/miner.rs index 14f7cd4dcb..bc7def8fc9 100644 --- a/core/src/miner/miner.rs +++ b/core/src/miner/miner.rs @@ -30,7 +30,7 @@ use crate::scheme::Scheme; use crate::transaction::{PendingVerifiedTransactions, UnverifiedTransaction, VerifiedTransaction}; use crate::types::{BlockId, TransactionId}; use ckey::{public_to_address, Address, Ed25519Public as Public, Password, PlatformAddress}; -use cstate::{FindActionHandler, TopLevelState}; +use cstate::{FindStakeHandler, TopLevelState}; use ctypes::errors::HistoryError; use ctypes::transaction::{Action, IncompleteTransaction}; use ctypes::{BlockHash, TxHash}; @@ -292,7 +292,7 @@ impl Miner { /// Prepares new block for sealing including top transactions from queue and seal it. fn prepare_and_seal_block< - C: AccountData + BlockChainTrait + BlockProducer + EngineInfo + FindActionHandler + TermInfo, + C: AccountData + BlockChainTrait + BlockProducer + EngineInfo + FindStakeHandler + TermInfo, >( &self, parent_block_id: BlockId, @@ -510,8 +510,7 @@ impl MinerService for Miner { fn update_sealing(&self, chain: &C, parent_block: BlockId, allow_empty_block: bool) where - C: AccountData + BlockChainTrait + BlockProducer + EngineInfo + ImportBlock + FindActionHandler + TermInfo, - { + C: AccountData + BlockChainTrait + BlockProducer + EngineInfo + ImportBlock + FindStakeHandler + TermInfo, { ctrace!(MINER, "update_sealing: preparing a block"); let block = match self.prepare_and_seal_block(parent_block, chain) { diff --git a/core/src/miner/mod.rs b/core/src/miner/mod.rs index d341bb33d7..458e697c33 100644 --- a/core/src/miner/mod.rs +++ b/core/src/miner/mod.rs @@ -21,7 +21,7 @@ mod mem_pool_types; mod miner; use ckey::{public_to_address, Address, Ed25519Public as Public, Password, PlatformAddress}; -use cstate::{FindActionHandler, TopStateView}; +use cstate::{FindStakeHandler, TopStateView}; use ctypes::transaction::IncompleteTransaction; use ctypes::{BlockHash, TxHash}; use primitives::Bytes; @@ -76,7 +76,7 @@ pub trait MinerService: Send + Sync { /// New chain head event. Restart mining operation. fn update_sealing(&self, chain: &C, parent_block: BlockId, allow_empty_block: bool) where - C: AccountData + BlockChainTrait + BlockProducer + ImportBlock + EngineInfo + FindActionHandler + TermInfo; + C: AccountData + BlockChainTrait + BlockProducer + ImportBlock + EngineInfo + FindStakeHandler + TermInfo; /// Imports transactions to mem pool. fn import_external_transactions( diff --git a/core/src/scheme/scheme.rs b/core/src/scheme/scheme.rs index a5c92cc2fc..6afd569efc 100644 --- a/core/src/scheme/scheme.rs +++ b/core/src/scheme/scheme.rs @@ -24,7 +24,7 @@ use crate::error::{Error, SchemeError}; use ccrypto::{blake256, BLAKE_NULL_RLP}; use cdb::{AsHashDB, HashDB}; use ckey::Address; -use cstate::{Metadata, MetadataAddress, Shard, ShardAddress, StateDB, StateResult, StateWithCache, TopLevelState}; +use cstate::{Metadata, MetadataAddress, Shard, ShardAddress, StateDB, StateResult}; use ctypes::errors::SyntaxError; use ctypes::{BlockHash, CommonParams, Header, ShardId}; use merkle_trie::{TrieFactory, TrieMut}; @@ -105,7 +105,6 @@ impl Scheme { let root = BLAKE_NULL_RLP; let (db, root) = self.initialize_accounts(db, root)?; let (db, root) = self.initialize_shards(db, root, genesis_params)?; - let (db, root) = self.initialize_action_handlers(db, root)?; let (db, root) = self.engine.initialize_genesis_state(db, root)?; *self.state_root_memo.write() = root; @@ -170,15 +169,6 @@ impl Scheme { Ok((db, root)) } - fn initialize_action_handlers(&self, db: StateDB, root: H256) -> StateResult<(StateDB, H256)> { - // basic accounts in scheme. - let mut top_level = TopLevelState::from_existing(db, root)?; - for handler in self.engine.action_handlers() { - handler.init(&mut top_level)?; - } - Ok(top_level.commit_and_into_db()?) - } - pub fn check_genesis_root(&self, db: &dyn HashDB) -> bool { if db.is_empty() { return true diff --git a/foundry/auto_self_nominate.rs b/foundry/auto_self_nominate.rs index f7244bf0ef..80bff4b9ee 100644 --- a/foundry/auto_self_nominate.rs +++ b/foundry/auto_self_nominate.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use crate::config::load_config; -use ccore::stake::Action::SelfNominate; +use ccore::stake::StakeAction::SelfNominate; use ccore::stake::{Banned, Candidates, Jail, CUSTOM_ACTION_HANDLER_ID}; use ccore::{AccountProvider, AccountProviderError, BlockId, ConsensusClient, Encodable, UnverifiedTransaction}; use ckey::PlatformAddress; diff --git a/json/src/scheme/solo.rs b/json/src/scheme/solo.rs index 0600bfb8f3..c301b51345 100644 --- a/json/src/scheme/solo.rs +++ b/json/src/scheme/solo.rs @@ -21,14 +21,6 @@ use std::collections::HashMap; #[derive(Debug, PartialEq, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SoloParams { - #[serde(flatten)] - pub action_handlers: SoloActionHandlersParams, -} - -#[derive(Debug, PartialEq, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SoloActionHandlersParams { - pub hit: Option>, pub genesis_stakes: Option>, } @@ -47,13 +39,11 @@ mod tests { let s = r#"{ "params": { "blockReward": "0x0d", - "hit": {}, "genesisStakes": {} } }"#; let deserialized: Solo = serde_json::from_str(s).unwrap(); - assert_eq!(deserialized.params.action_handlers.hit, Some(Default::default())); - assert_eq!(deserialized.params.action_handlers.genesis_stakes, Some(Default::default())); + assert_eq!(deserialized.params.genesis_stakes, Some(Default::default())); } } diff --git a/rpc/src/v1/impls/chain.rs b/rpc/src/v1/impls/chain.rs index c99fec8a4e..b4fc7f44b2 100644 --- a/rpc/src/v1/impls/chain.rs +++ b/rpc/src/v1/impls/chain.rs @@ -21,7 +21,7 @@ use ccore::{AccountData, BlockId, EngineInfo, ExecuteClient, MiningBlockChainCli use cjson::scheme::Params; use cjson::uint::Uint; use ckey::{public_to_address, NetworkId, PlatformAddress}; -use cstate::FindActionHandler; +use cstate::FindStakeHandler; use ctypes::transaction::Action; use ctypes::{BlockHash, BlockNumber, ShardId, TxHash}; use jsonrpc_core::Result; @@ -53,7 +53,7 @@ where + AccountData + ExecuteClient + EngineInfo - + FindActionHandler + + FindStakeHandler + TermInfo + 'static, { diff --git a/rpc/src/v1/impls/engine.rs b/rpc/src/v1/impls/engine.rs index 374ba4e86b..626fd2b462 100644 --- a/rpc/src/v1/impls/engine.rs +++ b/rpc/src/v1/impls/engine.rs @@ -19,13 +19,13 @@ use super::super::traits::Engine; use ccore::{BlockId, EngineInfo, MinerService, StateInfo}; use cjson::bytes::{Bytes, WithoutPrefix}; use ckey::PlatformAddress; -use cstate::FindActionHandler; +use cstate::{query_stake_state, FindStakeHandler}; use jsonrpc_core::Result; use std::sync::Arc; pub struct EngineClient where - C: EngineInfo + StateInfo + FindActionHandler, + C: EngineInfo + StateInfo + FindStakeHandler, M: MinerService, { client: Arc, miner: Arc, @@ -33,7 +33,7 @@ where impl EngineClient where - C: EngineInfo + StateInfo + FindActionHandler, + C: EngineInfo + StateInfo + FindStakeHandler, M: MinerService, { pub fn new(client: Arc, miner: Arc) -> Self { @@ -46,7 +46,7 @@ where impl Engine for EngineClient where - C: EngineInfo + StateInfo + FindActionHandler + 'static, + C: EngineInfo + StateInfo + FindStakeHandler + 'static, M: MinerService + 'static, { fn get_coinbase(&self) -> Result> { @@ -66,20 +66,14 @@ where fn get_custom_action_data( &self, - handler_id: u64, + _handler_id: u64, key_fragment: Bytes, block_number: Option, ) -> Result>> { - let handler = self.client.find_action_handler_for(handler_id).ok_or_else(|| { - errors::invalid_custom_action(format!( - "Current consensus engine doesn't have an action handler for a given handler_id({})", - handler_id - )) - })?; let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); let state = self.client.state_at(block_id).ok_or_else(errors::state_not_exist)?; - match handler.query(&key_fragment, &state) { + match query_stake_state(&key_fragment, &state) { Ok(Some(action_data)) => Ok(Some(Bytes::new(action_data).into_without_prefix())), Ok(None) => Ok(None), Err(e) => Err(errors::transaction_core(e)), diff --git a/state/src/action_handler/hit.rs b/state/src/action_handler/hit.rs deleted file mode 100644 index 7160cbe152..0000000000 --- a/state/src/action_handler/hit.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2018-2020 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use super::{ActionDataKeyBuilder, ActionHandler}; -use crate::{StateResult, TopLevelState, TopState, TopStateView}; -use ckey::{Address, Ed25519Public as Public}; -use ctypes::errors::SyntaxError; -use ctypes::{CommonParams, Header}; -use primitives::H256; -use rlp::{Decodable, Encodable, Rlp}; - -const CUSTOM_ACTION_HANDLER_ID: u64 = 1; - -#[derive(RlpDecodable)] -pub struct HitAction { - increase: u8, -} - -#[derive(Clone, Default)] -pub struct HitHandler {} - -impl HitHandler { - pub fn new() -> Self { - Self::default() - } - - fn hit_count(&self) -> H256 { - ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 1).append(&"hit count").into_key() - } - - fn close_count(&self) -> H256 { - ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 1).append(&"close count").into_key() - } -} - -impl ActionHandler for HitHandler { - fn name(&self) -> &'static str { - "hit handler" - } - - fn handler_id(&self) -> u64 { - CUSTOM_ACTION_HANDLER_ID - } - - fn init(&self, state: &mut TopLevelState) -> StateResult<()> { - let existing = state.action_data(&self.hit_count()); - debug_assert_eq!(Ok(None), existing); - state.update_action_data(&self.hit_count(), 1u32.rlp_bytes().to_vec())?; - state.update_action_data(&self.close_count(), 1u32.rlp_bytes().to_vec())?; - Ok(()) - } - - /// `bytes` must be valid encoding of HitAction - fn execute( - &self, - bytes: &[u8], - state: &mut TopLevelState, - _sender: &Address, - _sender_pubkey: &Public, - ) -> StateResult<()> { - let address = self.hit_count(); - let action = HitAction::decode(&Rlp::new(bytes)).expect("Verification passed"); - let action_data = state.action_data(&address)?.unwrap_or_default(); - let prev_counter: u32 = rlp::decode(&*action_data).unwrap(); - let increase = u32::from(action.increase); - state.update_action_data(&address, (prev_counter + increase).rlp_bytes().to_vec())?; - Ok(()) - } - - fn verify(&self, bytes: &[u8], _params: &CommonParams) -> Result<(), SyntaxError> { - HitAction::decode(&Rlp::new(bytes)).map_err(|err| SyntaxError::InvalidCustomAction(err.to_string()))?; - Ok(()) - } - - fn on_close_block(&self, state: &mut TopLevelState, _header: &Header) -> StateResult<()> { - let address = self.close_count(); - let action_data = state.action_data(&address)?.unwrap_or_default(); - let prev_counter: u32 = rlp::decode(&*action_data).unwrap(); - state.update_action_data(&address, (prev_counter + 1).rlp_bytes().to_vec())?; - Ok(()) - } -} diff --git a/state/src/impls/top_level.rs b/state/src/impls/top_level.rs index 3a85ad4561..a2f5344e56 100644 --- a/state/src/impls/top_level.rs +++ b/state/src/impls/top_level.rs @@ -39,7 +39,7 @@ use crate::cache::{ShardCache, TopCache}; use crate::checkpoint::{CheckpointId, StateWithCheckpoint}; use crate::traits::{ShardState, ShardStateView, StateWithCache, TopState, TopStateView}; use crate::{ - Account, ActionData, FindActionHandler, Metadata, MetadataAddress, Shard, ShardAddress, ShardLevelState, StateDB, + Account, ActionData, FindStakeHandler, Metadata, MetadataAddress, Shard, ShardAddress, ShardLevelState, StateDB, StateResult, }; use ccrypto::BLAKE_NULL_RLP; @@ -230,7 +230,7 @@ impl TopLevelState { /// Execute a given tranasction, charging tranasction fee. /// This will change the state accordingly. - pub fn apply( + pub fn apply( &mut self, tx: &Transaction, signed_hash: &TxHash, @@ -261,7 +261,7 @@ impl TopLevelState { result } - fn apply_internal( + fn apply_internal( &mut self, tx: &Transaction, signed_hash: &TxHash, @@ -313,7 +313,7 @@ impl TopLevelState { } #[allow(clippy::too_many_arguments)] - fn apply_action( + fn apply_action( &mut self, action: &Action, network_id: NetworkId, @@ -364,10 +364,10 @@ impl TopLevelState { return Ok(()) } Action::Custom { - handler_id, bytes, + .. } => { - let handler = client.find_action_handler_for(*handler_id).expect("Unknown custom parsel applied!"); + let handler = client.stake_handler().expect("Unknown custom transaction applied!"); handler.execute(bytes, self, sender_address, sender_public)?; return Ok(()) } diff --git a/state/src/lib.rs b/state/src/lib.rs index 12230186d3..4cad4ebe0f 100644 --- a/state/src/lib.rs +++ b/state/src/lib.rs @@ -22,21 +22,18 @@ extern crate codechain_key as ckey; extern crate codechain_types as ctypes; #[macro_use] extern crate log; -#[macro_use] -extern crate rlp_derive; -mod action_handler; mod cache; mod checkpoint; mod db; mod error; mod impls; mod item; +mod stake; mod traits; pub mod tests; -pub use crate::action_handler::{ActionDataKeyBuilder, ActionHandler, FindActionHandler, HitHandler}; pub use crate::checkpoint::{CheckpointId, StateWithCheckpoint}; pub use crate::db::StateDB; pub use crate::error::Error as StateError; @@ -46,6 +43,7 @@ pub use crate::item::action_data::ActionData; pub use crate::item::dummy_shard_text::{ShardText, ShardTextAddress}; pub use crate::item::metadata::{Metadata, MetadataAddress}; pub use crate::item::shard::{Shard, ShardAddress}; +pub use crate::stake::{query as query_stake_state, FindStakeHandler, StakeHandler, StakeKeyBuilder}; pub use crate::traits::{ShardState, ShardStateView, StateWithCache, TopState, TopStateView}; use crate::cache::CacheableItem; diff --git a/state/src/action_handler/mod.rs b/state/src/stake/mod.rs similarity index 54% rename from state/src/action_handler/mod.rs rename to state/src/stake/mod.rs index 375a0ef864..ba25f209e0 100644 --- a/state/src/action_handler/mod.rs +++ b/state/src/stake/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018-2019 Kodebox, Inc. +// Copyright 2018-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -14,22 +14,17 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -mod hit; - use super::TopStateView; use crate::{StateResult, TopLevelState}; use ccrypto::blake256; use ckey::{Address, Ed25519Public as Public}; use ctypes::errors::SyntaxError; -use ctypes::{CommonParams, Header}; +use ctypes::CommonParams; use primitives::H256; use rlp::{Encodable, RlpStream}; use std::convert::From; -pub trait ActionHandler: Send + Sync { - fn name(&self) -> &'static str; - fn handler_id(&self) -> u64; - fn init(&self, state: &mut TopLevelState) -> StateResult<()>; +pub trait StakeHandler: Send + Sync { fn execute( &self, bytes: &[u8], @@ -38,49 +33,46 @@ pub trait ActionHandler: Send + Sync { sender_pubkey: &Public, ) -> StateResult<()>; fn verify(&self, bytes: &[u8], common_params: &CommonParams) -> Result<(), SyntaxError>; +} - fn query(&self, key_fragment: &[u8], state: &TopLevelState) -> StateResult>> { - let key = ActionDataKeyBuilder::key_from_fragment(self.handler_id(), key_fragment); - let some_action_data = state.action_data(&key)?.map(Vec::from); - Ok(some_action_data) - } - - fn on_close_block(&self, state: &mut TopLevelState, header: &Header) -> StateResult<()>; +pub fn query(key_fragment: &[u8], state: &TopLevelState) -> StateResult>> { + let key = StakeKeyBuilder::key_from_fragment(key_fragment); + let some_action_data = state.action_data(&key)?.map(Vec::from); + Ok(some_action_data) } -pub trait FindActionHandler { - fn find_action_handler_for(&self, _id: u64) -> Option<&dyn ActionHandler> { +pub trait FindStakeHandler { + fn stake_handler(&self) -> Option<&dyn StakeHandler> { None } } -pub struct ActionDataKeyBuilder { +pub struct StakeKeyBuilder { rlp: RlpStream, } -impl ActionDataKeyBuilder { - fn prepare(handler_id: u64) -> ActionDataKeyBuilder { - let mut rlp = RlpStream::new_list(3); - rlp.append(&"ActionData"); - rlp.append(&handler_id); - ActionDataKeyBuilder { +impl StakeKeyBuilder { + fn prepare() -> StakeKeyBuilder { + let mut rlp = RlpStream::new_list(2); + rlp.append(&"Stake"); + StakeKeyBuilder { rlp, } } - pub fn key_from_fragment(handler_id: u64, key_fragment: &[u8]) -> H256 { - let mut builder = Self::prepare(handler_id); + pub fn key_from_fragment(key_fragment: &[u8]) -> H256 { + let mut builder = Self::prepare(); builder.rlp.append_raw(&key_fragment, 1); builder.into_key() } - pub fn new(handler_id: u64, fragment_length: usize) -> ActionDataKeyBuilder { - let mut builder = Self::prepare(handler_id); + pub fn new(fragment_length: usize) -> StakeKeyBuilder { + let mut builder = Self::prepare(); builder.rlp.begin_list(fragment_length); builder } - pub fn append(mut self, e: &E) -> ActionDataKeyBuilder + pub fn append(mut self, e: &E) -> StakeKeyBuilder where E: Encodable, { self.rlp.append(e); @@ -92,20 +84,17 @@ impl ActionDataKeyBuilder { } } -pub use self::hit::HitHandler; - #[cfg(test)] mod tests { use super::*; #[test] fn action_data_key_builder_raw_fragment_and_list_are_same() { - let key1 = - ActionDataKeyBuilder::new(1, 3).append(&"key").append(&"fragment").append(&"has trailing list").into_key(); + let key1 = StakeKeyBuilder::new(3).append(&"key").append(&"fragment").append(&"has trailing list").into_key(); let mut rlp = RlpStream::new_list(3); rlp.append(&"key").append(&"fragment").append(&"has trailing list"); - let key2 = ActionDataKeyBuilder::key_from_fragment(1, rlp.as_raw()); + let key2 = StakeKeyBuilder::key_from_fragment(rlp.as_raw()); assert_eq!(key1, key2); } } diff --git a/state/src/tests.rs b/state/src/tests.rs index d26f7ad41e..6aaf0fe555 100644 --- a/state/src/tests.rs +++ b/state/src/tests.rs @@ -16,7 +16,7 @@ pub mod helpers { use crate::impls::TopLevelState; - use crate::{FindActionHandler, Metadata, MetadataAddress, StateDB}; + use crate::{FindStakeHandler, Metadata, MetadataAddress, StateDB}; use cdb::AsHashDB; use ctypes::CommonParams; use kvdb::KeyValueDB; @@ -26,7 +26,7 @@ pub mod helpers { use std::sync::Arc; pub struct TestClient {} - impl FindActionHandler for TestClient {} + impl FindStakeHandler for TestClient {} pub fn get_memory_db() -> Arc { Arc::new(kvdb_memorydb::create(1)) diff --git a/sync/src/block/extension.rs b/sync/src/block/extension.rs index b8bd11a0d2..c33328d104 100644 --- a/sync/src/block/extension.rs +++ b/sync/src/block/extension.rs @@ -25,10 +25,9 @@ use ccore::{ use cdb::AsHashDB; use cnetwork::{Api, EventSender, IntoSocketAddr, NetworkExtension, NodeId}; use codechain_crypto::BLAKE_NULL_RLP; -use cstate::{FindActionHandler, TopLevelState, TopStateView}; +use cstate::{TopLevelState, TopStateView}; use ctimer::TimerToken; use ctypes::header::{Header, Seal}; -use ctypes::transaction::Action; use ctypes::{BlockHash, BlockNumber, ShardId}; use kvdb::DBTransaction; use merkle_trie::snapshot::{ChunkDecompressor, Restore as SnapshotRestore}; @@ -928,21 +927,6 @@ impl Extension { ); return false } - for body in bodies { - for tx in body { - let is_valid = match &tx.transaction().action { - Action::Custom { - handler_id, - .. - } => self.client.find_action_handler_for(*handler_id).is_some(), - _ => true, - }; - if !is_valid { - cwarn!(SYNC, "Received transaction has some invalid actions"); - return false - } - } - } true } (RequestMessage::StateChunk(_, roots), ResponseMessage::StateChunk(chunks)) => { diff --git a/test/src/e2e/customAction.test.ts b/test/src/e2e/customAction.test.ts deleted file mode 100644 index 37f905139a..0000000000 --- a/test/src/e2e/customAction.test.ts +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -import { fail } from "assert"; -import * as chai from "chai"; -import * as chaiAsPromised from "chai-as-promised"; -import { toHex } from "foundry-primitives/lib"; -import "mocha"; -import { - faucetAddress, - faucetSecret, - hitActionHandlerId -} from "../helper/constants"; -import { ERROR } from "../helper/error"; -import CodeChain from "../helper/spawn"; -import * as RLP from "rlp"; - -chai.use(chaiAsPromised); -const expect = chai.expect; - -const hitcount = toHex(RLP.encode(["hit count"])); -const closecount = toHex(RLP.encode(["close count"])); -const nonexistingkey = toHex(RLP.encode(["non-existing-key"])); -describe("customAction", function() { - let node: CodeChain; - - before(async function() { - node = new CodeChain(); - await node.start(); - }); - - describe("customAction", function() { - it("should get initial state", async function() { - const actionData = await node.rpc.engine.getCustomActionData({ - handlerId: hitActionHandlerId, - bytes: `0x${hitcount}`, - blockNumber: null - }); - - expect(actionData).to.be.equal(toHex(RLP.encode(1))); - }); - - it("should alter state", async function() { - const previousHitData = (await node.rpc.engine.getCustomActionData({ - handlerId: hitActionHandlerId, - bytes: `0x${hitcount}`, - blockNumber: null - }))!; - const previousHitCount = Buffer.from( - previousHitData, - "hex" - ).readUInt8(0); - - const previousBlockCloseData = (await node.rpc.engine.getCustomActionData( - { - handlerId: hitActionHandlerId, - bytes: `0x${closecount}`, - blockNumber: null - } - ))!; - const previousBlockCloseCount = Buffer.from( - previousBlockCloseData, - "hex" - ).readUInt8(0); - - const increment = 11; - const tx = node.testFramework.core - .createCustomTransaction({ - handlerId: hitActionHandlerId, - bytes: RLP.encode([increment]) - }) - .sign({ - secret: faucetSecret, - seq: (await node.rpc.chain.getSeq({ - address: faucetAddress.toString(), - blockNumber: null - }))!, - fee: 10 - }); - const trans = tx.rlpBytes().toString("hex"); - const hash = await node.rpc.mempool.sendSignedTransaction({ - tx: `0x${trans}` - }); - expect( - await node.rpc.chain.containsTransaction({ - transactionHash: hash - }) - ).be.true; - expect( - await node.rpc.chain.getTransaction({ transactionHash: hash }) - ).not.null; - - const hitData = (await node.rpc.engine.getCustomActionData({ - handlerId: hitActionHandlerId, - bytes: `0x${hitcount}`, - blockNumber: null - }))!; - - expect(hitData).to.be.equal( - toHex(RLP.encode(previousHitCount + increment)) - ); - const closeData = (await node.rpc.engine.getCustomActionData({ - handlerId: hitActionHandlerId, - bytes: `0x${closecount}`, - blockNumber: null - }))!; - expect(closeData).to.be.equal( - toHex(RLP.encode(previousBlockCloseCount + 1)) - ); - }); - - it("should return null", async function() { - const actionData = await node.rpc.engine.getCustomActionData({ - handlerId: hitActionHandlerId, - bytes: `0x${nonexistingkey}`, - blockNumber: null - }); - - expect(actionData).to.be.null; - }); - - it("should throw state not exist", async function() { - try { - await node.rpc.engine.getCustomActionData({ - handlerId: hitActionHandlerId, - bytes: `0x${hitcount}`, - blockNumber: 99999 - }); - fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.STATE_NOT_EXIST); - } - }); - - it("should throw handler not found on getCustomActionData", async function() { - try { - await node.rpc.engine.getCustomActionData({ - handlerId: 999999, - bytes: `0x${toHex(RLP.encode([]))}`, - blockNumber: null - }); - fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.ACTION_DATA_HANDLER_NOT_FOUND); - } - }); - - it("should throw handler not found on sendCustomTransaction", async function() { - try { - const tx = node.testFramework.core - .createCustomTransaction({ - handlerId: 99999, - bytes: RLP.encode([11]) - }) - .sign({ - secret: faucetSecret, - seq: (await node.rpc.chain.getSeq({ - address: faucetAddress.toString(), - blockNumber: null - }))!, - fee: 10 - }); - const trans = tx.rlpBytes().toString("hex"); - await node.rpc.mempool.sendSignedTransaction({ - tx: `0x${trans}` - }); - fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.ACTION_DATA_HANDLER_NOT_FOUND); - } - }); - - it("should fail on handling error", async function() { - const seq = (await node.rpc.chain.getSeq({ - address: faucetAddress.toString(), - blockNumber: null - }))!; - const blockNumber = await node.rpc.chain.getBestBlockNumber(); - const tx = node.testFramework.core - .createCustomTransaction({ - handlerId: hitActionHandlerId, - bytes: RLP.encode(["wrong", "format", "of", "message"]) - }) - .sign({ - secret: faucetSecret, - seq: seq + 1, - fee: 10 - }); - const trans = tx.rlpBytes().toString("hex"); - expect(node.rpc.mempool.sendSignedTransaction({ tx: `0x${trans}` })) - .be.rejected; - }); - }); - - afterEach(function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - }); - - after(async function() { - await node.clean(); - }); -});