diff --git a/coordinator/src/lib.rs b/coordinator/src/lib.rs index 1599bc6170..80ad1190e5 100644 --- a/coordinator/src/lib.rs +++ b/coordinator/src/lib.rs @@ -18,7 +18,7 @@ use self::traits::{BlockExecutor, Initializer, TxFilter}; use self::types::*; use context::StorageAccess; -use ctypes::{CompactValidatorSet, ConsensusParams}; +use ctypes::{ConsensusParams, Validators}; pub mod context; pub mod test_coordinator; @@ -34,7 +34,7 @@ pub mod types; pub struct Coordinator {} impl Initializer for Coordinator { - fn initialize_chain(&self, app_state: String) -> (CompactValidatorSet, ConsensusParams) { + fn initialize_chain(&self, app_state: String) -> (Validators, ConsensusParams) { unimplemented!() } } diff --git a/coordinator/src/test_coordinator.rs b/coordinator/src/test_coordinator.rs index e85471b9c1..e82f9a4bb3 100644 --- a/coordinator/src/test_coordinator.rs +++ b/coordinator/src/test_coordinator.rs @@ -17,12 +17,12 @@ use super::context::StorageAccess; use super::traits::{BlockExecutor, Initializer, TxFilter}; use super::types::*; -use ctypes::{CompactValidatorSet, ConsensusParams}; +use ctypes::{ConsensusParams, Validators}; use std::sync::atomic::{AtomicUsize, Ordering}; // Coordinator dedicated for mempool and miner testing pub struct TestCoordinator { - validator_set: CompactValidatorSet, + validator_set: Validators, consensus_params: ConsensusParams, body_count: AtomicUsize, body_size: AtomicUsize, @@ -40,7 +40,7 @@ impl Default for TestCoordinator { } impl Initializer for TestCoordinator { - fn initialize_chain(&self, _app_state: String) -> (CompactValidatorSet, ConsensusParams) { + fn initialize_chain(&self, _app_state: String) -> (Validators, ConsensusParams) { (self.validator_set.clone(), self.consensus_params) } } diff --git a/coordinator/src/traits.rs b/coordinator/src/traits.rs index 9554461e2f..a8ae53c9e3 100644 --- a/coordinator/src/traits.rs +++ b/coordinator/src/traits.rs @@ -16,10 +16,10 @@ use super::context::StorageAccess; use super::types::*; -use ctypes::{CompactValidatorSet, ConsensusParams}; +use ctypes::{ConsensusParams, Validators}; pub trait Initializer: Send + Sync { - fn initialize_chain(&self, app_state: String) -> (CompactValidatorSet, ConsensusParams); + fn initialize_chain(&self, app_state: String) -> (Validators, ConsensusParams); } pub trait BlockExecutor: Send + Sync { fn open_block( diff --git a/coordinator/src/types.rs b/coordinator/src/types.rs index e0521c9998..3321227e6a 100644 --- a/coordinator/src/types.rs +++ b/coordinator/src/types.rs @@ -16,7 +16,7 @@ use ccrypto::blake256; use ckey::Ed25519Public as Public; -use ctypes::{CompactValidatorSet, ConsensusParams, TxHash}; +use ctypes::{ConsensusParams, TxHash, Validators}; use primitives::Bytes; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; @@ -239,7 +239,7 @@ pub type ExecuteTransactionError = (); pub type CloseBlockError = String; pub struct BlockOutcome { - pub updated_validator_set: Option, + pub updated_validator_set: Option, pub updated_consensus_params: Option, pub events: Vec, } diff --git a/core/src/block.rs b/core/src/block.rs index bce1c76b99..e212a7a05a 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -20,10 +20,10 @@ use ccrypto::BLAKE_NULL_RLP; use ckey::Ed25519Public as Public; use coordinator::traits::BlockExecutor; use coordinator::types::{Event, Header as PreHeader, Transaction, TransactionWithMetadata, VerifiedCrime}; -use cstate::{CurrentValidatorSet, NextValidatorSet, StateDB, StateError, StateWithCache, TopLevelState, TopState}; +use cstate::{CurrentValidators, NextValidators, StateDB, StateError, StateWithCache, TopLevelState, TopState}; use ctypes::header::{Header, Seal}; use ctypes::util::unexpected::Mismatch; -use ctypes::{CompactValidatorSet, ConsensusParams, TxHash}; +use ctypes::{ConsensusParams, TxHash, Validators}; use merkle_trie::skewed_merkle_root; use primitives::{Bytes, H256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; @@ -204,7 +204,7 @@ impl OpenBlock { let updated_validator_set = block_outcome.updated_validator_set; let next_validator_set_hash = match updated_validator_set { Some(ref set) => set.hash(), - None => NextValidatorSet::load_from_state(self.block.state())?.create_compact_validator_set().hash(), + None => NextValidators::load_from_state(self.block.state())?.hash(), }; let updated_consensus_params = block_outcome.updated_consensus_params; if let Err(e) = self.update_next_block_state(updated_validator_set, updated_consensus_params) { @@ -278,8 +278,8 @@ impl OpenBlock { // called on open_block fn update_current_validator_set(&mut self) -> Result<(), Error> { - let mut current_validators = CurrentValidatorSet::load_from_state(self.state())?; - current_validators.update(NextValidatorSet::load_from_state(self.state())?); + let mut current_validators = CurrentValidators::load_from_state(self.state())?; + current_validators.update(NextValidators::load_from_state(self.state())?.into()); current_validators.save_to_state(self.state_mut())?; Ok(()) @@ -288,13 +288,13 @@ impl OpenBlock { // called on close_block fn update_next_block_state( &mut self, - updated_validator_set: Option, + updated_validator_set: Option, updated_consensus_params: Option, ) -> Result<(), Error> { let state = self.block.state_mut(); if let Some(set) = updated_validator_set { - let validators = NextValidatorSet::from_compact_validator_set(set); + let validators: NextValidators = set.into(); validators.save_to_state(state)?; } diff --git a/core/src/client/client.rs b/core/src/client/client.rs index fff2f5f68d..9b86dddc78 100644 --- a/core/src/client/client.rs +++ b/core/src/client/client.rs @@ -40,10 +40,10 @@ use coordinator::context::{ }; use coordinator::traits::{BlockExecutor, Initializer}; use coordinator::types::{Event, Transaction}; -use cstate::{Metadata, MetadataAddress, NextValidatorSet, StateDB, StateWithCache, TopLevelState, TopStateView}; +use cstate::{Metadata, MetadataAddress, NextValidators, StateDB, StateWithCache, TopLevelState, TopStateView}; use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken}; use ctypes::header::Header; -use ctypes::{BlockHash, BlockId, BlockNumber, CommonParams, CompactValidatorSet, ConsensusParams, TxHash}; +use ctypes::{BlockHash, BlockId, BlockNumber, CommonParams, ConsensusParams, TxHash, Validators}; use kvdb::{DBTransaction, KeyValueDB}; use merkle_trie::{TrieFactory, TrieMut}; use parking_lot::{Mutex, RwLock, RwLockReadGuard}; @@ -236,7 +236,7 @@ impl Client { fn initialize_state( db: StateDB, genesis_consensus_params: ConsensusParams, - genesis_validators: CompactValidatorSet, + genesis_validators: Validators, ) -> Result { let root = BLAKE_NULL_RLP; let (db, root) = Self::initialize_validator_set(db, root, genesis_validators)?; @@ -248,10 +248,10 @@ impl Client { fn initialize_validator_set( db: StateDB, root: H256, - genesis_validators: CompactValidatorSet, + genesis_validators: Validators, ) -> Result<(StateDB, H256), Error> { let mut state = TopLevelState::from_existing(db.clone(&root), root)?; - let validator_set = NextValidatorSet::from_compact_validator_set(genesis_validators); + let validator_set: NextValidators = genesis_validators.into(); validator_set.save_to_state(&mut state)?; let root = state.commit()?; Ok((db, root)) diff --git a/core/src/client/test_client.rs b/core/src/client/test_client.rs index fc4fb9be16..fc5751d91d 100644 --- a/core/src/client/test_client.rs +++ b/core/src/client/test_client.rs @@ -50,12 +50,12 @@ use ckey::{Ed25519Private as Private, Ed25519Public as Public, NetworkId, Platfo use coordinator::test_coordinator::TestCoordinator; use coordinator::types::{Event, Transaction}; use cstate::tests::helpers::empty_top_state_with_metadata; -use cstate::{FindDoubleVoteHandler, NextValidatorSet, StateDB, TopLevelState}; +use cstate::{FindDoubleVoteHandler, NextValidators, StateDB, TopLevelState}; use ctimer::{TimeoutHandler, TimerToken}; use ctypes::header::Header; use ctypes::{ - BlockHash, BlockId, BlockNumber, CommonParams, CompactValidatorEntry, CompactValidatorSet, ConsensusParams, - Header as BlockHeader, TxHash, + BlockHash, BlockId, BlockNumber, CommonParams, ConsensusParams, Header as BlockHeader, TxHash, Validator, + Validators, }; use kvdb::KeyValueDB; use merkle_trie::skewed_merkle_root; @@ -98,7 +98,7 @@ pub struct TestBlockChainClient { /// Fixed validator keys pub validator_keys: RwLock>, /// Fixed validators - pub validators: NextValidatorSet, + pub validators: NextValidators, } impl Default for TestBlockChainClient { @@ -146,7 +146,7 @@ impl TestBlockChainClient { history: RwLock::new(None), term_id: Some(1), validator_keys: RwLock::new(HashMap::new()), - validators: NextValidatorSet::from_compact_validator_set(CompactValidatorSet::new(Vec::new())), + validators: Validators::new(Vec::new()).into(), }; // insert genesis hash. @@ -273,17 +273,17 @@ impl TestBlockChainClient { pubkeys.push(public); } - let compact_validator_set = CompactValidatorSet::new( + let compact_validator_set = Validators::new( pubkeys .into_iter() - .map(|public_key| CompactValidatorEntry { + .map(|public_key| Validator { public_key, - delegation: 0, + voting_power: 0, }) .collect(), ); - let fixed_validators: NextValidatorSet = NextValidatorSet::from_compact_validator_set(compact_validator_set); + let fixed_validators: NextValidators = compact_validator_set.into(); self.validators = fixed_validators } diff --git a/core/src/consensus/validator_set/dynamic_validator.rs b/core/src/consensus/validator_set/dynamic_validator.rs index 2ae9ac8880..62c337ff60 100644 --- a/core/src/consensus/validator_set/dynamic_validator.rs +++ b/core/src/consensus/validator_set/dynamic_validator.rs @@ -19,9 +19,9 @@ use crate::client::ConsensusClient; use crate::consensus::bit_set::BitSet; use crate::consensus::EngineError; use ckey::Ed25519Public as Public; -use cstate::{CurrentValidatorSet, NextValidatorSet, SimpleValidator}; +use cstate::{CurrentValidators, NextValidators}; use ctypes::util::unexpected::OutOfBounds; -use ctypes::BlockHash; +use ctypes::{BlockHash, Validator, Validators}; use parking_lot::RwLock; use std::sync::{Arc, Weak}; @@ -31,31 +31,31 @@ pub struct DynamicValidator { } impl DynamicValidator { - fn next_validators(&self, hash: BlockHash) -> Vec { + fn next_validators(&self, hash: BlockHash) -> Vec { let client: Arc = self.client.read().as_ref().and_then(Weak::upgrade).expect("Client is not initialized"); let block_id = hash.into(); let state = client.state_at(block_id).expect("The next validators must be called on the confirmed block"); - let validators = NextValidatorSet::load_from_state(&state).unwrap(); - let mut validators: Vec<_> = validators.into(); + let validators = NextValidators::load_from_state(&state).unwrap(); + let mut validators: Vec<_> = Validators::from(validators).into(); validators.reverse(); validators } - fn current_validators(&self, hash: BlockHash) -> Vec { + fn current_validators(&self, hash: BlockHash) -> Vec { let client: Arc = self.client.read().as_ref().and_then(Weak::upgrade).expect("Client is not initialized"); let block_id = hash.into(); let state = client.state_at(block_id).expect("The current validators must be called on the confirmed block"); - let validators = CurrentValidatorSet::load_from_state(&state).unwrap(); - let mut validators: Vec<_> = validators.into(); + let validators = CurrentValidators::load_from_state(&state).unwrap(); + let mut validators: Vec<_> = Validators::from(validators).into(); validators.reverse(); validators } fn validators(&self, hash: BlockHash) -> Vec { let validators = self.next_validators(hash); - validators.into_iter().map(|val| *val.pubkey()).collect() + validators.into_iter().map(|val| val.public_key).collect() } pub fn proposer_index(&self, parent: BlockHash, proposed_view: usize) -> usize { @@ -67,7 +67,7 @@ impl DynamicValidator { pub fn get_current(&self, hash: &BlockHash, index: usize) -> Public { let validators = self.current_validators(*hash); let n_validators = validators.len(); - *validators.get(index % n_validators).unwrap().pubkey() + validators.get(index % n_validators).unwrap().public_key } pub fn check_enough_votes_with_current(&self, hash: &BlockHash, votes: &BitSet) -> Result<(), EngineError> { @@ -82,9 +82,9 @@ impl DynamicValidator { index, } })?; - voted_weight += validator.weight(); + voted_weight += validator.voting_power; } - let total_weight: u64 = validators.iter().map(|v| v.weight()).sum(); + let total_weight: u64 = validators.iter().map(|v| v.voting_power).sum(); if voted_weight * 3 > total_weight * 2 { Ok(()) } else { @@ -141,9 +141,9 @@ impl ValidatorSet for DynamicValidator { index, } })?; - voted_weight += validator.weight(); + voted_weight += validator.voting_power; } - let total_weight: u64 = validators.iter().map(SimpleValidator::weight).sum(); + let total_weight: u64 = validators.iter().map(|validator| validator.voting_power).sum(); if voted_weight * 3 > total_weight * 2 { Ok(()) } else { @@ -164,7 +164,7 @@ impl ValidatorSet for DynamicValidator { } fn current_validators(&self, hash: &BlockHash) -> Vec { - DynamicValidator::current_validators(self, *hash).into_iter().map(|v| *v.pubkey()).collect() + DynamicValidator::current_validators(self, *hash).into_iter().map(|v| v.public_key).collect() } fn next_validators(&self, hash: &BlockHash) -> Vec { diff --git a/json/src/scheme/params.rs b/json/src/scheme/params.rs index dbb669389a..871dad6a17 100644 --- a/json/src/scheme/params.rs +++ b/json/src/scheme/params.rs @@ -31,20 +31,6 @@ pub struct Params { pub max_body_size: Uint, /// Snapshot creation period in unit of block numbers. pub snapshot_period: Uint, - - pub term_seconds: Uint, - pub nomination_expiration: Uint, - pub custody_period: Uint, - pub release_period: Uint, - pub max_num_of_validators: Uint, - pub min_num_of_validators: Uint, - pub delegation_threshold: Uint, - pub min_deposit: Uint, - pub max_candidate_metadata_size: Uint, - - /// A monotonically increasing number to denote the consensus version. - /// It is increased when we fork. - pub era: Option, } #[cfg(test)] @@ -58,16 +44,7 @@ mod tests { "maxExtraDataSize": "0x20", "networkID" : "tc", "maxBodySize" : 4194304, - "snapshotPeriod": 16384, - "termSeconds": 3600, - "nominationExpiration": 24, - "custodyPeriod": 25, - "releasePeriod": 26, - "maxNumOfValidators": 27, - "minNumOfValidators": 28, - "delegationThreshold": 29, - "minDeposit": 30, - "maxCandidateMetadataSize": 31 + "snapshotPeriod": 16384 }"#; let deserialized: Params = serde_json::from_str(s).unwrap(); @@ -75,16 +52,6 @@ mod tests { assert_eq!(deserialized.network_id, "tc".into()); assert_eq!(deserialized.max_body_size, 4_194_304.into()); assert_eq!(deserialized.snapshot_period, 16_384.into()); - assert_eq!(deserialized.term_seconds, 3600.into()); - assert_eq!(deserialized.nomination_expiration, 24.into()); - assert_eq!(deserialized.custody_period, 25.into()); - assert_eq!(deserialized.release_period, 26.into()); - assert_eq!(deserialized.max_num_of_validators, 27.into()); - assert_eq!(deserialized.min_num_of_validators, 28.into()); - assert_eq!(deserialized.delegation_threshold, 29.into()); - assert_eq!(deserialized.min_deposit, 30.into()); - assert_eq!(deserialized.max_candidate_metadata_size, 31.into()); - assert_eq!(deserialized.era, None); } #[test] @@ -94,17 +61,7 @@ mod tests { "maxExtraDataSize": "0x20", "networkID" : "tc", "maxBodySize" : 4194304, - "snapshotPeriod": 16384, - "termSeconds": 3600, - "nominationExpiration": 24, - "custodyPeriod": 25, - "releasePeriod": 26, - "maxNumOfValidators": 27, - "minNumOfValidators": 28, - "delegationThreshold": 29, - "minDeposit": 30, - "maxCandidateMetadataSize": 31, - "era": 32 + "snapshotPeriod": 16384 }"#; let deserialized: Params = serde_json::from_str(s).unwrap(); @@ -112,15 +69,5 @@ mod tests { assert_eq!(deserialized.network_id, "tc".into()); assert_eq!(deserialized.max_body_size, 4_194_304.into()); assert_eq!(deserialized.snapshot_period, 16_384.into()); - assert_eq!(deserialized.term_seconds, 3600.into()); - assert_eq!(deserialized.nomination_expiration, 24.into()); - assert_eq!(deserialized.custody_period, 25.into()); - assert_eq!(deserialized.release_period, 26.into()); - assert_eq!(deserialized.max_num_of_validators, 27.into()); - assert_eq!(deserialized.min_num_of_validators, 28.into()); - assert_eq!(deserialized.delegation_threshold, 29.into()); - assert_eq!(deserialized.min_deposit, 30.into()); - assert_eq!(deserialized.max_candidate_metadata_size, 31.into()); - assert_eq!(deserialized.era, Some(32.into())); } } diff --git a/rpc/src/v1/types/action.rs b/rpc/src/v1/types/action.rs index 8c8f196cad..f2ce89f909 100644 --- a/rpc/src/v1/types/action.rs +++ b/rpc/src/v1/types/action.rs @@ -17,7 +17,7 @@ use super::super::errors::ConversionError; use cjson::uint::Uint; use ckey::{Error as KeyError, NetworkId, PlatformAddress}; -use ctypes::transaction::{Action as ActionType, Approval}; +use ctypes::transaction::Action as ActionType; use primitives::Bytes; use rlp::Encodable; use std::convert::TryFrom; @@ -29,42 +29,6 @@ pub enum Action { receiver: PlatformAddress, quantity: Uint, }, - TransferCCS { - address: PlatformAddress, - quantity: Uint, - }, - DelegateCCS { - address: PlatformAddress, - quantity: Uint, - }, - Revoke { - address: PlatformAddress, - quantity: Uint, - }, - #[serde(rename_all = "camelCase")] - Redelegate { - prev_delegatee: PlatformAddress, - next_delegatee: PlatformAddress, - quantity: Uint, - }, - SelfNominate { - deposit: Uint, - metadata: Bytes, - }, - #[serde(rename_all = "camelCase")] - ChangeParams { - metadata_seq: Uint, - params: Bytes, - approvals: Vec, - }, - ReportDoubleVote { - message1: Bytes, - message2: Bytes, - }, - UpdateValidators, - CloseTerm, - ChangeNextValidators, - Elect, } impl Action { @@ -77,71 +41,6 @@ impl Action { receiver: PlatformAddress::new_v0(network_id, receiver), quantity: quantity.into(), }, - ActionType::TransferCCS { - address, - quantity, - } => Action::TransferCCS { - address: PlatformAddress::new_v0(network_id, address), - quantity: quantity.into(), - }, - ActionType::DelegateCCS { - address, - quantity, - } => Action::DelegateCCS { - address: PlatformAddress::new_v0(network_id, address), - quantity: quantity.into(), - }, - ActionType::Revoke { - address, - quantity, - } => Action::Revoke { - address: PlatformAddress::new_v0(network_id, address), - quantity: quantity.into(), - }, - ActionType::Redelegate { - prev_delegatee, - next_delegatee, - quantity, - } => Action::Redelegate { - prev_delegatee: PlatformAddress::new_v0(network_id, prev_delegatee), - next_delegatee: PlatformAddress::new_v0(network_id, next_delegatee), - quantity: quantity.into(), - }, - ActionType::SelfNominate { - deposit, - metadata, - } => Action::SelfNominate { - deposit: deposit.into(), - metadata, - }, - ActionType::ChangeParams { - metadata_seq, - params, - approvals, - } => Action::ChangeParams { - metadata_seq: metadata_seq.into(), - params: params.rlp_bytes(), - approvals, - }, - ActionType::ReportDoubleVote { - message1, - message2, - } => Action::ReportDoubleVote { - message1, - message2, - }, - ActionType::UpdateValidators { - .. - } => Action::UpdateValidators, // TODO: Implement serialization - ActionType::CloseTerm { - .. - } => Action::CloseTerm, // TODO: Implement serialization - ActionType::ChangeNextValidators { - .. - } => Action::ChangeNextValidators, // TODO: Implement serialization - ActionType::Elect { - .. - } => Action::Elect, // TODO: Implement serialization } } } @@ -157,63 +56,6 @@ impl TryFrom for ActionType { receiver: receiver.try_into_pubkey()?, quantity: quantity.into(), }, - Action::TransferCCS { - address, - quantity, - } => ActionType::TransferCCS { - address: address.try_into_pubkey()?, - quantity: quantity.into(), - }, - Action::DelegateCCS { - address, - quantity, - } => ActionType::DelegateCCS { - address: address.try_into_pubkey()?, - quantity: quantity.into(), - }, - Action::Revoke { - address, - quantity, - } => ActionType::Revoke { - address: address.try_into_pubkey()?, - quantity: quantity.into(), - }, - Action::Redelegate { - prev_delegatee, - next_delegatee, - quantity, - } => ActionType::Redelegate { - prev_delegatee: prev_delegatee.try_into_pubkey()?, - next_delegatee: next_delegatee.try_into_pubkey()?, - quantity: quantity.into(), - }, - Action::SelfNominate { - deposit, - metadata, - } => ActionType::SelfNominate { - deposit: deposit.into(), - metadata, - }, - Action::ChangeParams { - metadata_seq, - params, - approvals, - } => ActionType::ChangeParams { - metadata_seq: metadata_seq.into(), - params: Box::new(rlp::decode(¶ms).map_err(KeyError::from)?), - approvals, - }, - Action::ReportDoubleVote { - message1, - message2, - } => ActionType::ReportDoubleVote { - message1, - message2, - }, - Action::UpdateValidators => unreachable!("No reason to get UpdateValidators from RPCs"), - Action::CloseTerm => unreachable!("No reason to get CloseTerm from RPCs"), - Action::ChangeNextValidators => unreachable!("No reason to get ChangeNextValidators from RPCs"), - Action::Elect => unreachable!("No reason to get Elect from RPCs"), }) } } diff --git a/state/src/impls/top_level.rs b/state/src/impls/top_level.rs index dbd127bff9..2e90b6bb28 100644 --- a/state/src/impls/top_level.rs +++ b/state/src/impls/top_level.rs @@ -37,22 +37,13 @@ use crate::cache::{ModuleCache, TopCache}; use crate::checkpoint::{CheckpointId, StateWithCheckpoint}; -use crate::stake::{ - change_params, close_term, delegate_ccs, jail, redelegate, release_jailed_prisoners, revoke, self_nominate, - transfer_ccs, -}; use crate::traits::{ModuleStateView, StateWithCache, TopState, TopStateView}; -use crate::{ - ActionData, CurrentValidators, FindDoubleVoteHandler, Metadata, MetadataAddress, Module, ModuleAddress, - ModuleLevelState, NextValidators, StateDB, StateResult, -}; +use crate::{ActionData, Metadata, MetadataAddress, Module, ModuleAddress, ModuleLevelState, StateDB, StateResult}; use cdb::{AsHashDB, DatabaseError}; -use ckey::{Ed25519Public as Public, NetworkId}; use coordinator::context::{Key as DbCxtKey, StorageAccess, Value as DbCxtValue}; use ctypes::errors::RuntimeError; -use ctypes::transaction::{Action, Transaction}; use ctypes::util::unexpected::Mismatch; -use ctypes::{BlockNumber, CommonParams, ConsensusParams, StorageId, TxHash}; +use ctypes::{CommonParams, ConsensusParams, StorageId}; use kvdb::DBTransaction; use merkle_trie::{Result as TrieResult, TrieError, TrieFactory}; use primitives::{Bytes, H256}; @@ -225,8 +216,6 @@ impl StateWithCache for TopLevelState { } const TOP_CHECKPOINT: CheckpointId = 777; -const FEE_CHECKPOINT: CheckpointId = 123; -const ACTION_CHECKPOINT: CheckpointId = 130; impl StateWithCheckpoint for TopLevelState { fn create_checkpoint(&mut self, id: CheckpointId) { @@ -279,172 +268,6 @@ impl TopLevelState { Ok(state) } - /// Execute a given tranasction, charging tranasction fee. - /// This will change the state accordingly. - pub fn apply( - &mut self, - tx: &Transaction, - sender_public: &Public, - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - current_block_timestamp: u64, - ) -> StateResult<()> { - StateWithCheckpoint::create_checkpoint(self, FEE_CHECKPOINT); - let result = self.apply_internal( - tx, - sender_public, - client, - parent_block_number, - parent_block_timestamp, - current_block_timestamp, - ); - match result { - Ok(()) => { - StateWithCheckpoint::discard_checkpoint(self, FEE_CHECKPOINT); - } - Err(_) => { - self.revert_to_checkpoint(FEE_CHECKPOINT); - } - } - result - } - - fn apply_internal( - &mut self, - tx: &Transaction, - sender: &Public, - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - current_block_timestamp: u64, - ) -> StateResult<()> { - let seq = Default::default(); - - if tx.seq != seq { - return Err(RuntimeError::InvalidSeq(Mismatch { - expected: seq, - found: tx.seq, - }) - .into()) - } - - let _fee = tx.fee; - - // The failed transaction also must pay the fee and increase seq. - StateWithCheckpoint::create_checkpoint(self, ACTION_CHECKPOINT); - let result = self.apply_action( - &tx.action, - tx.network_id, - tx.hash(), - sender, - client, - parent_block_number, - parent_block_timestamp, - current_block_timestamp, - ); - match &result { - Ok(()) => { - StateWithCheckpoint::discard_checkpoint(self, ACTION_CHECKPOINT); - } - Err(_) => { - self.revert_to_checkpoint(ACTION_CHECKPOINT); - } - } - result - } - - #[allow(clippy::too_many_arguments)] - fn apply_action( - &mut self, - action: &Action, - _network_id: NetworkId, - _tx_hash: TxHash, - sender: &Public, - client: &C, - parent_block_number: BlockNumber, - _parent_block_timestamp: u64, - _current_block_timestamp: u64, - ) -> StateResult<()> { - match action { - Action::Pay { - receiver: _, - quantity: _, - } => Ok(()), - Action::TransferCCS { - address, - quantity, - } => transfer_ccs(self, sender, &address, *quantity), - Action::DelegateCCS { - address, - quantity, - } => delegate_ccs(self, sender, &address, *quantity), - Action::Revoke { - address, - quantity, - } => revoke(self, sender, address, *quantity), - Action::Redelegate { - prev_delegatee, - next_delegatee, - quantity, - } => redelegate(self, sender, prev_delegatee, next_delegatee, *quantity), - Action::SelfNominate { - deposit, - metadata, - } => { - let (current_term, nomination_ends_at) = { - let metadata = self.metadata()?.expect("Metadata must exist"); - let current_term = metadata.current_term_id(); - let expiration = metadata.params().nomination_expiration(); - let nomination_ends_at = current_term + expiration; - (current_term, nomination_ends_at) - }; - self_nominate(self, sender, *deposit, current_term, nomination_ends_at, metadata.clone()) - } - Action::ChangeParams { - metadata_seq, - params, - approvals, - } => change_params(self, *metadata_seq, **params, &approvals), - Action::ReportDoubleVote { - message1, - .. - } => { - let handler = client.double_vote_handler().expect("Unknown custom transaction applied!"); - handler.execute(message1, self, sender)?; - Ok(()) - } - Action::UpdateValidators { - validators, - } => { - let next_validators_in_state = NextValidators::load_from_state(self)?; - if validators != &Vec::from(next_validators_in_state) { - return Err(RuntimeError::InvalidValidators.into()) - } - let mut current_validators = CurrentValidators::load_from_state(self)?; - current_validators.update(validators.clone()); - current_validators.save_to_state(self)?; - Ok(()) - } - Action::CloseTerm { - inactive_validators, - next_validators, - released_addresses, - custody_until, - kick_at, - } => { - close_term(self, next_validators, inactive_validators)?; - release_jailed_prisoners(self, released_addresses)?; - jail(self, inactive_validators, *custody_until, *kick_at)?; - self.increase_term_id(parent_block_number + 1) - } - Action::ChangeNextValidators { - validators, - } => NextValidators::from(validators.clone()).save_to_state(self), - Action::Elect => NextValidators::elect(self)?.save_to_state(self), - } - } - fn create_module_level_state(&mut self, storage_id: StorageId) -> StateResult<()> { const DEFAULT_MODULE_ROOT: H256 = ccrypto::BLAKE_NULL_RLP; { diff --git a/state/src/item/mod.rs b/state/src/item/mod.rs index 1d39abc55c..134a4419f1 100644 --- a/state/src/item/mod.rs +++ b/state/src/item/mod.rs @@ -22,7 +22,6 @@ pub mod metadata; pub mod module; pub mod module_datum; pub mod stake; -pub mod validator_set; #[derive(Clone, Copy)] #[repr(u8)] diff --git a/state/src/item/stake.rs b/state/src/item/stake.rs index 9521eb6340..4cbcf72a2d 100644 --- a/state/src/item/stake.rs +++ b/state/src/item/stake.rs @@ -14,364 +14,70 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::{ActionData, StakeKeyBuilder, StateResult, TopLevelState, TopState, TopStateView}; -use ckey::Ed25519Public as Public; -use ctypes::errors::RuntimeError; -use ctypes::transaction::Validator; -use ctypes::{CompactValidatorEntry, CompactValidatorSet}; -use primitives::{Bytes, H256}; -use rlp::{decode_list, encode_list, Decodable, Encodable, Rlp, RlpStream}; -use std::cmp::Ordering; -use std::collections::btree_map::{BTreeMap, Entry}; -use std::collections::btree_set::{self, BTreeSet}; -use std::collections::{btree_map, HashMap, HashSet}; +use crate::{StakeKeyBuilder, StateResult, TopLevelState, TopState, TopStateView}; +use ctypes::Validators; +use primitives::H256; +use rlp::{decode, encode}; use std::ops::Deref; -use std::vec; - -pub fn get_stake_account_key(pubkey: &Public) -> H256 { - StakeKeyBuilder::new(2).append(&"Account").append(pubkey).into_key() -} lazy_static! { - 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(pubkey: &Public) -> H256 { - StakeKeyBuilder::new(2).append(&"Delegation").append(pubkey).into_key() -} - -pub type StakeQuantity = u64; -pub type DepositQuantity = u64; - -pub struct StakeAccount<'a> { - pub pubkey: &'a Public, - pub balance: StakeQuantity, -} - -impl<'a> StakeAccount<'a> { - pub fn load_from_state(state: &TopLevelState, pubkey: &'a Public) -> StateResult> { - let account_key = get_stake_account_key(pubkey); - let action_data = state.action_data(&account_key)?; - - let balance = match action_data { - Some(data) => Rlp::new(&data).as_val().unwrap(), - None => StakeQuantity::default(), - }; - - Ok(StakeAccount { - pubkey, - balance, - }) - } - - pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { - let account_key = get_stake_account_key(self.pubkey); - if self.balance != 0 { - let rlp = rlp::encode(&self.balance); - state.update_action_data(&account_key, rlp)?; - } else { - state.remove_action_data(&account_key); - } - Ok(()) - } - - pub fn subtract_balance(&mut self, amount: u64) -> Result<(), RuntimeError> { - if self.balance < amount { - return Err(RuntimeError::InsufficientBalance { - pubkey: *self.pubkey, - cost: amount, - balance: self.balance, - }) - } - self.balance -= amount; - Ok(()) - } - - pub fn add_balance(&mut self, amount: u64) -> Result<(), RuntimeError> { - self.balance += amount; - Ok(()) - } -} - -pub struct Stakeholders(BTreeSet); - -impl Stakeholders { - pub fn load_from_state(state: &TopLevelState) -> StateResult { - let action_data = state.action_data(&*STAKEHOLDER_ADDRESSES_KEY)?; - let pubkeys = decode_set(action_data.as_ref()); - Ok(Stakeholders(pubkeys)) - } - - pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { - let key = *STAKEHOLDER_ADDRESSES_KEY; - if !self.0.is_empty() { - state.update_action_data(&key, encode_set(&self.0))?; - } else { - state.remove_action_data(&key); - } - Ok(()) - } - - fn delegatees(state: &TopLevelState) -> StateResult> { - let stakeholders = Stakeholders::load_from_state(state)?; - let mut result = HashMap::new(); - for stakeholder in stakeholders.iter() { - let delegation = Delegation::load_from_state(state, stakeholder)?; - for (delegatee, quantity) in delegation.iter() { - *result.entry(*delegatee).or_default() += *quantity; - } - } - Ok(result) - } - - #[allow(dead_code)] - pub fn contains(&self, pubkey: &Public) -> bool { - self.0.contains(pubkey) - } - - pub fn update_by_increased_balance(&mut self, account: &StakeAccount<'_>) { - if account.balance > 0 { - self.0.insert(*account.pubkey); - } - } - - pub fn update_by_decreased_balance(&mut self, account: &StakeAccount<'_>, delegation: &Delegation<'_>) { - assert!(account.pubkey == delegation.delegator); - if account.balance == 0 && delegation.sum() == 0 { - self.0.remove(account.pubkey); - } - } - - pub fn iter(&self) -> btree_set::Iter<'_, Public> { - self.0.iter() - } -} - -pub struct Delegation<'a> { - pub delegator: &'a Public, - delegatees: BTreeMap, -} - -impl<'a> Delegation<'a> { - pub fn load_from_state(state: &TopLevelState, delegator: &'a Public) -> StateResult> { - let key = get_delegation_key(delegator); - let action_data = state.action_data(&key)?; - let delegatees = decode_map(action_data.as_ref()); - - Ok(Delegation { - delegator, - delegatees, - }) - } - - pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { - let key = get_delegation_key(self.delegator); - if !self.delegatees.is_empty() { - let encoded = encode_map(&self.delegatees); - state.update_action_data(&key, encoded)?; - } else { - state.remove_action_data(&key); - } - Ok(()) - } - - pub fn add_quantity(&mut self, delegatee: Public, quantity: StakeQuantity) -> StateResult<()> { - if quantity == 0 { - return Ok(()) - } - *self.delegatees.entry(delegatee).or_insert(0) += quantity; - Ok(()) - } - - pub fn subtract_quantity(&mut self, delegatee: Public, quantity: StakeQuantity) -> StateResult<()> { - if quantity == 0 { - return Ok(()) - } - - if let Entry::Occupied(mut entry) = self.delegatees.entry(delegatee) { - match entry.get().cmp(&quantity) { - Ordering::Greater => { - *entry.get_mut() -= quantity; - return Ok(()) - } - Ordering::Equal => { - entry.remove(); - return Ok(()) - } - Ordering::Less => {} - } - } - - Err(RuntimeError::FailedToHandleCustomAction("Cannot subtract more than that is delegated to".to_string()) - .into()) - } - - pub fn get_quantity(&self, delegatee: &Public) -> StakeQuantity { - self.delegatees.get(delegatee).cloned().unwrap_or(0) - } - - pub fn iter(&self) -> btree_map::Iter<'_, Public, StakeQuantity> { - self.delegatees.iter() - } - - pub fn sum(&self) -> u64 { - self.delegatees.values().sum() - } -} - #[derive(Debug)] -pub struct NextValidators(Vec); +pub struct NextValidators(Validators); impl NextValidators { - pub fn from_vector(vec: Vec) -> Self { - Self(vec) - } - pub fn load_from_state(state: &TopLevelState) -> StateResult { let key = &*NEXT_VALIDATORS_KEY; - let validators = state.action_data(&key)?.map(|data| decode_list(&data)).unwrap_or_default(); + let validators = state + .action_data(&key)? + .map(|data| decode(&data).expect("Low level database error. Some issue with disk?")) + .unwrap_or_default(); Ok(Self(validators)) } - pub fn create_compact_validator_set(&self) -> CompactValidatorSet { - CompactValidatorSet::new( - self.0 - .iter() - .map(|x| CompactValidatorEntry { - public_key: *x.pubkey(), - delegation: x.delegation(), - }) - .collect(), - ) - } - - pub fn elect(state: &TopLevelState) -> StateResult { - let (delegation_threshold, max_num_of_validators, min_num_of_validators, min_deposit) = { - let metadata = state.metadata()?.expect("Metadata must exist"); - let common_params = metadata.params(); - ( - common_params.delegation_threshold(), - common_params.max_num_of_validators(), - common_params.min_num_of_validators(), - common_params.min_deposit(), - ) - }; - assert!(max_num_of_validators >= min_num_of_validators); - - let delegatees = Stakeholders::delegatees(&state)?; - // Step 1 & 2. - let mut validators = Candidates::prepare_validators(&state, min_deposit, &delegatees)?; - // validators are now sorted in descending order of (delegation, deposit, priority) - validators.reverse(); - - let banned = Banned::load_from_state(&state)?; - for validator in &validators { - assert!(!banned.is_banned(validator.pubkey()), "{:?} is banned public key", validator.pubkey()); - } - - // Step 3 - validators.truncate(max_num_of_validators); - - if validators.len() < min_num_of_validators { - cerror!( - ENGINE, - "There must be something wrong. {}, {} < {}", - "validators.len() < min_num_of_validators", - validators.len(), - min_num_of_validators - ); - } - // Step 4 & 5 - let (minimum, rest) = validators.split_at(min_num_of_validators.min(validators.len())); - let over_threshold = rest.iter().filter(|c| c.delegation() >= delegation_threshold); - - let mut result: Vec<_> = minimum.iter().chain(over_threshold).cloned().collect(); - result.reverse(); // Ascending order of (delegation, deposit, priority) - Ok(Self(result)) - } - pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { let key = &*NEXT_VALIDATORS_KEY; if !self.is_empty() { - state.update_action_data(&key, encode_list(&self.0).to_vec())?; + state.update_action_data(&key, encode(&self.0).to_vec())?; } else { state.remove_action_data(&key); } Ok(()) } - - pub fn update_weight(state: &TopLevelState, block_author: &Public) -> StateResult { - let mut validators = Self::load_from_state(state)?; - let min_delegation = validators.min_delegation(); - for validator in validators.0.iter_mut().rev() { - if *validator.pubkey() == *block_author { - // block author - validator.set_weight(validator.weight().saturating_sub(min_delegation)); - break - } - // neglecting validators - validator.set_weight(validator.weight().saturating_sub(min_delegation * 2)); - } - if validators.0.iter().all(|validator| validator.weight() == 0) { - validators.0.iter_mut().for_each(Validator::reset); - } - validators.0.sort_unstable(); - Ok(validators) - } - - pub fn remove(&mut self, target: &Public) { - self.0.retain(|v| *target != *v.pubkey()); - } - - pub fn delegation(&self, pubkey: &Public) -> Option { - self.0.iter().find(|validator| *validator.pubkey() == *pubkey).map(|&validator| validator.delegation()) - } - - fn min_delegation(&self) -> StakeQuantity { - self.0.iter().map(|&validator| validator.delegation()).min().expect("There must be at least one validators") - } } impl Deref for NextValidators { - type Target = Vec; + type Target = Validators; fn deref(&self) -> &Self::Target { &self.0 } } -impl From> for NextValidators { - fn from(validators: Vec) -> Self { - Self(validators) +impl From for NextValidators { + fn from(set: Validators) -> Self { + Self(set) } } -impl From for Vec { +impl From for Validators { fn from(val: NextValidators) -> Self { val.0 } } -impl IntoIterator for NextValidators { - type Item = Validator; - type IntoIter = vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - #[derive(Debug)] -pub struct CurrentValidators(Vec); +pub struct CurrentValidators(Validators); impl CurrentValidators { pub fn load_from_state(state: &TopLevelState) -> StateResult { let key = &*CURRENT_VALIDATORS_KEY; - let validators = state.action_data(&key)?.map(|data| decode_list(&data)).unwrap_or_default(); + let validators = state + .action_data(&key)? + .map(|data| decode(&data).expect("Low level database error. Some issue with disk?")) + .unwrap_or_default(); Ok(Self(validators)) } @@ -379,1268 +85,28 @@ impl CurrentValidators { pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { let key = &*CURRENT_VALIDATORS_KEY; if !self.is_empty() { - state.update_action_data(&key, encode_list(&self.0).to_vec())?; + state.update_action_data(&key, encode(&self.0).to_vec())?; } else { state.remove_action_data(&key); } Ok(()) } - pub fn update(&mut self, validators: Vec) { + pub fn update(&mut self, validators: Validators) { self.0 = validators; } - - pub fn pubkeys(&self) -> Vec { - self.0.iter().rev().map(|v| *v.pubkey()).collect() - } } impl Deref for CurrentValidators { - type Target = Vec; + type Target = Validators; fn deref(&self) -> &Self::Target { &self.0 } } -impl From for Vec { +impl From for Validators { fn from(val: CurrentValidators) -> Self { val.0 } } - -#[derive(Default)] -pub struct Candidates(Vec); -#[derive(Clone, Debug, Eq, PartialEq, RlpEncodable, RlpDecodable)] -pub struct Candidate { - pub pubkey: Public, - pub deposit: DepositQuantity, - pub nomination_ends_at: u64, - pub metadata: Bytes, -} - -impl Candidates { - pub fn load_from_state(state: &TopLevelState) -> StateResult { - let key = *CANDIDATES_KEY; - let candidates = state.action_data(&key)?.map(|data| decode_list::(&data)).unwrap_or_default(); - Ok(Candidates(candidates)) - } - - pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { - let key = *CANDIDATES_KEY; - if !self.0.is_empty() { - let encoded = encode_iter(self.0.iter()); - state.update_action_data(&key, encoded)?; - } else { - state.remove_action_data(&key); - } - Ok(()) - } - - // Sorted list of validators in ascending order of (delegation, deposit, priority). - fn prepare_validators( - state: &TopLevelState, - min_deposit: DepositQuantity, - delegations: &HashMap, - ) -> StateResult> { - let Candidates(candidates) = Self::load_from_state(state)?; - let mut result = Vec::new(); - for candidate in candidates.into_iter().filter(|c| c.deposit >= min_deposit) { - if let Some(delegation) = delegations.get(&candidate.pubkey).cloned() { - result.push(Validator::new(delegation, candidate.deposit, candidate.pubkey)); - } - } - // Candidates are sorted in low priority: low index, high priority: high index - // so stable sorting with the key (delegation, deposit) preserves its priority order. - // ascending order of (delegation, deposit, priority) - result.sort_by_key(|v| (v.delegation(), v.deposit())); - Ok(result) - } - - pub fn get_candidate(&self, account: &Public) -> Option<&Candidate> { - self.0.iter().find(|c| c.pubkey == *account) - } - - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn is_empty(&self) -> bool { - self.0.len() == 0 - } - - #[cfg(test)] - pub fn get_index(&self, account: &Public) -> Option { - self.0.iter().position(|c| c.pubkey == *account) - } - - pub fn add_deposit( - &mut self, - pubkey: &Public, - quantity: DepositQuantity, - nomination_ends_at: u64, - metadata: Bytes, - ) { - if let Some(index) = self.0.iter().position(|c| c.pubkey == *pubkey) { - let candidate = &mut self.0[index]; - candidate.deposit += quantity; - if candidate.nomination_ends_at < nomination_ends_at { - candidate.nomination_ends_at = nomination_ends_at; - } - candidate.metadata = metadata; - } else { - self.0.push(Candidate { - pubkey: *pubkey, - deposit: quantity, - nomination_ends_at, - metadata, - }); - }; - self.reprioritize(&[*pubkey]); - } - - pub fn renew_candidates( - &mut self, - validators: &[Validator], - nomination_ends_at: u64, - inactive_validators: &[Public], - banned: &Banned, - ) { - let to_renew: HashSet<_> = (validators.iter()) - .map(|validator| *validator.pubkey()) - .filter(|pubkey| !inactive_validators.contains(pubkey)) - .collect(); - - for candidate in self.0.iter_mut().filter(|c| to_renew.contains(&c.pubkey)) { - let pubkey = candidate.pubkey; - assert!(!banned.is_banned(&pubkey), "{:?} is banned public key", pubkey); - candidate.nomination_ends_at = nomination_ends_at; - } - - let to_reprioritize: Vec<_> = - self.0.iter().filter(|c| to_renew.contains(&c.pubkey)).map(|c| c.pubkey).collect(); - - self.reprioritize(&to_reprioritize); - } - - pub fn drain_expired_candidates(&mut self, term_index: u64) -> Vec { - let (expired, retained): (Vec<_>, Vec<_>) = self.0.drain(..).partition(|c| c.nomination_ends_at <= term_index); - self.0 = retained; - expired - } - - pub fn remove(&mut self, pubkey: &Public) -> Option { - if let Some(index) = self.0.iter().position(|c| c.pubkey == *pubkey) { - Some(self.0.remove(index)) - } else { - None - } - } - - fn reprioritize(&mut self, targets: &[Public]) { - let mut renewed = Vec::new(); - for target in targets { - let position = - (self.0.iter()).position(|c| c.pubkey == *target).expect("Reprioritize target should be a candidate"); - renewed.push(self.0.remove(position)); - } - self.0.append(&mut renewed); - } -} - -#[derive(Clone)] -pub struct Jail(BTreeMap); -#[derive(Clone, Debug, Eq, PartialEq, RlpEncodable, RlpDecodable)] -pub struct Prisoner { - pub pubkey: Public, - pub deposit: DepositQuantity, - pub custody_until: u64, - pub released_at: u64, -} - -#[derive(Debug, Eq, PartialEq)] -pub enum ReleaseResult { - NotExists, - InCustody, - Released(Prisoner), -} - -impl Jail { - pub fn load_from_state(state: &TopLevelState) -> StateResult { - let key = *JAIL_KEY; - let prisoner = state.action_data(&key)?.map(|data| decode_list::(&data)).unwrap_or_default(); - let indexed = prisoner.into_iter().map(|c| (c.pubkey, c)).collect(); - Ok(Jail(indexed)) - } - - pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { - let key = *JAIL_KEY; - if !self.0.is_empty() { - let encoded = encode_iter(self.0.values()); - state.update_action_data(&key, encoded)?; - } else { - state.remove_action_data(&key); - } - Ok(()) - } - - pub fn get_prisoner(&self, pubkey: &Public) -> Option<&Prisoner> { - self.0.get(pubkey) - } - - #[cfg(test)] - pub fn len(&self) -> usize { - self.0.len() - } - pub fn is_empty(&self) -> bool { - self.0.len() == 0 - } - - pub fn add(&mut self, candidate: Candidate, custody_until: u64, released_at: u64) { - assert!(custody_until <= released_at); - let pubkey = candidate.pubkey; - self.0.insert(pubkey, Prisoner { - pubkey, - deposit: candidate.deposit, - custody_until, - released_at, - }); - } - - pub fn remove(&mut self, pubkey: &Public) -> Option { - self.0.remove(pubkey) - } - - pub fn try_release(&mut self, pubkey: &Public, term_index: u64) -> ReleaseResult { - match self.0.entry(*pubkey) { - Entry::Occupied(entry) => { - if entry.get().custody_until < term_index { - ReleaseResult::Released(entry.remove()) - } else { - ReleaseResult::InCustody - } - } - _ => ReleaseResult::NotExists, - } - } - - pub fn released_addresses(self, term_index: u64) -> Vec { - self.0.values().filter(|c| c.released_at <= term_index).map(|c| c.pubkey).collect() - } -} - -pub struct Banned(BTreeSet); -impl Banned { - pub fn load_from_state(state: &TopLevelState) -> StateResult { - let key = *BANNED_KEY; - let action_data = state.action_data(&key)?; - Ok(Banned(decode_set(action_data.as_ref()))) - } - - pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { - let key = *BANNED_KEY; - if !self.0.is_empty() { - let encoded = encode_set(&self.0); - state.update_action_data(&key, encoded)?; - } else { - state.remove_action_data(&key); - } - Ok(()) - } - - pub fn add(&mut self, pubkey: Public) { - self.0.insert(pubkey); - } - - pub fn is_banned(&self, pubkey: &Public) -> bool { - self.0.contains(pubkey) - } -} - -fn decode_set(data: Option<&ActionData>) -> BTreeSet -where - V: Ord + Decodable, { - let mut result = BTreeSet::new(); - if let Some(rlp) = data.map(|x| Rlp::new(x)) { - for record in rlp.iter() { - let value: V = record.as_val().unwrap(); - result.insert(value); - } - } - result -} - -fn encode_set(set: &BTreeSet) -> Vec -where - V: Ord + Encodable, { - let mut rlp = RlpStream::new(); - rlp.begin_list(set.len()); - for value in set.iter() { - rlp.append(value); - } - rlp.drain() -} - -fn decode_map(data: Option<&ActionData>) -> BTreeMap -where - K: Ord + Decodable, - V: Decodable, { - if let Some(rlp) = data.map(|x| Rlp::new(x)) { - decode_map_impl(rlp) - } else { - Default::default() - } -} - -fn decode_map_impl(rlp: Rlp<'_>) -> BTreeMap -where - K: Ord + Decodable, - V: Decodable, { - let mut result = BTreeMap::new(); - for record in rlp.iter() { - let key: K = record.val_at(0).unwrap(); - let value: V = record.val_at(1).unwrap(); - assert_eq!(Ok(2), record.item_count()); - result.insert(key, value); - } - result -} - -fn encode_map(map: &BTreeMap) -> Vec -where - K: Ord + Encodable, - V: Encodable, { - let mut rlp = RlpStream::new(); - encode_map_impl(&mut rlp, map); - rlp.drain() -} - -fn encode_map_impl(rlp: &mut RlpStream, map: &BTreeMap) -where - K: Ord + Encodable, - V: Encodable, { - rlp.begin_list(map.len()); - for (key, value) in map.iter() { - let record = rlp.begin_list(2); - record.append(key); - record.append(value); - } -} - -fn encode_iter<'a, V, I>(iter: I) -> Vec -where - V: 'a + Encodable, - I: ExactSizeIterator + Clone, { - let mut rlp = RlpStream::new(); - rlp.begin_list(iter.clone().count()); - for value in iter { - rlp.append(value); - } - rlp.drain() -} - -#[allow(clippy::implicit_hasher)] // XXX: Fix this clippy warning if it becomes a real problem. -#[cfg(test)] -mod tests { - use super::*; - use crate::tests::helpers; - use rand::{Rng, SeedableRng}; - use rand_xorshift::XorShiftRng; - - fn rng() -> XorShiftRng { - let seed: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7]; - XorShiftRng::from_seed(seed) - } - - #[test] - fn default_balance_is_zero() { - let state = helpers::get_temp_state(); - let pubkey = Public::random(); - let account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - assert_eq!(account.pubkey, &pubkey); - assert_eq!(account.balance, 0); - } - - #[test] - fn balance_add() { - let mut state = helpers::get_temp_state(); - let pubkey = Public::random(); - { - let mut account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - account.add_balance(100).unwrap(); - account.save_to_state(&mut state).unwrap(); - } - let account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - assert_eq!(account.balance, 100); - } - - #[test] - fn balance_subtract_error_on_low() { - let mut state = helpers::get_temp_state(); - let pubkey = Public::random(); - { - let mut account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - account.add_balance(100).unwrap(); - account.save_to_state(&mut state).unwrap(); - } - { - let mut account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - let result = account.subtract_balance(110); - assert!(result.is_err()); - assert_eq!( - result, - Err(RuntimeError::InsufficientBalance { - pubkey, - cost: 110, - balance: 100, - }) - ); - } - let account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - assert_eq!(account.balance, 100); - } - - #[test] - fn balance_subtract() { - let mut state = helpers::get_temp_state(); - let pubkey = Public::random(); - - let mut account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - account.add_balance(100).unwrap(); - account.save_to_state(&mut state).unwrap(); - - let mut account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - let result = account.subtract_balance(90); - assert!(result.is_ok()); - account.save_to_state(&mut state).unwrap(); - - let account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - assert_eq!(account.balance, 10); - } - - #[test] - fn balance_subtract_all_should_remove_entry_from_db() { - let mut state = helpers::get_temp_state(); - let pubkey = Public::random(); - - let mut account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - account.add_balance(100).unwrap(); - account.save_to_state(&mut state).unwrap(); - - let mut account = StakeAccount::load_from_state(&state, &pubkey).unwrap(); - let result = account.subtract_balance(100); - assert!(result.is_ok()); - account.save_to_state(&mut state).unwrap(); - - let data = state.action_data(&get_stake_account_key(&pubkey)).unwrap(); - assert_eq!(data, None); - } - - #[test] - fn stakeholders_track() { - let mut rng = rng(); - let mut state = helpers::get_temp_state(); - let pubkeys: Vec<_> = (1..100).map(Public::from).collect(); - let accounts: Vec<_> = pubkeys - .iter() - .map(|pubkey| StakeAccount { - pubkey, - balance: rng.gen_range(1, 100), - }) - .collect(); - - let mut stakeholders = Stakeholders::load_from_state(&state).unwrap(); - for account in &accounts { - stakeholders.update_by_increased_balance(account); - } - stakeholders.save_to_state(&mut state).unwrap(); - - let stakeholders = Stakeholders::load_from_state(&state).unwrap(); - assert!(pubkeys.iter().all(|pubkey| stakeholders.contains(pubkey))); - } - - #[test] - fn stakeholders_untrack() { - let mut rng = rng(); - let mut state = helpers::get_temp_state(); - let pubkeys: Vec<_> = (1..100).map(Public::from).collect(); - let mut accounts: Vec<_> = pubkeys - .iter() - .map(|pubkey| StakeAccount { - pubkey, - balance: rng.gen_range(1, 100), - }) - .collect(); - - let mut stakeholders = Stakeholders::load_from_state(&state).unwrap(); - for account in &accounts { - stakeholders.update_by_increased_balance(account); - } - stakeholders.save_to_state(&mut state).unwrap(); - - let mut stakeholders = Stakeholders::load_from_state(&state).unwrap(); - for account in &mut accounts { - if rand::random() { - account.balance = 0; - } - let delegation = Delegation::load_from_state(&state, account.pubkey).unwrap(); - stakeholders.update_by_decreased_balance(account, &delegation); - } - stakeholders.save_to_state(&mut state).unwrap(); - - let stakeholders = Stakeholders::load_from_state(&state).unwrap(); - for account in &accounts { - let tracked = stakeholders.contains(account.pubkey); - let has_balance = account.balance > 0; - assert!(tracked && has_balance || !tracked && !has_balance); - } - } - - #[test] - fn stakeholders_doesnt_untrack_if_delegation_exists() { - let mut state = helpers::get_temp_state(); - let pubkeys: Vec<_> = (1..100).map(Public::from).collect(); - let mut accounts: Vec<_> = pubkeys - .iter() - .map(|pubkey| StakeAccount { - pubkey, - balance: 100, - }) - .collect(); - - let mut stakeholders = Stakeholders::load_from_state(&state).unwrap(); - for account in &accounts { - stakeholders.update_by_increased_balance(account); - } - stakeholders.save_to_state(&mut state).unwrap(); - - let mut stakeholders = Stakeholders::load_from_state(&state).unwrap(); - for account in &mut accounts { - // like self-delegate - let mut delegation = Delegation::load_from_state(&state, account.pubkey).unwrap(); - delegation.add_quantity(*account.pubkey, account.balance).unwrap(); - account.balance = 0; - stakeholders.update_by_decreased_balance(account, &delegation); - } - stakeholders.save_to_state(&mut state).unwrap(); - - let stakeholders = Stakeholders::load_from_state(&state).unwrap(); - for account in &accounts { - assert!(stakeholders.contains(account.pubkey)); - } - } - - #[test] - fn initial_delegation_is_empty() { - let state = helpers::get_temp_state(); - - let delegatee = Public::random(); - let delegation = Delegation::load_from_state(&state, &delegatee).unwrap(); - assert_eq!(delegation.delegator, &delegatee); - assert_eq!(delegation.iter().count(), 0); - } - - #[test] - fn delegation_add() { - let mut rng = rng(); - let mut state = helpers::get_temp_state(); - - // Prepare - let delegator = Public::random(); - let delegatees: Vec<_> = (0..10).map(Public::from).collect(); - let delegation_amount: HashMap<&Public, StakeQuantity> = - delegatees.iter().map(|pubkey| (pubkey, rng.gen_range(0, 100))).collect(); - - // Do delegate - let mut delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - for delegatee in delegatees.iter() { - delegation.add_quantity(*delegatee, delegation_amount[delegatee]).unwrap() - } - delegation.save_to_state(&mut state).unwrap(); - - // assert - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegation.iter().count(), delegatees.len()); - for delegatee in delegatees.iter() { - assert_eq!(delegation.get_quantity(delegatee), delegation_amount[delegatee]); - } - } - - #[test] - fn delegation_zero_add_should_not_be_included() { - let mut state = helpers::get_temp_state(); - - // Prepare - let delegator = Public::random(); - let delegatee1 = Public::random(); - let delegatee2 = Public::random(); - - // Do delegate - let mut delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - delegation.add_quantity(delegatee1, 100).unwrap(); - delegation.add_quantity(delegatee2, 0).unwrap(); - delegation.save_to_state(&mut state).unwrap(); - - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - let delegated = delegation.iter().collect::>(); - assert_eq!(&delegated, &[(&delegatee1, &100)]); - } - - #[test] - fn delegation_can_subtract() { - let mut state = helpers::get_temp_state(); - - // Prepare - let delegator = Public::random(); - let delegatee = Public::random(); - - let mut delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - delegation.add_quantity(delegatee, 100).unwrap(); - delegation.save_to_state(&mut state).unwrap(); - - // Do subtract - let mut delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - delegation.subtract_quantity(delegatee, 30).unwrap(); - delegation.save_to_state(&mut state).unwrap(); - - // Assert - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegation.get_quantity(&delegatee), 70); - } - - #[test] - fn delegation_cannot_subtract_mor_than_delegated() { - let mut state = helpers::get_temp_state(); - - // Prepare - let delegator = Public::random(); - let delegatee = Public::random(); - - let mut delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - delegation.add_quantity(delegatee, 100).unwrap(); - delegation.save_to_state(&mut state).unwrap(); - - // Do subtract - let mut delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert!(delegation.subtract_quantity(delegatee, 130).is_err()); - } - - #[test] - fn delegation_empty_removed_from_state() { - let mut state = helpers::get_temp_state(); - - // Prepare - let delegator = Public::random(); - let delegatee = Public::random(); - - // Do delegate - let mut delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - delegation.add_quantity(delegatee, 0).unwrap(); - delegation.save_to_state(&mut state).unwrap(); - - let result = state.action_data(&get_delegation_key(&delegator)).unwrap(); - assert_eq!(result, None); - } - - #[test] - fn delegation_became_empty_removed_from_state() { - let mut state = helpers::get_temp_state(); - - // Prepare - let delegator = Public::random(); - let delegatee = Public::random(); - - let mut delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - delegation.add_quantity(delegatee, 100).unwrap(); - delegation.save_to_state(&mut state).unwrap(); - - // Do subtract - let mut delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - delegation.subtract_quantity(delegatee, 100).unwrap(); - delegation.save_to_state(&mut state).unwrap(); - - // Assert - let result = state.action_data(&get_delegation_key(&delegator)).unwrap(); - assert_eq!(result, None); - } - - #[test] - fn candidates_deposit_add() { - let mut state = helpers::get_temp_state(); - - // Prepare - let pubkey = Public::random(); - let deposits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - - for deposit in deposits.iter() { - let mut candidates = Candidates::load_from_state(&state).unwrap(); - candidates.add_deposit(&pubkey, *deposit, 0, b"".to_vec()); - candidates.save_to_state(&mut state).unwrap(); - } - - // Assert - let candidates = Candidates::load_from_state(&state).unwrap(); - let candidate = candidates.get_candidate(&pubkey); - assert_ne!(candidate, None); - assert_eq!(candidate.unwrap().deposit, 55); - } - - #[test] - fn candidates_metadata() { - let mut state = helpers::get_temp_state(); - - // Prepare - let pubkey = Public::random(); - - let mut candidates = Candidates::load_from_state(&state).unwrap(); - candidates.add_deposit(&pubkey, 10, 0, b"metadata".to_vec()); - candidates.save_to_state(&mut state).unwrap(); - - // Assert - let candidates = Candidates::load_from_state(&state).unwrap(); - let candidate = candidates.get_candidate(&pubkey); - assert_ne!(candidate, None); - assert_eq!(&candidate.unwrap().metadata, b"metadata"); - } - - #[test] - fn candidates_update_metadata() { - let mut state = helpers::get_temp_state(); - - // Prepare - let pubkey = Public::random(); - - let mut candidates = Candidates::load_from_state(&state).unwrap(); - candidates.add_deposit(&pubkey, 10, 0, b"metadata".to_vec()); - candidates.save_to_state(&mut state).unwrap(); - - let mut candidates = Candidates::load_from_state(&state).unwrap(); - candidates.add_deposit(&pubkey, 10, 0, b"metadata-updated".to_vec()); - candidates.save_to_state(&mut state).unwrap(); - - // Assert - let candidates = Candidates::load_from_state(&state).unwrap(); - let candidate = candidates.get_candidate(&pubkey); - assert_ne!(candidate, None); - assert_eq!(&candidate.unwrap().metadata, b"metadata-updated"); - } - - #[test] - fn candidates_deposit_can_be_zero() { - let mut state = helpers::get_temp_state(); - - // Prepare - let pubkey = Public::random(); - let mut candidates = Candidates::load_from_state(&state).unwrap(); - candidates.add_deposit(&pubkey, 0, 10, b"".to_vec()); - candidates.save_to_state(&mut state).unwrap(); - - // Assert - let candidates = Candidates::load_from_state(&state).unwrap(); - let candidate = candidates.get_candidate(&pubkey); - assert_ne!(candidate, None); - assert_eq!(candidate.unwrap().deposit, 0); - assert_eq!(candidate.unwrap().nomination_ends_at, 10, "Can be a candidate with 0 deposit"); - } - - #[test] - fn candidates_update_metadata_with_zero_additional_deposit() { - let mut state = helpers::get_temp_state(); - - // Prepare - let pubkey = Public::random(); - - let mut candidates = Candidates::load_from_state(&state).unwrap(); - candidates.add_deposit(&pubkey, 10, 0, b"metadata".to_vec()); - candidates.save_to_state(&mut state).unwrap(); - - let mut candidates = Candidates::load_from_state(&state).unwrap(); - candidates.add_deposit(&pubkey, 0, 0, b"metadata-updated".to_vec()); - candidates.save_to_state(&mut state).unwrap(); - - // Assert - let candidates = Candidates::load_from_state(&state).unwrap(); - let candidate = candidates.get_candidate(&pubkey); - assert_ne!(candidate, None); - assert_eq!(&candidate.unwrap().metadata, b"metadata-updated"); - } - - #[test] - fn candidates_deposit_should_update_nomination_ends_at() { - let mut state = helpers::get_temp_state(); - - // Prepare - let pubkey = Public::random(); - let deposit_and_nomination_ends_at = [(10, 11), (20, 22), (30, 33), (0, 44)]; - - for (deposit, nomination_ends_at) in &deposit_and_nomination_ends_at { - let mut candidates = Candidates::load_from_state(&state).unwrap(); - candidates.add_deposit(&pubkey, *deposit, *nomination_ends_at, b"".to_vec()); - candidates.save_to_state(&mut state).unwrap(); - } - - // Assert - let candidates = Candidates::load_from_state(&state).unwrap(); - let candidate = candidates.get_candidate(&pubkey); - assert_ne!(candidate, None); - assert_eq!(candidate.unwrap().deposit, 60); - assert_eq!( - candidate.unwrap().nomination_ends_at, - 44, - "nomination_ends_at should be updated incrementally, and including zero deposit" - ); - } - - #[test] - fn candidates_can_remove_expired_deposit() { - let mut state = helpers::get_temp_state(); - - let pubkey0 = 0.into(); - let pubkey1 = 1.into(); - let pubkey2 = 2.into(); - let pubkey3 = 3.into(); - - // Prepare - let candidates_prepared = [ - Candidate { - pubkey: pubkey0, - deposit: 20, - nomination_ends_at: 11, - metadata: b"".to_vec(), - }, - Candidate { - pubkey: pubkey1, - deposit: 30, - nomination_ends_at: 22, - metadata: b"".to_vec(), - }, - Candidate { - pubkey: pubkey2, - deposit: 40, - nomination_ends_at: 33, - metadata: b"".to_vec(), - }, - Candidate { - pubkey: pubkey3, - deposit: 50, - nomination_ends_at: 44, - metadata: b"".to_vec(), - }, - ]; - - for Candidate { - pubkey, - deposit, - nomination_ends_at, - metadata, - } in &candidates_prepared - { - let mut candidates = Candidates::load_from_state(&state).unwrap(); - candidates.add_deposit(&pubkey, *deposit, *nomination_ends_at, metadata.clone()); - candidates.save_to_state(&mut state).unwrap(); - } - - // Remove Expired - let mut candidates = Candidates::load_from_state(&state).unwrap(); - let mut expired = candidates.drain_expired_candidates(22); - candidates.save_to_state(&mut state).unwrap(); - - // Assert - expired.sort_unstable_by_key(|c| c.pubkey); - let mut prepared_expired = candidates_prepared[0..=1].to_vec(); - prepared_expired.sort_unstable_by_key(|c| c.pubkey); - assert_eq!(expired, prepared_expired); - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!(candidates.len(), 2); - assert_eq!(candidates.get_candidate(&candidates_prepared[2].pubkey), Some(&candidates_prepared[2])); - assert_eq!(candidates.get_candidate(&candidates_prepared[3].pubkey), Some(&candidates_prepared[3])); - } - - #[test] - fn candidates_expire_all_cleanup_state() { - let mut state = helpers::get_temp_state(); - - let pubkey0 = 0.into(); - let pubkey1 = 1.into(); - let pubkey2 = 2.into(); - let pubkey3 = 3.into(); - - // Prepare - let candidates_prepared = [ - Candidate { - pubkey: pubkey0, - deposit: 20, - nomination_ends_at: 11, - metadata: b"".to_vec(), - }, - Candidate { - pubkey: pubkey1, - deposit: 30, - nomination_ends_at: 22, - metadata: b"".to_vec(), - }, - Candidate { - pubkey: pubkey2, - deposit: 40, - nomination_ends_at: 33, - metadata: b"".to_vec(), - }, - Candidate { - pubkey: pubkey3, - deposit: 50, - nomination_ends_at: 44, - metadata: b"".to_vec(), - }, - ]; - - for Candidate { - pubkey, - deposit, - nomination_ends_at, - metadata, - } in &candidates_prepared - { - let mut candidates = Candidates::load_from_state(&state).unwrap(); - candidates.add_deposit(&pubkey, *deposit, *nomination_ends_at, metadata.clone()); - candidates.save_to_state(&mut state).unwrap(); - } - - // Remove Expired - let mut candidates = Candidates::load_from_state(&state).unwrap(); - let mut expired = candidates.drain_expired_candidates(99); - candidates.save_to_state(&mut state).unwrap(); - - expired.sort_unstable_by_key(|c| c.pubkey); - let mut prepared_expired = candidates_prepared[0..4].to_vec(); - prepared_expired.sort_unstable_by_key(|c| c.pubkey); - - // Assert - assert_eq!(expired, prepared_expired); - let result = state.action_data(&*CANDIDATES_KEY).unwrap(); - assert_eq!(result, None); - } - - #[test] - fn jail_try_free_not_existing() { - let mut state = helpers::get_temp_state(); - - // Prepare - let pubkey = 1.into(); - let mut jail = Jail::load_from_state(&state).unwrap(); - jail.add( - Candidate { - pubkey, - deposit: 100, - nomination_ends_at: 0, - metadata: b"".to_vec(), - }, - 10, - 20, - ); - jail.save_to_state(&mut state).unwrap(); - - let mut jail = Jail::load_from_state(&state).unwrap(); - let freed = jail.try_release(&Public::from(1000), 5); - assert_eq!(freed, ReleaseResult::NotExists); - assert_eq!(jail.len(), 1); - assert_ne!(jail.get_prisoner(&pubkey), None); - } - - #[test] - fn jail_try_release_none_until_custody() { - let mut state = helpers::get_temp_state(); - - // Prepare - let pubkey = 1.into(); - let mut jail = Jail::load_from_state(&state).unwrap(); - jail.add( - Candidate { - pubkey, - deposit: 100, - nomination_ends_at: 0, - metadata: b"".to_vec(), - }, - 10, - 20, - ); - jail.save_to_state(&mut state).unwrap(); - - let mut jail = Jail::load_from_state(&state).unwrap(); - let released = jail.try_release(&pubkey, 10); - assert_eq!(released, ReleaseResult::InCustody); - assert_eq!(jail.len(), 1); - assert_ne!(jail.get_prisoner(&pubkey), None); - } - - #[test] - fn jail_try_release_prisoner_after_custody() { - let mut state = helpers::get_temp_state(); - - // Prepare - let pubkey = 1.into(); - let mut jail = Jail::load_from_state(&state).unwrap(); - jail.add( - Candidate { - pubkey, - deposit: 100, - nomination_ends_at: 0, - metadata: b"".to_vec(), - }, - 10, - 20, - ); - jail.save_to_state(&mut state).unwrap(); - - let mut jail = Jail::load_from_state(&state).unwrap(); - let released = jail.try_release(&pubkey, 11); - jail.save_to_state(&mut state).unwrap(); - - // Assert - assert_eq!( - released, - ReleaseResult::Released(Prisoner { - pubkey, - deposit: 100, - custody_until: 10, - released_at: 20, - }) - ); - assert_eq!(jail.len(), 0); - assert_eq!(jail.get_prisoner(&pubkey), None); - - let result = state.action_data(&*JAIL_KEY).unwrap(); - assert_eq!(result, None, "Should clean the state if all prisoners are released"); - } - - #[test] - fn jail_keep_prisoners_until_kick_at() { - let mut state = helpers::get_temp_state(); - - let pubkey1 = 1.into(); - let pubkey2 = 2.into(); - - // Prepare - let mut jail = Jail::load_from_state(&state).unwrap(); - jail.add( - Candidate { - pubkey: pubkey1, - deposit: 100, - nomination_ends_at: 0, - metadata: b"".to_vec(), - }, - 10, - 20, - ); - jail.add( - Candidate { - pubkey: pubkey2, - deposit: 200, - nomination_ends_at: 0, - metadata: b"".to_vec(), - }, - 15, - 25, - ); - jail.save_to_state(&mut state).unwrap(); - - // Kick - let mut jail = Jail::load_from_state(&state).unwrap(); - let released = - jail.clone().released_addresses(19).iter().map(|address| jail.remove(address).unwrap()).collect::>(); - jail.save_to_state(&mut state).unwrap(); - - // Assert - assert_eq!(released, Vec::new()); - assert_eq!(jail.len(), 2); - assert_ne!(jail.get_prisoner(&pubkey1), None); - assert_ne!(jail.get_prisoner(&pubkey2), None); - } - - #[test] - fn jail_partially_kick_prisoners() { - let mut state = helpers::get_temp_state(); - - let pubkey1 = 1.into(); - let pubkey2 = 2.into(); - - // Prepare - let mut jail = Jail::load_from_state(&state).unwrap(); - jail.add( - Candidate { - pubkey: pubkey1, - deposit: 100, - nomination_ends_at: 0, - metadata: b"".to_vec(), - }, - 10, - 20, - ); - jail.add( - Candidate { - pubkey: pubkey2, - deposit: 200, - nomination_ends_at: 0, - metadata: b"".to_vec(), - }, - 15, - 25, - ); - jail.save_to_state(&mut state).unwrap(); - - // Kick - let mut jail = Jail::load_from_state(&state).unwrap(); - let released = jail - .clone() - .released_addresses(20) - .into_iter() - .map(|address| jail.remove(&address).unwrap()) - .collect::>(); - jail.save_to_state(&mut state).unwrap(); - - // Assert - assert_eq!(released, vec![Prisoner { - pubkey: pubkey1, - deposit: 100, - custody_until: 10, - released_at: 20, - }]); - assert_eq!(jail.len(), 1); - assert_eq!(jail.get_prisoner(&pubkey1), None); - assert_ne!(jail.get_prisoner(&pubkey2), None); - } - - #[test] - fn jail_kick_all_prisoners() { - let mut state = helpers::get_temp_state(); - - let pubkey1 = 1.into(); - let pubkey2 = 2.into(); - - // Prepare - let mut jail = Jail::load_from_state(&state).unwrap(); - jail.add( - Candidate { - pubkey: pubkey1, - deposit: 100, - nomination_ends_at: 0, - metadata: b"".to_vec(), - }, - 10, - 20, - ); - jail.add( - Candidate { - pubkey: pubkey2, - deposit: 200, - nomination_ends_at: 0, - metadata: b"".to_vec(), - }, - 15, - 25, - ); - jail.save_to_state(&mut state).unwrap(); - - // Kick - let mut jail = Jail::load_from_state(&state).unwrap(); - let released = jail - .clone() - .released_addresses(25) - .into_iter() - .map(|address| jail.remove(&address).unwrap()) - .collect::>(); - jail.save_to_state(&mut state).unwrap(); - - // Assert - assert_eq!(released, vec![ - Prisoner { - pubkey: pubkey1, - deposit: 100, - custody_until: 10, - released_at: 20, - }, - Prisoner { - pubkey: pubkey2, - deposit: 200, - custody_until: 15, - released_at: 25, - } - ]); - assert_eq!(jail.len(), 0); - assert_eq!(jail.get_prisoner(&pubkey1), None); - assert_eq!(jail.get_prisoner(&pubkey2), None); - - let result = state.action_data(&*JAIL_KEY).unwrap(); - assert_eq!(result, None, "Should clean the state if all prisoners are released"); - } - - #[test] - fn empty_ban_save_clean_state() { - let mut state = helpers::get_temp_state(); - let banned = Banned::load_from_state(&state).unwrap(); - banned.save_to_state(&mut state).unwrap(); - - let result = state.action_data(&*BANNED_KEY).unwrap(); - assert_eq!(result, None, "Should clean the state if there are no banned accounts"); - } - - #[test] - fn added_to_ban_is_banned() { - let mut state = helpers::get_temp_state(); - - let pubkey = Public::from(1); - let innocent = Public::from(2); - - let mut banned = Banned::load_from_state(&state).unwrap(); - banned.add(pubkey); - banned.save_to_state(&mut state).unwrap(); - - let banned = Banned::load_from_state(&state).unwrap(); - assert!(banned.is_banned(&pubkey)); - assert!(!banned.is_banned(&innocent)); - } - - #[test] - fn latest_deposit_higher_priority() { - let mut state = helpers::get_temp_state(); - let pubkeys = (0..10).map(|_| Public::random()).collect::>(); - - let mut candidates = Candidates::load_from_state(&state).unwrap(); - for _ in 0..10 { - // Random pre-fill - let i = rand::thread_rng().gen_range(0, pubkeys.len()); - let pubkey = &pubkeys[i]; - candidates.add_deposit(pubkey, 0, 0, Bytes::new()); - } - // Inserting pubkey in this order, they'll get sorted. - for pubkey in &pubkeys { - candidates.add_deposit(pubkey, 10, 0, Bytes::new()); - } - candidates.save_to_state(&mut state).unwrap(); - - let candidates = Candidates::load_from_state(&state).unwrap(); - let results: Vec<_> = pubkeys.iter().map(|pubkey| candidates.get_index(&pubkey)).collect(); - // TODO assert!(results.is_sorted(), "Should be sorted in the insertion order"); - for i in 0..results.len() - 1 { - assert!(results[i] < results[i + 1], "Should be sorted in the insertion order"); - } - } - - #[test] - fn renew_doesnt_change_relative_priority() { - let mut state = helpers::get_temp_state(); - let pubkeys = (0..10).map(|_| Public::random()).collect::>(); - - let mut candidates = Candidates::load_from_state(&state).unwrap(); - for pubkey in &pubkeys { - candidates.add_deposit(pubkey, 10, 0, Bytes::new()); - } - candidates.save_to_state(&mut state).unwrap(); - - let dummy_validators = pubkeys[0..5].iter().map(|pubkey| Validator::new(0, 0, *pubkey)).collect::>(); - let dummy_banned = Banned::load_from_state(&state).unwrap(); - candidates.renew_candidates(&dummy_validators, 0, &[], &dummy_banned); - - let indexes: Vec<_> = pubkeys.iter().map(|pubkey| candidates.get_index(pubkey).unwrap()).collect(); - assert_eq!(indexes, vec![5, 6, 7, 8, 9, 0, 1, 2, 3, 4]); - } -} diff --git a/state/src/item/validator_set.rs b/state/src/item/validator_set.rs deleted file mode 100644 index 53f7106e30..0000000000 --- a/state/src/item/validator_set.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 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::stake::{CurrentValidators, NextValidators}; -use crate::{StateResult, TopLevelState}; -use ckey::Ed25519Public as Public; -use ctypes::{transaction::Validator, CompactValidatorEntry, CompactValidatorSet}; -use std::ops::Deref; - -// Validator information just enough for the host -pub struct SimpleValidator(Validator); - -impl SimpleValidator { - pub fn weight(&self) -> u64 { - self.0.delegation() - } - - pub fn pubkey(&self) -> &Public { - self.0.pubkey() - } -} - -// TODO: implementation will be changed as we move NextValidators into a separate module -pub struct NextValidatorSet(NextValidators); - -impl NextValidatorSet { - // Validator::close_block will return validator_set - // The host should update its next validators from the information - pub fn from_compact_validator_set(validators: CompactValidatorSet) -> Self { - let validators: Vec<_> = validators - .iter() - .map(|entry| Validator::new(entry.delegation, entry.delegation, entry.public_key)) - .collect(); - Self(NextValidators::from_vector(validators)) - } - - pub fn create_compact_validator_set(&self) -> CompactValidatorSet { - self.0.create_compact_validator_set() - } - - pub fn load_from_state(state: &TopLevelState) -> StateResult { - Ok(NextValidatorSet(NextValidators::load_from_state(state)?)) - } - - pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { - self.0.save_to_state(state) - } -} - -impl Deref for NextValidatorSet { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - self.0.deref() - } -} - -impl From for Vec { - fn from(validator_set: NextValidatorSet) -> Self { - validator_set.0.iter().map(|val| SimpleValidator(*val)).collect() - } -} - -// TODO: implementation will be changed as we move CurrentValidators into a separate module -pub struct CurrentValidatorSet(CurrentValidators); - -impl CurrentValidatorSet { - pub fn create_compact_validator_set(&self) -> CompactValidatorSet { - CompactValidatorSet::new( - self.0 - .iter() - .map(|x| CompactValidatorEntry { - public_key: *x.pubkey(), - delegation: x.delegation(), - }) - .collect(), - ) - } - - pub fn load_from_state(state: &TopLevelState) -> StateResult { - Ok(CurrentValidatorSet(CurrentValidators::load_from_state(state)?)) - } - - pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { - self.0.save_to_state(state) - } - - pub fn update(&mut self, next_validator_set: NextValidatorSet) { - self.0.update(next_validator_set.clone()); - } -} - -impl From for Vec { - fn from(validator_set: CurrentValidatorSet) -> Self { - validator_set.0.iter().map(|val| SimpleValidator(*val)).collect() - } -} diff --git a/state/src/lib.rs b/state/src/lib.rs index cebab67dea..5968f3e7f5 100644 --- a/state/src/lib.rs +++ b/state/src/lib.rs @@ -22,8 +22,6 @@ extern crate codechain_key as ckey; extern crate codechain_types as ctypes; #[macro_use] extern crate log; -#[macro_use] -extern crate rlp_derive; mod cache; mod checkpoint; @@ -44,13 +42,8 @@ pub use crate::item::action_data::ActionData; pub use crate::item::metadata::{Metadata, MetadataAddress}; pub use crate::item::module::{Module, ModuleAddress}; pub use crate::item::module_datum::{ModuleDatum, ModuleDatumAddress}; -pub use crate::item::stake::{ - get_delegation_key, get_stake_account_key, Banned, Candidates, CurrentValidators, Jail, NextValidators, -}; -pub use crate::item::validator_set::{CurrentValidatorSet, NextValidatorSet, SimpleValidator}; -pub use crate::stake::{ - ban, init_stake, query as query_stake_state, DoubleVoteHandler, FindDoubleVoteHandler, StakeKeyBuilder, -}; +pub use crate::item::stake::{CurrentValidators, NextValidators}; +pub use crate::stake::{query as query_stake_state, DoubleVoteHandler, FindDoubleVoteHandler, StakeKeyBuilder}; pub use crate::traits::{StateWithCache, TopState, TopStateView}; use crate::cache::CacheableItem; diff --git a/state/src/stake/actions.rs b/state/src/stake/actions.rs deleted file mode 100644 index 6ffa1997a2..0000000000 --- a/state/src/stake/actions.rs +++ /dev/null @@ -1,1093 +0,0 @@ -// Copyright 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 crate::item::stake::{Delegation, ReleaseResult, StakeAccount, Stakeholders}; -use crate::{Banned, Candidates, Jail, NextValidators, StateResult, TopLevelState, TopState, TopStateView}; -use ckey::Ed25519Public as Public; -use ctypes::errors::RuntimeError; -use ctypes::transaction::{Approval, Validator}; -use ctypes::util::unexpected::Mismatch; -use ctypes::{CommonParams, Deposit}; -use primitives::Bytes; -use std::collections::HashMap; - -#[allow(clippy::implicit_hasher)] // XXX: Fix this clippy warning if it becomes a real problem. -pub fn init_stake( - 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 (pubkey, amount) in &genesis_stakes { - let account = StakeAccount { - pubkey, - balance: *amount, - }; - account.save_to_state(state)?; - stakeholders.update_by_increased_balance(&account); - } - stakeholders.save_to_state(state)?; - - for (pubkey, deposit) in &genesis_candidates { - // This balance was an element of `TopLevelState`, but the concept of `Account` was moved - // to a module level, and the element was removed from `TopLevelState`. Therefore, this balance - // was newly defiend for build, and its value is temporarily Default::default(). - - let balance: u64 = Default::default(); - if balance < deposit.deposit { - cerror!(STATE, "{:?} has insufficient balance to become the candidate", pubkey); - return Err(RuntimeError::InsufficientBalance { - pubkey: *pubkey, - balance, - cost: deposit.deposit, - } - .into()) - } - } - - 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(()) -} - -pub fn transfer_ccs(state: &mut TopLevelState, sender: &Public, receiver: &Public, quantity: u64) -> StateResult<()> { - let mut stakeholders = Stakeholders::load_from_state(state)?; - let mut sender_account = StakeAccount::load_from_state(state, sender)?; - let mut receiver_account = StakeAccount::load_from_state(state, receiver)?; - let sender_delegations = Delegation::load_from_state(state, sender)?; - - sender_account.subtract_balance(quantity)?; - receiver_account.add_balance(quantity)?; - - stakeholders.update_by_decreased_balance(&sender_account, &sender_delegations); - stakeholders.update_by_increased_balance(&receiver_account); - - stakeholders.save_to_state(state)?; - sender_account.save_to_state(state)?; - receiver_account.save_to_state(state)?; - - ctrace!(ENGINE, "Transferred CCS sender: {:?}, receiver: {:?}, quantity: {}", sender, receiver, quantity); - Ok(()) -} - -pub fn delegate_ccs( - state: &mut TopLevelState, - delegator: &Public, - delegatee: &Public, - quantity: u64, -) -> StateResult<()> { - let candidates = Candidates::load_from_state(state)?; - if candidates.get_candidate(delegatee).is_none() { - return Err(RuntimeError::FailedToHandleCustomAction("Can delegate to who is a candidate".into()).into()) - } - - let banned = Banned::load_from_state(state)?; - let jailed = Jail::load_from_state(state)?; - assert!(!banned.is_banned(&delegatee), "A candidate must not be banned"); - assert_eq!(None, jailed.get_prisoner(delegatee), "A candidate must not be jailed"); - - let mut delegator_account = StakeAccount::load_from_state(state, delegator)?; - let mut delegation = Delegation::load_from_state(state, &delegator)?; - - delegator_account.subtract_balance(quantity)?; - delegation.add_quantity(*delegatee, quantity)?; - // delegation does not touch stakeholders - - delegation.save_to_state(state)?; - delegator_account.save_to_state(state)?; - - ctrace!(ENGINE, "Delegated CCS. delegator: {:?}, delegatee: {:?}, quantity: {}", delegator, delegatee, quantity); - Ok(()) -} - -pub fn revoke(state: &mut TopLevelState, delegator: &Public, delegatee: &Public, quantity: u64) -> StateResult<()> { - let mut delegator_account = StakeAccount::load_from_state(state, delegator)?; - let mut delegation = Delegation::load_from_state(state, &delegator)?; - - delegator_account.add_balance(quantity)?; - delegation.subtract_quantity(*delegatee, quantity)?; - // delegation does not touch stakeholders - - delegation.save_to_state(state)?; - delegator_account.save_to_state(state)?; - - ctrace!(ENGINE, "Revoked CCS. delegator: {:?}, delegatee: {:?}, quantity: {}", delegator, delegatee, quantity); - Ok(()) -} - -pub fn redelegate( - state: &mut TopLevelState, - delegator: &Public, - prev_delegatee: &Public, - next_delegatee: &Public, - quantity: u64, -) -> StateResult<()> { - let candidates = Candidates::load_from_state(state)?; - if candidates.get_candidate(next_delegatee).is_none() { - return Err(RuntimeError::FailedToHandleCustomAction("Can delegate to who is a candidate".into()).into()) - } - - let banned = Banned::load_from_state(state)?; - let jailed = Jail::load_from_state(state)?; - assert!(!banned.is_banned(&next_delegatee), "A candidate must not be banned"); - assert_eq!(None, jailed.get_prisoner(next_delegatee), "A candidate must not be jailed"); - - let delegator_account = StakeAccount::load_from_state(state, delegator)?; - let mut delegation = Delegation::load_from_state(state, &delegator)?; - - delegation.subtract_quantity(*prev_delegatee, quantity)?; - delegation.add_quantity(*next_delegatee, quantity)?; - - delegation.save_to_state(state)?; - delegator_account.save_to_state(state)?; - - ctrace!( - ENGINE, - "Redelegated CCS. delegator: {:?}, prev_delegatee: {:?}, next_delegatee: {:?}, quantity: {}", - delegator, - prev_delegatee, - next_delegatee, - quantity - ); - Ok(()) -} - -pub fn self_nominate( - state: &mut TopLevelState, - nominee: &Public, - deposit: u64, - current_term: u64, - nomination_ends_at: u64, - metadata: Bytes, -) -> StateResult<()> { - let blacklist = Banned::load_from_state(state)?; - if blacklist.is_banned(&nominee) { - return Err(RuntimeError::FailedToHandleCustomAction("Account is blacklisted".to_string()).into()) - } - - let mut jail = Jail::load_from_state(&state)?; - let total_deposit = match jail.try_release(nominee, current_term) { - ReleaseResult::InCustody => { - return Err(RuntimeError::FailedToHandleCustomAction("Account is still in custody".to_string()).into()) - } - ReleaseResult::NotExists => deposit, - ReleaseResult::Released(prisoner) => { - assert_eq!(&prisoner.pubkey, nominee); - prisoner.deposit + deposit - } - }; - - let mut candidates = Candidates::load_from_state(&state)?; - candidates.add_deposit(nominee, total_deposit, nomination_ends_at, metadata); - - jail.save_to_state(state)?; - candidates.save_to_state(state)?; - - ctrace!( - ENGINE, - "Self-nominated. nominee: {:?}, deposit: {}, current_term: {}, ends_at: {}", - nominee, - deposit, - current_term, - nomination_ends_at - ); - Ok(()) -} - -pub fn change_params( - state: &mut TopLevelState, - metadata_seq: u64, - params: CommonParams, - approvals: &[Approval], -) -> StateResult<()> { - // Update state first because the signature validation is more expensive. - state.update_params(metadata_seq, params)?; - - let stakes = get_stakes(state)?; - // Approvals are verified - let signed_stakes = approvals.iter().try_fold(0, |sum, approval| { - let public = approval.signer_public(); - stakes.get(public).map(|stake| sum + stake).ok_or_else(|| RuntimeError::SignatureOfInvalidAccount(*public)) - })?; - let total_stakes: u64 = stakes.values().sum(); - if total_stakes / 2 >= signed_stakes { - return Err(RuntimeError::InsufficientStakes(Mismatch { - expected: total_stakes, - found: signed_stakes, - }) - .into()) - } - - ctrace!(ENGINE, "ChangeParams. params: {:?}", params); - Ok(()) -} - -fn get_stakes(state: &TopLevelState) -> StateResult> { - let stakeholders = Stakeholders::load_from_state(state)?; - let mut result = HashMap::new(); - for stakeholder in stakeholders.iter() { - let account = StakeAccount::load_from_state(state, stakeholder)?; - let delegation = Delegation::load_from_state(state, stakeholder)?; - result.insert(*stakeholder, account.balance + delegation.sum()); - } - Ok(result) -} - -pub fn release_jailed_prisoners(state: &mut TopLevelState, released: &[Public]) -> StateResult<()> { - if released.is_empty() { - return Ok(()) - } - - let mut jailed = Jail::load_from_state(&state)?; - for pubkey in released { - let prisoner = jailed.remove(pubkey).unwrap(); - ctrace!(ENGINE, "on_term_close::released. prisoner: {:?}, deposit: {}", prisoner.pubkey, prisoner.deposit); - } - jailed.save_to_state(state)?; - revert_delegations(state, released) -} - -pub fn jail(state: &mut TopLevelState, pubkeys: &[Public], custody_until: u64, kick_at: u64) -> StateResult<()> { - if pubkeys.is_empty() { - return Ok(()) - } - let mut candidates = Candidates::load_from_state(state)?; - let mut jail = Jail::load_from_state(state)?; - - for pubkey in pubkeys { - let candidate = candidates.remove(pubkey).expect("There should be a candidate to jail"); - ctrace!(ENGINE, "on_term_close::jail. candidate: {:?}, deposit: {}", pubkey, candidate.deposit); - jail.add(candidate, custody_until, kick_at); - } - - jail.save_to_state(state)?; - candidates.save_to_state(state)?; - Ok(()) -} - -pub fn ban(state: &mut TopLevelState, _informant: &Public, criminal: Public) -> StateResult<()> { - let mut banned = Banned::load_from_state(state)?; - if banned.is_banned(&criminal) { - return Err(RuntimeError::FailedToHandleCustomAction("Account is already banned".to_string()).into()) - } - - let mut candidates = Candidates::load_from_state(state)?; - let mut jailed = Jail::load_from_state(state)?; - let mut validators = NextValidators::load_from_state(state)?; - - let _deposit = match (candidates.remove(&criminal), jailed.remove(&criminal)) { - (Some(_), Some(_)) => unreachable!("A candidate that are jailed cannot exist"), - (Some(candidate), _) => candidate.deposit, - (_, Some(jailed)) => jailed.deposit, - _ => 0, - }; - // confiscate criminal's deposit and give the same deposit amount to the informant. - - jailed.remove(&criminal); - banned.add(criminal); - validators.remove(&criminal); - - jailed.save_to_state(state)?; - banned.save_to_state(state)?; - candidates.save_to_state(state)?; - validators.save_to_state(state)?; - - // Revert delegations - revert_delegations(state, &[criminal])?; - - Ok(()) -} - -pub fn revert_delegations(state: &mut TopLevelState, reverted_delegatees: &[Public]) -> StateResult<()> { - // Stakeholders list isn't changed while reverting. - - let stakeholders = Stakeholders::load_from_state(state)?; - for stakeholder in stakeholders.iter() { - let mut delegator = StakeAccount::load_from_state(state, stakeholder)?; - let mut delegation = Delegation::load_from_state(state, stakeholder)?; - - for delegatee in reverted_delegatees { - let quantity = delegation.get_quantity(delegatee); - if quantity > 0 { - delegation.subtract_quantity(*delegatee, quantity)?; - delegator.add_balance(quantity)?; - ctrace!( - ENGINE, - "revert_delegation delegator: {:?}, delegatee: {:?}, quantity: {}", - stakeholder, - delegatee, - quantity - ); - } - } - delegation.save_to_state(state)?; - delegator.save_to_state(state)?; - } - Ok(()) -} - -pub fn update_candidates( - state: &mut TopLevelState, - current_term: u64, - nomination_expiration: u64, - next_validators: &[Validator], - inactive_validators: &[Public], -) -> StateResult<()> { - let banned = Banned::load_from_state(state)?; - - let mut candidates = Candidates::load_from_state(state)?; - let nomination_ends_at = current_term + nomination_expiration; - - candidates.renew_candidates(next_validators, nomination_ends_at, &inactive_validators, &banned); - - let expired = candidates.drain_expired_candidates(current_term); - for candidate in &expired { - let pubkey = candidate.pubkey; - ctrace!(ENGINE, "on_term_close::expired. candidate: {:?}, deposit: {}", pubkey, candidate.deposit); - } - candidates.save_to_state(state)?; - let expired: Vec<_> = expired.into_iter().map(|c| c.pubkey).collect(); - revert_delegations(state, &expired) -} - -pub fn close_term( - state: &mut TopLevelState, - next_validators: &[Validator], - inactive_validators: &[Public], -) -> StateResult<()> { - let metadata = state.metadata()?.expect("The metadata must exist"); - let current_term = metadata.current_term_id(); - ctrace!(ENGINE, "on_term_close. current_term: {}", current_term); - - let metadata = metadata.params(); - let nomination_expiration = metadata.nomination_expiration(); - assert_ne!(0, nomination_expiration); - - update_candidates(state, current_term, nomination_expiration, next_validators, inactive_validators)?; - NextValidators::from(next_validators.to_vec()).save_to_state(state) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::item::stake::{Banned, Candidate, Candidates, Delegation, Jail, Prisoner, StakeAccount, Stakeholders}; - use crate::tests::helpers; - use crate::{get_delegation_key, get_stake_account_key, init_stake, TopStateView}; - use std::collections::HashMap; - - #[test] - fn genesis_stakes() { - let pubkey1 = Public::random(); - let pubkey2 = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(pubkey1, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - - let account1 = StakeAccount::load_from_state(&state, &pubkey1).unwrap(); - assert_eq!(account1.balance, 100); - - let account2 = StakeAccount::load_from_state(&state, &pubkey2).unwrap(); - assert_eq!(account2.balance, 0); - - let stakeholders = Stakeholders::load_from_state(&state).unwrap(); - assert_eq!(stakeholders.iter().len(), 1); - assert!(stakeholders.contains(&pubkey1)); - assert!(!stakeholders.contains(&pubkey2)); - } - - #[test] - fn balance_transfer_partial() { - let pubkey1 = Public::random(); - let pubkey2 = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(pubkey1, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - - let result = transfer_ccs(&mut state, &pubkey1, &pubkey2, 10); - assert_eq!(result, Ok(())); - - let account1 = StakeAccount::load_from_state(&state, &pubkey1).unwrap(); - assert_eq!(account1.balance, 90); - - let account2 = StakeAccount::load_from_state(&state, &pubkey2).unwrap(); - assert_eq!(account2.balance, 10); - - let stakeholders = Stakeholders::load_from_state(&state).unwrap(); - assert_eq!(stakeholders.iter().len(), 2); - assert!(stakeholders.contains(&pubkey1)); - assert!(stakeholders.contains(&pubkey2)); - } - - #[test] - fn balance_transfer_all() { - let pubkey1 = Public::random(); - let pubkey2 = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(pubkey1, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - - let result = transfer_ccs(&mut state, &pubkey1, &pubkey2, 100); - assert_eq!(result, Ok(())); - - let account1 = StakeAccount::load_from_state(&state, &pubkey1).unwrap(); - assert_eq!(account1.balance, 0); - assert_eq!(state.action_data(&get_stake_account_key(&pubkey1)).unwrap(), None, "Should clear state"); - - let account2 = StakeAccount::load_from_state(&state, &pubkey2).unwrap(); - assert_eq!(account2.balance, 100); - - let stakeholders = Stakeholders::load_from_state(&state).unwrap(); - assert_eq!(stakeholders.iter().len(), 1); - assert!(!stakeholders.contains(&pubkey1), "Not be a stakeholder anymore"); - assert!(stakeholders.contains(&pubkey2)); - } - - #[test] - fn delegate() { - let delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegatee, 100); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 40; - delegate_ccs(&mut state, &delegator, &delegatee, quantity).unwrap(); - - let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegator_account.balance, 60); - - let delegatee_account = StakeAccount::load_from_state(&state, &delegatee).unwrap(); - assert_eq!(delegatee_account.balance, 100, "Shouldn't be touched"); - - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegation.iter().count(), 1); - assert_eq!(delegation.get_quantity(&delegatee), 40); - - let delegation_delegatee = Delegation::load_from_state(&state, &delegatee).unwrap(); - assert_eq!(delegation_delegatee.iter().count(), 0, "Shouldn't be touched"); - - let stakeholders = Stakeholders::load_from_state(&state).unwrap(); - assert_eq!(stakeholders.iter().len(), 2); - assert!(stakeholders.contains(&delegator)); - assert!(stakeholders.contains(&delegatee)); - } - - #[test] - fn delegate_all() { - let delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegatee, 100); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 100; - delegate_ccs(&mut state, &delegator, &delegatee, quantity).unwrap(); - - let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegator_account.balance, 0); - assert_eq!(state.action_data(&get_stake_account_key(&delegator)).unwrap(), None, "Should clear state"); - - let delegatee_account = StakeAccount::load_from_state(&state, &delegatee).unwrap(); - assert_eq!(delegatee_account.balance, 100, "Shouldn't be touched"); - - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegation.iter().count(), 1); - assert_eq!(delegation.get_quantity(&delegatee), 100); - - let delegation_delegatee = Delegation::load_from_state(&state, &delegatee).unwrap(); - assert_eq!(delegation_delegatee.iter().count(), 0, "Shouldn't be touched"); - - let stakeholders = Stakeholders::load_from_state(&state).unwrap(); - assert_eq!(stakeholders.iter().len(), 2); - assert!(stakeholders.contains(&delegator), "Should still be a stakeholder after delegated all"); - assert!(stakeholders.contains(&delegatee)); - } - - #[test] - fn delegate_only_to_candidate() { - let delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegatee, 100); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - - let quantity = 40; - delegate_ccs(&mut state, &delegator, &delegatee, quantity).unwrap_err(); - } - - #[test] - fn delegate_too_much() { - let delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegatee, 100); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 200; - delegate_ccs(&mut state, &delegator, &delegatee, quantity).unwrap_err(); - } - - #[test] - fn can_transfer_within_non_delegated_tokens() { - let delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegatee, 100); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 50; - delegate_ccs(&mut state, &delegator, &delegatee, quantity).unwrap(); - - let quantity = 50; - transfer_ccs(&mut state, &delegator, &delegatee, quantity).unwrap(); - } - - #[test] - fn cannot_transfer_over_non_delegated_tokens() { - let delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegatee, 100); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 50; - delegate_ccs(&mut state, &delegator, &delegatee, quantity).unwrap(); - - let quantity = 100; - transfer_ccs(&mut state, &delegator, &delegatee, quantity).unwrap_err(); - } - - #[test] - fn can_revoke_delegated_tokens() { - let delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegatee, 100); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 50; - delegate_ccs(&mut state, &delegator, &delegatee, quantity).unwrap(); - - let quantity = 20; - revoke(&mut state, &delegator, &delegatee, quantity).unwrap(); - - let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegator_account.balance, 100 - 50 + 20); - assert_eq!(delegation.iter().count(), 1); - assert_eq!(delegation.get_quantity(&delegatee), 50 - 20); - } - - #[test] - fn cannot_revoke_more_than_delegated_tokens() { - let delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegatee, 100); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 50; - delegate_ccs(&mut state, &delegator, &delegatee, quantity).unwrap(); - - let quantity = 70; - revoke(&mut state, &delegator, &delegatee, quantity).unwrap_err(); - - let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegator_account.balance, 100 - 50); - assert_eq!(delegation.iter().count(), 1); - assert_eq!(delegation.get_quantity(&delegatee), 50); - } - - #[test] - fn revoke_all_should_clear_state() { - let delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegatee, 100); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 50; - delegate_ccs(&mut state, &delegator, &delegatee, quantity).unwrap(); - - let quantity = 50; - revoke(&mut state, &delegator, &delegatee, quantity).unwrap(); - - let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegator_account.balance, 100); - assert_eq!(state.action_data(&get_delegation_key(&delegator)).unwrap(), None); - } - - #[test] - fn can_redelegate_tokens() { - let prev_delegatee = Public::random(); - let next_delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &prev_delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - self_nominate(&mut state, &next_delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 50; - delegate_ccs(&mut state, &delegator, &prev_delegatee, quantity).unwrap(); - - let quantity = 20; - redelegate(&mut state, &delegator, &prev_delegatee, &next_delegatee, quantity).unwrap(); - - let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegator_account.balance, 100 - 50); - assert_eq!(delegation.iter().count(), 2); - assert_eq!(delegation.get_quantity(&prev_delegatee), 50 - 20); - assert_eq!(delegation.get_quantity(&next_delegatee), 20); - } - - #[test] - fn cannot_redelegate_more_than_delegated_tokens() { - let prev_delegatee = Public::random(); - let next_delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &prev_delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - self_nominate(&mut state, &next_delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 50; - delegate_ccs(&mut state, &delegator, &prev_delegatee, quantity).unwrap(); - - let quantity = 70; - redelegate(&mut state, &delegator, &prev_delegatee, &next_delegatee, quantity).unwrap_err(); - - let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegator_account.balance, 100 - 50); - assert_eq!(delegation.iter().count(), 1); - assert_eq!(delegation.get_quantity(&prev_delegatee), 50); - assert_eq!(delegation.get_quantity(&next_delegatee), 0); - } - - #[test] - fn redelegate_all_should_clear_state() { - let prev_delegatee = Public::random(); - let next_delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &prev_delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - self_nominate(&mut state, &next_delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 50; - delegate_ccs(&mut state, &delegator, &prev_delegatee, quantity).unwrap(); - - let quantity = 50; - redelegate(&mut state, &delegator, &prev_delegatee, &next_delegatee, quantity).unwrap(); - - let delegator_account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegator_account.balance, 50); - assert_eq!(delegation.iter().count(), 1); - assert_eq!(delegation.get_quantity(&prev_delegatee), 0); - assert_eq!(delegation.get_quantity(&next_delegatee), 50); - } - - #[test] - fn redelegate_only_to_candidate() { - let prev_delegatee = Public::random(); - let next_delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - - self_nominate(&mut state, &prev_delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 40; - delegate_ccs(&mut state, &delegator, &prev_delegatee, quantity).unwrap(); - - let quantity = 50; - redelegate(&mut state, &delegator, &prev_delegatee, &next_delegatee, quantity).unwrap_err(); - } - - #[test] - fn cannot_redelegate_to_banned_account() { - let informant = Public::random(); - let criminal = Public::random(); - let delegator = Public::random(); - let prev_delegatee = Public::random(); - - let mut state = helpers::get_temp_state(); - - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &prev_delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - self_nominate(&mut state, &criminal, 100, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 40; - delegate_ccs(&mut state, &delegator, &criminal, quantity).unwrap(); - let quantity = 40; - delegate_ccs(&mut state, &delegator, &prev_delegatee, quantity).unwrap(); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!(candidates.len(), 2); - - assert_eq!(Ok(()), ban(&mut state, &informant, criminal)); - - let banned = Banned::load_from_state(&state).unwrap(); - assert!(banned.is_banned(&criminal)); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!(candidates.len(), 1); - - let quantity = 40; - redelegate(&mut state, &delegator, &prev_delegatee, &criminal, quantity).unwrap_err(); - } - - #[test] - fn cannot_redelegate_to_jailed_account() { - let jail_pubkey = Public::random(); - let prev_delegatee = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - self_nominate(&mut state, &prev_delegatee, 0, 0, 10, b"".to_vec()).unwrap(); - - let deposit = 200; - self_nominate(&mut state, &jail_pubkey, deposit, 0, 5, b"".to_vec()).unwrap(); - - let quantity = 40; - delegate_ccs(&mut state, &delegator, &prev_delegatee, quantity).unwrap(); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!(candidates.len(), 2); - - let custody_until = 10; - let released_at = 20; - let result = jail(&mut state, &[jail_pubkey], custody_until, released_at); - assert!(result.is_ok()); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!(candidates.len(), 1); - - let quantity = 40; - redelegate(&mut state, &delegator, &prev_delegatee, &jail_pubkey, quantity).unwrap_err(); - } - - #[test] - fn self_nominate_deposit_test() { - let pubkey = Public::random(); - - let mut state = helpers::get_temp_state(); - - init_stake(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - self_nominate(&mut state, &pubkey, 0, 0, 5, b"metadata1".to_vec()).unwrap(); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!( - candidates.get_candidate(&pubkey), - Some(&Candidate { - pubkey, - deposit: 0, - nomination_ends_at: 5, - metadata: b"metadata1".to_vec(), - }), - "nomination_ends_at should be updated even if candidate deposits 0" - ); - - self_nominate(&mut state, &pubkey, 200, 0, 10, b"metadata2".to_vec()).unwrap(); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!( - candidates.get_candidate(&pubkey), - Some(&Candidate { - pubkey, - deposit: 200, - nomination_ends_at: 10, - metadata: b"metadata2".to_vec(), - }) - ); - - self_nominate(&mut state, &pubkey, 0, 0, 15, b"metadata3".to_vec()).unwrap(); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!( - candidates.get_candidate(&pubkey), - Some(&Candidate { - pubkey, - deposit: 200, - nomination_ends_at: 15, - metadata: b"metadata3".to_vec(), - }), - "nomination_ends_at should be updated even if candidate deposits 0" - ); - } - - #[allow(dead_code)] - fn self_nominate_fail_with_insufficient_balance() { - let pubkey = Public::random(); - - let mut state = helpers::get_temp_state(); - - init_stake(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - let result = self_nominate(&mut state, &pubkey, 2000, 0, 5, b"".to_vec()); - assert!(result.is_err(), "Cannot self-nominate without a sufficient balance"); - } - - #[test] - fn jail_candidate() { - let pubkey = Public::random(); - - let mut state = helpers::get_temp_state(); - init_stake(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - let deposit = 200; - self_nominate(&mut state, &pubkey, deposit, 0, 5, b"".to_vec()).unwrap(); - - let custody_until = 10; - let released_at = 20; - let result = jail(&mut state, &[pubkey], custody_until, released_at); - assert!(result.is_ok()); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!(candidates.get_candidate(&pubkey), None, "The candidate is removed"); - - let jail = Jail::load_from_state(&state).unwrap(); - assert_eq!( - jail.get_prisoner(&pubkey), - Some(&Prisoner { - pubkey, - deposit, - custody_until, - released_at, - }), - "The candidate become a prisoner" - ); - } - - #[test] - fn test_ban() { - let informant = Public::random(); - let criminal = Public::random(); - let delegator = Public::random(); - - let mut state = helpers::get_temp_state(); - - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - - let deposit = 100; - self_nominate(&mut state, &criminal, deposit, 0, 10, b"".to_vec()).unwrap(); - - let quantity = 40; - delegate_ccs(&mut state, &delegator, &criminal, quantity).unwrap(); - - assert_eq!(Ok(()), ban(&mut state, &informant, criminal)); - - let banned = Banned::load_from_state(&state).unwrap(); - assert!(banned.is_banned(&criminal)); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!(candidates.len(), 0); - - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegation.get_quantity(&criminal), 0, "Delegation should be reverted"); - - let account_delegator = StakeAccount::load_from_state(&state, &delegator).unwrap(); - assert_eq!(account_delegator.balance, 100, "Delegation should be reverted"); - } - - #[test] - fn ban_should_remove_prisoner_from_jail() { - let informant = Public::random(); - let criminal = Public::random(); - - let mut state = helpers::get_temp_state(); - init_stake(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - - let deposit = 10; - self_nominate(&mut state, &criminal, deposit, 0, 10, b"".to_vec()).unwrap(); - let custody_until = 10; - let released_at = 20; - jail(&mut state, &[criminal], custody_until, released_at).unwrap(); - - assert_eq!(Ok(()), ban(&mut state, &informant, criminal)); - - let jail = Jail::load_from_state(&state).unwrap(); - assert_eq!(jail.get_prisoner(&criminal), None, "Should be removed from the jail"); - } -} diff --git a/state/src/stake/mod.rs b/state/src/stake/mod.rs index 4f94ebedfd..ad91a941f0 100644 --- a/state/src/stake/mod.rs +++ b/state/src/stake/mod.rs @@ -14,12 +14,6 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -mod actions; - -pub use self::actions::{ - ban, change_params, close_term, delegate_ccs, init_stake, jail, redelegate, release_jailed_prisoners, - revert_delegations, revoke, self_nominate, transfer_ccs, update_candidates, -}; use super::TopStateView; use crate::{StateResult, TopLevelState}; use ccrypto::blake256; @@ -86,12 +80,6 @@ impl StakeKeyBuilder { #[cfg(test)] mod tests { use super::*; - use crate::item::stake::{Candidate, Candidates, Delegation, Jail, StakeAccount}; - use crate::tests::helpers; - use crate::{NextValidators, TopLevelState, TopState, TopStateView}; - use ckey::Ed25519Public as Public; - use ctypes::{CommonParams, ConsensusParams}; - use std::collections::HashMap; #[test] fn action_data_key_builder_raw_fragment_and_list_are_same() { @@ -102,392 +90,4 @@ mod tests { let key2 = StakeKeyBuilder::key_from_fragment(rlp.as_raw()); assert_eq!(key1, key2); } - - fn metadata_for_election() -> TopLevelState { - let mut params = CommonParams::default_for_test(); - let consensus_params = ConsensusParams::default_for_test(); - let mut state = helpers::get_temp_state_with_metadata(params, consensus_params); - state.metadata().unwrap().unwrap().set_consensus_params(ConsensusParams::default_for_test()); - params.set_dynamic_validator_params_for_test(30, 10, 3, 20, 30, 4, 1000, 10000, 100); - assert_eq!(Ok(()), state.update_params(0, params)); - state - } - - fn increase_term_id_until(state: &mut TopLevelState, term_id: u64) { - let mut block_num = state.metadata().unwrap().unwrap().last_term_finished_block_num() + 1; - while state.metadata().unwrap().unwrap().current_term_id() != term_id { - assert_eq!(Ok(()), state.increase_term_id(block_num)); - block_num += 1; - } - } - - #[test] - fn self_nominate_returns_deposits_after_expiration() { - let pubkey = Public::random(); - - let mut state = metadata_for_election(); - increase_term_id_until(&mut state, 29); - - init_stake(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - self_nominate(&mut state, &pubkey, 200, 0, 30, b"".to_vec()).unwrap(); - - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(29)).unwrap(); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!( - candidates.get_candidate(&pubkey), - Some(&Candidate { - pubkey, - deposit: 200, - nomination_ends_at: 30, - metadata: b"".to_vec(), - }), - "Keep deposit before expiration", - ); - - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(30)).unwrap(); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!(candidates.get_candidate(&pubkey), None, "Removed from candidates after expiration"); - } - - #[test] - fn self_nominate_reverts_delegations_after_expiration() { - let pubkey = Public::random(); - let delegator = Public::random(); - - let mut state = metadata_for_election(); - increase_term_id_until(&mut state, 29); - - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - self_nominate(&mut state, &pubkey, 0, 0, 30, b"".to_vec()).unwrap(); - - let quantity = 40; - delegate_ccs(&mut state, &delegator, &pubkey, quantity).unwrap(); - - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(29)).unwrap(); - - let account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - assert_eq!(account.balance, 100 - 40); - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegation.get_quantity(&pubkey), 40, "Should keep delegation before expiration"); - - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(30)).unwrap(); - - let account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - assert_eq!(account.balance, 100); - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegation.get_quantity(&pubkey), 0, "Should revert before expiration"); - } - - #[test] - fn cannot_self_nominate_while_custody() { - let pubkey = Public::random(); - - let mut state = metadata_for_election(); - - init_stake(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - let deposit = 200; - let nominate_expire = 5; - let custody_until = 10; - let released_at = 20; - self_nominate(&mut state, &pubkey, deposit, 0, nominate_expire, b"".to_vec()).unwrap(); - jail(&mut state, &[pubkey], custody_until, released_at).unwrap(); - - for current_term in 0..=custody_until { - let result = - self_nominate(&mut state, &pubkey, 0, current_term, current_term + nominate_expire, b"".to_vec()); - assert!( - result.is_err(), - "Shouldn't nominate while current_term({}) <= custody_until({})", - current_term, - custody_until - ); - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term_id = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term_id); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(current_term)).unwrap(); - } - } - - #[test] - fn can_self_nominate_after_custody() { - let pubkey = Public::random(); - - let mut state = metadata_for_election(); - - init_stake(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - let deposit = 200; - let nominate_expire = 5; - let custody_until = 10; - let released_at = 20; - self_nominate(&mut state, &pubkey, deposit, 0, nominate_expire, b"metadata-before".to_vec()).unwrap(); - jail(&mut state, &[pubkey], custody_until, released_at).unwrap(); - for current_term in 0..=custody_until { - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term_id = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term_id); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(current_term)).unwrap(); - } - - let current_term = custody_until + 1; - let additional_deposit = 123; - let result = self_nominate( - &mut state, - &pubkey, - additional_deposit, - current_term, - current_term + nominate_expire, - b"metadata-after".to_vec(), - ); - assert!(result.is_ok()); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!( - candidates.get_candidate(&pubkey), - Some(&Candidate { - deposit: deposit + additional_deposit, - nomination_ends_at: current_term + nominate_expire, - pubkey, - metadata: "metadata-after".into() - }), - "The prisoner is become a candidate", - ); - - let jail = Jail::load_from_state(&state).unwrap(); - assert_eq!(jail.get_prisoner(&pubkey), None, "The prisoner is removed"); - } - - #[test] - fn jail_released_after() { - let pubkey = Public::random(); - - let mut state = metadata_for_election(); - - init_stake(&mut state, Default::default(), Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - let deposit = 200; - let nominate_expire = 5; - let custody_until = 10; - let released_at = 20; - self_nominate(&mut state, &pubkey, deposit, 0, nominate_expire, b"".to_vec()).unwrap(); - jail(&mut state, &[pubkey], custody_until, released_at).unwrap(); - - for current_term in 0..released_at { - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term_id = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term_id); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(current_term)).unwrap(); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!(candidates.get_candidate(&pubkey), None); - - let jail = Jail::load_from_state(&state).unwrap(); - assert!(jail.get_prisoner(&pubkey).is_some()); - } - - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(released_at)).unwrap(); - - let candidates = Candidates::load_from_state(&state).unwrap(); - assert_eq!(candidates.get_candidate(&pubkey), None, "A prisoner should not become a candidate"); - - let jail = Jail::load_from_state(&state).unwrap(); - assert_eq!(jail.get_prisoner(&pubkey), None, "A prisoner should be released"); - } - - #[test] - fn cannot_delegate_until_released() { - let pubkey = Public::random(); - let delegator = Public::random(); - - let mut state = metadata_for_election(); - - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - let deposit = 200; - let nominate_expire = 5; - let custody_until = 10; - let released_at = 20; - self_nominate(&mut state, &pubkey, deposit, 0, nominate_expire, b"".to_vec()).unwrap(); - jail(&mut state, &[pubkey], custody_until, released_at).unwrap(); - - for current_term in 0..=released_at { - let quantity = 1; - delegate_ccs(&mut state, &delegator, &pubkey, quantity).unwrap_err(); - - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term_id = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term_id); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(current_term)).unwrap(); - } - - let quantity = 1; - delegate_ccs(&mut state, &delegator, &pubkey, quantity).unwrap_err(); - } - - #[test] - fn kick_reverts_delegations() { - let pubkey = Public::random(); - let delegator = Public::random(); - - let mut state = metadata_for_election(); - - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - let deposit = 200; - let nominate_expire = 5; - let custody_until = 10; - let released_at = 20; - self_nominate(&mut state, &pubkey, deposit, 0, nominate_expire, b"".to_vec()).unwrap(); - - let quantity = 40; - delegate_ccs(&mut state, &delegator, &pubkey, quantity).unwrap(); - - jail(&mut state, &[pubkey], custody_until, released_at).unwrap(); - - for current_term in 0..=released_at { - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term_id = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term_id); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(current_term)).unwrap(); - } - - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegation.get_quantity(&pubkey), 0, "Delegation should be reverted"); - - let account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - assert_eq!(account.balance, 100, "Delegation should be reverted"); - } - - #[test] - fn self_nomination_before_kick_preserves_delegations() { - let pubkey = Public::random(); - let delegator = Public::random(); - - let mut state = metadata_for_election(); - - let genesis_stakes = { - let mut genesis_stakes = HashMap::new(); - genesis_stakes.insert(delegator, 100); - genesis_stakes - }; - init_stake(&mut state, genesis_stakes, Default::default(), Default::default()).unwrap(); - - // TODO: change with stake::execute() - let nominate_expire = 5; - let custody_until = 10; - let released_at = 20; - self_nominate(&mut state, &pubkey, 0, 0, nominate_expire, b"".to_vec()).unwrap(); - - let quantity = 40; - delegate_ccs(&mut state, &delegator, &pubkey, quantity).unwrap(); - - jail(&mut state, &[pubkey], custody_until, released_at).unwrap(); - - for current_term in 0..custody_until { - let next_validators = Vec::from(NextValidators::load_from_state(&state).unwrap()); - close_term(&mut state, &next_validators, &[]).unwrap(); - - let current_term_id = state.metadata().unwrap().unwrap().current_term_id(); - let released_addresses = Jail::load_from_state(&state).unwrap().released_addresses(current_term_id); - release_jailed_prisoners(&mut state, &released_addresses).unwrap(); - - state.increase_term_id(pseudo_term_to_block_num_calculator(current_term)).unwrap(); - } - - let current_term = custody_until + 1; - let result = self_nominate(&mut state, &pubkey, 0, current_term, current_term + nominate_expire, b"".to_vec()); - assert!(result.is_ok()); - - let delegation = Delegation::load_from_state(&state, &delegator).unwrap(); - assert_eq!(delegation.get_quantity(&pubkey), 40, "Delegation should be preserved"); - - let account = StakeAccount::load_from_state(&state, &delegator).unwrap(); - assert_eq!(account.balance, 100 - 40, "Delegation should be preserved"); - } - - fn pseudo_term_to_block_num_calculator(term_id: u64) -> u64 { - term_id * 10 + 1 - } } diff --git a/types/src/common_params.rs b/types/src/common_params.rs index 9e6250e036..24309dd8b7 100644 --- a/types/src/common_params.rs +++ b/types/src/common_params.rs @@ -28,18 +28,6 @@ pub struct CommonParams { max_body_size: usize, /// Snapshot creation period in unit of block numbers. snapshot_period: u64, - - term_seconds: u64, - nomination_expiration: u64, - custody_period: u64, - release_period: u64, - max_num_of_validators: usize, - min_num_of_validators: usize, - delegation_threshold: u64, - min_deposit: u64, - max_candidate_metadata_size: usize, - - era: u64, } impl CommonParams { @@ -56,74 +44,7 @@ impl CommonParams { self.snapshot_period } - pub fn term_seconds(&self) -> u64 { - self.term_seconds - } - pub fn nomination_expiration(&self) -> u64 { - self.nomination_expiration - } - pub fn custody_period(&self) -> u64 { - self.custody_period - } - pub fn release_period(&self) -> u64 { - self.release_period - } - pub fn max_num_of_validators(&self) -> usize { - self.max_num_of_validators - } - pub fn min_num_of_validators(&self) -> usize { - self.min_num_of_validators - } - pub fn delegation_threshold(&self) -> u64 { - self.delegation_threshold - } - pub fn min_deposit(&self) -> u64 { - self.min_deposit - } - pub fn max_candidate_metadata_size(&self) -> usize { - self.max_candidate_metadata_size - } - - pub fn era(&self) -> u64 { - self.era - } - pub fn verify(&self) -> Result<(), String> { - if self.nomination_expiration == 0 { - return Err("You should set the nomination expiration".to_string()) - } - if self.custody_period == 0 { - return Err("You should set the custody period".to_string()) - } - if self.release_period == 0 { - return Err("You should set the release period".to_string()) - } - if self.max_num_of_validators == 0 { - return Err("You should set the maximum number of validators".to_string()) - } - if self.min_num_of_validators == 0 { - return Err("You should set the minimum number of validators".to_string()) - } - if self.delegation_threshold == 0 { - return Err("You should set the delegation threshold".to_string()) - } - if self.min_deposit == 0 { - return Err("You should set the minimum deposit".to_string()) - } - - if self.min_num_of_validators > self.max_num_of_validators { - return Err(format!( - "The minimum number of validators({}) is larger than the maximum number of validators({})", - self.min_num_of_validators, self.max_num_of_validators - )) - } - if self.custody_period >= self.release_period { - return Err(format!( - "The release period({}) should be longer than the custody period({})", - self.release_period, self.custody_period - )) - } - Ok(()) } @@ -137,9 +58,6 @@ impl CommonParams { current_network_id, transaction_network_id )) } - if self.era < current_params.era { - return Err(format!("The era({}) shouldn't be less than the current era({})", self.era, current_params.era)) - } Ok(()) } } @@ -151,72 +69,37 @@ impl From for CommonParams { network_id: p.network_id, max_body_size: p.max_body_size.into(), snapshot_period: p.snapshot_period.into(), - term_seconds: p.term_seconds.into(), - nomination_expiration: p.nomination_expiration.into(), - custody_period: p.custody_period.into(), - release_period: p.release_period.into(), - max_num_of_validators: p.max_num_of_validators.into(), - min_num_of_validators: p.min_num_of_validators.into(), - delegation_threshold: p.delegation_threshold.into(), - min_deposit: p.min_deposit.into(), - max_candidate_metadata_size: p.max_candidate_metadata_size.into(), - era: p.era.map(From::from).unwrap_or_default(), } } } impl From for Params { fn from(p: CommonParams) -> Params { - let mut result: Params = Params { + Params { max_extra_data_size: p.max_extra_data_size().into(), network_id: p.network_id(), max_body_size: p.max_body_size().into(), snapshot_period: p.snapshot_period().into(), - term_seconds: p.term_seconds().into(), - nomination_expiration: p.nomination_expiration().into(), - custody_period: p.custody_period().into(), - release_period: p.release_period().into(), - max_num_of_validators: p.max_num_of_validators().into(), - min_num_of_validators: p.min_num_of_validators().into(), - delegation_threshold: p.delegation_threshold().into(), - min_deposit: p.min_deposit().into(), - max_candidate_metadata_size: p.max_candidate_metadata_size().into(), - era: None, - }; - let era = p.era(); - if era != 0 { - result.era = Some(era.into()); } - result } } impl Encodable for CommonParams { fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(14) + s.begin_list(4) .append(&self.max_extra_data_size) .append(&self.network_id) .append(&self.max_body_size) - .append(&self.snapshot_period) - .append(&self.term_seconds) - .append(&self.nomination_expiration) - .append(&self.custody_period) - .append(&self.release_period) - .append(&self.max_num_of_validators) - .append(&self.min_num_of_validators) - .append(&self.delegation_threshold) - .append(&self.min_deposit) - .append(&self.max_candidate_metadata_size) - .append(&self.era); + .append(&self.snapshot_period); } } impl Decodable for CommonParams { fn decode(rlp: &Rlp<'_>) -> Result { let size = rlp.item_count()?; - if size != 14 { + if size != 4 { return Err(DecoderError::RlpIncorrectListLen { - expected: 14, + expected: 4, got: size, }) } @@ -226,32 +109,11 @@ impl Decodable for CommonParams { let max_body_size = rlp.val_at(2)?; let snapshot_period = rlp.val_at(3)?; - let term_seconds = rlp.val_at(4)?; - let nomination_expiration = rlp.val_at(5)?; - let custody_period = rlp.val_at(6)?; - let release_period = rlp.val_at(7)?; - let max_num_of_validators = rlp.val_at(8)?; - let min_num_of_validators = rlp.val_at(9)?; - let delegation_threshold = rlp.val_at(10)?; - let min_deposit = rlp.val_at(11)?; - let max_candidate_metadata_size = rlp.val_at(12)?; - let era = rlp.val_at(13)?; - Ok(Self { max_extra_data_size, network_id, max_body_size, snapshot_period, - term_seconds, - nomination_expiration, - custody_period, - release_period, - max_num_of_validators, - min_num_of_validators, - delegation_threshold, - min_deposit, - max_candidate_metadata_size, - era, }) } } @@ -260,31 +122,6 @@ impl CommonParams { pub fn default_for_test() -> Self { Self::from(Params::default()) } - - pub fn set_dynamic_validator_params_for_test( - &mut self, - term_seconds: u64, - nomination_expiration: u64, - custody_period: u64, - release_period: u64, - max_num_of_validators: usize, - min_num_of_validators: usize, - delegation_threshold: u64, - min_deposit: u64, - max_candidate_metadata_size: usize, - ) { - self.term_seconds = term_seconds; - self.nomination_expiration = nomination_expiration; - self.custody_period = custody_period; - self.release_period = release_period; - - self.min_num_of_validators = min_num_of_validators; - self.max_num_of_validators = max_num_of_validators; - - self.delegation_threshold = delegation_threshold; - self.min_deposit = min_deposit; - self.max_candidate_metadata_size = max_candidate_metadata_size; - } } #[cfg(test)] @@ -297,31 +134,13 @@ mod tests { rlp_encode_and_decode_test!(CommonParams::default_for_test()); } - #[test] - fn rlp_with_extra_fields() { - let mut params = CommonParams::default_for_test(); - params.term_seconds = 100; - params.min_deposit = 123; - rlp_encode_and_decode_test!(params); - } - #[test] fn params_from_json_with_stake_params() { let s = r#"{ "maxExtraDataSize": "0x20", "networkID" : "tc", "maxBodySize" : 4194304, - "snapshotPeriod": 16384, - "termSeconds": 3600, - "nominationExpiration": 24, - "custodyPeriod": 25, - "releasePeriod": 26, - "maxNumOfValidators": 27, - "minNumOfValidators": 28, - "delegationThreshold": 29, - "minDeposit": 30, - "maxCandidateMetadataSize": 31, - "era": 32 + "snapshotPeriod": 16384 }"#; let params = serde_json::from_str::(s).unwrap(); let deserialized = CommonParams::from(params.clone()); @@ -329,16 +148,6 @@ mod tests { assert_eq!(deserialized.network_id, "tc".into()); assert_eq!(deserialized.max_body_size, 4_194_304); assert_eq!(deserialized.snapshot_period, 16_384); - assert_eq!(deserialized.term_seconds, 3600); - assert_eq!(deserialized.nomination_expiration, 24); - assert_eq!(deserialized.custody_period, 25); - assert_eq!(deserialized.release_period, 26); - assert_eq!(deserialized.max_num_of_validators, 27); - assert_eq!(deserialized.min_num_of_validators, 28); - assert_eq!(deserialized.delegation_threshold, 29); - assert_eq!(deserialized.min_deposit, 30); - assert_eq!(deserialized.max_candidate_metadata_size, 31); - assert_eq!(deserialized.era, 32); assert_eq!(params, deserialized.into()); } @@ -349,17 +158,7 @@ mod tests { "maxExtraDataSize": "0x20", "networkID" : "tc", "maxBodySize" : 4194304, - "snapshotPeriod": 16384, - "termSeconds": 3600, - "nominationExpiration": 24, - "custodyPeriod": 25, - "releasePeriod": 26, - "maxNumOfValidators": 27, - "minNumOfValidators": 28, - "delegationThreshold": 29, - "minDeposit": 30, - "maxCandidateMetadataSize": 31, - "era": 32 + "snapshotPeriod": 16384 }"#; let params = serde_json::from_str::(s).unwrap(); let deserialized = CommonParams::from(params.clone()); @@ -367,16 +166,6 @@ mod tests { assert_eq!(deserialized.network_id, "tc".into()); assert_eq!(deserialized.max_body_size, 4_194_304); assert_eq!(deserialized.snapshot_period, 16_384); - assert_eq!(deserialized.term_seconds, 3600); - assert_eq!(deserialized.nomination_expiration, 24); - assert_eq!(deserialized.custody_period, 25); - assert_eq!(deserialized.release_period, 26); - assert_eq!(deserialized.max_num_of_validators, 27); - assert_eq!(deserialized.min_num_of_validators, 28); - assert_eq!(deserialized.delegation_threshold, 29); - assert_eq!(deserialized.min_deposit, 30); - assert_eq!(deserialized.max_candidate_metadata_size, 31); - assert_eq!(deserialized.era, 32); assert_eq!(params, deserialized.into()); } diff --git a/types/src/consensus_params.rs b/types/src/consensus_params.rs index 61ba2c80fa..e2a4f98ef6 100644 --- a/types/src/consensus_params.rs +++ b/types/src/consensus_params.rs @@ -31,8 +31,6 @@ pub struct ConsensusParams { max_gas_total: usize, /// Snapshot creation period in unit of block numbers. snapshot_period: u64, - - term_seconds: u64, } impl ConsensusParams { @@ -51,9 +49,6 @@ impl ConsensusParams { pub fn snapshot_period(&self) -> u64 { self.snapshot_period } - pub fn term_seconds(&self) -> u64 { - self.term_seconds - } pub fn default_for_test() -> Self { Self { @@ -62,27 +57,25 @@ impl ConsensusParams { max_body_size: 1000, max_gas_total: 1000, snapshot_period: 1000, - term_seconds: 1000, } } } impl Encodable for ConsensusParams { fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(6) + s.begin_list(5) .append(&self.max_extra_data_size) .append(&self.network_id) .append(&self.max_body_size) .append(&self.max_gas_total) - .append(&self.snapshot_period) - .append(&self.term_seconds); + .append(&self.snapshot_period); } } impl Decodable for ConsensusParams { fn decode(rlp: &Rlp<'_>) -> Result { let size = rlp.item_count()?; - if size != 6 { + if size != 5 { return Err(DecoderError::RlpIncorrectListLen { expected: 6, got: size, @@ -94,7 +87,6 @@ impl Decodable for ConsensusParams { let max_body_size = rlp.val_at(2)?; let max_gas_total = rlp.val_at(3)?; let snapshot_period = rlp.val_at(4)?; - let term_seconds = rlp.val_at(5)?; Ok(Self { max_extra_data_size, @@ -102,7 +94,6 @@ impl Decodable for ConsensusParams { max_body_size, max_gas_total, snapshot_period, - term_seconds, }) } } @@ -115,7 +106,6 @@ impl From for ConsensusParams { max_body_size: p.max_body_size.into(), max_gas_total: usize::max_value(), // TODO: add a parameter to scheme snapshot_period: p.snapshot_period.into(), - term_seconds: p.term_seconds.into(), } } } diff --git a/types/src/lib.rs b/types/src/lib.rs index d34fa58989..73d3e3449e 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -16,8 +16,6 @@ #[macro_use] extern crate serde_derive; -#[macro_use] -extern crate rlp_derive; mod block_hash; mod block_id; @@ -42,5 +40,4 @@ pub use consensus_params::ConsensusParams; pub use deposit::Deposit; pub use header::Header; pub use tx_hash::TxHash; -pub use validator_set::CompactValidatorEntry; -pub use validator_set::CompactValidatorSet; +pub use validator_set::{Validator, Validators}; diff --git a/types/src/transaction/action.rs b/types/src/transaction/action.rs index 90fe26a169..77656b38c6 100644 --- a/types/src/transaction/action.rs +++ b/types/src/transaction/action.rs @@ -15,28 +15,15 @@ // along with this program. If not, see . use crate::errors::SyntaxError; -use crate::transaction::{Approval, Validator}; -use crate::CommonParams; use ccrypto::Blake; -use ckey::{verify, Ed25519Public as Public, NetworkId}; -use primitives::{Bytes, H256}; +use ckey::Ed25519Public as Public; +use primitives::H256; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; #[derive(Clone, Copy)] #[repr(u8)] enum ActionTag { Pay = 0x02, - TransferCCS = 0x21, - DelegateCCS = 0x22, - Revoke = 0x23, - SelfNominate = 0x24, - ReportDoubleVote = 0x25, - Redelegate = 0x26, - UpdateValidators = 0x30, - CloseTerm = 0x31, - ChangeNextValidators = 0x32, - Elect = 0x33, - ChangeParams = 0xFF, } impl Encodable for ActionTag { @@ -50,17 +37,6 @@ impl Decodable for ActionTag { let tag = rlp.as_val()?; match tag { 0x02u8 => Ok(Self::Pay), - 0x21 => Ok(Self::TransferCCS), - 0x22 => Ok(Self::DelegateCCS), - 0x23 => Ok(Self::Revoke), - 0x24 => Ok(Self::SelfNominate), - 0x25 => Ok(Self::ReportDoubleVote), - 0x26 => Ok(Self::Redelegate), - 0x30 => Ok(Self::UpdateValidators), - 0x31 => Ok(Self::CloseTerm), - 0x32 => Ok(Self::ChangeNextValidators), - 0x33 => Ok(Self::Elect), - 0xFF => Ok(Self::ChangeParams), _ => Err(DecoderError::Custom("Unexpected action prefix")), } } @@ -73,50 +49,6 @@ pub enum Action { /// Transferred quantity. quantity: u64, }, - TransferCCS { - address: Public, - quantity: u64, - }, - DelegateCCS { - address: Public, - quantity: u64, - }, - Revoke { - address: Public, - quantity: u64, - }, - Redelegate { - prev_delegatee: Public, - next_delegatee: Public, - quantity: u64, - }, - SelfNominate { - deposit: u64, - metadata: Bytes, - }, - ChangeParams { - metadata_seq: u64, - params: Box, - approvals: Vec, - }, - ReportDoubleVote { - message1: Bytes, - message2: Bytes, - }, - UpdateValidators { - validators: Vec, - }, - CloseTerm { - inactive_validators: Vec, - next_validators: Vec, - released_addresses: Vec, - custody_until: u64, - kick_at: u64, - }, - ChangeNextValidators { - validators: Vec, - }, - Elect, } impl Action { @@ -128,78 +60,6 @@ impl Action { pub fn verify(&self) -> Result<(), SyntaxError> { Ok(()) } - - pub fn verify_with_params(&self, common_params: &CommonParams) -> Result<(), SyntaxError> { - if let Some(network_id) = self.network_id() { - let system_network_id = common_params.network_id(); - if network_id != system_network_id { - return Err(SyntaxError::InvalidNetworkId(network_id)) - } - } - - match self { - Action::TransferCCS { - .. - } => {} - Action::DelegateCCS { - .. - } => {} - Action::Revoke { - .. - } => {} - Action::Redelegate { - .. - } => {} - Action::SelfNominate { - metadata, - .. - } => { - if metadata.len() > common_params.max_candidate_metadata_size() { - return Err(SyntaxError::InvalidCustomAction(format!( - "Too long candidate metadata: the size limit is {}", - common_params.max_candidate_metadata_size() - ))) - } - } - Action::ChangeParams { - metadata_seq, - params, - approvals, - } => { - params.verify_change(common_params).map_err(SyntaxError::InvalidCustomAction)?; - let action = Action::ChangeParams { - metadata_seq: *metadata_seq, - params: params.clone(), - approvals: vec![], - }; - let encoded_action = H256::blake(rlp::encode(&action)); - for approval in approvals { - if !verify(approval.signature(), &encoded_action, approval.signer_public()) { - return Err(SyntaxError::InvalidCustomAction(format!( - "Cannot decode the signature {:?} with public {:?} and the message {:?}", - approval.signature(), - approval.signer_public(), - &encoded_action, - ))) - } - } - } - Action::ReportDoubleVote { - message1, - message2, - } => { - if message1 == message2 { - return Err(SyntaxError::InvalidCustomAction(String::from("Messages are duplicated"))) - } - } - _ => {} - } - Ok(()) - } - - fn network_id(&self) -> Option { - None - } } impl Encodable for Action { @@ -214,94 +74,6 @@ impl Encodable for Action { s.append(receiver); s.append(quantity); } - Action::TransferCCS { - address, - quantity, - } => { - s.begin_list(3).append(&ActionTag::TransferCCS).append(address).append(quantity); - } - Action::DelegateCCS { - address, - quantity, - } => { - s.begin_list(3).append(&ActionTag::DelegateCCS).append(address).append(quantity); - } - Action::Revoke { - address, - quantity, - } => { - s.begin_list(3).append(&ActionTag::Revoke).append(address).append(quantity); - } - Action::Redelegate { - prev_delegatee, - next_delegatee, - quantity, - } => { - s.begin_list(4) - .append(&ActionTag::Redelegate) - .append(prev_delegatee) - .append(next_delegatee) - .append(quantity); - } - Action::SelfNominate { - deposit, - metadata, - } => { - s.begin_list(3).append(&ActionTag::SelfNominate).append(deposit).append(metadata); - } - Action::ChangeParams { - metadata_seq, - params, - approvals, - } => { - s.begin_list(3 + approvals.len()) - .append(&ActionTag::ChangeParams) - .append(metadata_seq) - .append(&**params); - for approval in approvals { - s.append(approval); - } - } - Action::ReportDoubleVote { - message1, - message2, - } => { - s.begin_list(3).append(&ActionTag::ReportDoubleVote).append(message1).append(message2); - } - Action::UpdateValidators { - validators, - } => { - let s = s.begin_list(validators.len() + 1).append(&ActionTag::UpdateValidators); - for validator in validators { - s.append(validator); - } - } - Action::CloseTerm { - inactive_validators, - next_validators, - released_addresses, - custody_until, - kick_at, - } => { - s.begin_list(6) - .append(&ActionTag::CloseTerm) - .append_list(inactive_validators) - .append_list(next_validators) - .append_list(released_addresses) - .append(custody_until) - .append(kick_at); - } - Action::ChangeNextValidators { - validators, - } => { - s.begin_list(1 + validators.len()).append(&ActionTag::ChangeNextValidators); - for validator in validators { - s.append(validator); - } - } - Action::Elect => { - s.begin_list(1).append(&ActionTag::Elect); - } } } } @@ -322,161 +94,6 @@ impl Decodable for Action { quantity: rlp.val_at(2)?, }) } - ActionTag::TransferCCS => { - let item_count = rlp.item_count()?; - if item_count != 3 { - return Err(DecoderError::RlpInvalidLength { - expected: 3, - got: item_count, - }) - } - Ok(Action::TransferCCS { - address: rlp.val_at(1)?, - quantity: rlp.val_at(2)?, - }) - } - ActionTag::DelegateCCS => { - let item_count = rlp.item_count()?; - if item_count != 3 { - return Err(DecoderError::RlpInvalidLength { - expected: 3, - got: item_count, - }) - } - Ok(Action::DelegateCCS { - address: rlp.val_at(1)?, - quantity: rlp.val_at(2)?, - }) - } - ActionTag::Revoke => { - let item_count = rlp.item_count()?; - if item_count != 3 { - return Err(DecoderError::RlpInvalidLength { - expected: 3, - got: item_count, - }) - } - Ok(Action::Revoke { - address: rlp.val_at(1)?, - quantity: rlp.val_at(2)?, - }) - } - ActionTag::Redelegate => { - let item_count = rlp.item_count()?; - if item_count != 4 { - return Err(DecoderError::RlpInvalidLength { - expected: 4, - got: item_count, - }) - } - Ok(Action::Redelegate { - prev_delegatee: rlp.val_at(1)?, - next_delegatee: rlp.val_at(2)?, - quantity: rlp.val_at(3)?, - }) - } - ActionTag::SelfNominate => { - let item_count = rlp.item_count()?; - if item_count != 3 { - return Err(DecoderError::RlpInvalidLength { - expected: 3, - got: item_count, - }) - } - Ok(Action::SelfNominate { - deposit: rlp.val_at(1)?, - metadata: rlp.val_at(2)?, - }) - } - ActionTag::ChangeParams => { - let item_count = rlp.item_count()?; - if item_count < 4 { - return Err(DecoderError::RlpIncorrectListLen { - expected: 4, - got: item_count, - }) - } - 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 { - metadata_seq, - params, - approvals, - }) - } - ActionTag::ReportDoubleVote => { - let item_count = rlp.item_count()?; - if item_count != 3 { - return Err(DecoderError::RlpIncorrectListLen { - expected: 3, - got: item_count, - }) - } - let message1 = rlp.val_at(1)?; - let message2 = rlp.val_at(2)?; - Ok(Action::ReportDoubleVote { - message1, - message2, - }) - } - ActionTag::UpdateValidators => { - let item_count = rlp.item_count()?; - if item_count < 1 { - return Err(DecoderError::RlpIncorrectListLen { - expected: 1, - got: item_count, - }) - } - let validators = rlp.iter().skip(1).map(|rlp| rlp.as_val()).collect::>()?; - Ok(Action::UpdateValidators { - validators, - }) - } - ActionTag::CloseTerm => { - let item_count = rlp.item_count()?; - if item_count != 6 { - return Err(DecoderError::RlpIncorrectListLen { - expected: 6, - got: item_count, - }) - } - let inactive_validators = rlp.list_at(1)?; - let next_validators = rlp.list_at(2)?; - let released_addresses = rlp.list_at(3)?; - let custody_until = rlp.val_at(4)?; - let kick_at = rlp.val_at(5)?; - Ok(Action::CloseTerm { - inactive_validators, - next_validators, - released_addresses, - custody_until, - kick_at, - }) - } - ActionTag::ChangeNextValidators => { - let item_count = rlp.item_count()?; - if item_count < 1 { - return Err(DecoderError::RlpIncorrectListLen { - expected: 1, - got: item_count, - }) - } - let validators = rlp.iter().skip(1).map(|rlp| rlp.as_val()).collect::>()?; - Ok(Action::ChangeNextValidators { - validators, - }) - } - ActionTag::Elect => { - let item_count = rlp.item_count()?; - if item_count != 1 { - return Err(DecoderError::RlpIncorrectListLen { - expected: 1, - got: item_count, - }) - } - Ok(Action::Elect) - } } } } @@ -484,7 +101,7 @@ impl Decodable for Action { #[cfg(test)] mod tests { use super::*; - use ckey::{Ed25519Public as Public, Signature}; + use ckey::Ed25519Public as Public; use rlp::rlp_encode_and_decode_test; #[test] @@ -494,62 +111,4 @@ mod tests { quantity: 300, }); } - - #[test] - fn rlp_of_change_params() { - rlp_encode_and_decode_test!(Action::ChangeParams { - metadata_seq: 3, - params: CommonParams::default_for_test().into(), - approvals: vec![ - Approval::new(Signature::random(), Public::random()), - Approval::new(Signature::random(), Public::random()), - ], - }); - } - - #[test] - fn rlp_of_update_validators() { - rlp_encode_and_decode_test!(Action::UpdateValidators { - validators: vec![Validator::new(1, 2, Public::random()), Validator::new(3, 4, Public::random())], - }); - } - - #[test] - fn rlp_of_close_term() { - rlp_encode_and_decode_test!(Action::CloseTerm { - inactive_validators: vec![Public::random(), Public::random(), Public::random()], - next_validators: vec![], - released_addresses: vec![Public::random(), Public::random()], - custody_until: 17, - kick_at: 31, - }); - } - - #[test] - fn rlp_of_change_next_validators() { - rlp_encode_and_decode_test!(Action::ChangeNextValidators { - validators: vec![], - }); - } - - #[test] - fn rlp_of_elect() { - rlp_encode_and_decode_test!(Action::Elect); - } - - #[test] - fn decode_fail_if_change_params_have_no_signatures() { - let action = Action::ChangeParams { - metadata_seq: 3, - params: CommonParams::default_for_test().into(), - approvals: vec![], - }; - assert_eq!( - Err(DecoderError::RlpIncorrectListLen { - expected: 4, - got: 3, - }), - Rlp::new(&rlp::encode(&action)).as_val::() - ); - } } diff --git a/types/src/transaction/approval.rs b/types/src/transaction/approval.rs deleted file mode 100644 index 9069bdbf61..0000000000 --- a/types/src/transaction/approval.rs +++ /dev/null @@ -1,39 +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 ckey::{Ed25519Public as Public, Signature}; - -#[derive(Clone, Debug, Eq, PartialEq, RlpEncodable, RlpDecodable, Serialize, Deserialize)] -pub struct Approval { - signature: Signature, - signer_public: Public, -} - -impl Approval { - pub fn new(signature: Signature, signer_public: Public) -> Self { - Self { - signature, - signer_public, - } - } - pub fn signature(&self) -> &Signature { - &self.signature - } - - pub fn signer_public(&self) -> &Public { - &self.signer_public - } -} diff --git a/types/src/transaction/mod.rs b/types/src/transaction/mod.rs index 4b9215b3ff..3c2f226ea3 100644 --- a/types/src/transaction/mod.rs +++ b/types/src/transaction/mod.rs @@ -15,18 +15,14 @@ // along with this program. If not, see . mod action; -mod approval; mod incomplete_transaction; mod partial_hashing; mod timelock; #[cfg_attr(feature = "cargo-clippy", allow(clippy::module_inception))] mod transaction; -mod validator; pub use self::action::Action; -pub use self::approval::Approval; pub use self::incomplete_transaction::IncompleteTransaction; pub use self::partial_hashing::{HashingError, PartialHashing}; pub use self::timelock::Timelock; pub use self::transaction::Transaction; -pub use self::validator::Validator; diff --git a/types/src/transaction/validator.rs b/types/src/transaction/validator.rs deleted file mode 100644 index e2752481e4..0000000000 --- a/types/src/transaction/validator.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 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 ckey::Ed25519Public as Public; - -pub type StakeQuantity = u64; -pub type DepositQuantity = u64; - -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, RlpDecodable, RlpEncodable)] -pub struct Validator { - weight: StakeQuantity, - delegation: StakeQuantity, - deposit: DepositQuantity, - pubkey: Public, -} - -impl Validator { - pub fn new(delegation: StakeQuantity, deposit: DepositQuantity, pubkey: Public) -> Self { - Self { - weight: delegation, - delegation, - deposit, - pubkey, - } - } - - pub fn reset(&mut self) { - self.weight = self.delegation; - } - - pub fn weight(&self) -> StakeQuantity { - self.weight - } - - pub fn set_weight(&mut self, weight: StakeQuantity) { - self.weight = weight; - } - - pub fn pubkey(&self) -> &Public { - &self.pubkey - } - - pub fn delegation(&self) -> StakeQuantity { - self.delegation - } - - pub fn deposit(&self) -> DepositQuantity { - self.deposit - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ckey::Ed25519Public as Public; - use rlp::rlp_encode_and_decode_test; - - #[test] - fn encode_and_decode_pay_action() { - rlp_encode_and_decode_test!(Validator { - weight: 1, - delegation: 2, - deposit: 3, - pubkey: Public::random(), - }); - } -} diff --git a/types/src/validator_set.rs b/types/src/validator_set.rs index c5cccc8870..f64a09df54 100644 --- a/types/src/validator_set.rs +++ b/types/src/validator_set.rs @@ -20,16 +20,16 @@ use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; use std::ops::{Deref, DerefMut}; #[derive(Clone, Debug, Eq, PartialEq)] -pub struct CompactValidatorEntry { +pub struct Validator { pub public_key: Public, - pub delegation: u64, + pub voting_power: u64, } // It will be hashed in the header. #[derive(Clone, Debug, Eq, PartialEq, Default)] -pub struct CompactValidatorSet(Vec); -impl CompactValidatorSet { - pub fn new(x: Vec) -> Self { +pub struct Validators(Vec); +impl Validators { + pub fn new(x: Vec) -> Self { Self(x) } @@ -38,30 +38,36 @@ impl CompactValidatorSet { } } -impl Deref for CompactValidatorSet { - type Target = Vec; - fn deref(&self) -> &Vec { +impl From for Vec { + fn from(set: Validators) -> Self { + set.0 + } +} + +impl Deref for Validators { + type Target = Vec; + fn deref(&self) -> &Vec { &self.0 } } -impl DerefMut for CompactValidatorSet { - fn deref_mut(&mut self) -> &mut Vec { +impl DerefMut for Validators { + fn deref_mut(&mut self) -> &mut Vec { &mut self.0 } } -impl Encodable for CompactValidatorSet { +impl Encodable for Validators { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(self.0.len() * 2); for validator in self.0.iter() { s.append(&validator.public_key); - s.append(&validator.delegation); + s.append(&validator.voting_power); } } } -impl Decodable for CompactValidatorSet { +impl Decodable for Validators { fn decode(rlp: &Rlp<'_>) -> Result { let item_count = rlp.item_count()?; if item_count % 2 == 1 { @@ -73,9 +79,9 @@ impl Decodable for CompactValidatorSet { let mut vec = Vec::with_capacity(item_count / 2); // TODO: Optimzie the below code for i in 0..(item_count / 2) { - vec.push(CompactValidatorEntry { + vec.push(Validator { public_key: rlp.val_at(i * 2)?, - delegation: rlp.val_at(i * 2 + 1)?, + voting_power: rlp.val_at(i * 2 + 1)?, }); } Ok(Self::new(vec)) @@ -96,13 +102,13 @@ mod tests { let mut rng: StdRng = rand::SeedableRng::from_seed(seed); for _ in 0..iteration { - let mut vset = CompactValidatorSet::new(Vec::new()); + let mut vset = Validators::new(Vec::new()); let n = rng.gen::(); for _ in 0..n { - vset.0.push(CompactValidatorEntry { + vset.0.push(Validator { public_key: Public::random(), - delegation: rng.gen::(), + voting_power: rng.gen::(), }) } rlp_encode_and_decode_test!(vset);