diff --git a/core/src/block.rs b/core/src/block.rs index fb488aff7b..ec598eda67 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -22,7 +22,7 @@ use crate::transaction::{SignedTransaction, UnverifiedTransaction}; use crate::BlockId; use ccrypto::BLAKE_NULL_RLP; use ckey::Address; -use cstate::{FindActionHandler, StateDB, StateError, StateWithCache, TopLevelState}; +use cstate::{FindActionHandler, IBCTransactionExecutor, StateDB, StateError, StateWithCache, TopLevelState}; use ctypes::errors::HistoryError; use ctypes::header::{Header, Seal}; use ctypes::util::unexpected::Mismatch; @@ -149,7 +149,7 @@ impl<'x> OpenBlock<'x> { } /// Push a transaction into the block. - pub fn push_transaction( + pub fn push_transaction( &mut self, tx: SignedTransaction, h: Option, @@ -192,7 +192,7 @@ impl<'x> OpenBlock<'x> { } /// Push transactions onto the block. - pub fn push_transactions( + pub fn push_transactions( &mut self, transactions: &[SignedTransaction], client: &C, @@ -455,7 +455,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles -pub fn enact( +pub fn enact( header: &Header, transactions: &[SignedTransaction], engine: &dyn CodeChainEngine, diff --git a/core/src/client/client.rs b/core/src/client/client.rs index db701cee44..5b2f14e580 100644 --- a/core/src/client/client.rs +++ b/core/src/client/client.rs @@ -26,6 +26,7 @@ use crate::client::{ConsensusClient, SnapshotClient, TermInfo}; use crate::consensus::{CodeChainEngine, EngineError}; use crate::encoded; use crate::error::{BlockImportError, Error, ImportError, SchemeError}; +use crate::ibc; use crate::miner::{Miner, MinerService}; use crate::scheme::Scheme; use crate::service::ClientIoMessage; @@ -36,7 +37,9 @@ use cdb::{new_journaldb, Algorithm, AsHashDB, DatabaseError}; use cio::IoChannel; use ckey::{Address, NetworkId, PlatformAddress, Public}; use cnetwork::NodeId; -use cstate::{ActionHandler, FindActionHandler, StateDB, StateResult, TopLevelState, TopStateView}; +use cstate::{ + ActionHandler, FindActionHandler, IBCTransactionExecutor, StateDB, StateResult, TopLevelState, TopStateView, +}; use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken}; use ctypes::header::Header; use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction}; @@ -856,3 +859,15 @@ impl SnapshotClient for Client { } } } + +impl IBCTransactionExecutor for Client { + fn execute( + &self, + bytes: &[u8], + state: &mut TopLevelState, + fee_payer: &Address, + sender_pubkey: &Public, + ) -> StateResult<()> { + ibc::execute_transaction(bytes, state, fee_payer, sender_pubkey) + } +} diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index 53bc350b07..7d90a9b9de 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -324,3 +324,5 @@ pub trait StateInfo { pub trait SnapshotClient { fn notify_snapshot(&self, id: BlockId); } + +pub trait IBCClient {} diff --git a/core/src/client/test_client.rs b/core/src/client/test_client.rs index 527a150f57..28bba4a399 100644 --- a/core/src/client/test_client.rs +++ b/core/src/client/test_client.rs @@ -50,7 +50,7 @@ use cdb; use ckey::{public_to_address, Address, Generator, KeyPair, NetworkId, PlatformAddress, Private, Public, Random}; use cnetwork::NodeId; use cstate::tests::helpers::empty_top_state; -use cstate::{FindActionHandler, StateDB, TopLevelState}; +use cstate::{FindActionHandler, IBCTransactionExecutor, StateDB, TopLevelState}; use ctimer::{TimeoutHandler, TimerToken}; use ctypes::header::Header; use ctypes::transaction::{Action, Transaction}; @@ -691,3 +691,5 @@ impl StateInfo for TestBlockChainClient { Some(top_state) } } + +impl IBCTransactionExecutor for TestBlockChainClient {} diff --git a/core/src/codechain_machine.rs b/core/src/codechain_machine.rs index 93cc47612a..e69431a31e 100644 --- a/core/src/codechain_machine.rs +++ b/core/src/codechain_machine.rs @@ -110,6 +110,12 @@ impl CodeChainMachine { // FIXME 0 } + Action::IBC { + .. + } => { + // FIXME + 0 + } } } diff --git a/core/src/consensus/solo/mod.rs b/core/src/consensus/solo/mod.rs index 461b2f2d97..d254114a88 100644 --- a/core/src/consensus/solo/mod.rs +++ b/core/src/consensus/solo/mod.rs @@ -25,7 +25,6 @@ use crate::client::ConsensusClient; use crate::codechain_machine::CodeChainMachine; use crate::consensus::{EngineError, EngineType}; use crate::error::Error; -use crate::ibc; use ckey::Address; use cstate::{ActionHandler, HitHandler, TopStateView}; use ctypes::{BlockHash, CommonParams, Header}; @@ -49,7 +48,6 @@ impl Solo { action_handlers.push(Arc::new(HitHandler::new())); } action_handlers.push(Arc::new(stake::Stake::new(params.genesis_stakes.clone()))); - action_handlers.push(Arc::new(ibc::custom_action_handler::IBC::new())); Solo { client: Default::default(), diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index a43ef716bd..7ede900f87 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -262,7 +262,6 @@ impl ConsensusEngine for Tendermint { fn register_client(&self, client: Weak) { *self.client.write() = Some(Weak::clone(&client)); self.stake.register_resources(Weak::clone(&client), Arc::downgrade(&self.validators)); - self.ibc.register_resources(client); } fn is_proposal(&self, header: &Header) -> bool { diff --git a/core/src/consensus/tendermint/mod.rs b/core/src/consensus/tendermint/mod.rs index 612460cc02..27d22fae3d 100644 --- a/core/src/consensus/tendermint/mod.rs +++ b/core/src/consensus/tendermint/mod.rs @@ -32,7 +32,6 @@ pub use self::types::{Height, Step, View}; pub use super::{stake, ValidatorSet}; use crate::client::ConsensusClient; use crate::codechain_machine::CodeChainMachine; -use crate::ibc; use crate::snapshot_notify::NotifySender as SnapshotNotifySender; use crate::ChainNotify; use crossbeam_channel as crossbeam; @@ -72,7 +71,6 @@ pub struct Tendermint { action_handlers: Vec>, /// stake object to register client data later stake: Arc, - ibc: Arc, /// Chain notify chain_notify: Arc, has_signer: AtomicBool, @@ -92,7 +90,6 @@ impl Tendermint { pub fn new(our_params: TendermintParams, machine: CodeChainMachine) -> Arc { let validators = Arc::clone(&our_params.validators); let stake = Arc::new(stake::Stake::new(our_params.genesis_stakes)); - let ibc = Arc::new(ibc::custom_action_handler::IBC::new()); let timeouts = our_params.timeouts; let machine = Arc::new(machine); @@ -104,7 +101,7 @@ impl Tendermint { inner, quit_tendermint, ) = worker::spawn(our_params.validators); - let action_handlers: Vec> = vec![stake.clone(), ibc.clone()]; + let action_handlers: Vec> = vec![stake.clone()]; let chain_notify = Arc::new(TendermintChainNotify::new(inner.clone())); Arc::new(Tendermint { @@ -121,7 +118,6 @@ impl Tendermint { machine, action_handlers, stake, - ibc, chain_notify, has_signer: false.into(), }) diff --git a/core/src/ibc/context.rs b/core/src/ibc/context.rs index 10e80be94d..6fb2792741 100644 --- a/core/src/ibc/context.rs +++ b/core/src/ibc/context.rs @@ -14,10 +14,11 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . use super::kv_store; -use crate::ibc::custom_action_handler::CUSTOM_ACTION_HANDLER_ID; use crate::ibc::KVStore; -use cstate::{ActionDataKeyBuilder, TopLevelState, TopState, TopStateView}; +use ccrypto::blake256; +use cstate::{TopLevelState, TopState, TopStateView}; use primitives::H256; +use rlp::RlpStream; pub trait Context { fn get_kv_store(&mut self) -> &mut dyn kv_store::KVStore; @@ -49,8 +50,10 @@ struct TopLevelKVStore<'a> { impl<'a> TopLevelKVStore<'a> { fn key(path: &str) -> H256 { - let key_builder = ActionDataKeyBuilder::new(CUSTOM_ACTION_HANDLER_ID, 1); - key_builder.append(&path.as_bytes()).into_key() + let mut rlp = RlpStream::new_list(2); + rlp.append(&"IBCData"); + rlp.append(&path); + blake256(rlp.drain()) } } diff --git a/core/src/ibc/mod.rs b/core/src/ibc/mod.rs index 726b95267d..1952c23347 100644 --- a/core/src/ibc/mod.rs +++ b/core/src/ibc/mod.rs @@ -19,11 +19,10 @@ pub mod client_02; #[allow(unused_variables)] mod commitment_23; pub mod context; -#[allow(dead_code)] -#[allow(unused_variables)] -pub mod custom_action_handler; mod kv_store; +mod transaction_handler; pub use self::client_02 as client; pub use self::context::Context; pub use self::kv_store::KVStore; +pub use transaction_handler::execute as execute_transaction; diff --git a/core/src/ibc/custom_action_handler/actions.rs b/core/src/ibc/transaction_handler/actions.rs similarity index 84% rename from core/src/ibc/custom_action_handler/actions.rs rename to core/src/ibc/transaction_handler/actions.rs index d0a33a3a6a..3816cff1ff 100644 --- a/core/src/ibc/custom_action_handler/actions.rs +++ b/core/src/ibc/transaction_handler/actions.rs @@ -1,4 +1,4 @@ -// Copyright 2019 Kodebox, Inc. +// Copyright 2019-2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -14,11 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::client::ConsensusClient; -use ctypes::errors::SyntaxError; -use ctypes::CommonParams; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; -use std::sync::Arc; const ACTION_CREATE_CLIENT: u8 = 1; const ACTION_UPDATE_CLIENT: u8 = 2; @@ -36,24 +32,6 @@ pub enum Action { }, } -impl Action { - pub fn verify( - &self, - current_params: &CommonParams, - client: Option>, - ) -> Result<(), SyntaxError> { - match self { - Action::CreateClient { - .. - } => {} - Action::UpdateClient { - .. - } => {} - } - Ok(()) - } -} - impl Encodable for Action { fn rlp_append(&self, s: &mut RlpStream) { match self { diff --git a/core/src/ibc/custom_action_handler/mod.rs b/core/src/ibc/transaction_handler/mod.rs similarity index 52% rename from core/src/ibc/custom_action_handler/mod.rs rename to core/src/ibc/transaction_handler/mod.rs index 0bf9215451..ec26e92f2b 100644 --- a/core/src/ibc/custom_action_handler/mod.rs +++ b/core/src/ibc/transaction_handler/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2020 Kodebox, Inc. +// Copyright 2020 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -17,88 +17,39 @@ mod actions; use self::actions::Action; -use crate::client::ConsensusClient; use crate::ibc; use ckey::{Address, Public}; -use cstate::{ActionHandler, StateResult, TopLevelState}; +use cstate::{StateResult, TopLevelState}; use ctypes::errors::RuntimeError; -use ctypes::errors::SyntaxError; -use ctypes::{CommonParams, Header}; use ibc::client_02 as ibc_client; use ibc::client_02::foundry as ibc_foundry; use ibc::context as ibc_context; -use parking_lot::RwLock; use rlp::{Decodable, Rlp}; -use std::sync::{Arc, Weak}; -pub const CUSTOM_ACTION_HANDLER_ID: u64 = 3; - -#[derive(Default)] -pub struct IBC { - client: RwLock>>, -} - -impl IBC { - pub fn new() -> Self { - IBC { - client: Default::default(), - } - } - - pub fn register_resources(&self, client: Weak) { - *self.client.write() = Some(Weak::clone(&client)); +pub fn execute( + bytes: &[u8], + state: &mut TopLevelState, + fee_payer: &Address, + _sender_public: &Public, +) -> StateResult<()> { + let action = Action::decode(&Rlp::new(bytes)).expect("Verification passed"); + match action { + Action::CreateClient { + id, + kind, + consensus_state, + } => create_client(state, fee_payer, &id, kind, &consensus_state), + Action::UpdateClient { + id, + header, + } => update_client(state, &id, &header), } } -impl ActionHandler for IBC { - fn name(&self) -> &'static str { - "IBC handler" - } - - fn handler_id(&self) -> u64 { - CUSTOM_ACTION_HANDLER_ID - } - - fn init(&self, state: &mut TopLevelState) -> StateResult<()> { - Ok(()) - } - - fn execute( - &self, - bytes: &[u8], - state: &mut TopLevelState, - fee_payer: &Address, - sender_public: &Public, - ) -> StateResult<()> { - let action = Action::decode(&Rlp::new(bytes)).expect("Verification passed"); - match action { - Action::CreateClient { - id, - kind, - consensus_state, - } => create_client(state, fee_payer, &id, kind, &consensus_state), - Action::UpdateClient { - id, - header, - } => update_client(state, &id, &header), - } - } - - 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()))?; - let client: Option> = self.client.read().as_ref().and_then(Weak::upgrade); - action.verify(current_params, client) - } - - fn on_close_block(&self, _state: &mut TopLevelState, _header: &Header) -> StateResult<()> { - Ok(()) - } -} fn create_client( state: &mut TopLevelState, - fee_payer: &Address, + _fee_payer: &Address, id: &str, kind: ibc_client::Kind, consensus_state: &[u8], diff --git a/core/src/miner/mem_pool_types.rs b/core/src/miner/mem_pool_types.rs index b16ede787c..435fb128d1 100644 --- a/core/src/miner/mem_pool_types.rs +++ b/core/src/miner/mem_pool_types.rs @@ -472,6 +472,12 @@ impl MemPoolMinFees { // FIXME 0 } + Action::IBC { + .. + } => { + // FIXME + 0 + } } } } diff --git a/core/src/miner/miner.rs b/core/src/miner/miner.rs index da684d09a5..2f7f2df0a3 100644 --- a/core/src/miner/miner.rs +++ b/core/src/miner/miner.rs @@ -30,7 +30,7 @@ use crate::scheme::Scheme; use crate::transaction::{PendingSignedTransactions, SignedTransaction, UnverifiedTransaction}; use crate::types::{BlockId, TransactionId}; use ckey::{public_to_address, Address, Password, PlatformAddress, Public}; -use cstate::{FindActionHandler, TopLevelState}; +use cstate::{FindActionHandler, IBCTransactionExecutor, TopLevelState}; use ctypes::errors::HistoryError; use ctypes::transaction::{Action, IncompleteTransaction}; use ctypes::{BlockHash, TxHash}; @@ -287,7 +287,14 @@ impl Miner { /// Prepares new block for sealing including top transactions from queue and seal it. fn prepare_and_seal_block< - C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo, + C: AccountData + + BlockChainTrait + + BlockProducer + + ChainTimeInfo + + EngineInfo + + FindActionHandler + + TermInfo + + IBCTransactionExecutor, >( &self, parent_block_id: BlockId, @@ -519,7 +526,8 @@ impl MinerService for Miner { + ImportBlock + ChainTimeInfo + FindActionHandler - + TermInfo, { + + TermInfo + + IBCTransactionExecutor, { ctrace!(MINER, "update_sealing: preparing a block"); let block = match self.prepare_and_seal_block(parent_block, chain) { @@ -557,7 +565,7 @@ impl MinerService for Miner { } } - fn import_external_transactions( + fn import_external_transactions( &self, client: &C, transactions: Vec, @@ -582,7 +590,7 @@ impl MinerService for Miner { results } - fn import_own_transaction( + fn import_own_transaction( &self, chain: &C, tx: SignedTransaction, @@ -627,7 +635,9 @@ impl MinerService for Miner { imported } - fn import_incomplete_transaction( + fn import_incomplete_transaction< + C: MiningBlockChainClient + AccountData + EngineInfo + TermInfo + IBCTransactionExecutor, + >( &self, client: &C, account_provider: &AccountProvider, @@ -687,7 +697,7 @@ impl MinerService for Miner { self.mem_pool.read().future_transactions() } - fn start_sealing(&self, client: &C) { + fn start_sealing(&self, client: &C) { cdebug!(MINER, "Start sealing"); self.sealing_enabled.store(true, Ordering::Relaxed); // ------------------------------------------------------------------ diff --git a/core/src/miner/mod.rs b/core/src/miner/mod.rs index 24be1d0841..6cd0722dc1 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, Password, PlatformAddress, Public}; -use cstate::{FindActionHandler, TopStateView}; +use cstate::{FindActionHandler, IBCTransactionExecutor, TopStateView}; use ctypes::transaction::IncompleteTransaction; use ctypes::{BlockHash, TxHash}; use cvm::ChainTimeInfo; @@ -84,24 +84,27 @@ pub trait MinerService: Send + Sync { + ChainTimeInfo + EngineInfo + FindActionHandler + + IBCTransactionExecutor + TermInfo; /// Imports transactions to mem pool. - fn import_external_transactions( + fn import_external_transactions( &self, client: &C, transactions: Vec, ) -> Vec>; /// Imports own (node owner) transaction to mem pool. - fn import_own_transaction( + fn import_own_transaction( &self, chain: &C, tx: SignedTransaction, ) -> Result; /// Imports incomplete (node owner) transaction to mem pool. - fn import_incomplete_transaction( + fn import_incomplete_transaction< + C: MiningBlockChainClient + AccountData + EngineInfo + TermInfo + IBCTransactionExecutor, + >( &self, chain: &C, account_provider: &AccountProvider, @@ -121,7 +124,7 @@ pub trait MinerService: Send + Sync { fn future_transactions(&self) -> Vec; /// Start sealing. - fn start_sealing(&self, client: &C); + fn start_sealing(&self, client: &C); /// Stop sealing. fn stop_sealing(&self); diff --git a/rpc/src/v1/impls/account.rs b/rpc/src/v1/impls/account.rs index d67f905dde..dd4b65eb4c 100644 --- a/rpc/src/v1/impls/account.rs +++ b/rpc/src/v1/impls/account.rs @@ -19,6 +19,7 @@ use super::super::traits::Account; use super::super::types::{SendTransactionResult, UnsignedTransaction}; use ccore::{AccountData, AccountProvider, EngineInfo, MinerService, MiningBlockChainClient, TermInfo}; use ckey::{Password, PlatformAddress, Signature}; +use cstate::IBCTransactionExecutor; use ctypes::transaction::IncompleteTransaction; use jsonrpc_core::Result; use parking_lot::Mutex; @@ -48,7 +49,7 @@ where impl Account for AccountClient where - C: EngineInfo + MiningBlockChainClient + AccountData + TermInfo + 'static, + C: EngineInfo + MiningBlockChainClient + AccountData + TermInfo + IBCTransactionExecutor + 'static, M: MinerService + 'static, { fn get_account_list(&self) -> Result> { diff --git a/rpc/src/v1/impls/devel.rs b/rpc/src/v1/impls/devel.rs index c8ef52994d..6074dabe1f 100644 --- a/rpc/src/v1/impls/devel.rs +++ b/rpc/src/v1/impls/devel.rs @@ -24,6 +24,7 @@ use ccore::{ use cjson::bytes::Bytes; use ckey::{Address, KeyPair, Private}; use cnetwork::{unbounded_event_callback, EventSender, IntoSocketAddr}; +use cstate::IBCTransactionExecutor; use csync::BlockSyncEvent; use ctypes::transaction::{Action, Transaction}; use ctypes::BlockHash; @@ -63,7 +64,14 @@ where impl Devel for DevelClient where - C: DatabaseClient + EngineInfo + EngineClient + MiningBlockChainClient + TermInfo + SnapshotClient + 'static, + C: DatabaseClient + + EngineInfo + + EngineClient + + MiningBlockChainClient + + TermInfo + + SnapshotClient + + IBCTransactionExecutor + + 'static, M: MinerService + 'static, { fn get_state_trie_keys(&self, offset: usize, limit: usize) -> Result> { diff --git a/rpc/src/v1/types/action.rs b/rpc/src/v1/types/action.rs index 5817f99779..c8eef171fa 100644 --- a/rpc/src/v1/types/action.rs +++ b/rpc/src/v1/types/action.rs @@ -55,6 +55,9 @@ pub enum Action { shard_id: ShardId, content: String, }, + IBC { + bytes: Bytes, + }, } #[derive(Debug, Serialize)] @@ -91,6 +94,9 @@ pub enum ActionWithTracker { content: String, tracker: Tracker, }, + IBC { + bytes: Bytes, + }, } impl ActionWithTracker { @@ -148,6 +154,11 @@ impl ActionWithTracker { content, tracker: tracker.unwrap(), }, + ActionType::IBC { + bytes, + } => ActionWithTracker::IBC { + bytes, + }, } } } @@ -212,6 +223,11 @@ impl TryFrom for ActionType { shard_id, content, }, + Action::IBC { + bytes, + } => ActionType::IBC { + bytes, + }, }) } } diff --git a/state/src/cache/global_cache.rs b/state/src/cache/global_cache.rs index dcf96b664f..477b5f5045 100644 --- a/state/src/cache/global_cache.rs +++ b/state/src/cache/global_cache.rs @@ -16,7 +16,7 @@ use super::lru_cache::LruCache; use super::{ShardCache, TopCache}; -use crate::{Account, ActionData, Metadata, RegularAccount, Shard, ShardText}; +use crate::{Account, ActionData, IBCData, Metadata, RegularAccount, Shard, ShardText}; use ctypes::ShardId; use std::collections::{HashMap, HashSet}; @@ -26,18 +26,27 @@ pub struct GlobalCache { metadata: LruCache, shard: LruCache, action_data: LruCache, + ibc_data: LruCache, shard_text: LruCache, } impl GlobalCache { - pub fn new(account: usize, regular_account: usize, shard: usize, action_data: usize, shard_text: usize) -> Self { + pub fn new( + account: usize, + regular_account: usize, + shard: usize, + action_data: usize, + ibc_data: usize, + shard_text: usize, + ) -> Self { Self { account: LruCache::new(account), regular_account: LruCache::new(regular_account), metadata: LruCache::new(1), shard: LruCache::new(shard), action_data: LruCache::new(action_data), + ibc_data: LruCache::new(ibc_data), shard_text: LruCache::new(shard_text), } @@ -50,6 +59,7 @@ impl GlobalCache { self.metadata.iter().map(|(addr, item)| (*addr, item.clone())), self.shard.iter().map(|(addr, item)| (*addr, item.clone())), self.action_data.iter().map(|(addr, item)| (*addr, item.clone())), + self.ibc_data.iter().map(|(addr, item)| (*addr, item.clone())), ) } @@ -103,6 +113,12 @@ impl GlobalCache { None => self.action_data.remove(&addr), }; } + for (addr, item) in top_cache.cached_ibc_data().into_iter() { + match item { + Some(item) => self.ibc_data.insert(addr, item), + None => self.ibc_data.remove(&addr), + }; + } let mut cached_shard_texts: Vec<_> = shard_caches.iter().flat_map(|(_, shard_cache)| shard_cache.cached_shard_text().into_iter()).collect(); @@ -121,6 +137,7 @@ impl GlobalCache { self.metadata.clear(); self.shard.clear(); self.action_data.clear(); + self.ibc_data.clear(); self.shard_text.clear(); } } @@ -132,8 +149,9 @@ impl Default for GlobalCache { const N_REGULAR_ACCOUNT: usize = 100; const N_SHARD: usize = 100; const N_ACTION_DATA: usize = 10; + const N_IBC_DATA: usize = 100; const N_SHARD_TEXT: usize = 1000; - Self::new(N_ACCOUNT, N_REGULAR_ACCOUNT, N_SHARD, N_ACTION_DATA, N_SHARD_TEXT) + Self::new(N_ACCOUNT, N_REGULAR_ACCOUNT, N_SHARD, N_ACTION_DATA, N_IBC_DATA, N_SHARD_TEXT) } } @@ -145,6 +163,7 @@ impl Clone for GlobalCache { metadata: self.metadata.clone(), shard: self.shard.clone(), action_data: self.action_data.clone(), + ibc_data: self.ibc_data.clone(), shard_text: self.shard_text.clone(), } diff --git a/state/src/cache/top_cache.rs b/state/src/cache/top_cache.rs index f731cc32c0..0b0640d877 100644 --- a/state/src/cache/top_cache.rs +++ b/state/src/cache/top_cache.rs @@ -16,7 +16,7 @@ use super::WriteBack; use crate::{ - Account, ActionData, Metadata, MetadataAddress, RegularAccount, RegularAccountAddress, Shard, ShardAddress, + Account, ActionData, IBCData, Metadata, MetadataAddress, RegularAccount, RegularAccountAddress, Shard, ShardAddress, }; use ckey::Address; use merkle_trie::{Result as TrieResult, Trie, TrieMut}; @@ -29,6 +29,7 @@ pub struct TopCache { metadata: WriteBack, shard: WriteBack, action_data: WriteBack, + ibc_data: WriteBack, } impl TopCache { @@ -38,6 +39,7 @@ impl TopCache { metadata: impl Iterator, shards: impl Iterator, action_data: impl Iterator, + ibc_data: impl Iterator, ) -> Self { Self { account: WriteBack::new_with_iter(accounts), @@ -45,6 +47,7 @@ impl TopCache { metadata: WriteBack::new_with_iter(metadata), shard: WriteBack::new_with_iter(shards), action_data: WriteBack::new_with_iter(action_data), + ibc_data: WriteBack::new_with_iter(ibc_data), } } @@ -54,6 +57,7 @@ impl TopCache { self.metadata.checkpoint(); self.shard.checkpoint(); self.action_data.checkpoint(); + self.ibc_data.checkpoint(); } pub fn discard_checkpoint(&mut self) { @@ -62,6 +66,7 @@ impl TopCache { self.metadata.discard_checkpoint(); self.shard.discard_checkpoint(); self.action_data.discard_checkpoint(); + self.ibc_data.discard_checkpoint(); } pub fn revert_to_checkpoint(&mut self) { @@ -70,6 +75,7 @@ impl TopCache { self.metadata.revert_to_checkpoint(); self.shard.revert_to_checkpoint(); self.action_data.revert_to_checkpoint(); + self.ibc_data.revert_to_checkpoint(); } pub fn commit<'db>(&mut self, trie: &mut (dyn TrieMut + 'db)) -> TrieResult<()> { @@ -78,6 +84,7 @@ impl TopCache { self.metadata.commit(trie)?; self.shard.commit(trie)?; self.action_data.commit(trie)?; + self.ibc_data.commit(trie)?; Ok(()) } @@ -142,6 +149,18 @@ impl TopCache { self.action_data.remove(address) } + pub fn ibc_data(&self, a: &H256, db: &dyn Trie) -> TrieResult> { + self.ibc_data.get(a, db) + } + + pub fn ibc_data_mut(&self, a: &H256, db: &dyn Trie) -> TrieResult> { + self.ibc_data.get_mut(a, db) + } + + pub fn remove_ibc_data(&self, address: &H256) { + self.ibc_data.remove(address) + } + pub fn cached_accounts(&self) -> Vec<(Address, Option)> { let mut items = self.account.items(); items.sort_unstable_by(|lhs, rhs| lhs.0.cmp(&rhs.0)); @@ -171,6 +190,12 @@ impl TopCache { items.sort_unstable_by(|lhs, rhs| lhs.0.cmp(&rhs.0)); items.into_iter().map(|(_, addr, item)| (addr, item)).collect() } + + pub fn cached_ibc_data(&self) -> Vec<(H256, Option)> { + let mut items = self.ibc_data.items(); + items.sort_unstable_by(|lhs, rhs| lhs.0.cmp(&rhs.0)); + items.into_iter().map(|(_, addr, item)| (addr, item)).collect() + } } impl Clone for TopCache { @@ -181,6 +206,7 @@ impl Clone for TopCache { metadata: self.metadata.clone(), shard: self.shard.clone(), action_data: self.action_data.clone(), + ibc_data: self.ibc_data.clone(), } } } diff --git a/state/src/ibc.rs b/state/src/ibc.rs new file mode 100644 index 0000000000..a9f14bac58 --- /dev/null +++ b/state/src/ibc.rs @@ -0,0 +1,30 @@ +// Copyright 2020 Kodebox, Inc. +// This file is part of CodeChain. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use crate::{StateResult, TopLevelState}; +use ckey::{Address, Public}; + +pub trait IBCTransactionExecutor { + fn execute( + &self, + _bytes: &[u8], + _state: &mut TopLevelState, + _fee_payer: &Address, + _sender_pubkey: &Public, + ) -> StateResult<()> { + Ok(()) + } +} diff --git a/state/src/impls/top_level.rs b/state/src/impls/top_level.rs index b9710260a3..740960df5c 100644 --- a/state/src/impls/top_level.rs +++ b/state/src/impls/top_level.rs @@ -37,10 +37,11 @@ use crate::cache::{ShardCache, TopCache}; use crate::checkpoint::{CheckpointId, StateWithCheckpoint}; +use crate::error::Error; use crate::traits::{ShardState, ShardStateView, StateWithCache, TopState, TopStateView}; use crate::{ - Account, ActionData, FindActionHandler, Metadata, MetadataAddress, RegularAccount, RegularAccountAddress, Shard, - ShardAddress, ShardLevelState, StateDB, StateResult, + Account, ActionData, FindActionHandler, IBCData, IBCTransactionExecutor, Metadata, MetadataAddress, RegularAccount, + RegularAccountAddress, Shard, ShardAddress, ShardLevelState, StateDB, StateResult, }; use ccrypto::BLAKE_NULL_RLP; use cdb::{AsHashDB, DatabaseError}; @@ -136,6 +137,12 @@ impl TopStateView for TopLevelState { let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; Ok(self.top_cache.action_data(key, &trie)?.map(Into::into)) } + + fn ibc_data(&self, key: &H256) -> Result, TrieError> { + let db = self.db.borrow(); + let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; + Ok(self.top_cache.ibc_data(key, &trie)?.map(Into::into)) + } } impl StateWithCache for TopLevelState { @@ -238,7 +245,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, @@ -269,7 +276,7 @@ impl TopLevelState { result } - fn apply_internal( + fn apply_internal( &mut self, tx: &Transaction, signed_hash: &TxHash, @@ -334,7 +341,7 @@ impl TopLevelState { } #[allow(clippy::too_many_arguments)] - fn apply_action( + fn apply_action( &mut self, action: &Action, network_id: NetworkId, @@ -398,6 +405,12 @@ impl TopLevelState { handler.execute(bytes, self, fee_payer, signer_public)?; return Ok(()) } + Action::IBC { + bytes, + } => { + IBCTransactionExecutor::execute(client, bytes, self, fee_payer, signer_public)?; + return Ok(()) + } }; self.apply_shard_transaction( &transaction, @@ -513,6 +526,12 @@ impl TopLevelState { self.top_cache.action_data_mut(key, &trie) } + fn get_ibc_data_mut(&self, key: &H256) -> TrieResult> { + let db = self.db.borrow(); + let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; + self.top_cache.ibc_data_mut(key, &trie) + } + pub fn journal_under(&self, batch: &mut DBTransaction, now: u64) -> Result { self.db.borrow_mut().journal_under(batch, now, self.root) } @@ -723,6 +742,16 @@ impl TopState for TopLevelState { self.top_cache.remove_action_data(key) } + fn update_ibc_data(&mut self, key: &H256, data: Vec) -> Result<(), Error> { + let mut ibc_data = self.get_ibc_data_mut(key)?; + *ibc_data = data.into(); + Ok(()) + } + + fn remove_ibc_data(&mut self, key: &H256) { + self.top_cache.remove_ibc_data(key) + } + fn update_params(&mut self, metadata_seq: u64, params: CommonParams) -> StateResult<()> { let mut metadata = self.get_metadata_mut()?; if metadata.seq() != metadata_seq { diff --git a/state/src/item/ibc_data.rs b/state/src/item/ibc_data.rs new file mode 100644 index 0000000000..85294b74b1 --- /dev/null +++ b/state/src/item/ibc_data.rs @@ -0,0 +1,68 @@ +// Copyright 2020 Kodebox, Inc. +// This file is part of CodeChain. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use crate::CacheableItem; +use primitives::{Bytes, H256}; +use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream, NULL_RLP}; +use std::ops::Deref; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct IBCData(Bytes); + +impl Default for IBCData { + fn default() -> Self { + IBCData(NULL_RLP.to_vec()) + } +} + +impl Deref for IBCData { + type Target = Bytes; + + fn deref(&self) -> &::Target { + &self.0 + } +} + +impl CacheableItem for IBCData { + type Address = H256; + fn is_null(&self) -> bool { + self.is_empty() + } +} + +impl Encodable for IBCData { + fn rlp_append(&self, s: &mut RlpStream) { + self.0.rlp_append(s); + } +} + +impl Decodable for IBCData { + fn decode(rlp: &Rlp<'_>) -> Result { + Bytes::decode(rlp).map(IBCData) + } +} + +impl From for IBCData { + fn from(f: Vec) -> Self { + IBCData(f) + } +} + +impl From for Bytes { + fn from(f: IBCData) -> Self { + f.0 + } +} diff --git a/state/src/item/mod.rs b/state/src/item/mod.rs index 3a852029b2..f5f6cd68b6 100644 --- a/state/src/item/mod.rs +++ b/state/src/item/mod.rs @@ -20,6 +20,7 @@ mod address; pub mod account; pub mod action_data; pub mod dummy_shard_text; +pub mod ibc_data; pub mod metadata; pub mod regular_account; pub mod shard; diff --git a/state/src/lib.rs b/state/src/lib.rs index 243c16730a..ada98ba07a 100644 --- a/state/src/lib.rs +++ b/state/src/lib.rs @@ -33,6 +33,7 @@ mod cache; mod checkpoint; mod db; mod error; +mod ibc; mod impls; mod item; mod traits; @@ -43,10 +44,12 @@ pub use crate::action_handler::{ActionDataKeyBuilder, ActionHandler, FindActionH pub use crate::checkpoint::{CheckpointId, StateWithCheckpoint}; pub use crate::db::StateDB; pub use crate::error::Error as StateError; +pub use crate::ibc::IBCTransactionExecutor; pub use crate::impls::{ShardLevelState, TopLevelState}; pub use crate::item::account::Account; pub use crate::item::action_data::ActionData; pub use crate::item::dummy_shard_text::{ShardText, ShardTextAddress}; +pub use crate::item::ibc_data::IBCData; pub use crate::item::metadata::{Metadata, MetadataAddress}; pub use crate::item::regular_account::{RegularAccount, RegularAccountAddress}; pub use crate::item::shard::{Shard, ShardAddress}; diff --git a/state/src/tests.rs b/state/src/tests.rs index 7df020d29d..7421b8aeea 100644 --- a/state/src/tests.rs +++ b/state/src/tests.rs @@ -27,7 +27,7 @@ pub mod helpers { use rlp::Encodable; use crate::impls::TopLevelState; - use crate::{FindActionHandler, Metadata, MetadataAddress, StateDB}; + use crate::{FindActionHandler, IBCTransactionExecutor, Metadata, MetadataAddress, StateDB}; pub struct TestClient {} @@ -43,6 +43,8 @@ pub mod helpers { impl FindActionHandler for TestClient {} + impl IBCTransactionExecutor for TestClient {} + pub fn get_memory_db() -> Arc { Arc::new(kvdb_memorydb::create(1)) } diff --git a/state/src/traits.rs b/state/src/traits.rs index 1d13ed227f..a1735244be 100644 --- a/state/src/traits.rs +++ b/state/src/traits.rs @@ -14,7 +14,9 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::{Account, ActionData, CacheableItem, Metadata, RegularAccount, Shard, ShardText, StateDB, StateResult}; +use crate::{ + Account, ActionData, CacheableItem, IBCData, Metadata, RegularAccount, Shard, ShardText, StateDB, StateResult, +}; use ckey::{public_to_address, Address, Public}; use ctypes::transaction::ShardTransaction; use ctypes::{BlockNumber, CommonParams, ShardId, Tracker, TxHash}; @@ -110,6 +112,8 @@ pub trait TopStateView { Some(state) => state.text(tracker), } } + + fn ibc_data(&self, key: &H256) -> TrieResult>; } pub trait ShardStateView { @@ -161,6 +165,9 @@ pub trait TopState { fn update_action_data(&mut self, key: &H256, data: Bytes) -> StateResult<()>; fn remove_action_data(&mut self, key: &H256); + fn update_ibc_data(&mut self, key: &H256, data: Bytes) -> StateResult<()>; + fn remove_ibc_data(&mut self, key: &H256); + fn update_params(&mut self, metadata_seq: u64, params: CommonParams) -> StateResult<()>; fn update_term_params(&mut self) -> StateResult<()>; } diff --git a/types/src/transaction/action.rs b/types/src/transaction/action.rs index cc6af5cb09..112c872a46 100644 --- a/types/src/transaction/action.rs +++ b/types/src/transaction/action.rs @@ -31,6 +31,7 @@ enum ActionTag { SetShardOwners = 0x05, SetShardUsers = 0x06, ShardStore = 0x19, + IBC = 0x20, Custom = 0xFF, } @@ -86,6 +87,9 @@ pub enum Action { shard_id: ShardId, content: String, }, + IBC { + bytes: Bytes, + }, } impl Action { @@ -231,6 +235,13 @@ impl Encodable for Action { s.append(shard_id); s.append(content); } + Action::IBC { + bytes, + } => { + s.begin_list(2); + s.append(&ActionTag::IBC); + s.append(bytes); + } } } } @@ -328,6 +339,18 @@ impl Decodable for Action { content: rlp.val_at(3)?, }) } + ActionTag::IBC => { + let item_count = rlp.item_count()?; + if item_count != 2 { + return Err(DecoderError::RlpIncorrectListLen { + got: item_count, + expected: 2, + }) + } + Ok(Action::IBC { + bytes: rlp.val_at(1)?, + }) + } } } }