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