From 91e789b5ff88f670d921356f56acd0240df92c45 Mon Sep 17 00:00:00 2001 From: Park Juhyung Date: Thu, 19 Dec 2019 18:15:53 +0900 Subject: [PATCH 1/6] Remove unused external crates from RPC crate --- Cargo.lock | 3 --- rpc/Cargo.toml | 3 --- rpc/src/lib.rs | 3 --- 3 files changed, 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af7a7d9c13..fab914eb38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -471,14 +471,12 @@ dependencies = [ "codechain-state", "codechain-sync", "codechain-types", - "codechain-vm", "jsonrpc-core", "jsonrpc-derive", "jsonrpc-http-server", "jsonrpc-ipc-server", "jsonrpc-ws-server", "kvdb", - "kvdb-rocksdb", "lazy_static 1.2.0", "log 0.4.6", "parking_lot 0.6.4", @@ -491,7 +489,6 @@ dependencies = [ "serde_derive", "serde_json", "time", - "tokio-core", ] [[package]] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index aea4fc5467..896e622d4c 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -18,9 +18,7 @@ codechain-network = { path = "../network" } codechain-state = { path = "../state" } codechain-sync = { path = "../sync" } codechain-types = { path = "../types" } -codechain-vm = { path = "../vm" } kvdb = "0.1" -kvdb-rocksdb = "0.1" lazy_static = "1.2" log = "0.4.6" parking_lot = "0.6.0" @@ -33,7 +31,6 @@ rand = "0.6.1" rustc-hex = "1.0" rustc-serialize = "0.3" time = "0.1" -tokio-core = "0.1.17" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", tag = "v14.0.3" } jsonrpc-derive = { git = "https://github.com/paritytech/jsonrpc.git", tag = "v14.0.3" } jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", tag = "v14.0.3" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index a0d8d4771e..3ff5d06628 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -25,13 +25,11 @@ extern crate codechain_network as cnetwork; extern crate codechain_state as cstate; extern crate codechain_sync as csync; extern crate codechain_types as ctypes; -extern crate codechain_vm as cvm; pub extern crate jsonrpc_core; extern crate jsonrpc_http_server; extern crate jsonrpc_ipc_server; extern crate jsonrpc_ws_server; extern crate kvdb; -extern crate kvdb_rocksdb as rocksdb; #[macro_use] extern crate lazy_static; #[macro_use] @@ -48,7 +46,6 @@ extern crate serde_derive; extern crate cidr; extern crate serde_json; extern crate time; -extern crate tokio_core; #[macro_use] extern crate jsonrpc_derive; From 7186f3c1970b9155c1c5422f608d323ea4855aec Mon Sep 17 00:00:00 2001 From: Park Juhyung Date: Fri, 20 Dec 2019 14:59:44 +0900 Subject: [PATCH 2/6] Remove asset related RPCs --- Cargo.lock | 1 - rpc/Cargo.toml | 1 - rpc/src/lib.rs | 1 - rpc/src/v1/errors.rs | 9 -- rpc/src/v1/impls/chain.rs | 124 ++----------------- rpc/src/v1/impls/devel.rs | 200 ++----------------------------- rpc/src/v1/traits/chain.rs | 68 +---------- rpc/src/v1/types/asset.rs | 26 ---- rpc/src/v1/types/asset_scheme.rs | 21 +--- rpc/src/v1/types/mod.rs | 31 ----- 10 files changed, 24 insertions(+), 458 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fab914eb38..11bfba567d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -462,7 +462,6 @@ version = "0.1.0" dependencies = [ "cidr", "codechain-core", - "codechain-crypto", "codechain-json", "codechain-key", "codechain-keystore", diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 896e622d4c..c5c0b717ea 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -9,7 +9,6 @@ edition = "2018" [dependencies] cidr = "0.0.4" codechain-core = { path = "../core" } -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } codechain-json = { path = "../json" } codechain-key = { path = "../key" } codechain-keystore = { path = "../keystore" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 3ff5d06628..321007d1be 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -15,7 +15,6 @@ // along with this program. If not, see . extern crate codechain_core as ccore; -extern crate codechain_crypto as ccrypto; #[macro_use] extern crate codechain_logger as clogger; extern crate codechain_json as cjson; diff --git a/rpc/src/v1/errors.rs b/rpc/src/v1/errors.rs index 2dc961786b..c979967187 100644 --- a/rpc/src/v1/errors.rs +++ b/rpc/src/v1/errors.rs @@ -69,7 +69,6 @@ mod codes { pub const NO_SUCH_ACCOUNT: i64 = -32044; pub const NOT_UNLOCKED: i64 = -32045; pub const TRANSFER_ONLY_IN_EXECUTE_VM: i64 = -32046; - pub const ASSET_TRANSACTION_ONLY_IN_EXECUTE_TRANSACITON: i64 = -32047; pub const STATE_NOT_EXIST: i64 = -32048; pub const ACTION_DATA_HANDLER_NOT_FOUND: i64 = -32049; pub const UNKNOWN_ERROR: i64 = -32099; @@ -270,14 +269,6 @@ pub fn transfer_only() -> Error { } } -pub fn asset_transaction_only() -> Error { - Error { - code: ErrorCode::ServerError(codes::ASSET_TRANSACTION_ONLY_IN_EXECUTE_TRANSACITON), - message: "chain_executeTransaction() only accepts asset transactions.".into(), - data: None, - } -} - pub fn state_not_exist() -> Error { Error { code: ErrorCode::ServerError(codes::STATE_NOT_EXIST), diff --git a/rpc/src/v1/impls/chain.rs b/rpc/src/v1/impls/chain.rs index 576e571d00..79a6862c41 100644 --- a/rpc/src/v1/impls/chain.rs +++ b/rpc/src/v1/impls/chain.rs @@ -14,36 +14,33 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::convert::{TryFrom, TryInto}; +use std::convert::TryInto; use std::sync::Arc; -use ccore::{ - AccountData, AssetClient, BlockId, EngineInfo, ExecuteClient, MiningBlockChainClient, Shard, TermInfo, TextClient, -}; -use ccrypto::Blake; +use ccore::{AccountData, BlockId, EngineInfo, ExecuteClient, MiningBlockChainClient, TermInfo, TextClient}; use cjson::scheme::Params; use cjson::uint::Uint; use ckey::{public_to_address, NetworkId, PlatformAddress, Public}; use cstate::FindActionHandler; use ctypes::transaction::{Action, ShardTransaction as ShardTransactionType}; -use ctypes::{BlockHash, BlockNumber, ShardId, Tracker, TxHash}; -use primitives::{Bytes as BytesArray, H160, H256}; +use ctypes::{BlockHash, BlockNumber, Tracker, TxHash}; +use primitives::Bytes as BytesArray; use jsonrpc_core::Result; use super::super::errors; use super::super::traits::Chain; -use super::super::types::{AssetScheme, Block, BlockNumberAndHash, OwnedAsset, Text, Transaction, UnsignedTransaction}; +use super::super::types::{Block, BlockNumberAndHash, Text, Transaction, UnsignedTransaction}; pub struct ChainClient where - C: AssetClient + MiningBlockChainClient + Shard + ExecuteClient + EngineInfo, { + C: MiningBlockChainClient + ExecuteClient + EngineInfo, { client: Arc, } impl ChainClient where - C: AssetClient + MiningBlockChainClient + Shard + AccountData + ExecuteClient + EngineInfo + TextClient, + C: MiningBlockChainClient + AccountData + ExecuteClient + EngineInfo + TextClient, { pub fn new(client: Arc) -> Self { ChainClient { @@ -54,9 +51,7 @@ where impl Chain for ChainClient where - C: AssetClient - + MiningBlockChainClient - + Shard + C: MiningBlockChainClient + AccountData + ExecuteClient + EngineInfo @@ -90,39 +85,6 @@ where Ok(self.client.transaction_by_tracker(&tracker).map(From::from)) } - fn get_asset_scheme_by_tracker( - &self, - tracker: Tracker, - shard_id: ShardId, - block_number: Option, - ) -> Result> { - let asset_type = Blake::blake(*tracker); - self.get_asset_scheme_by_type(asset_type, shard_id, block_number) - } - - fn get_asset_scheme_by_type( - &self, - asset_type: H160, - shard_id: ShardId, - block_number: Option, - ) -> Result> { - if block_number == Some(0) { - return Ok(None) - } - let parent_block_id = block_number.map(|n| (n - 1).into()).unwrap_or(BlockId::ParentOfLatest); - if let Some(common_params) = self.client.common_params(parent_block_id) { - let network_id = common_params.network_id(); - let block_id = block_number.map(BlockId::from).unwrap_or(BlockId::Latest); - Ok(self - .client - .get_asset_scheme(asset_type, shard_id, block_id) - .map_err(errors::transaction_state)? - .map(|asset_scheme| AssetScheme::from_core(asset_scheme, network_id))) - } else { - Ok(None) - } - } - fn get_text(&self, transaction_hash: TxHash, block_number: Option) -> Result> { if block_number == Some(0) { return Ok(None) @@ -134,29 +96,6 @@ where })) } - fn get_asset( - &self, - tracker: Tracker, - index: usize, - shard_id: ShardId, - block_number: Option, - ) -> Result> { - let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); - let asset = self.client.get_asset(tracker, index, shard_id, block_id).map_err(errors::transaction_state)?; - Ok(asset.map(From::from)) - } - - fn is_asset_spent( - &self, - tracker: Tracker, - index: usize, - shard_id: ShardId, - block_number: Option, - ) -> Result> { - let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); - self.client.is_asset_spent(tracker, index, shard_id, block_id).map_err(errors::transaction_state) - } - fn get_seq(&self, address: PlatformAddress, block_number: Option) -> Result> { let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); let address = address.try_address().map_err(errors::core)?; @@ -188,39 +127,6 @@ where Ok(self.client.genesis_accounts()) } - fn get_number_of_shards(&self, block_number: Option) -> Result> { - let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); - Ok(self.client.number_of_shards(block_id.into())) - } - - fn get_shard_id_by_hash(&self, create_shard_tx_hash: TxHash, block_number: Option) -> Result> { - let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); - Ok(self.client.shard_id_by_hash(&create_shard_tx_hash, block_id.into())) - } - - fn get_shard_root(&self, shard_id: ShardId, block_number: Option) -> Result> { - let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); - Ok(self.client.shard_root(shard_id, block_id.into())) - } - - fn get_shard_owners(&self, shard_id: ShardId, block_number: Option) -> Result>> { - let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); - Ok(self.client.shard_owners(shard_id, block_id.into()).map(|owners| { - let parent_block_id = block_number.map(|n| (n - 1).into()).unwrap_or(BlockId::ParentOfLatest); - let network_id = self.client.common_params(parent_block_id).unwrap().network_id(); - owners.into_iter().map(|owner| PlatformAddress::new_v1(network_id, owner)).collect() - })) - } - - fn get_shard_users(&self, shard_id: ShardId, block_number: Option) -> Result>> { - let block_id = block_number.map(BlockId::Number).unwrap_or(BlockId::Latest); - Ok(self.client.shard_users(shard_id, block_id.into()).map(|users| { - let parent_block_id = block_number.map(|n| (n - 1).into()).unwrap_or(BlockId::ParentOfLatest); - let network_id = self.client.common_params(parent_block_id).unwrap().network_id(); - users.into_iter().map(|user| PlatformAddress::new_v1(network_id, user)).collect() - })) - } - fn get_best_block_number(&self) -> Result { Ok(self.client.chain_info().best_block_number) } @@ -331,20 +237,6 @@ where Ok(self.client.possible_authors(block_number).map_err(errors::core)?) } - fn execute_transaction(&self, tx: UnsignedTransaction, sender: PlatformAddress) -> Result> { - let sender_address = sender.try_address().map_err(errors::core)?; - let action = Action::try_from(tx.action).map_err(errors::conversion)?; - if let Some(transaction) = action.asset_transaction() { - let result = self.client.execute_transaction(&transaction, sender_address); - match result { - Ok(()) => Ok(None), - Err(err) => Ok(Some(err.to_string())), - } - } else { - Err(errors::asset_transaction_only()) - } - } - fn execute_vm( &self, tx: UnsignedTransaction, diff --git a/rpc/src/v1/impls/devel.rs b/rpc/src/v1/impls/devel.rs index 588b4f8f83..86a7832a58 100644 --- a/rpc/src/v1/impls/devel.rs +++ b/rpc/src/v1/impls/devel.rs @@ -18,33 +18,27 @@ use std::net::SocketAddr; use std::ops::Deref; use std::sync::Arc; use std::thread; -use std::time::{Duration, Instant}; +use std::time::Duration; use std::vec::Vec; use ccore::{ BlockId, DatabaseClient, EngineClient, EngineInfo, MinerService, MiningBlockChainClient, SignedTransaction, TermInfo, COL_STATE, }; -use ccrypto::Blake; use cjson::bytes::Bytes; use ckey::{Address, KeyPair, Private}; use cnetwork::{unbounded_event_callback, EventSender, IntoSocketAddr}; use csync::BlockSyncEvent; -use ctypes::transaction::{ - Action, AssetMintOutput, AssetOutPoint, AssetTransferInput, AssetTransferOutput, Transaction, -}; -use ctypes::{Tracker, TxHash}; +use ctypes::transaction::{Action, Transaction}; use jsonrpc_core::Result; use kvdb::KeyValueDB; -use primitives::{H160, H256}; -use rand::rngs::SmallRng; -use rand::{Rng, SeedableRng}; +use primitives::H256; use rlp::Rlp; use time::PreciseTime; use super::super::errors; use super::super::traits::Devel; -use super::super::types::{TPSTestOption, TPSTestSetting}; +use super::super::types::TPSTestSetting; pub struct DevelClient { client: Arc, @@ -110,8 +104,6 @@ where fn test_tps(&self, setting: TPSTestSetting) -> Result { let common_params = self.client.common_params(BlockId::Latest).unwrap(); - let mint_fee = common_params.min_asset_mint_cost(); - let transfer_fee = common_params.min_asset_transfer_cost(); let pay_fee = common_params.min_pay_transaction_cost(); let network_id = common_params.network_id(); @@ -120,7 +112,6 @@ where let genesis_keypair = KeyPair::from_private(genesis_secret).map_err(errors::transaction_core)?; let base_seq = self.client.seq(&genesis_keypair.address(), BlockId::Latest).unwrap(); - let lock_script_hash_empty_sig = H160::from("b042ad154a3359d276835c903587ebafefea22af"); // Helper macros macro_rules! pay_tx { @@ -140,96 +131,11 @@ where }; } - macro_rules! mint_tx { - ($seq:expr, $supply:expr) => { - Transaction { - seq: $seq, - fee: mint_fee, - network_id, - action: Action::MintAsset { - network_id, - shard_id: 0, - metadata: format!("{:?}", Instant::now()), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - output: Box::new(AssetMintOutput { - lock_script_hash: lock_script_hash_empty_sig, - parameters: vec![], - supply: $supply, - }), - approvals: vec![], - }, - } - }; - } - - macro_rules! transfer_tx { - ($seq:expr, $inputs:expr, $outputs:expr) => { - Transaction { - seq: $seq, - fee: transfer_fee, - network_id, - action: Action::TransferAsset { - network_id, - burns: vec![], - inputs: $inputs, - outputs: $outputs, - metadata: "".to_string(), - approvals: vec![], - expiration: None, - }, - } - }; - } - - macro_rules! transfer_input { - ($tracker:expr, $index:expr, $asset_type:expr, $quantity:expr) => { - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: $tracker, - index: $index, - asset_type: $asset_type, - shard_id: 0, - quantity: $quantity, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - } - }; - } - - macro_rules! transfer_output { - ($asset_type:expr, $quantity:expr) => { - AssetTransferOutput { - lock_script_hash: lock_script_hash_empty_sig, - parameters: vec![], - asset_type: $asset_type, - shard_id: 0, - quantity: $quantity, - } - }; - } - // Helper functions fn sign_tx(tx: Transaction, key_pair: &KeyPair) -> SignedTransaction { SignedTransaction::new_with_sign(tx, key_pair.private()) } - fn send_tx(tx: Transaction, client: &C, key_pair: &KeyPair) -> Result - where - C: MiningBlockChainClient + EngineInfo + TermInfo, { - let signed = SignedTransaction::new_with_sign(tx, key_pair.private()); - let hash = signed.hash(); - client.queue_own_transaction(signed).map_err(errors::transaction_core)?; - Ok(hash) - } - - fn asset_type(tx: &Transaction) -> H160 { - Blake::blake(*tx.tracker().unwrap()) - } - fn tps(count: u64, start_time: PreciseTime, end_time: PreciseTime) -> f64 { f64::from(count as u32) * 1000.0_f64 / f64::from(start_time.to(end_time).num_milliseconds() as i32) } @@ -239,98 +145,14 @@ where if count == 0 { return Ok(0.0) } - let mut rng = SmallRng::seed_from_u64(setting.seed); - let transactions = match setting.option { - TPSTestOption::PayOnly => { - let mut transactions = Vec::with_capacity(count as usize); - for i in 0..count { - let address = Address::random(); - let tx = sign_tx(pay_tx!(base_seq + i, address), &genesis_keypair); - transactions.push(tx); - } - transactions - } - TPSTestOption::TransferSingle => { - let mint_tx = mint_tx!(base_seq, 1); - let asset_type = asset_type(&mint_tx); - let mut previous_tracker = mint_tx.tracker().unwrap(); - send_tx(mint_tx, &*self.client, &genesis_keypair)?; - - let mut transactions = Vec::with_capacity(count as usize); - for i in 0..count { - let transfer_tx = transfer_tx!( - base_seq + i + 1, - vec![transfer_input!(previous_tracker, 0, asset_type, 1)], - vec![transfer_output!(asset_type, 1)] - ); - previous_tracker = transfer_tx.tracker().unwrap(); - let tx = sign_tx(transfer_tx, &genesis_keypair); - transactions.push(tx); - } - transactions - } - TPSTestOption::TransferMultiple => { - let number_of_in_out: usize = 10; - let mint_tx = mint_tx!(base_seq, number_of_in_out as u64); - let asset_type = asset_type(&mint_tx); - let mut previous_tracker = mint_tx.tracker().unwrap(); - send_tx(mint_tx, &*self.client, &genesis_keypair)?; - - fn create_inputs( - tracker: Tracker, - asset_type: H160, - total_amount: u64, - count: usize, - ) -> Vec { - let mut inputs = Vec::new(); - let amount = total_amount / (count as u64); - for i in 0..(count as usize) { - let input = transfer_input!(tracker, i, asset_type, amount); - inputs.push(input); - } - inputs - } - - let mut transactions = Vec::with_capacity(count as usize); - for i in 0..count { - let num_input = 1 + 9 * (i > 0) as usize; - let inputs = create_inputs(previous_tracker, asset_type, number_of_in_out as u64, num_input); - let outputs = vec![transfer_output!(asset_type, 1); number_of_in_out]; - - let transfer_tx = transfer_tx!(base_seq + i + 1, inputs, outputs); - previous_tracker = transfer_tx.tracker().unwrap(); - transactions.push(sign_tx(transfer_tx, &genesis_keypair)); - } - transactions - } - TPSTestOption::PayOrTransfer => { - let mint_tx = mint_tx!(base_seq, 1); - let asset_type = asset_type(&mint_tx); - let mut previous_tracker = mint_tx.tracker().unwrap(); - send_tx(mint_tx, &*self.client, &genesis_keypair)?; - - let mut transactions = Vec::with_capacity(count as usize); - for i in 0..count { - // 0. Payment - let tx = if rng.gen::() { - let address = Address::random(); - pay_tx!(base_seq + i + 1, address) - } - // 1. Transfer - else { - let transfer_tx = transfer_tx!( - base_seq + i + 1, - vec![transfer_input!(previous_tracker, 0, asset_type, 1)], - vec![transfer_output!(asset_type, 1)] - ); - previous_tracker = transfer_tx.tracker().unwrap(); - transfer_tx - }; - let tx = sign_tx(tx, &genesis_keypair); - transactions.push(tx); - } - transactions + let transactions = { + let mut transactions = Vec::with_capacity(count as usize); + for i in 0..count { + let address = Address::random(); + let tx = sign_tx(pay_tx!(base_seq + i, address), &genesis_keypair); + transactions.push(tx); } + transactions }; let last_hash = transactions.last().unwrap().hash(); diff --git a/rpc/src/v1/traits/chain.rs b/rpc/src/v1/traits/chain.rs index d9dc27b3d8..1aac70608d 100644 --- a/rpc/src/v1/traits/chain.rs +++ b/rpc/src/v1/traits/chain.rs @@ -17,12 +17,12 @@ use cjson::scheme::Params; use cjson::uint::Uint; use ckey::{NetworkId, PlatformAddress, Public}; -use ctypes::{BlockHash, BlockNumber, ShardId, Tracker, TxHash}; -use primitives::{Bytes as BytesArray, H160, H256}; +use ctypes::{BlockHash, BlockNumber, Tracker, TxHash}; +use primitives::Bytes as BytesArray; use jsonrpc_core::Result; -use super::super::types::{AssetScheme, Block, BlockNumberAndHash, OwnedAsset, Text, Transaction, UnsignedTransaction}; +use super::super::types::{Block, BlockNumberAndHash, Text, Transaction, UnsignedTransaction}; #[rpc(server)] pub trait Chain { @@ -45,48 +45,10 @@ pub trait Chain { #[rpc(name = "chain_getTransactionByTracker")] fn get_transaction_by_tracker(&self, tracker: Tracker) -> Result>; - /// Gets asset scheme with given transaction tracker. - #[rpc(name = "chain_getAssetSchemeByTracker")] - fn get_asset_scheme_by_tracker( - &self, - tracker: Tracker, - shard_id: ShardId, - block_number: Option, - ) -> Result>; - - /// Gets asset scheme with given asset type. - #[rpc(name = "chain_getAssetSchemeByType")] - fn get_asset_scheme_by_type( - &self, - asset_type: H160, - shard_id: ShardId, - block_number: Option, - ) -> Result>; - /// Gets text with given transaction hash. #[rpc(name = "chain_getText")] fn get_text(&self, transaction_hash: TxHash, block_number: Option) -> Result>; - /// Gets asset with given asset type. - #[rpc(name = "chain_getAsset")] - fn get_asset( - &self, - tracker: Tracker, - index: usize, - shard_id: ShardId, - block_number: Option, - ) -> Result>; - - /// Checks whether an asset is spent or not. - #[rpc(name = "chain_isAssetSpent")] - fn is_asset_spent( - &self, - tracker: Tracker, - index: usize, - shard_id: ShardId, - block_number: Option, - ) -> Result>; - /// Gets seq with given account. #[rpc(name = "chain_getSeq")] fn get_seq(&self, address: PlatformAddress, block_number: Option) -> Result>; @@ -107,26 +69,6 @@ pub trait Chain { #[rpc(name = "chain_getGenesisAccounts")] fn get_genesis_accounts(&self) -> Result>; - /// Gets the number of shards - #[rpc(name = "chain_getNumberOfShards")] - fn get_number_of_shards(&self, block_number: Option) -> Result>; - - /// Gets shard id - #[rpc(name = "chain_getShardIdByHash")] - fn get_shard_id_by_hash(&self, create_shard_tx_hash: TxHash, block_number: Option) -> Result>; - - /// Gets shard root - #[rpc(name = "chain_getShardRoot")] - fn get_shard_root(&self, shard_id: ShardId, block_number: Option) -> Result>; - - /// Gets shard owners - #[rpc(name = "chain_getShardOwners")] - fn get_shard_owners(&self, shard_id: ShardId, block_number: Option) -> Result>>; - - /// Gets shard users - #[rpc(name = "chain_getShardUsers")] - fn get_shard_users(&self, shard_id: ShardId, block_number: Option) -> Result>>; - /// Gets number of best block. #[rpc(name = "chain_getBestBlockNumber")] fn get_best_block_number(&self) -> Result; @@ -179,10 +121,6 @@ pub trait Chain { #[rpc(name = "chain_getPossibleAuthors")] fn get_possible_authors(&self, block_number: Option) -> Result>>; - /// Execute Transactions - #[rpc(name = "chain_executeTransaction")] - fn execute_transaction(&self, tx: UnsignedTransaction, sender: PlatformAddress) -> Result>; - /// Execute AssetTransfer transaction inputs in VM #[rpc(name = "chain_executeVM")] fn execute_vm( diff --git a/rpc/src/v1/types/asset.rs b/rpc/src/v1/types/asset.rs index bba19e06e9..63e2244480 100644 --- a/rpc/src/v1/types/asset.rs +++ b/rpc/src/v1/types/asset.rs @@ -14,12 +14,8 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::ops::Deref; - use cjson::uint::Uint; -use cstate::{Asset as AssetType, OwnedAsset as OwnedAssetType}; use primitives::H160; -use rustc_serialize::hex::ToHex; #[derive(Clone, Debug, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] @@ -36,25 +32,3 @@ pub struct OwnedAsset { lock_script_hash: H160, parameters: Vec, } - -impl From for Asset { - fn from(asset: AssetType) -> Self { - Self { - asset_type: *asset.asset_type(), - quantity: asset.quantity().into(), - } - } -} - -impl From for OwnedAsset { - fn from(asset: OwnedAssetType) -> Self { - Self { - asset: Asset { - asset_type: *asset.asset_type(), - quantity: asset.quantity().into(), - }, - lock_script_hash: *asset.lock_script_hash(), - parameters: asset.parameters().iter().map(Deref::deref).map(<[u8]>::to_hex).collect(), - } - } -} diff --git a/rpc/src/v1/types/asset_scheme.rs b/rpc/src/v1/types/asset_scheme.rs index aa4d23b3d4..9a9e6fa74a 100644 --- a/rpc/src/v1/types/asset_scheme.rs +++ b/rpc/src/v1/types/asset_scheme.rs @@ -15,8 +15,8 @@ // along with this program. If not, see . use cjson::uint::Uint; -use ckey::{NetworkId, PlatformAddress}; -use cstate::AssetScheme as AssetSchemeType; +use ckey::PlatformAddress; + use primitives::H160; use super::Asset; @@ -32,20 +32,3 @@ pub struct AssetScheme { pool: Vec, seq: u64, } - -impl AssetScheme { - pub fn from_core(asset_scheme: AssetSchemeType, network_id: NetworkId) -> Self { - Self { - metadata: asset_scheme.metadata().clone(), - supply: asset_scheme.supply().into(), - approver: asset_scheme.approver().as_ref().map(|approver| PlatformAddress::new_v1(network_id, *approver)), - registrar: asset_scheme - .registrar() - .as_ref() - .map(|registrar| PlatformAddress::new_v1(network_id, *registrar)), - allowed_script_hashes: asset_scheme.allowed_script_hashes().to_owned(), - pool: asset_scheme.pool().iter().map(|asset| asset.clone().into()).collect(), - seq: asset_scheme.seq() as u64, - } - } -} diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 66d9b30ba5..412c049f4f 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -40,7 +40,6 @@ pub use self::unsigned_transaction::UnsignedTransaction; pub use self::work::Work; use ctypes::TxHash; -use serde::de::{self, Deserialize, Deserializer}; #[derive(Debug, Serialize, Deserialize)] pub struct FilterStatus { @@ -54,39 +53,9 @@ pub struct SendTransactionResult { pub seq: u64, } -#[derive(Debug)] -pub enum TPSTestOption { - PayOnly, - TransferSingle, - TransferMultiple, - PayOrTransfer, -} - -impl<'de> Deserialize<'de> for TPSTestOption { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, { - let s = String::deserialize(deserializer)?; - Ok(match s.as_str() { - "payOnly" => TPSTestOption::PayOnly, - "transferSingle" => TPSTestOption::TransferSingle, - "transferMultiple" => TPSTestOption::TransferMultiple, - "payOrTransfer" => TPSTestOption::PayOrTransfer, - v => { - return Err(de::Error::custom(format!( - "Invalid params: unknown variant `{}`, expected one of \ - `payOnly`, `transferSingle`, `transferMultiple`, `payOrTransfer`.", - v - ))) - } - }) - } -} - #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TPSTestSetting { pub count: u64, pub seed: u64, - pub option: TPSTestOption, } From f74dc53424820595633f61e7680ddf359a4e9077 Mon Sep 17 00:00:00 2001 From: Park Juhyung Date: Thu, 19 Dec 2019 19:33:30 +0900 Subject: [PATCH 3/6] Remove unused parking_lot from the state module --- Cargo.lock | 1 - state/Cargo.toml | 1 - state/src/lib.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 11bfba567d..c0d7ca8f4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -505,7 +505,6 @@ dependencies = [ "kvdb-memorydb", "log 0.4.6", "lru-cache", - "parking_lot 0.6.4", "primitives", "rlp", "rlp_derive", diff --git a/state/Cargo.toml b/state/Cargo.toml index b98bcae969..4b5abc1b49 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -16,7 +16,6 @@ kvdb = "0.1" kvdb-memorydb = "0.1" log = "0.4.6" lru-cache = "0.1.1" -parking_lot = "0.6.0" primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } rlp_derive = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.2" } diff --git a/state/src/lib.rs b/state/src/lib.rs index ba63d993ee..e940524ec5 100644 --- a/state/src/lib.rs +++ b/state/src/lib.rs @@ -27,7 +27,6 @@ extern crate kvdb_memorydb; extern crate lru_cache; #[macro_use] extern crate log; -extern crate parking_lot; extern crate primitives; extern crate rlp; #[cfg(test)] From 91ee3a7d556405488aa4fd99c0f3daaa1aafb1e5 Mon Sep 17 00:00:00 2001 From: Park Juhyung Date: Fri, 20 Dec 2019 15:36:55 +0900 Subject: [PATCH 4/6] Remove shard level transactions --- Cargo.lock | 1 - core/res/beagle.json | 18 - core/res/blake_pow.json | 7 - core/res/corgi.json | 7 - core/res/cuckoo.json | 7 - core/res/husky.json | 7 - core/res/mainnet.json | 18 - core/res/null.json | 7 - core/res/saluki.json | 7 - core/res/simple_poa.json | 7 - core/res/solo.json | 7 - core/res/tendermint.json | 7 - core/src/client/client.rs | 119 +- core/src/client/mod.rs | 41 +- core/src/lib.rs | 6 +- core/src/scheme/scheme.rs | 47 +- state/Cargo.toml | 1 - state/src/cache/global_cache.rs | 89 +- state/src/cache/mod.rs | 2 - state/src/cache/shard_cache.rs | 112 -- state/src/cache/top_cache.rs | 31 +- state/src/cache/write_back.rs | 10 - state/src/db/state_db.rs | 10 +- state/src/impls/mod.rs | 2 - state/src/impls/shard_level.rs | 1793 -------------------------- state/src/impls/test_helper.rs | 564 --------- state/src/impls/top_level.rs | 2081 +------------------------------ state/src/item/address.rs | 23 +- state/src/item/asset.rs | 259 ---- state/src/item/asset_scheme.rs | 271 ---- state/src/item/metadata.rs | 86 +- state/src/item/mod.rs | 6 - state/src/item/shard.rs | 163 --- state/src/lib.rs | 8 +- state/src/tests.rs | 16 +- state/src/traits.rs | 78 +- 36 files changed, 88 insertions(+), 5830 deletions(-) delete mode 100644 state/src/cache/shard_cache.rs delete mode 100644 state/src/impls/shard_level.rs delete mode 100644 state/src/item/asset.rs delete mode 100644 state/src/item/asset_scheme.rs delete mode 100644 state/src/item/shard.rs diff --git a/Cargo.lock b/Cargo.lock index c0d7ca8f4d..67df2ceaeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -500,7 +500,6 @@ dependencies = [ "codechain-logger", "codechain-merkle", "codechain-types", - "codechain-vm", "kvdb", "kvdb-memorydb", "log 0.4.6", diff --git a/core/res/beagle.json b/core/res/beagle.json index 4e1419ff8c..8606e57ead 100644 --- a/core/res/beagle.json +++ b/core/res/beagle.json @@ -108,23 +108,5 @@ "bccqyczcz3lgeun43tujs5fkygfg4phvuk2gcs2sny0": { "balance": "10000000000" } - }, - "shards": { - "0": { - "seq": 0, - "owners": [ - "bccqypclxxrlr8f9n75dt6ayasvkdkxx6k3qgedauzj", - "bccqy204w0m6stuahxlx3p58kc0hsgd42npqcrx8lce", - "bccqxkppqfqwwl6vwge62qq22eh3xkmzqwvschr8thm", - "bccq8mjrws63vw27na5t6nxjf5yvjhpac5nyga4psjx", - "bccq9apfpuhwe5m62ejpfyxtmad2536xj9sfqpdt76p", - "bccq8yrcc4tlwlfrtmuaewv9u9fv9xjfj9czsfeyra7", - "bccqy9tavttkl87gscjmkpmc56evz3m42ugxclxwp2h", - "bccq8ah0efv5ckpx6wy5mwva2aklzwsdw027s4t6vux", - "bccqyfrwupcdmj85gzam90yua50qz3mkgskgudmg7df", - "bccqyczcz3lgeun43tujs5fkygfg4phvuk2gcs2sny0" - ], - "users": [] - } } } diff --git a/core/res/blake_pow.json b/core/res/blake_pow.json index 10a111a3cb..690cbad4e9 100644 --- a/core/res/blake_pow.json +++ b/core/res/blake_pow.json @@ -55,12 +55,5 @@ "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqc2ul2h": { "balance": "1000000" }, "tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u": { "balance": "1000000" }, "tccq9h7vnl68frvqapzv3tujrxtxtwqdnxw6yamrrgd": { "balance": "10000000000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"], - "users": [] - } } } diff --git a/core/res/corgi.json b/core/res/corgi.json index e581a30593..3798b87b8b 100644 --- a/core/res/corgi.json +++ b/core/res/corgi.json @@ -94,12 +94,5 @@ }, "accounts": { "wccqx6n79wgvye8l8rx49xuqvm3vtwkffz28sff8axv": { "balance": "2100000000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["wccqx6n79wgvye8l8rx49xuqvm3vtwkffz28sff8axv"], - "users": [] - } } } diff --git a/core/res/cuckoo.json b/core/res/cuckoo.json index 585bcb55dd..51aee9cdff 100644 --- a/core/res/cuckoo.json +++ b/core/res/cuckoo.json @@ -58,12 +58,5 @@ "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqc2ul2h": { "balance": "1000000" }, "tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u": { "balance": "1000000" }, "tccq9h7vnl68frvqapzv3tujrxtxtwqdnxw6yamrrgd": { "balance": "10000000000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"], - "users": [] - } } } diff --git a/core/res/husky.json b/core/res/husky.json index 91dd4316d6..3b4e8a5c9a 100644 --- a/core/res/husky.json +++ b/core/res/husky.json @@ -50,12 +50,5 @@ }, "accounts": { "tccqynz79luhx4cfakvcqe29rwaajnkzz6aev5deztu": { "balance": "2100000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["tccqynz79luhx4cfakvcqe29rwaajnkzz6aev5deztu"], - "users": [] - } } } diff --git a/core/res/mainnet.json b/core/res/mainnet.json index d2fa853451..c5963db720 100644 --- a/core/res/mainnet.json +++ b/core/res/mainnet.json @@ -130,23 +130,5 @@ "cccq8dhpcfqt94mx8dntxxd6420782vtd4tpvpgcgjh": { "balance": "10000000000" } - }, - "shards": { - "0": { - "seq": 0, - "owners": [ - "cccq8u8se8k00vcqk4pl707qe9v60hs3jj27g4rqkm9", - "cccq9hpz4m5sx0ea42l2hfm8nja0xzzsnx0vv0p7mzw", - "cccqxgwashdy0fp5cwlvp4ntkzmy3xvjedfjgfzrxf7", - "cccq9g0ayvrvmzcs2qf8yygat0dg9073g5xccd3sydw", - "cccq8r9as2drgp4xwfzz7t0xc9k977y8mw7hus3zq8e", - "cccqx7ycl2awx6awqyjf9ns4532xj7eg63w6v6hlnu0", - "cccq826j0p6fvpk02p0n5th7ukqu5clrnyldcxgrgtz", - "cccqyhk4388mymckk40ctf0skgkl8nf89f6sgpzwzke", - "cccqxgupxd5j0squ7t8w3etxjf0fn2z4axz0spycqum", - "cccq8dhpcfqt94mx8dntxxd6420782vtd4tpvpgcgjh" - ], - "users": [] - } } } diff --git a/core/res/null.json b/core/res/null.json index 696767cfbb..acb22d30e4 100644 --- a/core/res/null.json +++ b/core/res/null.json @@ -51,12 +51,5 @@ "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqc2ul2h": { "balance": "1000000" }, "tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u": { "balance": "1000000" }, "tccq9h7vnl68frvqapzv3tujrxtxtwqdnxw6yamrrgd": { "balance": "10000000000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"], - "users": [] - } } } diff --git a/core/res/saluki.json b/core/res/saluki.json index 6e213b7955..ac3f1dd763 100644 --- a/core/res/saluki.json +++ b/core/res/saluki.json @@ -47,12 +47,5 @@ }, "accounts": { "sccqx74ftz8ct6yks4mq3u06g2wt07zxfqrss777pj2": { "balance": "2100000000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["sccqx74ftz8ct6yks4mq3u06g2wt07zxfqrss777pj2"], - "users": [] - } } } diff --git a/core/res/simple_poa.json b/core/res/simple_poa.json index 6c0853c169..aa659c3098 100644 --- a/core/res/simple_poa.json +++ b/core/res/simple_poa.json @@ -56,12 +56,5 @@ "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqc2ul2h": { "balance": "1000000" }, "tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u": { "balance": "1000000" }, "tccq9h7vnl68frvqapzv3tujrxtxtwqdnxw6yamrrgd": { "balance": "10000000000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"], - "users": [] - } } } diff --git a/core/res/solo.json b/core/res/solo.json index 43c8b27a90..99455183f8 100644 --- a/core/res/solo.json +++ b/core/res/solo.json @@ -58,12 +58,5 @@ "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqc2ul2h": { "balance": "1000000" }, "tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u": { "balance": "1000000" }, "tccq9h7vnl68frvqapzv3tujrxtxtwqdnxw6yamrrgd": { "balance": "10000000000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"], - "users": [] - } } } diff --git a/core/res/tendermint.json b/core/res/tendermint.json index 53f6e40948..cb539a4c67 100644 --- a/core/res/tendermint.json +++ b/core/res/tendermint.json @@ -74,12 +74,5 @@ "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqc2ul2h": { "balance": "1000000" }, "tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u": { "balance": "1000000" }, "tccq9h7vnl68frvqapzv3tujrxtxtwqdnxw6yamrrgd": { "balance": "10000000000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"], - "users": [] - } } } diff --git a/core/src/client/client.rs b/core/src/client/client.rs index 4dd3bff944..2e31912c62 100644 --- a/core/src/client/client.rs +++ b/core/src/client/client.rs @@ -23,23 +23,21 @@ use cio::IoChannel; use ckey::{Address, NetworkId, PlatformAddress, Public}; use cmerkle::Result as TrieResult; use cnetwork::NodeId; -use cstate::{ - ActionHandler, AssetScheme, FindActionHandler, OwnedAsset, StateDB, StateResult, Text, TopLevelState, TopStateView, -}; +use cstate::{ActionHandler, FindActionHandler, StateDB, Text, TopLevelState, TopStateView}; use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken}; -use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction}; -use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash}; +use ctypes::transaction::{AssetTransferInput, PartialHashing}; +use ctypes::{BlockHash, BlockNumber, CommonParams, Tracker, TxHash}; use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig}; use kvdb::{DBTransaction, KeyValueDB}; use parking_lot::{Mutex, RwLock, RwLockReadGuard}; -use primitives::{Bytes, H160, H256, U256}; +use primitives::{Bytes, U256}; use rlp::Rlp; use super::importer::Importer; use super::{ - AccountData, AssetClient, BlockChainClient, BlockChainInfo, BlockChainTrait, BlockProducer, ChainNotify, - ClientConfig, DatabaseClient, EngineClient, EngineInfo, Error as ClientError, ExecuteClient, ImportBlock, - ImportResult, MiningBlockChainClient, Shard, StateInfo, StateOrBlock, TextClient, + AccountData, BlockChainClient, BlockChainInfo, BlockChainTrait, BlockProducer, ChainNotify, ClientConfig, + DatabaseClient, EngineClient, EngineInfo, Error as ClientError, ExecuteClient, ImportBlock, ImportResult, + MiningBlockChainClient, StateInfo, StateOrBlock, TextClient, }; use crate::block::{ClosedBlock, IsBlock, OpenBlock, SealedBlock}; use crate::blockchain::{BlockChain, BlockProvider, BodyProvider, HeaderProvider, InvoiceProvider, TransactionAddress}; @@ -347,70 +345,6 @@ impl DatabaseClient for Client { } } -impl AssetClient for Client { - fn get_asset_scheme(&self, asset_type: H160, shard_id: ShardId, id: BlockId) -> TrieResult> { - if let Some(state) = Client::state_at(&self, id) { - Ok(state.asset_scheme(shard_id, asset_type)?) - } else { - Ok(None) - } - } - - fn get_asset( - &self, - tracker: Tracker, - index: usize, - shard_id: ShardId, - id: BlockId, - ) -> TrieResult> { - if let Some(state) = Client::state_at(&self, id) { - Ok(state.asset(shard_id, tracker, index)?) - } else { - Ok(None) - } - } - - /// Checks whether an asset is spent or not. - /// - /// It returns None if such an asset never existed in the shard at the given block. - fn is_asset_spent( - &self, - tracker: Tracker, - index: usize, - shard_id: ShardId, - block_id: BlockId, - ) -> TrieResult> { - let tx_address = match self.transaction_addresses(&tracker) { - Some(itx_address) => itx_address, - None => return Ok(None), - }; - - match self.block_number(&block_id) { - None => return Ok(None), - Some(block_number) - if block_number - < self.block_number(&tx_address.block_hash.into()).expect("There is a successful transaction") => - { - return Ok(None) - } - Some(_) => {} - } - - let localized = self.transaction_by_tracker(&tracker).expect("There is a successful transaction"); - let transaction = if let Some(tx) = Option::::from(localized.action.clone()) { - tx - } else { - return Ok(None) - }; - if !transaction.is_valid_shard_id_index(index, shard_id) { - return Ok(None) - } - - let state = Client::state_at(&self, block_id).unwrap(); - Ok(Some(state.asset(shard_id, tracker, index)?.is_none())) - } -} - impl TextClient for Client { fn get_text(&self, tx_hash: TxHash, id: BlockId) -> TrieResult> { if let Some(state) = Client::state_at(&self, id) { @@ -422,18 +356,6 @@ impl TextClient for Client { } impl ExecuteClient for Client { - fn execute_transaction(&self, transaction: &ShardTransaction, sender: &Address) -> StateResult<()> { - let mut state = Client::state_at(&self, BlockId::Latest).expect("Latest state MUST exist"); - state.apply_shard_transaction( - transaction, - sender, - &[], - self, - self.best_block_header().number(), - self.best_block_header().timestamp(), - ) - } - fn execute_vm( &self, tx: &dyn PartialHashing, @@ -844,33 +766,6 @@ impl AccountData for Client { } } -impl Shard for Client { - fn number_of_shards(&self, state: StateOrBlock) -> Option { - let state = self.state_info(state)?; - state.number_of_shards().ok() - } - - fn shard_id_by_hash(&self, create_shard_tx_hash: &TxHash, state: StateOrBlock) -> Option { - let state = self.state_info(state)?; - state.shard_id_by_hash(&create_shard_tx_hash).ok()? - } - - fn shard_root(&self, shard_id: ShardId, state: StateOrBlock) -> Option { - let state = self.state_info(state)?; - state.shard_root(shard_id).ok()? - } - - fn shard_owners(&self, shard_id: u16, state: StateOrBlock) -> Option> { - let state = self.state_info(state)?; - state.shard_owners(shard_id).ok()? - } - - fn shard_users(&self, shard_id: u16, state: StateOrBlock) -> Option> { - let state = self.state_info(state)?; - state.shard_users(shard_id).ok()? - } -} - impl BlockProducer for Client { fn reopen_block(&self, block: ClosedBlock) -> OpenBlock { let engine = &*self.engine; diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index edb8abc76f..49d713323a 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -35,12 +35,12 @@ use std::sync::Arc; use ckey::{Address, NetworkId, PlatformAddress, Public}; use cmerkle::Result as TrieResult; use cnetwork::NodeId; -use cstate::{AssetScheme, FindActionHandler, OwnedAsset, StateResult, Text, TopLevelState, TopStateView}; -use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction}; -use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash}; +use cstate::{FindActionHandler, Text, TopLevelState, TopStateView}; +use ctypes::transaction::{AssetTransferInput, PartialHashing}; +use ctypes::{BlockHash, BlockNumber, CommonParams, Tracker, TxHash}; use cvm::ChainTimeInfo; use kvdb::KeyValueDB; -use primitives::{Bytes, H160, H256, U256}; +use primitives::{Bytes, U256}; use crate::block::{ClosedBlock, OpenBlock, SealedBlock}; use crate::blockchain_info::BlockChainInfo; @@ -183,16 +183,6 @@ impl From for StateOrBlock { } } -pub trait Shard { - fn number_of_shards(&self, state: StateOrBlock) -> Option; - - fn shard_id_by_hash(&self, create_shard_tx_hash: &TxHash, state: StateOrBlock) -> Option; - fn shard_root(&self, shard_id: ShardId, state: StateOrBlock) -> Option; - - fn shard_owners(&self, shard_id: ShardId, state: StateOrBlock) -> Option>; - fn shard_users(&self, shard_id: ShardId, state: StateOrBlock) -> Option>; -} - /// Provides methods to import block into blockchain pub trait ImportBlock { /// Import a block into the blockchain. @@ -297,35 +287,12 @@ pub trait DatabaseClient { fn database(&self) -> Arc; } -/// Provides methods to access asset -pub trait AssetClient { - fn get_asset_scheme(&self, asset_type: H160, shard_id: ShardId, id: BlockId) -> TrieResult>; - - fn get_asset( - &self, - tracker: Tracker, - index: usize, - shard_id: ShardId, - id: BlockId, - ) -> TrieResult>; - - fn is_asset_spent( - &self, - tracker: Tracker, - index: usize, - shard_id: ShardId, - block_id: BlockId, - ) -> TrieResult>; -} - /// Provides methods to texts pub trait TextClient { fn get_text(&self, tx_hash: TxHash, id: BlockId) -> TrieResult>; } pub trait ExecuteClient: ChainTimeInfo { - fn execute_transaction(&self, transaction: &ShardTransaction, sender: &Address) -> StateResult<()>; - fn execute_vm( &self, tx: &dyn PartialHashing, diff --git a/core/src/lib.rs b/core/src/lib.rs index b316febdc6..185389b896 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -83,9 +83,9 @@ mod tests; pub use crate::account_provider::{AccountProvider, Error as AccountProviderError}; pub use crate::block::Block; pub use crate::client::{ - AccountData, AssetClient, BlockChainClient, BlockChainTrait, ChainNotify, Client, ClientConfig, DatabaseClient, - EngineClient, EngineInfo, ExecuteClient, ImportBlock, MiningBlockChainClient, Shard, StateInfo, TermInfo, - TestBlockChainClient, TextClient, + AccountData, BlockChainClient, BlockChainTrait, ChainNotify, Client, ClientConfig, DatabaseClient, EngineClient, + EngineInfo, ExecuteClient, ImportBlock, MiningBlockChainClient, StateInfo, TermInfo, TestBlockChainClient, + TextClient, }; pub use crate::consensus::{EngineType, TimeGapParams}; pub use crate::db::{COL_STATE, NUM_COLUMNS}; diff --git a/core/src/scheme/scheme.rs b/core/src/scheme/scheme.rs index 64c427131b..7c386c480b 100644 --- a/core/src/scheme/scheme.rs +++ b/core/src/scheme/scheme.rs @@ -22,16 +22,16 @@ use cdb::{AsHashDB, HashDB}; use cjson; use ckey::Address; use cmerkle::{TrieFactory, TrieMut}; -use cstate::{Metadata, MetadataAddress, Shard, ShardAddress, StateDB, StateResult, StateWithCache, TopLevelState}; +use cstate::{StateDB, StateResult, StateWithCache, TopLevelState}; use ctypes::errors::SyntaxError; -use ctypes::{BlockHash, CommonParams, Header, ShardId}; +use ctypes::{BlockHash, CommonParams, Header}; use parking_lot::RwLock; use primitives::{Bytes, H256, U256}; use rlp::{Encodable, Rlp, RlpStream}; use crate::blockchain::HeaderProvider; -use super::pod_state::{PodAccounts, PodShards}; +use super::pod_state::PodAccounts; use super::seal::Generic as GenericSeal; use super::Genesis; use crate::codechain_machine::CodeChainMachine; @@ -71,7 +71,6 @@ pub struct Scheme { /// Genesis state as plain old data. genesis_accounts: PodAccounts, - genesis_shards: PodShards, } // helper for formatting errors. @@ -113,7 +112,6 @@ impl Scheme { fn initialize_state(&self, db: StateDB) -> Result { let root = BLAKE_NULL_RLP; let (db, root) = self.initialize_accounts(db, root)?; - let (db, root) = self.initialize_shards(db, root)?; let (db, root) = self.initialize_action_handlers(db, root)?; *self.state_root_memo.write() = root; @@ -135,44 +133,6 @@ impl Scheme { Ok((db, root)) } - fn initialize_shards(&self, mut db: DB, mut root: H256) -> Result<(DB, H256), Error> { - let mut shards = Vec::<(ShardAddress, Shard)>::with_capacity(self.genesis_shards.len()); - - // Initialize shard-level tries - for (shard_id, shard) in &*self.genesis_shards { - let shard_root = BLAKE_NULL_RLP; - let owners = shard.owners.clone(); - if owners.is_empty() { - return Err(SyntaxError::EmptyShardOwners(*shard_id).into()) - } - let users = shard.users.clone(); - shards.push((ShardAddress::new(*shard_id), Shard::new(shard_root, owners, users))); - } - - debug_assert_eq!(::std::mem::size_of::(), ::std::mem::size_of::()); - debug_assert!(shards.len() <= ::std::u16::MAX as usize, "{} <= {}", shards.len(), ::std::u16::MAX as usize); - let global_metadata = Metadata::new(shards.len() as ShardId); - - // Initialize shards - for (address, shard) in shards.into_iter() { - let mut t = TrieFactory::from_existing(db.as_hashdb_mut(), &mut root)?; - let r = t.insert(&*address, &shard.rlp_bytes()); - debug_assert_eq!(Ok(None), r); - r?; - } - - { - let mut t = TrieFactory::from_existing(db.as_hashdb_mut(), &mut root)?; - let address = MetadataAddress::new(); - - let r = t.insert(&*address, &global_metadata.rlp_bytes()); - debug_assert_eq!(Ok(None), r); - r?; - } - - 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)?; @@ -343,7 +303,6 @@ fn load_from(s: cjson::scheme::Scheme) -> Result { seal_rlp, state_root_memo: RwLock::new(Default::default()), // will be overwritten right after. genesis_accounts: s.accounts.into(), - genesis_shards: s.shards.into(), }; // use memoized state root if provided. diff --git a/state/Cargo.toml b/state/Cargo.toml index 4b5abc1b49..2b2d32021a 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -11,7 +11,6 @@ codechain-logger = { path = "../util/logger" } codechain-merkle = { path = "../util/merkle" } codechain-key = { path = "../key" } codechain-types = { path = "../types" } -codechain-vm = { path = "../vm" } kvdb = "0.1" kvdb-memorydb = "0.1" log = "0.4.6" diff --git a/state/src/cache/global_cache.rs b/state/src/cache/global_cache.rs index 076d3935ca..e6522fa30c 100644 --- a/state/src/cache/global_cache.rs +++ b/state/src/cache/global_cache.rs @@ -14,46 +14,26 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::collections::{HashMap, HashSet}; - use super::lru_cache::LruCache; -use super::{ShardCache, TopCache}; -use crate::{Account, ActionData, AssetScheme, Metadata, OwnedAsset, RegularAccount, Shard, Text}; - -use ctypes::ShardId; +use super::TopCache; +use crate::{Account, ActionData, Metadata, RegularAccount, Text}; pub struct GlobalCache { account: LruCache, regular_account: LruCache, metadata: LruCache, - shard: LruCache, text: LruCache, action_data: LruCache, - - asset_scheme: LruCache, - asset: LruCache, } impl GlobalCache { - pub fn new( - account: usize, - regular_account: usize, - shard: usize, - text: usize, - action_data: usize, - asset_scheme: usize, - asset: usize, - ) -> Self { + pub fn new(account: usize, regular_account: usize, text: usize, action_data: usize) -> Self { Self { account: LruCache::new(account), regular_account: LruCache::new(regular_account), metadata: LruCache::new(1), - shard: LruCache::new(shard), text: LruCache::new(text), action_data: LruCache::new(action_data), - - asset_scheme: LruCache::new(asset_scheme), - asset: LruCache::new(asset), } } @@ -62,35 +42,12 @@ impl GlobalCache { self.account.iter().map(|(addr, item)| (*addr, item.clone())), self.regular_account.iter().map(|(addr, item)| (*addr, item.clone())), self.metadata.iter().map(|(addr, item)| (*addr, item.clone())), - self.shard.iter().map(|(addr, item)| (*addr, item.clone())), self.text.iter().map(|(addr, item)| (*addr, item.clone())), self.action_data.iter().map(|(addr, item)| (*addr, item.clone())), ) } - fn shard_cache(&self, shard_id: ShardId) -> ShardCache { - ShardCache::new( - self.asset_scheme - .iter() - .filter(|(addr, _)| addr.shard_id() == shard_id) - .map(|(addr, item)| (*addr, item.clone())), - self.asset.iter().filter(|(addr, _)| addr.shard_id() == shard_id).map(|(addr, item)| (*addr, item.clone())), - ) - } - - fn shard_ids(&self) -> HashSet { - self.asset_scheme - .iter() - .map(|(addr, _)| addr.shard_id()) - .chain(self.asset.iter().map(|(addr, _)| addr.shard_id())) - .collect() - } - - pub fn shard_caches(&self) -> HashMap { - self.shard_ids().into_iter().map(|shard_id| (shard_id, self.shard_cache(shard_id))).collect() - } - - pub fn override_cache(&mut self, top_cache: &TopCache, shard_caches: &HashMap) { + pub fn override_cache(&mut self, top_cache: &TopCache) { self.clear(); for (addr, item) in top_cache.cached_accounts().into_iter() { @@ -111,12 +68,6 @@ impl GlobalCache { None => self.metadata.remove(&addr), }; } - for (addr, item) in top_cache.cached_shards().into_iter() { - match item { - Some(item) => self.shard.insert(addr, item), - None => self.shard.remove(&addr), - }; - } for (addr, item) in top_cache.cached_texts().into_iter() { match item { Some(item) => self.text.insert(addr, item), @@ -129,37 +80,14 @@ impl GlobalCache { None => self.action_data.remove(&addr), }; } - - let mut cached_asset_schemes: Vec<_> = - shard_caches.iter().flat_map(|(_, shard_cache)| shard_cache.cached_asset_schemes().into_iter()).collect(); - cached_asset_schemes.sort_unstable_by(|lhs, rhs| lhs.0.cmp(&rhs.0)); - for (_, addr, item) in cached_asset_schemes.into_iter() { - match item { - Some(item) => self.asset_scheme.insert(addr, item), - None => self.asset_scheme.remove(&addr), - }; - } - - let mut cached_assets: Vec<_> = - shard_caches.iter().flat_map(|(_, shard_cache)| shard_cache.cached_assets().into_iter()).collect(); - cached_assets.sort_unstable_by(|lhs, rhs| lhs.0.cmp(&rhs.0)); - for (_, addr, item) in cached_assets.into_iter() { - match item { - Some(item) => self.asset.insert(addr, item), - None => self.asset.remove(&addr), - }; - } } pub fn clear(&mut self) { self.account.clear(); self.regular_account.clear(); self.metadata.clear(); - self.shard.clear(); self.text.clear(); self.action_data.clear(); - self.asset_scheme.clear(); - self.asset.clear(); } } @@ -168,12 +96,9 @@ impl Default for GlobalCache { // FIXME: Set the right number const N_ACCOUNT: usize = 100; const N_REGULAR_ACCOUNT: usize = 100; - const N_SHARD: usize = 100; const N_TEXT: usize = 100; const N_ACTION_DATA: usize = 10; - const N_ASSET_SCHEME: usize = 100; - const N_ASSET: usize = 1000; - Self::new(N_ACCOUNT, N_REGULAR_ACCOUNT, N_SHARD, N_TEXT, N_ACTION_DATA, N_ASSET_SCHEME, N_ASSET) + Self::new(N_ACCOUNT, N_REGULAR_ACCOUNT, N_TEXT, N_ACTION_DATA) } } @@ -183,12 +108,8 @@ impl Clone for GlobalCache { account: self.account.clone(), regular_account: self.regular_account.clone(), metadata: self.metadata.clone(), - shard: self.shard.clone(), text: self.text.clone(), action_data: self.action_data.clone(), - - asset_scheme: self.asset_scheme.clone(), - asset: self.asset.clone(), } } } diff --git a/state/src/cache/mod.rs b/state/src/cache/mod.rs index 453c11ab9b..5447df8bf9 100644 --- a/state/src/cache/mod.rs +++ b/state/src/cache/mod.rs @@ -21,12 +21,10 @@ use rlp::{Decodable, Encodable}; mod global_cache; mod lru_cache; -mod shard_cache; mod top_cache; mod write_back; pub use self::global_cache::GlobalCache; -pub use self::shard_cache::ShardCache; pub use self::top_cache::TopCache; pub use self::write_back::WriteBack; diff --git a/state/src/cache/shard_cache.rs b/state/src/cache/shard_cache.rs deleted file mode 100644 index ae76ef8b65..0000000000 --- a/state/src/cache/shard_cache.rs +++ /dev/null @@ -1,112 +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 . - -use std::cell::RefMut; - -use cmerkle::{Result as TrieResult, Trie, TrieMut}; - -use super::WriteBack; -use crate::{AssetScheme, AssetSchemeAddress, OwnedAsset, OwnedAssetAddress}; - -pub struct ShardCache { - asset_scheme: WriteBack, - asset: WriteBack, -} - -impl ShardCache { - pub fn new( - asset_schemes: impl Iterator, - assets: impl Iterator, - ) -> Self { - Self { - asset_scheme: WriteBack::new_with_iter(asset_schemes), - asset: WriteBack::new_with_iter(assets), - } - } - - pub fn checkpoint(&mut self) { - self.asset_scheme.checkpoint(); - self.asset.checkpoint(); - } - - pub fn discard_checkpoint(&mut self) { - self.asset_scheme.discard_checkpoint(); - self.asset.discard_checkpoint(); - } - - pub fn revert_to_checkpoint(&mut self) { - self.asset_scheme.revert_to_checkpoint(); - self.asset.revert_to_checkpoint(); - } - - pub fn commit(&mut self, trie: &mut dyn TrieMut) -> TrieResult<()> { - self.asset_scheme.commit(trie)?; - self.asset.commit(trie)?; - Ok(()) - } - - pub fn asset_scheme(&self, a: &AssetSchemeAddress, db: &dyn Trie) -> TrieResult> { - self.asset_scheme.get(a, db) - } - - pub fn asset_scheme_mut(&self, a: &AssetSchemeAddress, db: &dyn Trie) -> TrieResult> { - self.asset_scheme.get_mut(a, db) - } - - pub fn create_asset_scheme(&self, a: &AssetSchemeAddress, f: F) -> TrieResult - where - F: FnOnce() -> AssetScheme, { - self.asset_scheme.create(a, f) - } - - pub fn asset(&self, a: &OwnedAssetAddress, db: &dyn Trie) -> TrieResult> { - self.asset.get(a, db) - } - - pub fn create_asset(&self, a: &OwnedAssetAddress, f: F) -> TrieResult - where - F: FnOnce() -> OwnedAsset, { - self.asset.create(a, f) - } - - - pub fn remove_asset(&self, address: &OwnedAssetAddress) { - self.asset.remove(address) - } - - pub fn cached_assets(&self) -> Vec<(usize, OwnedAssetAddress, Option)> { - self.asset.items() - } - - pub fn cached_asset_schemes(&self) -> Vec<(usize, AssetSchemeAddress, Option)> { - self.asset_scheme.items() - } -} - -impl Clone for ShardCache { - fn clone(&self) -> Self { - Self { - asset_scheme: self.asset_scheme.clone(), - asset: self.asset.clone(), - } - } -} - -impl Default for ShardCache { - fn default() -> Self { - Self::new(::std::iter::empty(), ::std::iter::empty()) - } -} diff --git a/state/src/cache/top_cache.rs b/state/src/cache/top_cache.rs index 1b592f6d0c..693da72c30 100644 --- a/state/src/cache/top_cache.rs +++ b/state/src/cache/top_cache.rs @@ -21,15 +21,12 @@ use cmerkle::{Result as TrieResult, Trie, TrieMut}; use primitives::H256; use super::WriteBack; -use crate::{ - Account, ActionData, Metadata, MetadataAddress, RegularAccount, RegularAccountAddress, Shard, ShardAddress, Text, -}; +use crate::{Account, ActionData, Metadata, MetadataAddress, RegularAccount, RegularAccountAddress, Text}; pub struct TopCache { account: WriteBack, regular_account: WriteBack, metadata: WriteBack, - shard: WriteBack, text: WriteBack, action_data: WriteBack, } @@ -39,7 +36,6 @@ impl TopCache { accounts: impl Iterator, regular_accounts: impl Iterator, metadata: impl Iterator, - shards: impl Iterator, text: impl Iterator, action_data: impl Iterator, ) -> Self { @@ -47,7 +43,6 @@ impl TopCache { account: WriteBack::new_with_iter(accounts), regular_account: WriteBack::new_with_iter(regular_accounts), metadata: WriteBack::new_with_iter(metadata), - shard: WriteBack::new_with_iter(shards), text: WriteBack::new_with_iter(text), action_data: WriteBack::new_with_iter(action_data), } @@ -57,7 +52,6 @@ impl TopCache { self.account.checkpoint(); self.regular_account.checkpoint(); self.metadata.checkpoint(); - self.shard.checkpoint(); self.text.checkpoint(); self.action_data.checkpoint(); } @@ -66,7 +60,6 @@ impl TopCache { self.account.discard_checkpoint(); self.regular_account.discard_checkpoint(); self.metadata.discard_checkpoint(); - self.shard.discard_checkpoint(); self.text.discard_checkpoint(); self.action_data.discard_checkpoint(); } @@ -75,7 +68,6 @@ impl TopCache { self.account.revert_to_checkpoint(); self.regular_account.revert_to_checkpoint(); self.metadata.revert_to_checkpoint(); - self.shard.revert_to_checkpoint(); self.text.revert_to_checkpoint(); self.action_data.revert_to_checkpoint(); } @@ -84,7 +76,6 @@ impl TopCache { self.account.commit(trie)?; self.regular_account.commit(trie)?; self.metadata.commit(trie)?; - self.shard.commit(trie)?; self.text.commit(trie)?; self.action_data.commit(trie)?; Ok(()) @@ -122,19 +113,6 @@ impl TopCache { self.metadata.get_mut(a, db) } - pub fn shard(&self, a: &ShardAddress, db: &dyn Trie) -> TrieResult> { - self.shard.get(a, db) - } - - pub fn shard_mut(&self, a: &ShardAddress, db: &dyn Trie) -> TrieResult> { - self.shard.get_mut(a, db) - } - - #[allow(dead_code)] - pub fn remove_shard(&self, address: &ShardAddress) { - self.shard.remove(address) - } - pub fn text(&self, a: &H256, db: &dyn Trie) -> TrieResult> { self.text.get(a, db) } @@ -177,12 +155,6 @@ impl TopCache { items.into_iter().map(|(_, addr, item)| (addr, item)).collect() } - pub fn cached_shards(&self) -> Vec<(ShardAddress, Option)> { - let mut items = self.shard.items(); - items.sort_unstable_by(|lhs, rhs| lhs.0.cmp(&rhs.0)); - items.into_iter().map(|(_, addr, item)| (addr, item)).collect() - } - pub fn cached_texts(&self) -> Vec<(H256, Option)> { let mut items = self.text.items(); items.sort_unstable_by(|lhs, rhs| lhs.0.cmp(&rhs.0)); @@ -202,7 +174,6 @@ impl Clone for TopCache { account: self.account.clone(), regular_account: self.regular_account.clone(), metadata: self.metadata.clone(), - shard: self.shard.clone(), text: self.text.clone(), action_data: self.action_data.clone(), } diff --git a/state/src/cache/write_back.rs b/state/src/cache/write_back.rs index 07b3c0a213..e8ebfb22e6 100644 --- a/state/src/cache/write_back.rs +++ b/state/src/cache/write_back.rs @@ -234,16 +234,6 @@ where })) } - pub fn create Item>(&self, a: &Item::Address, f: F) -> cmerkle::Result { - if let Some(cached) = self.cache.borrow().get(a) { - assert!(cached.item.is_none()); - } - let item = f(); - self.insert(a, Entry::::new_dirty(Some(item.clone()))); - - Ok(item) - } - pub fn items(&self) -> Vec<(usize, Item::Address, Option)> { let cache = self.cache.borrow(); cache diff --git a/state/src/db/state_db.rs b/state/src/db/state_db.rs index aa77cb3677..f9c3c75f0b 100644 --- a/state/src/db/state_db.rs +++ b/state/src/db/state_db.rs @@ -30,17 +30,15 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::collections::HashMap; use std::sync::Arc; use cdb::{new_journaldb, Algorithm, AsHashDB, HashDB, JournalDB}; -use ctypes::ShardId; use kvdb::DBTransaction; use kvdb_memorydb; use primitives::H256; use util_error::UtilError; -use crate::cache::{GlobalCache, ShardCache, TopCache}; +use crate::cache::{GlobalCache, TopCache}; use crate::impls::TopLevelState; /// State database abstraction. @@ -99,12 +97,8 @@ impl StateDB { self.cache.top_cache() } - pub fn shard_caches(&self) -> HashMap { - self.cache.shard_caches() - } - pub fn override_state(&mut self, state: &TopLevelState) { - self.cache.override_cache(state.top_cache(), state.shard_caches()); + self.cache.override_cache(state.top_cache()); self.current_hash = Some(state.root()); } diff --git a/state/src/impls/mod.rs b/state/src/impls/mod.rs index 08100dfea8..c172164acb 100644 --- a/state/src/impls/mod.rs +++ b/state/src/impls/mod.rs @@ -17,8 +17,6 @@ #[cfg(test)] mod test_helper; // It must be placed above other modules -mod shard_level; mod top_level; -pub use self::shard_level::ShardLevelState; pub use self::top_level::TopLevelState; diff --git a/state/src/impls/shard_level.rs b/state/src/impls/shard_level.rs deleted file mode 100644 index f5f83ade78..0000000000 --- a/state/src/impls/shard_level.rs +++ /dev/null @@ -1,1793 +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 . - -use std::cell::{RefCell, RefMut}; -use std::collections::HashSet; -use std::iter::{once, FromIterator}; - -use ccrypto::{Blake, BLAKE_NULL_RLP}; -use cdb::AsHashDB; -use ckey::Address; -use cmerkle::{self, TrieError, TrieFactory}; -use ctypes::errors::{RuntimeError, UnlockFailureReason}; -use ctypes::transaction::{ - AssetMintOutput, AssetOutPoint, AssetTransferInput, AssetTransferOutput, AssetWrapCCCOutput, PartialHashing, - ShardTransaction, -}; -use ctypes::util::unexpected::Mismatch; -use ctypes::{BlockNumber, ShardId, Tracker}; -use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig}; -use primitives::{Bytes, H160, H256}; - -use crate::cache::ShardCache; -use crate::checkpoint::{CheckpointId, StateWithCheckpoint}; -use crate::traits::{ShardState, ShardStateView}; -use crate::{Asset, AssetScheme, AssetSchemeAddress, OwnedAsset, OwnedAssetAddress, StateDB, StateResult}; - - -pub struct ShardLevelState<'db> { - db: &'db mut RefCell, - root: H256, - cache: &'db mut ShardCache, - id_of_checkpoints: Vec, - shard_id: ShardId, -} - -impl<'db> ShardLevelState<'db> { - /// Creates new state with empty state root - pub fn try_new(shard_id: ShardId, db: &'db mut RefCell, cache: &'db mut ShardCache) -> StateResult { - let root = BLAKE_NULL_RLP; - Ok(Self { - db, - root, - cache, - id_of_checkpoints: Default::default(), - shard_id, - }) - } - - /// Creates new state with existing state root - pub fn from_existing( - shard_id: ShardId, - db: &'db mut RefCell, - root: H256, - cache: &'db mut ShardCache, - ) -> cmerkle::Result { - if !db.borrow().as_hashdb().contains(&root) { - return Err(TrieError::InvalidStateRoot(root)) - } - - Ok(Self { - db, - root, - cache, - id_of_checkpoints: Default::default(), - shard_id, - }) - } - - /// Creates immutable shard state - pub fn read_only( - shard_id: ShardId, - db: &RefCell, - root: H256, - cache: ShardCache, - ) -> cmerkle::Result { - if !db.borrow().as_hashdb().contains(&root) { - return Err(TrieError::InvalidStateRoot(root)) - } - - Ok(ReadOnlyShardLevelState { - db, - root, - cache, - shard_id, - }) - } - - fn apply_internal( - &mut self, - transaction: &ShardTransaction, - sender: &Address, - shard_users: &[Address], - approvers: &[Address], - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - ) -> StateResult<()> { - match transaction { - ShardTransaction::MintAsset { - metadata, - shard_id, - approver, - registrar, - allowed_script_hashes, - output, - .. - } => { - assert_eq!(*shard_id, self.shard_id); - self.mint_asset( - transaction.tracker(), - metadata, - output, - approver, - approvers, - registrar, - allowed_script_hashes, - sender, - shard_users, - Vec::new(), - )?; - Ok(()) - } - ShardTransaction::TransferAsset { - burns, - inputs, - outputs, - .. - } => { - debug_assert!(outputs.len() <= 512); - self.transfer_asset( - &transaction, - sender, - approvers, - burns, - inputs, - outputs, - client, - parent_block_number, - parent_block_timestamp, - ) - } - ShardTransaction::ChangeAssetScheme { - shard_id, - asset_type, - seq, - metadata, - approver, - registrar, - allowed_script_hashes, - .. - } => { - assert_eq!(*shard_id, self.shard_id); - self.change_asset_scheme( - sender, - approvers, - asset_type, - *seq, - metadata, - approver, - registrar, - allowed_script_hashes, - ) - } - ShardTransaction::IncreaseAssetSupply { - shard_id, - asset_type, - output, - seq, - .. - } => { - assert_eq!(*shard_id, self.shard_id); - self.increase_asset_supply(transaction.tracker(), *seq, sender, approvers, asset_type, output) - } - ShardTransaction::UnwrapCCC { - burn, - .. - } => { - assert_eq!(burn.prev_out.shard_id, self.shard_id); - self.unwrap_ccc(&transaction, sender, burn, client, parent_block_number, parent_block_timestamp) - } - ShardTransaction::WrapCCC { - tx_hash, - output: - AssetWrapCCCOutput { - lock_script_hash, - quantity, - parameters, - }, - shard_id, - .. - } => { - assert_eq!(*shard_id, self.shard_id); - self.wrap_ccc(tx_hash, lock_script_hash, ¶meters, *quantity) - } - } - } - - // FIXME: Remove this clippy config - #[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))] - fn mint_asset( - &mut self, - transaction_tracker: Tracker, - metadata: &str, - output: &AssetMintOutput, - approver: &Option
, - approvers: &[Address], - registrar: &Option
, - allowed_script_hashes: &[H160], - sender: &Address, - shard_users: &[Address], - pool: Vec, - ) -> StateResult<()> { - if !shard_users.is_empty() { - let sender_and_approvers: HashSet<&Address> = HashSet::from_iter(once(sender).chain(approvers.iter())); - let shard_users = HashSet::from_iter(shard_users.iter()); - if shard_users.is_disjoint(&sender_and_approvers) { - return Err(RuntimeError::InsufficientPermission.into()) - } - } - - let asset_type = Blake::blake(*transaction_tracker); - if self.asset_scheme(asset_type)?.is_some() { - return Err(RuntimeError::AssetSchemeDuplicated { - tracker: transaction_tracker, - shard_id: self.shard_id, - } - .into()) - } - let asset_scheme = self.create_asset_scheme( - self.shard_id, - asset_type, - metadata.to_string(), - output.supply, - *approver, - *registrar, - allowed_script_hashes.to_vec(), - pool, - )?; - - ctrace!(TX, "{:?} is minted on {}:{:?}", asset_scheme, self.shard_id, asset_type); - - self.create_asset( - transaction_tracker, - 0, - asset_type, - output.lock_script_hash, - output.parameters.clone(), - output.supply, - )?; - ctrace!(TX, "Created asset on {}:{}:{}", self.shard_id, transaction_tracker, 0); - Ok(()) - } - - // FIXME: Remove this clippy config - #[cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))] - fn transfer_asset( - &mut self, - transaction: &ShardTransaction, - sender: &Address, - approvers: &[Address], - burns: &[AssetTransferInput], - inputs: &[AssetTransferInput], - outputs: &[AssetTransferOutput], - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - ) -> StateResult<()> { - for (input, transaction, burn) in inputs - .iter() - .map(|input| (input, transaction, false)) - .chain(burns.iter().map(|input| (input, transaction, true))) - { - if input.prev_out.shard_id != self.shard_id { - continue - } - self.check_and_run_input_script( - input, - transaction, - burn, - sender, - approvers, - client, - parent_block_number, - parent_block_timestamp, - )?; - } - - let mut deleted_asset = Vec::with_capacity(inputs.len() + burns.len()); - for input in inputs.iter().chain(burns) { - if input.prev_out.shard_id != self.shard_id { - continue - } - self.kill_asset(input.prev_out.tracker, input.prev_out.index); - deleted_asset.push((input.prev_out.tracker, input.prev_out.index, input.prev_out.quantity)); - } - let transaction_tracker = transaction.tracker(); - for (index, output) in outputs.iter().enumerate() { - if output.shard_id != self.shard_id { - continue - } - self.check_output_script_hash(output, sender, approvers)?; - self.create_asset( - transaction_tracker, - index, - output.asset_type, - output.lock_script_hash, - output.parameters.clone(), - output.quantity, - )?; - } - let mut reduced_supplies = Vec::with_capacity(burns.len()); - for burn in burns { - let AssetOutPoint { - asset_type, - shard_id, - quantity, - .. - } = burn.prev_out; - if shard_id != self.shard_id { - continue - } - let mut asset_scheme = self.get_asset_scheme_mut(shard_id, asset_type)?; - let previous_supply = asset_scheme.reduce_supply(quantity); - reduced_supplies.push((asset_type, previous_supply, quantity)) - } - - ctrace!(TX, "Deleted assets on {} {:?}", self.shard_id, deleted_asset); - ctrace!(TX, "Created assets {}:{}:(0..{})", self.shard_id, transaction_tracker, outputs.len()); - ctrace!(TX, "Reduced asset supplies {:?}", reduced_supplies); - Ok(()) - } - - fn approved_by_registrar(&self, asset_type: H160, sender: &Address, approvers: &[Address]) -> StateResult { - let asset_scheme = self.asset_scheme(asset_type)?.ok_or_else(|| RuntimeError::AssetSchemeNotFound { - asset_type, - shard_id: self.shard_id, - })?; - - if let Some(registrar) = asset_scheme.registrar() { - Ok(registrar == sender || approvers.contains(registrar)) - } else { - Ok(false) - } - } - - fn change_asset_scheme( - &mut self, - sender: &Address, - approvers: &[Address], - asset_type: &H160, - seq: usize, - metadata: &str, - approver: &Option
, - registrar: &Option
, - allowed_script_hashes: &[H160], - ) -> StateResult<()> { - if !self.approved_by_registrar(*asset_type, sender, approvers)? { - return Err(RuntimeError::InsufficientPermission.into()) - } - - let mut asset_scheme = self.get_asset_scheme_mut(self.shard_id, *asset_type)?; - if asset_scheme.seq() != seq { - return Err(RuntimeError::InvalidSeqOfAssetScheme { - asset_type: *asset_type, - shard_id: self.shard_id, - expected: asset_scheme.seq(), - actual: seq, - } - .into()) - } - - asset_scheme.change_data( - metadata.to_string(), - approver.clone(), - registrar.clone(), - allowed_script_hashes.to_vec(), - ); - asset_scheme.increase_seq(); - - Ok(()) - } - - fn increase_asset_supply( - &mut self, - transaction_tracker: Tracker, - seq: usize, - sender: &Address, - approvers: &[Address], - asset_type: &H160, - output: &AssetMintOutput, - ) -> StateResult<()> { - if !self.approved_by_registrar(*asset_type, sender, approvers)? { - return Err(RuntimeError::InsufficientPermission.into()) - } - - // This assertion should be filtered while verifying action. - assert!(output.supply > 0, "Supply increasing quantity must be specified and greater than 0"); - - let mut asset_scheme = self.get_asset_scheme_mut(self.shard_id, *asset_type)?; - if seq != asset_scheme.seq() { - return Err(RuntimeError::InvalidSeqOfAssetScheme { - asset_type: *asset_type, - shard_id: self.shard_id, - expected: asset_scheme.seq(), - actual: seq, - } - .into()) - } - let previous_supply = asset_scheme.increase_supply(output.supply)?; - asset_scheme.increase_seq(); - self.create_asset( - transaction_tracker, - 0, - *asset_type, - output.lock_script_hash, - output.parameters.clone(), - output.supply, - )?; - ctrace!(TX, "Increased asset supply {:?} {:?} => {:?}", asset_type, previous_supply, output.supply); - ctrace!(TX, "Created asset on {}:{}", self.shard_id, transaction_tracker); - - Ok(()) - } - - fn check_input_asset( - &self, - input: &AssetTransferInput, - sender: &Address, - approvers: &[Address], - ) -> StateResult<(OwnedAsset, bool)> { - let AssetOutPoint { - index, - tracker, - asset_type, - shard_id, - quantity, - } = input.prev_out; - - assert_eq!(self.shard_id, shard_id); - let approved_by_regulator = self.approved_by_registrar(asset_type, sender, approvers)?; - if !approved_by_regulator { - let asset_scheme = self.asset_scheme(asset_type)?.ok_or_else(|| RuntimeError::AssetSchemeNotFound { - shard_id, - asset_type, - })?; - if let Some(approver) = asset_scheme.approver() { - if sender != approver && !approvers.contains(approver) { - return Err(RuntimeError::NotApproved(*approver).into()) - } - } - } - - let asset = self.asset(tracker, index)?.ok_or_else(|| RuntimeError::AssetNotFound { - shard_id, - tracker, - index, - })?; - if asset.quantity() != quantity { - return Err(RuntimeError::InvalidAssetQuantity { - shard_id, - tracker, - index, - expected: asset.quantity(), - got: quantity, - } - .into()) - } - if *asset.asset_type() != asset_type { - return Err(RuntimeError::UnexpectedAssetType { - index, - mismatch: Mismatch { - expected: *asset.asset_type(), - found: asset_type, - }, - } - .into()) - } - Ok((asset, approved_by_regulator)) - } - - fn check_output_script_hash( - &self, - output: &AssetTransferOutput, - sender: &Address, - approvers: &[Address], - ) -> StateResult<()> { - let asset_scheme = { - assert_eq!(self.shard_id, output.shard_id); - self.asset_scheme(output.asset_type)?.ok_or_else(|| RuntimeError::AssetSchemeNotFound { - asset_type: output.asset_type, - shard_id: self.shard_id, - })? - }; - if let Some(registrar) = asset_scheme.registrar().as_ref() { - if sender == registrar || approvers.contains(registrar) { - return Ok(()) - } - } - - let lock_script_hash = output.lock_script_hash; - if asset_scheme.is_allowed_script_hash(&lock_script_hash) { - Ok(()) - } else { - Err(RuntimeError::ScriptNotAllowed(lock_script_hash).into()) - } - } - - fn check_and_run_input_script( - &self, - input: &AssetTransferInput, - transaction: &dyn PartialHashing, - burn: bool, - sender: &Address, - approvers: &[Address], - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - ) -> StateResult<()> { - let (asset, from_regulator) = self.check_input_asset(input, sender, approvers)?; - if from_regulator { - return Ok(()) // Don't execute scripts when regulator sends the transaction. - } - - let to_hash: &dyn PartialHashing = transaction; - - if *asset.lock_script_hash() != Blake::blake(&input.lock_script) { - return Err(RuntimeError::ScriptHashMismatch(Mismatch { - expected: *asset.lock_script_hash(), - found: Blake::blake(&input.lock_script), - }) - .into()) - } - - let script_result = match (decode(&input.lock_script), decode(&input.unlock_script)) { - (Ok(lock_script), Ok(unlock_script)) => execute( - &unlock_script, - &asset.parameters(), - &lock_script, - to_hash, - VMConfig::default(), - input, - burn, - client, - parent_block_number, - parent_block_timestamp, - ), - // FIXME : Deliver full decode error - _ => return Err(RuntimeError::InvalidScript.into()), - }; - - match (script_result, burn) { - (Ok(ScriptResult::Burnt), true) => Ok(()), - (Ok(ScriptResult::Burnt), false) => Err(UnlockFailureReason::ScriptShouldBeBurnt), - (Ok(ScriptResult::Unlocked), false) => Ok(()), - (Ok(ScriptResult::Unlocked), true) => Err(UnlockFailureReason::ScriptShouldNotBeBurnt), - (Ok(ScriptResult::Fail), _) | (Err(_), _) => Err(UnlockFailureReason::ScriptError), - } - .map_err(|reason| { - ctrace!(TX, "Cannot run unlock/lock script {:?}", reason); - RuntimeError::FailedToUnlock { - shard_id: self.shard_id, - tracker: input.prev_out.tracker, - index: input.prev_out.index, - reason, - } - .into() - }) - } - - fn wrap_ccc( - &mut self, - tx_hash: &H256, - lock_script_hash: &H160, - parameters: &[Bytes], - quantity: u64, - ) -> StateResult<()> { - let asset_type = H160::zero(); - if self.asset_scheme(asset_type)?.is_none() { - let asset_scheme = self.create_asset_scheme( - self.shard_id, - asset_type, - String::new(), - 0, - None, - None, - Vec::new(), - Vec::new(), - ); - // FIXME: Wrapped CCC is minted in here, but the metadata is not well-defined. - ctrace!(TX, "Wrapped CCC in shard {} ({:?}) is minted on {:?}", self.shard_id, asset_scheme, asset_type); - } - let mut asset_scheme = self.get_asset_scheme_mut(self.shard_id, asset_type)?; - asset_scheme.increase_supply(quantity)?; - - self.create_asset((*tx_hash).into(), 0, asset_type, *lock_script_hash, parameters.to_vec(), quantity)?; - ctrace!(TX, "Created Wrapped CCC on {}:{}:{}", self.shard_id, tx_hash, 0); - Ok(()) - } - - fn unwrap_ccc( - &mut self, - transaction: &ShardTransaction, - sender: &Address, - burn: &AssetTransferInput, - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - ) -> StateResult<()> { - // WCCC has no approvers - let approvers = []; - self.check_and_run_input_script( - burn, - transaction, - true, - sender, - &approvers, - client, - parent_block_number, - parent_block_timestamp, - )?; - - self.kill_asset(burn.prev_out.tracker, burn.prev_out.index); - let asset_type = H160::zero(); - let mut asset_scheme = self.get_asset_scheme_mut(self.shard_id, asset_type)?; - asset_scheme.reduce_supply(burn.prev_out.quantity); - ctrace!( - TX, - "Removed Wrapped CCC asset {}:{}:{}, quantity {:?}", - self.shard_id, - burn.prev_out.tracker, - burn.prev_out.index, - burn.prev_out.quantity - ); - Ok(()) - } - - fn kill_asset(&mut self, tracker: Tracker, index: usize) { - self.cache.remove_asset(&OwnedAssetAddress::new(tracker, index, self.shard_id)); - } - - pub fn create_asset_scheme( - &self, - shard_id: ShardId, - asset_type: H160, - metadata: String, - supply: u64, - approver: Option
, - registrar: Option
, - allowed_script_hashes: Vec, - pool: Vec, - ) -> cmerkle::Result { - self.cache.create_asset_scheme(&AssetSchemeAddress::new(asset_type, shard_id), || { - AssetScheme::new_with_pool(metadata, supply, approver, registrar, allowed_script_hashes, pool) - }) - } - - fn get_asset_scheme_mut(&self, shard_id: ShardId, asset_type: H160) -> cmerkle::Result> { - let db = self.db.borrow(); - let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; - self.cache.asset_scheme_mut(&AssetSchemeAddress::new(asset_type, shard_id), &trie) - } - - pub fn create_asset( - &self, - tracker: Tracker, - index: usize, - asset_type: H160, - lock_script_hash: H160, - parameters: Vec, - quantity: u64, - ) -> cmerkle::Result { - self.cache.create_asset(&OwnedAssetAddress::new(tracker, index, self.shard_id), || { - OwnedAsset::new(asset_type, lock_script_hash, parameters, quantity) - }) - } - - #[cfg(test)] - fn shard_id(&self) -> ShardId { - self.shard_id - } -} - -impl<'db> ShardStateView for ShardLevelState<'db> { - fn asset_scheme(&self, asset_type: H160) -> cmerkle::Result> { - let db = self.db.borrow(); - let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; - self.cache.asset_scheme(&AssetSchemeAddress::new(asset_type, self.shard_id), &trie) - } - - fn asset(&self, tracker: Tracker, index: usize) -> Result, TrieError> { - let db = self.db.borrow(); - let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; - self.cache.asset(&OwnedAssetAddress::new(tracker, index, self.shard_id), &trie) - } -} - -impl<'db> StateWithCheckpoint for ShardLevelState<'db> { - fn create_checkpoint(&mut self, id: CheckpointId) { - ctrace!(STATE, "Checkpoint({}) for shard({}) is created", id, self.shard_id); - self.id_of_checkpoints.push(id); - self.cache.checkpoint(); - } - - fn discard_checkpoint(&mut self, id: CheckpointId) { - let expected = self.id_of_checkpoints.pop().expect("The checkpoint must exist"); - assert_eq!(expected, id); - - ctrace!(STATE, "Checkpoint({}) for shard({}) is discarded", id, self.shard_id); - self.cache.discard_checkpoint(); - } - - fn revert_to_checkpoint(&mut self, id: CheckpointId) { - let expected = self.id_of_checkpoints.pop().expect("The checkpoint must exist"); - assert_eq!(expected, id); - - ctrace!(STATE, "Checkpoint({}) for shard({}) is reverted", id, self.shard_id); - self.cache.revert_to_checkpoint(); - } -} - -const TRANSACTION_CHECKPOINT: CheckpointId = 456; - -impl<'db> ShardState for ShardLevelState<'db> { - fn apply( - &mut self, - transaction: &ShardTransaction, - sender: &Address, - shard_users: &[Address], - approvers: &[Address], - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - ) -> StateResult<()> { - ctrace!(TX, "Execute InnerTx {:?}(InnerTxHash:{:?})", transaction, transaction.tracker()); - - self.create_checkpoint(TRANSACTION_CHECKPOINT); - let result = self.apply_internal( - transaction, - sender, - shard_users, - approvers, - client, - parent_block_number, - parent_block_timestamp, - ); - match result { - Ok(_) => { - self.discard_checkpoint(TRANSACTION_CHECKPOINT); - Ok(()) - } - Err(err) => { - self.revert_to_checkpoint(TRANSACTION_CHECKPOINT); - Err(err) - } - } - } -} - -pub struct ReadOnlyShardLevelState<'db> { - db: &'db RefCell, - root: H256, - cache: ShardCache, - shard_id: ShardId, -} - -impl<'db> ShardStateView for ReadOnlyShardLevelState<'db> { - fn asset_scheme(&self, asset_type: H160) -> cmerkle::Result> { - let db = self.db.borrow(); - let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; - self.cache.asset_scheme(&AssetSchemeAddress::new(asset_type, self.shard_id), &trie) - } - - fn asset(&self, tracker: Tracker, index: usize) -> Result, TrieError> { - let db = self.db.borrow(); - let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; - self.cache.asset(&OwnedAssetAddress::new(tracker, index, self.shard_id), &trie) - } -} - -#[cfg(test)] -mod tests { - use ctypes::TxHash; - - use super::super::super::StateError; - use super::super::test_helper::SHARD_ID; - use super::*; - use crate::tests::helpers::{get_temp_state_db, get_test_client}; - - fn address() -> Address { - Address::random() - } - - fn get_temp_shard_state<'d>( - state_db: &'d mut RefCell, - shard_id: ShardId, - cache: &'d mut ShardCache, - ) -> ShardLevelState<'d> { - ShardLevelState::try_new(shard_id, state_db, cache).unwrap() - } - - #[test] - fn mint_permissioned_asset() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let amount = 100; - let approver = Address::random(); - let transaction = - asset_mint!(asset_mint_output!(lock_script_hash, parameters, amount), metadata.clone(), approver: approver); - - let transaction_tracker = transaction.tracker(); - let asset_type = Blake::blake(*transaction_tracker); - assert_eq!(Ok(()), state.apply(&transaction, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, approver: approver }), - (asset: (transaction_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - } - - #[test] - fn mint_infinite_asset() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let approver = Address::random(); - let transaction = asset_mint!( - asset_mint_output!(lock_script_hash, parameters: parameters), - metadata.clone(), - approver: approver - ); - let transaction_tracker = transaction.tracker(); - let asset_type = Blake::blake(*transaction_tracker); - - assert_eq!(Ok(()), state.apply(&transaction, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: ::std::u64::MAX, approver: approver }), - (asset: (transaction_tracker, 0) => { asset_type: asset_type, quantity: ::std::u64::MAX }) - ]); - } - - #[test] - fn cannot_mint_twice() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let approver = Address::random(); - let transaction = asset_mint!( - asset_mint_output!(lock_script_hash, parameters: parameters), - metadata.clone(), - approver: approver - ); - - let transaction_tracker = transaction.tracker(); - let asset_type = Blake::blake(*transaction_tracker); - assert_eq!(Ok(()), state.apply(&transaction, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - assert_eq!( - Err(StateError::Runtime(RuntimeError::AssetSchemeDuplicated { - tracker: transaction_tracker, - shard_id: SHARD_ID - })), - state.apply(&transaction, &sender, &[sender], &[], &get_test_client(), 0, 0) - ); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: ::std::u64::MAX, approver: approver }), - (asset: (transaction_tracker, 0) => { asset_type: asset_type, quantity: ::std::u64::MAX }) - ]); - } - - #[test] - fn invalid_approver() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let approver = Address::random(); - let amount = 30; - let mint = - asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata.clone(), approver: approver); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, approver: approver }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let transfer = asset_transfer!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![(lock_script_hash, asset_type, 30)] - ); - let transfer_tracker = transfer.tracker(); - - assert_eq!( - Err(StateError::Runtime(RuntimeError::NotApproved(approver))), - state.apply(&transfer, &sender, &[sender], &[], &get_test_client(), 0, 0) - ); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, approver: approver }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }), - (asset: (transfer_tracker, 0)) - ]); - } - - #[test] - fn mint_and_transfer() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let mint = asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata.clone()); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let random_lock_script_hash = H160::random(); - let transfer = asset_transfer!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type, 10), - (lock_script_hash, asset_type, 5), - (random_lock_script_hash, asset_type, 15), - ] - ); - let transfer_tracker = transfer.tracker(); - - assert_eq!(Ok(()), state.apply(&transfer, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount }), - (asset: (mint_tracker, 0)), - (asset: (transfer_tracker, 0) => { asset_type: asset_type, quantity: 10, lock_script_hash: lock_script_hash }), - (asset: (transfer_tracker, 1) => { asset_type: asset_type, quantity: 5, lock_script_hash: lock_script_hash }), - (asset: (transfer_tracker, 2) => { asset_type: asset_type, quantity: 15, lock_script_hash: random_lock_script_hash }) - ]); - } - - #[test] - fn mint_and_transfer_allowed() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let random_lock_script_hash = H160::random(); - let allowed_script_hashes = vec![lock_script_hash, random_lock_script_hash]; - - let amount = 30; - let mint = asset_mint!( - asset_mint_output!(lock_script_hash, supply: amount), - metadata.clone(), - allowed_script_hashes: allowed_script_hashes.clone() - ); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, allowed_script_hashes: allowed_script_hashes}), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let transfer = asset_transfer!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type, 10), - (lock_script_hash, asset_type, 5), - (random_lock_script_hash, asset_type, 15), - ] - ); - let transfer_tracker = transfer.tracker(); - - assert_eq!(Ok(()), state.apply(&transfer, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, allowed_script_hashes: allowed_script_hashes}), - (asset: (mint_tracker, 0)), - (asset: (transfer_tracker, 0) => { asset_type: asset_type, quantity: 10, lock_script_hash: lock_script_hash }), - (asset: (transfer_tracker, 1) => { asset_type: asset_type, quantity: 5, lock_script_hash: lock_script_hash }), - (asset: (transfer_tracker, 2) => { asset_type: asset_type, quantity: 15, lock_script_hash: random_lock_script_hash }) - ]); - } - - #[test] - fn mint_and_transfer_not_allowed() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let allowed_lock_script_hash = H160::from("ca5d3fa0a6887285ef6aa85cb12960a2b6706e00"); - let allowed_script_hashes = vec![allowed_lock_script_hash]; - let mint = asset_mint!( - asset_mint_output!(lock_script_hash, supply: amount), - metadata.clone(), - allowed_script_hashes: allowed_script_hashes.clone() - ); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, allowed_script_hashes: allowed_script_hashes}), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let transfer = asset_transfer!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![(lock_script_hash, asset_type, 30)] - ); - let transfer_tracker = transfer.tracker(); - - assert_eq!( - Err(StateError::Runtime(RuntimeError::ScriptNotAllowed(lock_script_hash))), - state.apply(&transfer, &sender, &[sender], &[], &get_test_client(), 0, 0) - ); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, allowed_script_hashes: allowed_script_hashes}), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }), - (asset: (transfer_tracker, 0)) - ]); - } - - #[test] - fn mint_and_burn() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("ca5d3fa0a6887285ef6aa85cb12960a2b6706e00"); - let amount = 30; - let mint = asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata.clone()); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let burn = asset_transfer!( - burns: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, amount), vec![0x01])] - ); - - let burn_tracker = burn.tracker(); - - assert_eq!(Ok(()), state.apply(&burn, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: 0 }), - (asset: (mint_tracker, 0)), - (asset: (burn_tracker, 0)) - ]); - } - - #[test] - #[allow(clippy::cognitive_complexity)] - fn mint_and_transfer_and_burn() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let mint = asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata.clone()); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let burn_amount = 5; - let lock_script_hash_burn = H160::from("ca5d3fa0a6887285ef6aa85cb12960a2b6706e00"); - let random_lock_script_hash = H160::random(); - let transfer = asset_transfer!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type, 10), - (lock_script_hash_burn, asset_type, burn_amount), - (random_lock_script_hash, asset_type, 15), - ] - ); - let transfer_tracker = transfer.tracker(); - - assert_eq!(Ok(()), state.apply(&transfer, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount }), - (asset: (mint_tracker, 0)), - (asset: (transfer_tracker, 0) => { asset_type: asset_type, quantity: 10 }), - (asset: (transfer_tracker, 1) => { asset_type: asset_type, quantity: burn_amount }), - (asset: (transfer_tracker, 2) => { asset_type: asset_type, quantity: 15 }) - ]); - - let burn = asset_transfer!( - burns: asset_transfer_inputs![(asset_out_point!(transfer_tracker, 1, asset_type, 5), vec![0x01])] - ); - let burn_tracker = burn.tracker(); - - assert_eq!(Ok(()), state.apply(&burn, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount - burn_amount }), - (asset: (mint_tracker, 0)), - (asset: (transfer_tracker, 0) => { asset_type: asset_type, quantity: 10 }), - (asset: (transfer_tracker, 1)), - (asset: (transfer_tracker, 2) => { asset_type: asset_type, quantity: 15 }), - (asset: (burn_tracker, 0)) - ]); - } - - - #[test] - fn registrar_can_transfer() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let registrar = address(); - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let mint = - asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata.clone(), registrar: registrar); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, registrar: registrar }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let lock_script_hash1 = H160::random(); - let lock_script_hash2 = H160::random(); - let transfer = asset_transfer!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30))], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type, 10), - (lock_script_hash1, asset_type, 5), - (lock_script_hash2, asset_type, 15), - ] - ); - let transfer_tracker = transfer.tracker(); - - assert_eq!(Ok(()), state.apply(&transfer, ®istrar, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, registrar: registrar }), - (asset: (mint_tracker, 0)), - (asset: (transfer_tracker, 0) => { asset_type: asset_type, quantity: 10 }), - (asset: (transfer_tracker, 1) => { asset_type: asset_type, quantity: 5 }), - (asset: (transfer_tracker, 2) => { asset_type: asset_type, quantity: 15 }) - ]); - } - - - #[test] - fn registrar_can_burn() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let registrar = address(); - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let mint = - asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata.clone(), registrar: registrar); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, registrar: registrar }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let burn = - asset_transfer!(burns: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, amount))]); - let burn_tracker = burn.tracker(); - - assert_eq!(Ok(()), state.apply(&burn, ®istrar, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: 0, registrar: registrar }), - (asset: (mint_tracker, 0)), - (asset: (burn_tracker, 0)) - ]); - } - - #[test] - fn cannot_transfer_because_prev_out_amount_is_invalid() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let mint = asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata.clone()); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let transfer = asset_transfer!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 20), vec![0x30, 0x01])], - asset_transfer_outputs![(lock_script_hash, vec![vec![1]], asset_type, 20)] - ); - let transfer_tracker = transfer.tracker(); - - assert_eq!( - Err(StateError::Runtime(RuntimeError::InvalidAssetQuantity { - shard_id: SHARD_ID, - tracker: mint_tracker, - index: 0, - expected: 30, - got: 20 - })), - state.apply(&transfer, &sender, &[sender], &[], &get_test_client(), 0, 0) - ); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }), - (asset: (transfer_tracker, 0)) - ]); - } - - #[test] - #[allow(clippy::cognitive_complexity)] - fn cannot_transfer_because_prev_out_type_is_invalid() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - - let metadata1 = "metadata".to_string(); - let mint1 = asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata1.clone()); - let mint_tracker1 = mint1.tracker(); - let asset_type1 = Blake::blake(*mint_tracker1); - - let metadata2 = "metadata2".to_string(); - let mint2 = asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata2.clone()); - let mint_tracker2 = mint2.tracker(); - let asset_type2 = Blake::blake(*mint_tracker2); - - assert_eq!(Ok(()), state.apply(&mint1, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type1) => { metadata: metadata1, supply: amount }), - (scheme: (asset_type2)), - (asset: (mint_tracker1, 0) => { asset_type: asset_type1, quantity: amount }) - ]); - - assert_eq!(Ok(()), state.apply(&mint2, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type1) => { metadata: metadata1, supply: amount }), - (scheme: (asset_type2) => { metadata: metadata2, supply: amount }), - (asset: (mint_tracker1, 0) => { asset_type: asset_type1, quantity: amount }), - (asset: (mint_tracker2, 0) => { asset_type: asset_type2, quantity: amount }) - ]); - - let transfer = asset_transfer!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker1, 0, asset_type2, 30), vec![0x30, 0x01])], - asset_transfer_outputs![(lock_script_hash, vec![vec![1]], asset_type2, 30)] - ); - let transfer_tracker = transfer.tracker(); - - assert_eq!( - Err(StateError::Runtime(RuntimeError::UnexpectedAssetType { - index: 0, - mismatch: Mismatch { - found: asset_type2, - expected: asset_type1, - } - })), - state.apply(&transfer, &sender, &[sender], &[], &get_test_client(), 0, 0) - ); - - check_shard_level_state!(state, [ - (scheme: (asset_type1) => { metadata: metadata1, supply: amount }), - (scheme: (asset_type2) => { metadata: metadata2, supply: amount }), - (asset: (mint_tracker1, 0) => { asset_type: asset_type1, quantity: amount }), - (asset: (mint_tracker2, 0) => { asset_type: asset_type2, quantity: amount }), - (asset: (transfer_tracker, 0)) - ]); - } - - #[test] - fn wrap_and_unwrap_ccc() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let lock_script_hash = H160::from("ca5d3fa0a6887285ef6aa85cb12960a2b6706e00"); - let tx_hash = TxHash::from(H256::random()); - let amount = 30; - - let wrap_ccc = asset_wrap_ccc!(tx_hash, asset_wrap_ccc_output!(lock_script_hash, amount)); - let wrap_ccc_tracker = wrap_ccc.tracker(); - let asset_type = H160::zero(); - - assert_eq!(*wrap_ccc_tracker, *tx_hash); - assert_eq!(Ok(()), state.apply(&wrap_ccc, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { supply: amount }), - (asset: (wrap_ccc_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let unwrap_amount = 30; - let unwrap_ccc = asset_unwrap_ccc!( - asset_transfer_input!(asset_out_point!(wrap_ccc_tracker, 0, asset_type, unwrap_amount), vec![0x01]), - sender - ); - - assert_eq!(Ok(()), state.apply(&unwrap_ccc, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { supply: amount - unwrap_amount }), - (asset: (wrap_ccc_tracker, 0)) - ]); - } - - #[test] - fn wrap_ccc_and_transfer_and_unwrap_ccc() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let tx_hash = TxHash::from(H256::random()); - let amount = 30; - - let wrap_ccc = asset_wrap_ccc!(tx_hash, asset_wrap_ccc_output!(lock_script_hash, amount)); - let wrap_ccc_tracker = wrap_ccc.tracker(); - - assert_eq!(*wrap_ccc_tracker, *tx_hash); - assert_eq!(Ok(()), state.apply(&wrap_ccc, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - let asset_type = H160::zero(); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { supply: amount }), - (asset: (wrap_ccc_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let lock_script_hash_burn = H160::from("ca5d3fa0a6887285ef6aa85cb12960a2b6706e00"); - let random_lock_script_hash = H160::random(); - let transfer = asset_transfer!( - inputs: asset_transfer_inputs![(asset_out_point!(wrap_ccc_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type, 10), - (lock_script_hash_burn, asset_type, 5), - (random_lock_script_hash, asset_type, 15), - ] - ); - let transfer_tracker = transfer.tracker(); - - assert_eq!(Ok(()), state.apply(&transfer, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { supply: amount }), - (asset: (wrap_ccc_tracker, 0)), - (asset: (transfer_tracker, 0) => { asset_type: asset_type, quantity: 10 }), - (asset: (transfer_tracker, 1) => { asset_type: asset_type, quantity: 5 }), - (asset: (transfer_tracker, 2) => { asset_type: asset_type, quantity: 15 }) - ]); - - let unwrap_amount = 5; - let unwrap_ccc = asset_unwrap_ccc!( - asset_transfer_input!(asset_out_point!(transfer_tracker, 1, asset_type, unwrap_amount), vec![0x01]), - sender - ); - - assert_eq!(Ok(()), state.apply(&unwrap_ccc, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { supply: amount - unwrap_amount }), - (asset: (wrap_ccc_tracker, 0)), - (asset: (transfer_tracker, 0) => { asset_type: asset_type, quantity: 10 }), - (asset: (transfer_tracker, 1)), - (asset: (transfer_tracker, 2) => { asset_type: asset_type, quantity: 15 }) - ]); - } - - #[test] - fn mint_and_failed_transfer_and_successful_transfer() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let mint = asset_mint!(asset_mint_output!(lock_script_hash, supply: amount), metadata.clone()); - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata.clone(), supply: amount }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let failed_lock_script = vec![0x30]; - let failed_transfer = asset_transfer!( - inputs: - asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30), failed_lock_script.clone())], - asset_transfer_outputs![(lock_script_hash, vec![vec![1]], asset_type, 30)] - ); - let failed_transfer_tracker = failed_transfer.tracker(); - - let sender = address(); - assert_eq!( - Err(StateError::Runtime(RuntimeError::ScriptHashMismatch(Mismatch { - expected: lock_script_hash, - found: Blake::blake(&failed_lock_script), - }))), - state.apply(&failed_transfer, &sender, &[sender], &[], &get_test_client(), 0, 0) - ); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata.clone(), supply: amount }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }), - (asset: (failed_transfer_tracker, 0)) - ]); - - let random_lock_script_hash = H160::random(); - let successful_transfer = asset_transfer!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type, 10), - (lock_script_hash, asset_type, 5), - (random_lock_script_hash, asset_type, 15), - ] - ); - let successful_transfer_tracker = successful_transfer.tracker(); - - assert_eq!(Ok(()), state.apply(&successful_transfer, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount }), - (asset: (mint_tracker, 0)), - (asset: (failed_transfer_tracker, 0)), - (asset: (successful_transfer_tracker, 0) => { asset_type: asset_type, quantity: 10 }), - (asset: (successful_transfer_tracker, 1) => { asset_type: asset_type, quantity: 5 }), - (asset: (successful_transfer_tracker, 2) => { asset_type: asset_type, quantity: 15 }) - ]); - } - - #[test] - fn users_can_mint_asset() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let approver = Address::random(); - let transaction = asset_mint!( - asset_mint_output!(lock_script_hash, parameters: parameters), - metadata.clone(), - approver: approver - ); - let transaction_tracker = transaction.tracker(); - let asset_type = Blake::blake(*transaction_tracker); - - assert_eq!(Ok(()), state.apply(&transaction, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: ::std::u64::MAX }), - (asset: (transaction_tracker, 0) => { asset_type: asset_type, quantity: ::std::u64::MAX }) - ]); - } - - #[test] - fn mint_is_failed_when_shard_users_are_disjoint_to_sender_and_approvers() { - let shard_users = [address(), address(), address()]; - let sender = address(); - let approvers = [address(), address(), address()]; - - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let approver = Address::random(); - let transaction = - asset_mint!(asset_mint_output!(lock_script_hash, parameters: parameters), metadata, approver: approver); - - let transaction_tracker = transaction.tracker(); - let asset_type = Blake::blake(*transaction_tracker); - - assert_eq!( - Err(StateError::Runtime(RuntimeError::InsufficientPermission)), - state.apply(&transaction, &sender, &shard_users, &approvers, &get_test_client(), 0, 0) - ); - - check_shard_level_state!(state, [ - (scheme: (asset_type)), - (asset: (transaction_tracker, 0)) - ]); - } - - #[test] - fn can_mint_when_shard_user_sent_a_transaction() { - let shard_users = [address(), address(), address()]; - let sender = shard_users[0]; - let approvers = [address(), address(), address()]; - - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let approver = Address::random(); - let transaction = asset_mint!( - asset_mint_output!(lock_script_hash, parameters: parameters), - metadata.clone(), - approver: approver - ); - - let transaction_tracker = transaction.tracker(); - let asset_type = Blake::blake(*transaction_tracker); - - check_shard_level_state!(state, [ - (scheme: (asset_type)), - (asset: (transaction_tracker, 0)) - ]); - - assert_eq!(Ok(()), state.apply(&transaction, &sender, &shard_users, &approvers, &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: ::std::u64::MAX }), - (asset: (transaction_tracker, 0) => { asset_type: asset_type, quantity: ::std::u64::MAX }) - ]); - } - - #[test] - fn can_mint_when_shard_user_approves_a_transaction() { - let shard_users = [address(), address(), address()]; - let sender = address(); - let approvers = [shard_users[0], address(), address()]; - - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let approver = Address::random(); - let transaction = asset_mint!( - asset_mint_output!(lock_script_hash, parameters: parameters), - metadata.clone(), - approver: approver - ); - - let transaction_tracker = transaction.tracker(); - let asset_type = Blake::blake(*transaction_tracker); - - check_shard_level_state!(state, [ - (scheme: (asset_type)), - (asset: (transaction_tracker, 0)) - ]); - - assert_eq!(Ok(()), state.apply(&transaction, &sender, &shard_users, &approvers, &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: ::std::u64::MAX }), - (asset: (transaction_tracker, 0) => { asset_type: asset_type, quantity: ::std::u64::MAX }) - ]); - } - - #[test] - fn anyone_can_mint_if_no_users() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let approver = Address::random(); - let transaction = asset_mint!( - asset_mint_output!(lock_script_hash, parameters: parameters), - metadata.clone(), - approver: approver - ); - - let transaction_tracker = transaction.tracker(); - let asset_type = Blake::blake(*transaction_tracker); - - assert_eq!(Ok(()), state.apply(&transaction, &sender, &[], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: ::std::u64::MAX, approver: approver }), - (asset: (transaction_tracker, 0) => { asset_type: asset_type, quantity: ::std::u64::MAX }) - ]); - } - - #[test] - fn change_asset_scheme() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let amount = 100; - let registrar = Address::random(); - let mint = asset_mint!( - asset_mint_output!(lock_script_hash, parameters, amount), - metadata.clone(), - registrar: registrar - ); - - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, approver, registrar: registrar }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let approver = Address::random(); - let change_asset_scheme = ShardTransaction::ChangeAssetScheme { - network_id: "tc".into(), - shard_id: SHARD_ID, - asset_type, - seq: 0, - metadata: "New metadata".to_string(), - approver: Some(approver), - registrar: None, - allowed_script_hashes: Vec::new(), - }; - assert_eq!(Ok(()), state.apply(&change_asset_scheme, &sender, &[], &[registrar], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: "New metadata".to_string(), supply: amount, approver: approver, registrar }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - } - - #[test] - fn increase_asset_amount() { - let sender = address(); - let mut state_db = RefCell::new(get_temp_state_db()); - let mut shard_cache = ShardCache::default(); - let mut state = get_temp_shard_state(&mut state_db, SHARD_ID, &mut shard_cache); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let amount = 100; - let registrar = Address::random(); - let mint = asset_mint!( - asset_mint_output!(lock_script_hash, parameters, amount), - metadata.clone(), - registrar: registrar - ); - - let mint_tracker = mint.tracker(); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint, &sender, &[sender], &[], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: metadata, supply: amount, approver, registrar: registrar }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }) - ]); - - let new_supply = 200; - let increase_supply = ShardTransaction::IncreaseAssetSupply { - network_id: "tc".into(), - shard_id: SHARD_ID, - asset_type, - seq: 0, - output: AssetMintOutput { - lock_script_hash: H160::random(), - parameters: vec![], - supply: new_supply, - }, - }; - let supply_tracker = increase_supply.tracker(); - - assert_eq!(Ok(()), state.apply(&increase_supply, &sender, &[], &[registrar], &get_test_client(), 0, 0)); - - check_shard_level_state!(state, [ - (scheme: (asset_type) => { metadata: "metadata".to_string(), supply: amount + new_supply, approver, registrar: registrar }), - (asset: (mint_tracker, 0) => { asset_type: asset_type, quantity: amount }), - (asset: (supply_tracker, 0) => { asset_type: asset_type, quantity: new_supply }) - ]); - } -} diff --git a/state/src/impls/test_helper.rs b/state/src/impls/test_helper.rs index a05729e7c2..56b2a4d6c1 100644 --- a/state/src/impls/test_helper.rs +++ b/state/src/impls/test_helper.rs @@ -16,308 +16,7 @@ #![macro_use] -use ctypes::ShardId; - pub const NETWORK_ID: &str = "tc"; -pub const SHARD_ID: ShardId = 0; - -macro_rules! mint_asset { - ($output:expr, $metadata:expr) => { - $crate::ctypes::transaction::Action::MintAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - shard_id: $crate::impls::test_helper::SHARD_ID, - metadata: $metadata, - output: $output, - approver: None, - registrar: None, - allowed_script_hashes: vec![], - approvals: vec![], - } - }; - ($output:expr, $metadata:expr, approver: $approver:expr) => { - $crate::ctypes::transaction::Action::MintAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - shard_id: $crate::impls::test_helper::SHARD_ID, - metadata: $metadata, - output: $output, - approver: Some($approver), - registrar: None, - allowed_script_hashes: vec![], - approvals: vec![], - } - }; - ($output:expr, $metadata:expr, registrar: $admin:expr) => { - $crate::ctypes::transaction::Action::MintAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - shard_id: $crate::impls::test_helper::SHARD_ID, - metadata: $metadata, - output: $output, - approver: None, - registrar: Some($admin), - allowed_script_hashes: vec![], - approvals: vec![], - } - }; -} - -macro_rules! asset_mint { - ($output:expr, $metadata:expr) => { - $crate::ctypes::transaction::ShardTransaction::MintAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - shard_id: $crate::impls::test_helper::SHARD_ID, - metadata: $metadata, - output: $output, - approver: None, - registrar: None, - allowed_script_hashes: vec![], - } - }; - ($output:expr, $metadata:expr, approver: $approver:expr) => { - $crate::ctypes::transaction::ShardTransaction::MintAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - shard_id: $crate::impls::test_helper::SHARD_ID, - metadata: $metadata, - output: $output, - approver: Some($approver), - registrar: None, - allowed_script_hashes: vec![], - } - }; - ($output:expr, $metadata:expr, registrar: $admin:expr) => { - $crate::ctypes::transaction::ShardTransaction::MintAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - shard_id: $crate::impls::test_helper::SHARD_ID, - metadata: $metadata, - output: $output, - approver: None, - registrar: Some($admin), - allowed_script_hashes: vec![], - } - }; - ($output:expr, $metadata:expr, allowed_script_hashes: $allowed:expr) => { - $crate::ctypes::transaction::ShardTransaction::MintAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - shard_id: $crate::impls::test_helper::SHARD_ID, - metadata: $metadata, - output: $output, - approver: None, - registrar: None, - allowed_script_hashes: $allowed, - } - }; -} - -macro_rules! asset_mint_output { - ($lock_script_hash:expr, supply: $supply:expr) => { - asset_mint_output!($lock_script_hash, Default::default(), $supply) - }; - ($lock_script_hash:expr, parameters: $params:expr) => { - $crate::ctypes::transaction::AssetMintOutput { - lock_script_hash: $lock_script_hash, - parameters: $params, - supply: ::std::u64::MAX, - } - }; - ($lock_script_hash:expr, $params:expr, $supply:expr) => { - $crate::ctypes::transaction::AssetMintOutput { - lock_script_hash: $lock_script_hash, - parameters: $params, - supply: $supply, - } - }; -} - -macro_rules! asset_out_point { - ($tracker:expr, $index:expr, $asset_type:expr, $quantity:expr) => { - asset_out_point!($tracker, $index, $asset_type, $crate::impls::test_helper::SHARD_ID, $quantity) - }; - ($tracker:expr, $index:expr, $asset_type:expr, $shard_id:expr, $quantity:expr) => { - $crate::ctypes::transaction::AssetOutPoint { - tracker: $tracker, - index: $index, - asset_type: $asset_type, - shard_id: $shard_id, - quantity: $quantity, - } - }; -} - -macro_rules! asset_transfer_input { - ($prev_out:expr) => { - asset_transfer_input!($prev_out, Vec::new()) - }; - ($prev_out:expr, $lock_script:expr) => { - $crate::ctypes::transaction::AssetTransferInput { - prev_out: $prev_out, - timelock: None, - lock_script: $lock_script, - unlock_script: Vec::new(), - } - }; -} - -macro_rules! asset_transfer_inputs { - [$($x:tt),*] => { - vec![$(asset_transfer_input! $x),*] - }; - [$($x:tt,)*] => { - asset_transfer_inputs![$($x),*] - }; -} - -macro_rules! asset_transfer_output { - ($lock_script_hash:expr, $asset_type:expr, $quantity:expr) => { - $crate::ctypes::transaction::AssetTransferOutput { - lock_script_hash: $lock_script_hash, - parameters: Vec::new(), - asset_type: $asset_type, - shard_id: $crate::impls::test_helper::SHARD_ID, - quantity: $quantity, - } - }; - ($lock_script_hash:expr, $parameters:expr, $asset_type:expr, $quantity:expr) => { - $crate::ctypes::transaction::AssetTransferOutput { - lock_script_hash: $lock_script_hash, - parameters: $parameters, - asset_type: $asset_type, - shard_id: $crate::impls::test_helper::SHARD_ID, - quantity: $quantity, - } - }; - ($lock_script_hash:expr, $parameters:expr, $asset_type:expr, $shard_id:expr, $quantity:expr) => { - $crate::ctypes::transaction::AssetTransferOutput { - lock_script_hash: $lock_script_hash, - parameters: $parameters, - asset_type: $asset_type, - shard_id: $shard_id, - quantity: $quantity, - } - }; -} - -macro_rules! asset_transfer_outputs { - [$($x:tt),*] => { - vec![$(asset_transfer_output! $x),*] - }; - [$($x:tt,)*] => { - asset_transfer_outputs![$($x),*] - }; -} - -macro_rules! transfer_asset { - (inputs: $inputs:expr, $outputs:expr) => { - $crate::ctypes::transaction::Action::TransferAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - burns: Vec::new(), - inputs: $inputs, - outputs: $outputs, - metadata: "".into(), - approvals: vec![], - expiration: None, - } - }; - (inputs: $inputs:expr, $outputs:expr, approvals: $approvals:expr) => { - $crate::ctypes::transaction::Action::TransferAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - burns: Vec::new(), - inputs: $inputs, - outputs: $outputs, - metadata: "".into(), - approvals: $approvals, - expiration: None, - } - }; - (inputs: $inputs:expr, $outputs:expr) => { - $crate::ctypes::transaction::Action::TransferAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - burns: Vec::new(), - inputs: $inputs, - outputs: $outputs, - metadata: "".into(), - approvals: vec![], - expiration: None, - } - }; - (burns: $burns:expr) => { - $crate::ctypes::transaction::Action::TransferAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - burns: $burns, - inputs: Vec::new(), - outputs: Vec::new(), - metadata: "".into(), - approvals: vec![], - expiration: None, - } - }; -} - -macro_rules! asset_transfer { - (inputs: $inputs:expr, $outputs:expr) => { - $crate::ctypes::transaction::ShardTransaction::TransferAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - burns: Vec::new(), - inputs: $inputs, - outputs: $outputs, - } - }; - (inputs: $inputs:expr, $outputs:expr) => { - $crate::ctypes::transaction::ShardTransaction::TransferAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - burns: Vec::new(), - inputs: $inputs, - outputs: $outputs, - } - }; - (burns: $burns:expr) => { - $crate::ctypes::transaction::ShardTransaction::TransferAsset { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - burns: $burns, - inputs: Vec::new(), - outputs: Vec::new(), - } - }; -} - -macro_rules! asset_wrap_ccc_output { - ($lock_script_hash:expr, $quantity:expr) => { - $crate::ctypes::transaction::AssetWrapCCCOutput { - lock_script_hash: $lock_script_hash, - parameters: Vec::new(), - quantity: $quantity, - } - }; -} - -macro_rules! asset_wrap_ccc { - ($tx_hash:expr, $output:expr) => { - $crate::ctypes::transaction::ShardTransaction::WrapCCC { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - shard_id: $crate::impls::test_helper::SHARD_ID, - tx_hash: $tx_hash, - output: $output, - } - }; -} - -macro_rules! unwrap_ccc { - ($burn:expr, $receiver:expr) => { - $crate::ctypes::transaction::Action::UnwrapCCC { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - burn: $burn, - receiver: $receiver, - } - }; -} - -macro_rules! asset_unwrap_ccc { - ($burn:expr, $receiver:expr) => { - $crate::ctypes::transaction::ShardTransaction::UnwrapCCC { - network_id: $crate::impls::test_helper::NETWORK_ID.into(), - burn: $burn, - receiver: $receiver, - } - }; -} macro_rules! pay { ($receiver:expr, $quantity:expr) => { @@ -336,18 +35,6 @@ macro_rules! set_regular_key { }; } -macro_rules! wrap_ccc { - ($lock_script_hash:expr, $quantity:expr) => { - $crate::ctypes::transaction::Action::WrapCCC { - shard_id: $crate::impls::test_helper::SHARD_ID, - lock_script_hash: $lock_script_hash, - parameters: Vec::new(), - quantity: $quantity, - payer: Default::default(), // The payer field is used for validation only. - } - }; -} - macro_rules! store { ($content:expr, $certifier:expr, $signature:expr) => { $crate::ctypes::transaction::Action::Store { @@ -367,29 +54,6 @@ macro_rules! remove { }; } -macro_rules! set_shard_owners { - (shard_id: $shard_id:expr, $owners:expr) => { - $crate::ctypes::transaction::Action::SetShardOwners { - shard_id: $shard_id, - owners: $owners, - } - }; - ($owners:expr) => { - $crate::ctypes::transaction::Action::SetShardOwners { - shard_id: $crate::impls::test_helper::SHARD_ID, - owners: $owners, - } - }; -} - -macro_rules! set_shard_users { - ($users:expr) => { - $crate::ctypes::transaction::Action::SetShardUsers { - shard_id: $crate::impls::test_helper::SHARD_ID, - users: $users, - } - }; -} macro_rules! transaction { (fee: $fee:expr, $action:expr) => { @@ -421,40 +85,6 @@ macro_rules! set_top_level_state { ($state:expr, [(account: $addr:expr => seq: $seq:expr) $(,$x:tt)*]) => { assert_eq!(Ok(()), $state.set_seq(&$addr, $seq)); - set_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(shard: $shard_id:expr => owners: [$($owner:expr),*]) $(,$x:tt)*]) => { - set_top_level_state!($state, [(shard: $shard_id => owners: [$($owner),*], users: Vec::new()) $(,$x)*]); - }; - ($state:expr, [(shard: $shard_id:expr => owners: [$($owner:expr),*], users: [$($user:expr),*]) $(,$x:tt)*]) => { - set_top_level_state!($state, [(shard: $shard_id => owners: [$($owner),*], users: vec![$($user),*]) $(,$x)*]); - }; - ($state:expr, [(shard: $shard_id:expr => owners: [$($owner:expr),*], users: $users:expr) $(,$x:tt)*]) => { - set_top_level_state!($state, [(shard: $shard_id => owners: vec![$($owner),*], users: $users) $(,$x)*]); - }; - ($state:expr, [(shard: $shard_id:expr => owners: $owners:expr, users: $users:expr) $(,$x:tt)*]) => { - assert_eq!(Ok(()), $state.create_shard_level_state($shard_id, $owners, $users)); - - set_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(metadata: shards: $number_of_shards:expr) $(,$x:tt)*]) => { - assert_eq!(Ok(()), $state.set_number_of_shards($number_of_shards)); - - set_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($shard_id:expr, $asset_type:expr) => { supply: $supply:expr, metadata: $metadata:expr }) $(,$x:tt)*]) => { - assert_eq!(Ok((true)), $state.create_asset_scheme($shard_id, $asset_type, $metadata, $supply, None, None, Vec::new(), Vec::new())); - - set_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($shard_id:expr, $asset_type:expr) => { supply: $supply:expr, metadata: $metadata:expr, approver: $approver:expr }) $(,$x:tt)*]) => { - assert_eq!(Ok((true)), $state.create_asset_scheme($shard_id, $asset_type, $metadata, $supply, $approver, None, Vec::new(), Vec::new())); - - set_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(asset: ($shard:expr, $tx_hash:expr, $index:expr) => { asset_type: $asset_type: expr, quantity: $quantity:expr, lock_script_hash: $lock_script_hash:expr }) $(,$x:tt)*]) => { - assert_eq!(Ok((true)), $state.create_asset($shard, $tx_hash, $index, $asset_type, $lock_script_hash, Vec::new(), $quantity)); - set_top_level_state!($state, [$($x),*]); }; } @@ -478,70 +108,6 @@ macro_rules! check_top_level_state { ($state:expr, [(account: $addr:expr) $(,$x:tt)*]) => { check_top_level_state!($state, [(account: $addr => (seq: 0, balance: 0)) $(,$x)*]); }; - ($state:expr, [(shard: $shard_id:expr => owners: [$($owner:expr),*]) $(,$x:tt)*]) => { - check_top_level_state!($state, [(shard: $shard_id => owners: vec![$($owner,)*]) $(,$x)*]); - }; - ($state:expr, [(shard: $shard_id:expr => owners: $owners:expr) $(,$x:tt)*]) => { - assert_eq!(Ok(Some($owners)), $state.shard_owners($shard_id)); - - check_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(shard: $shard_id:expr => owners: $owners:expr, users: $users:expr) $(,$x:tt)*]) => { - assert_eq!(Ok(Some($users)), $state.shard_users($shard_id)); - - check_top_level_state!($state, [(shard: $shard_id => owners: $owners) $(,$x)*]); - }; - ($state:expr, [(shard: $shard_id:expr) $(,$x:tt)*]) => { - assert_eq!(Ok(None), $state.shard_root($shard_id)); - - check_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($shard_id:expr, $asset_type:expr) => { supply: $supply:expr }) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($shard_id, $asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $shard_id, $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $shard_id, $asset_type)); - assert_eq!($supply, scheme.supply()); - - check_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($shard_id:expr, $asset_type:expr) => { metadata: $metadata:expr, supply: $supply:expr }) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($shard_id, $asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $shard_id, $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $shard_id, $asset_type)); - assert_eq!(&$metadata, scheme.metadata()); - assert_eq!($supply, scheme.supply()); - - check_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($shard_id:expr, $asset_type:expr) => { metadata: $metadata:expr, supply: $supply:expr, approver: $approver:expr }) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($shard_id, $asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $shard_id, $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $shard_id, $asset_type)); - assert_eq!(&$metadata, scheme.metadata()); - assert_eq!($supply, scheme.supply()); - assert_eq!(Some(&$approver), scheme.approver().as_ref()); - - check_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($shard_id:expr, $asset_type:expr)) $(,$x:tt)*]) => { - assert_eq!(Ok(None), $state.asset_scheme($shard_id, $asset_type)); - - check_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(asset: ($tx_hash:expr, $index:expr, $shard_id:expr)) $(,$x:tt)*]) => { - assert_eq!(Ok(None), $state.asset($shard_id, $tx_hash, $index)); - - check_top_level_state!($state, [$($x),*]); - }; - ($state:expr, [(asset: ($tx_hash:expr, $index:expr, $shard_id:expr) => { asset_type: $asset_type:expr, quantity: $quantity:expr }) $(,$x:tt)*]) => { - let asset = $state.asset($shard_id, $tx_hash, $index) - .expect(&format!("Cannot read Asset from {}:{}:{}", $shard_id, $tx_hash, $index)) - .expect(&format!("Asset for {}:{}:{} not exist", $shard_id, $tx_hash, $index)); - assert_eq!(&$asset_type, asset.asset_type()); - assert_eq!($quantity, asset.quantity()); - - check_top_level_state!($state, [$($x),*]); - }; ($state:expr, [(text: $tx_hash:expr) $(,$x:tt)*]) => { assert_eq!(Ok(None), $state.text($tx_hash)); @@ -554,133 +120,3 @@ macro_rules! check_top_level_state { check_top_level_state!($state, [$($x),*]); }; } - -macro_rules! check_shard_level_state { - ($state: expr, []) => { }; - ($state:expr, [(scheme: ($asset_type:expr) => { supply: $supply:expr }) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $state.shard_id(), $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $state.shard_id(), $asset_type)); - assert_eq!($supply, scheme.supply()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($asset_type:expr) => { metadata: $metadata:expr, supply: $supply:expr }) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $state.shard_id(), $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $state.shard_id(), $asset_type)); - assert_eq!(&$metadata, scheme.metadata()); - assert_eq!($supply, scheme.supply()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($asset_type:expr) => { metadata: $metadata:expr, supply: $supply:expr, allowed_script_hashes: $allowed:expr}) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $state.shard_id(), $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $state.shard_id(), $asset_type)); - assert_eq!(&$metadata, scheme.metadata()); - assert_eq!($supply, scheme.supply()); - assert_eq!($allowed, scheme.allowed_script_hashes()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($asset_type:expr) => { metadata: $metadata:expr, supply: $supply:expr, pool: $pool:expr }) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $state.shard_id(), $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $state.shard_id(), $asset_type)); - assert_eq!(&$metadata, scheme.metadata()); - assert_eq!($supply, scheme.supply()); - assert_eq!($pool, scheme.pool()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($asset_type:expr) => { metadata: $metadata:expr, supply: $supply:expr, approver: $approver:expr }) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $state.shard_id(), $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $state.shard_id(), $asset_type)); - assert_eq!(&$metadata, scheme.metadata()); - assert_eq!($supply, scheme.supply()); - assert_eq!(Some(&$approver), scheme.approver().as_ref()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($asset_type:expr) => { metadata: $metadata:expr, supply: $supply:expr, approver: $approver:expr, registrar }) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $state.shard_id(), $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $state.shard_id(), $asset_type)); - assert_eq!(&$metadata, scheme.metadata()); - assert_eq!($supply, scheme.supply()); - assert_eq!(Some(&$approver), scheme.approver().as_ref()); - assert_eq!(&None, scheme.registrar()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($asset_type:expr) => { metadata: $metadata:expr, supply: $supply:expr, approver, registrar: $registrar:expr }) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $state.shard_id(), $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $state.shard_id(), $asset_type)); - assert_eq!(&$metadata, scheme.metadata()); - assert_eq!($supply, scheme.supply()); - assert_eq!(&None, scheme.approver()); - assert_eq!(Some(&$registrar), scheme.registrar().as_ref()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($asset_type:expr) => { metadata: $metadata:expr, supply: $supply:expr, registrar: $registrar:expr }) $(,$x:tt)*]) => { - let scheme = $state.asset_scheme($asset_type) - .expect(&format!("Cannot read AssetScheme from {}:{}", $state.shard_id(), $asset_type)) - .expect(&format!("AssetScheme for {}:{} not exist", $state.shard_id(), $asset_type)); - assert_eq!(&$metadata, scheme.metadata()); - assert_eq!($supply, scheme.supply()); - assert_eq!(Some(&$registrar), scheme.registrar().as_ref()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(scheme: ($asset_type:expr)) $(,$x:tt)*]) => { - assert_eq!(Ok(None), $state.asset_scheme($asset_type)); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(asset: ($tracker:expr, $index:expr) => { asset_type: $asset_type:expr, quantity: $quantity:expr }) $(,$x:tt)*]) => { - let asset = $state.asset($tracker, $index) - .expect(&format!("Cannot read Asset from {}:{}:{}", $state.shard_id(), $tracker, $index)) - .expect(&format!("Asset for {}:{}:{} not exist", $state.shard_id(), $tracker, $index)); - assert_eq!(&$asset_type, asset.asset_type()); - assert_eq!($quantity, asset.quantity()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(asset: ($tracker:expr, $index:expr) => { asset_type: $asset_type:expr, quantity: $quantity:expr }) $(,$x:tt)*]) => { - let asset = $state.asset($tracker, $index) - .expect(&format!("Cannot read Asset from {}:{}:{}", $state.shard_id(), $tracker, $index)) - .expect(&format!("Asset for {}:{}:{} not exist", $state.shard_id(), $tracker, $index)); - assert_eq!(&$asset_type, asset.asset_type()); - assert_eq!($quantity, asset.quantity()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(asset: ($tracker:expr, $index:expr) => { asset_type: $asset_type:expr, quantity: $quantity:expr }) $(,$x:tt)*]) => { - let asset = $state.asset($tracker, $index) - .expect(&format!("Cannot read Asset from {}:{}:{}", $state.shard_id(), $tracker, $index)) - .expect(&format!("Asset for {}:{}:{} not exist", $state.shard_id(), $tracker, $index)); - assert_eq!(&$asset_type, asset.asset_type()); - assert_eq!($quantity, asset.quantity()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(asset: ($tracker:expr, $index:expr) => { asset_type: $asset_type:expr, quantity: $quantity:expr, lock_script_hash: $lock_script_hash:expr }) $(,$x:tt)*]) => { - let asset = $state.asset($tracker, $index) - .expect(&format!("Cannot read Asset from {}:{}:{}", $state.shard_id(), $tracker, $index)) - .expect(&format!("Asset for {}:{}:{} not exist", $state.shard_id(), $tracker, $index)); - assert_eq!(&$asset_type, asset.asset_type()); - assert_eq!($quantity, asset.quantity()); - assert_eq!(&$lock_script_hash, asset.lock_script_hash()); - - check_shard_level_state!($state, [$($x),*]); - }; - ($state:expr, [(asset: ($tracker:expr, $index:expr)) $(,$x:tt)*]) => { - assert_eq!(Ok(None), $state.asset($tracker, $index)); - - check_shard_level_state!($state, [$($x),*]); - }; -} diff --git a/state/src/impls/top_level.rs b/state/src/impls/top_level.rs index 74b1f64972..3e2d50a670 100644 --- a/state/src/impls/top_level.rs +++ b/state/src/impls/top_level.rs @@ -36,35 +36,24 @@ //! or rolled back. use std::cell::{RefCell, RefMut}; -use std::collections::HashMap; -use ccrypto::BLAKE_NULL_RLP; use cdb::AsHashDB; -use ckey::{public_to_address, recover, verify_address, Address, NetworkId, Public, Signature}; +use ckey::{public_to_address, verify_address, Address, Public, Signature}; use cmerkle::{Result as TrieResult, TrieError, TrieFactory}; use ctypes::errors::RuntimeError; -use ctypes::transaction::{ - Action, AssetOutPoint, AssetTransferInput, AssetWrapCCCOutput, ShardTransaction, Transaction, -}; +use ctypes::transaction::{Action, Transaction}; use ctypes::util::unexpected::Mismatch; -#[cfg(test)] -use ctypes::Tracker; -use ctypes::{BlockNumber, CommonParams, ShardId, TxHash}; -use cvm::ChainTimeInfo; +use ctypes::{BlockNumber, CommonParams, TxHash}; use kvdb::DBTransaction; -#[cfg(test)] -use primitives::H160; use primitives::{Bytes, H256}; use util_error::UtilError; -use crate::cache::{ShardCache, TopCache}; +use crate::cache::TopCache; use crate::checkpoint::{CheckpointId, StateWithCheckpoint}; -use crate::traits::{ShardState, ShardStateView, StateWithCache, TopState, TopStateView}; -#[cfg(test)] -use crate::Asset; +use crate::traits::{StateWithCache, TopState, TopStateView}; use crate::{ - Account, ActionData, FindActionHandler, Metadata, MetadataAddress, RegularAccount, RegularAccountAddress, Shard, - ShardAddress, ShardLevelState, StateDB, StateResult, Text, + Account, ActionData, FindActionHandler, Metadata, MetadataAddress, RegularAccount, RegularAccountAddress, StateDB, + StateResult, Text, }; /// Representation of the entire state of all accounts in the system. @@ -94,7 +83,6 @@ pub struct TopLevelState { root: H256, top_cache: TopCache, - shard_caches: HashMap, id_of_checkpoints: Vec, } @@ -122,24 +110,6 @@ impl TopStateView for TopLevelState { self.top_cache.metadata(&address, &trie) } - fn shard(&self, shard_id: ShardId) -> TrieResult> { - let db = self.db.borrow(); - let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; - let shard_address = ShardAddress::new(shard_id); - self.top_cache.shard(&shard_address, &trie) - } - - fn shard_state<'db>(&'db self, shard_id: ShardId) -> TrieResult>> { - match self.shard_root(shard_id)? { - // FIXME: Find a way to use stored cache. - Some(shard_root) => { - let shard_cache = self.shard_caches.get(&shard_id).cloned().unwrap_or_default(); - Ok(Some(Box::new(ShardLevelState::read_only(shard_id, &self.db, shard_root, shard_cache)?))) - } - None => Ok(None), - } - } - fn text(&self, key: &H256) -> TrieResult> { let db = self.db.borrow(); let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; @@ -155,33 +125,12 @@ impl TopStateView for TopLevelState { impl StateWithCache for TopLevelState { fn commit(&mut self) -> StateResult { - let shard_ids: Vec<_> = self.shard_caches.iter().map(|(shard_id, _)| *shard_id).collect(); - let shard_changes = shard_ids - .into_iter() - .map(|shard_id| { - if let Some(shard_root) = self.shard_root(shard_id)? { - Ok(Some((shard_id, shard_root))) - } else { - Ok(None) - } - }) - .collect::>>()?; - for (shard_id, mut shard_root) in shard_changes.into_iter().filter_map(|result| result) { - { - let mut db = self.db.borrow_mut(); - let mut trie = TrieFactory::from_existing(db.as_hashdb_mut(), &mut shard_root)?; - - let shard_cache = self.shard_caches.get_mut(&shard_id).expect("Shard must exist"); - - shard_cache.commit(&mut trie)?; - } - self.set_shard_root(shard_id, shard_root)?; - } { let mut db = self.db.borrow_mut(); let mut trie = TrieFactory::from_existing(db.as_hashdb_mut(), &mut self.root)?; self.top_cache.commit(&mut trie)?; } + Ok(self.root) } @@ -199,10 +148,6 @@ impl StateWithCheckpoint for TopLevelState { ctrace!(STATE, "Checkpoint({}) for top level is created", id); self.id_of_checkpoints.push(id); self.top_cache.checkpoint(); - - for (_, cache) in self.shard_caches.iter_mut() { - cache.checkpoint() - } } fn discard_checkpoint(&mut self, id: CheckpointId) { @@ -211,10 +156,6 @@ impl StateWithCheckpoint for TopLevelState { ctrace!(STATE, "Checkpoint({}) for top level is discarded", id); self.top_cache.discard_checkpoint(); - - for (_, cache) in self.shard_caches.iter_mut() { - cache.discard_checkpoint(); - } } fn revert_to_checkpoint(&mut self, id: CheckpointId) { @@ -223,10 +164,6 @@ impl StateWithCheckpoint for TopLevelState { ctrace!(STATE, "Checkpoint({}) for top level is reverted", id); self.top_cache.revert_to_checkpoint(); - - for (_, cache) in self.shard_caches.iter_mut() { - cache.revert_to_checkpoint(); - } } } @@ -238,13 +175,11 @@ impl TopLevelState { } let top_cache = db.top_cache(); - let shard_caches = db.shard_caches(); let state = TopLevelState { db: RefCell::new(db), root, top_cache, - shard_caches, id_of_checkpoints: Default::default(), }; @@ -253,7 +188,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, @@ -284,25 +219,15 @@ impl TopLevelState { result } - // Change the public to an owner address if it is a regular key. - fn public_to_owner_address(&self, public: &Public) -> StateResult
{ - Ok(if self.regular_account_exists_and_not_null(public)? { - let regular_account = self.get_regular_account_mut(public)?; - public_to_address(®ular_account.owner_public()) - } else { - public_to_address(public) - }) - } - - fn apply_internal( + fn apply_internal( &mut self, tx: &Transaction, signed_hash: &TxHash, signer_public: &Public, client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - current_block_timestamp: u64, + _parent_block_number: BlockNumber, + _parent_block_timestamp: u64, + _current_block_timestamp: u64, ) -> StateResult<()> { let fee_payer = if self.regular_account_exists_and_not_null(signer_public)? { let regular_account = self.get_regular_account_mut(signer_public)?; @@ -335,18 +260,7 @@ impl TopLevelState { // The failed transaction also must pay the fee and increase seq. self.create_checkpoint(ACTION_CHECKPOINT); - let result = self.apply_action( - &tx.action, - tx.network_id, - tx.hash(), - signed_hash, - &fee_payer, - signer_public, - client, - parent_block_number, - parent_block_timestamp, - current_block_timestamp, - ); + let result = self.apply_action(&tx.action, signed_hash, &fee_payer, signer_public, client); match &result { Ok(()) => { self.discard_checkpoint(ACTION_CHECKPOINT); @@ -359,173 +273,27 @@ impl TopLevelState { } #[allow(clippy::too_many_arguments)] - fn apply_action( + fn apply_action( &mut self, action: &Action, - network_id: NetworkId, - tx_hash: TxHash, signed_hash: &TxHash, fee_payer: &Address, signer_public: &Public, client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - _current_block_timestamp: u64, ) -> StateResult<()> { - let (transaction, approvers) = match action { - Action::MintAsset { - approvals, - approver, - registrar, - .. - } - | Action::ChangeAssetScheme { - approvals, - approver, - registrar, - .. - } => { - if let Some(approver) = approver { - if !is_active_account(self, approver)? { - return Err(RuntimeError::NonActiveAccount { - address: *approver, - name: "approver of asset".to_string(), - } - .into()) - } - } - if let Some(registrar) = registrar { - if !is_active_account(self, registrar)? { - return Err(RuntimeError::NonActiveAccount { - address: *registrar, - name: "registrar of asset".to_string(), - } - .into()) - } - } - let transaction = Option::::from(action.clone()).expect("It's a shard transaction"); - let transaction_tracker = transaction.tracker(); - let approvers = approvals_to_approvers( - approvals, - |public| self.public_to_owner_address(public), - &transaction_tracker, - )?; - let shard_ids = transaction.related_shards(); - assert_eq!(1, shard_ids.len()); - (transaction, approvers) - } - Action::IncreaseAssetSupply { - approvals, - .. - } => { - let transaction = Option::::from(action.clone()).expect("It's a shard transaction"); - let transaction_tracker = transaction.tracker(); - let approvers = approvals_to_approvers( - approvals, - |public| self.public_to_owner_address(public), - &transaction_tracker, - )?; - let shard_ids = transaction.related_shards(); - assert_eq!(1, shard_ids.len()); - (transaction, approvers) - } - Action::TransferAsset { - approvals, - .. - } => { - let transaction = Option::::from(action.clone()).expect("It's a shard transaction"); - debug_assert_eq!(network_id, transaction.network_id()); - - let transaction_tracker = transaction.tracker(); - let approvers = approvals_to_approvers( - approvals, - |public| self.public_to_owner_address(public), - &transaction_tracker, - )?; - (transaction, approvers) - } - Action::UnwrapCCC { - burn: - AssetTransferInput { - prev_out: - AssetOutPoint { - quantity, - .. - }, - .. - }, - receiver, - .. - } => { - if self.regular_account_exists_and_not_null_by_address(receiver)? { - return Err(RuntimeError::InvalidTransferDestination.into()) - } - let transaction = Option::::from(action.clone()).expect("It's an unwrap transaction"); - debug_assert_eq!(network_id, transaction.network_id()); - self.apply_shard_transaction( - &transaction, - fee_payer, - &[], - client, - parent_block_number, - parent_block_timestamp, - )?; - self.add_balance(receiver, *quantity)?; - return Ok(()) - } + match action { Action::Pay { receiver, quantity, } => { self.transfer_balance(fee_payer, receiver, *quantity)?; - return Ok(()) + Ok(()) } Action::SetRegularKey { key, } => { self.set_regular_key(signer_public, key)?; - return Ok(()) - } - Action::CreateShard { - users, - } => { - self.create_shard(fee_payer, *signed_hash, users.clone())?; - return Ok(()) - } - Action::SetShardOwners { - shard_id, - owners, - } => { - self.change_shard_owners(*shard_id, owners, fee_payer)?; - return Ok(()) - } - Action::SetShardUsers { - shard_id, - users, - } => { - self.change_shard_users(*shard_id, users, fee_payer)?; - return Ok(()) - } - Action::WrapCCC { - shard_id, - lock_script_hash, - parameters, - quantity, - .. - } => { - self.sub_balance(fee_payer, *quantity)?; - let transaction = ShardTransaction::WrapCCC { - network_id, - shard_id: *shard_id, - tx_hash, - output: AssetWrapCCCOutput { - lock_script_hash: *lock_script_hash, - parameters: parameters.clone(), - quantity: *quantity, - }, - }; - let approvers = vec![]; // WrapCCC doesn't have approvers - (transaction, approvers) + Ok(()) } Action::Store { content, @@ -534,14 +302,14 @@ impl TopLevelState { } => { let text = Text::new(content, certifier); self.store_text(signed_hash, text, signature)?; - return Ok(()) + Ok(()) } Action::Remove { hash, signature, } => { self.remove_text(hash, signature)?; - return Ok(()) + Ok(()) } Action::Custom { handler_id, @@ -549,86 +317,13 @@ impl TopLevelState { } => { let handler = client.find_action_handler_for(*handler_id).expect("Unknown custom parsel applied!"); handler.execute(bytes, self, fee_payer, signer_public)?; - return Ok(()) + Ok(()) + } + _ => { + // FIXME: Transactions related to Assets will be removed + Ok(()) } - }; - self.apply_shard_transaction( - &transaction, - fee_payer, - &approvers, - client, - parent_block_number, - parent_block_timestamp, - ) - } - - pub fn apply_shard_transaction( - &mut self, - transaction: &ShardTransaction, - sender: &Address, - approvers: &[Address], - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - ) -> StateResult<()> { - for shard_id in transaction.related_shards() { - self.apply_shard_transaction_to_shard( - transaction, - shard_id, - sender, - approvers, - client, - parent_block_number, - parent_block_timestamp, - )?; - } - Ok(()) - } - - fn apply_shard_transaction_to_shard( - &mut self, - transaction: &ShardTransaction, - shard_id: ShardId, - sender: &Address, - approvers: &[Address], - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - ) -> StateResult<()> { - let shard_root = self.shard_root(shard_id)?.ok_or_else(|| RuntimeError::InvalidShardId(shard_id))?; - let shard_users = self.shard_users(shard_id)?.expect("Shard must exist"); - - let shard_cache = self.shard_caches.entry(shard_id).or_default(); - let mut shard_level_state = ShardLevelState::from_existing(shard_id, &mut self.db, shard_root, shard_cache)?; - shard_level_state.apply( - &transaction, - sender, - &shard_users, - approvers, - client, - parent_block_number, - parent_block_timestamp, - ) - } - - fn create_shard_level_state( - &mut self, - shard_id: ShardId, - owners: Vec
, - users: Vec
, - ) -> StateResult<()> { - const DEFAULT_SHARD_ROOT: H256 = BLAKE_NULL_RLP; - { - let shard_cache = self.shard_caches.entry(shard_id).or_default(); - ShardLevelState::from_existing(shard_id, &mut self.db, DEFAULT_SHARD_ROOT, shard_cache)?; } - - ctrace!(STATE, "shard({}) created. owners: {:?}, users: {:?}", shard_id, owners, users); - - self.set_shard_root(shard_id, DEFAULT_SHARD_ROOT)?; - self.set_shard_owners(shard_id, owners)?; - self.set_shard_users(shard_id, users)?; - Ok(()) } fn get_account_mut(&self, a: &Address) -> TrieResult> { @@ -653,13 +348,6 @@ impl TopLevelState { self.top_cache.metadata_mut(&address, &trie) } - fn get_shard_mut(&self, shard_id: ShardId) -> TrieResult> { - let db = self.db.borrow(); - let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; - let shard_address = ShardAddress::new(shard_id); - self.top_cache.shard_mut(&shard_address, &trie) - } - fn get_text(&self, key: &TxHash) -> TrieResult> { let db = self.db.borrow(); let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; @@ -685,9 +373,6 @@ impl TopLevelState { pub fn top_cache(&self) -> &TopCache { &self.top_cache } - pub fn shard_caches(&self) -> &HashMap { - &self.shard_caches - } pub fn root(&self) -> H256 { self.root @@ -698,88 +383,6 @@ impl TopLevelState { self.get_account_mut(a)?.set_balance(balance); Ok(()) } - #[cfg(test)] - fn set_seq(&mut self, a: &Address, seq: u64) -> TrieResult<()> { - self.get_account_mut(a)?.set_seq(seq); - Ok(()) - } - - - #[cfg(test)] - fn set_number_of_shards(&mut self, number_of_shards: ShardId) -> TrieResult<()> { - self.get_metadata_mut()?.set_number_of_shards(number_of_shards); - Ok(()) - } - - #[cfg(test)] - fn create_asset_scheme( - &mut self, - shard_id: ShardId, - asset_type: H160, - metadata: String, - amount: u64, - approver: Option
, - registrar: Option
, - allowed_script_hashes: Vec, - pool: Vec, - ) -> TrieResult { - match self.shard_root(shard_id)? { - Some(shard_root) => { - let mut shard_cache = self.shard_caches.entry(shard_id).or_default(); - let state = ShardLevelState::from_existing(shard_id, &mut self.db, shard_root, &mut shard_cache)?; - state.create_asset_scheme( - shard_id, - asset_type, - metadata, - amount, - approver, - registrar, - allowed_script_hashes, - pool, - )?; - Ok(true) - } - None => Ok(false), - } - } - - #[cfg(test)] - fn create_asset( - &mut self, - shard_id: ShardId, - tracker: Tracker, - index: usize, - asset_type: H160, - lock_script_hash: H160, - parameters: Vec, - amount: u64, - ) -> TrieResult { - match self.shard_root(shard_id)? { - Some(shard_root) => { - let mut shard_cache = self.shard_caches.entry(shard_id).or_default(); - let state = ShardLevelState::from_existing(shard_id, &mut self.db, shard_root, &mut shard_cache)?; - state.create_asset(tracker, index, asset_type, lock_script_hash, parameters, amount)?; - Ok(true) - } - None => Ok(false), - } - } -} - -fn approvals_to_approvers( - approvals: &[Signature], - public_to_owner_address: F, - tracker: &H256, -) -> StateResult> -where - F: Fn(&Public) -> StateResult
, { - approvals - .iter() - .map(|signature| { - let public = recover(&signature, tracker).expect("An invalid approval is a syntax error"); - public_to_owner_address(&public) - }) - .collect() } // TODO: cloning for `State` shouldn't be possible in general; Remove this and use @@ -791,7 +394,6 @@ impl Clone for TopLevelState { root: self.root, id_of_checkpoints: self.id_of_checkpoints.clone(), top_cache: self.top_cache.clone(), - shard_caches: self.shard_caches.clone(), } } } @@ -876,73 +478,6 @@ impl TopState for TopLevelState { Ok(()) } - fn create_shard(&mut self, fee_payer: &Address, tx_hash: TxHash, users: Vec
) -> StateResult<()> { - let shard_id = { - let mut metadata = self.get_metadata_mut()?; - metadata.add_shard(tx_hash) - }; - self.create_shard_level_state(shard_id, vec![*fee_payer], users)?; - - Ok(()) - } - - fn change_shard_owners(&mut self, shard_id: ShardId, owners: &[Address], sender: &Address) -> StateResult<()> { - let old_owners = self.shard_owners(shard_id)?.ok_or_else(|| RuntimeError::InvalidShardId(shard_id))?; - if !old_owners.contains(sender) { - return Err(RuntimeError::InsufficientPermission.into()) - } - if !owners.contains(sender) { - return Err(RuntimeError::NewOwnersMustContainSender.into()) - } - - self.set_shard_owners(shard_id, owners.to_vec()) - } - - fn change_shard_users(&mut self, shard_id: ShardId, users: &[Address], sender: &Address) -> StateResult<()> { - let owners = self.shard_owners(shard_id)?.ok_or_else(|| RuntimeError::InvalidShardId(shard_id))?; - if !owners.contains(sender) { - return Err(RuntimeError::InsufficientPermission.into()) - } - - self.set_shard_users(shard_id, users.to_vec()) - } - - fn set_shard_root(&mut self, shard_id: ShardId, new_root: H256) -> StateResult<()> { - let mut shard = self.get_shard_mut(shard_id)?; - shard.set_root(new_root); - Ok(()) - } - - fn set_shard_owners(&mut self, shard_id: ShardId, new_owners: Vec
) -> StateResult<()> { - for owner in &new_owners { - if !is_active_account(self, owner)? { - return Err(RuntimeError::NonActiveAccount { - name: "shard owner".to_string(), - address: *owner, - } - .into()) - } - } - let mut shard = self.get_shard_mut(shard_id)?; - shard.set_owners(new_owners); - Ok(()) - } - - fn set_shard_users(&mut self, shard_id: ShardId, new_users: Vec
) -> StateResult<()> { - for user in &new_users { - if !is_active_account(self, user)? { - return Err(RuntimeError::NonActiveAccount { - name: "shard user".to_string(), - address: *user, - } - .into()) - } - } - let mut shard = self.get_shard_mut(shard_id)?; - shard.set_users(new_users); - Ok(()) - } - fn store_text(&mut self, key: &TxHash, text: Text, sig: &Signature) -> StateResult<()> { match verify_address(text.certifier(), sig, &text.content_hash()) { Ok(false) => { @@ -1001,17 +536,11 @@ impl TopState for TopLevelState { } } -fn is_active_account(state: &dyn TopStateView, address: &Address) -> TrieResult { - match &state.account(address)? { - Some(account) if account.is_active() => Ok(true), - _ => Ok(false), - } -} - #[cfg(test)] mod tests_state { use std::sync::Arc; + use ccrypto::BLAKE_NULL_RLP; use cdb::{new_journaldb, Algorithm}; use super::*; @@ -1357,7 +886,7 @@ mod tests_tx { use ccrypto::Blake; use ckey::{sign, Generator, Private, Random}; use ctypes::errors::RuntimeError; - use primitives::H160; + use rlp::Encodable; use super::*; @@ -1471,42 +1000,6 @@ mod tests_tx { ]); } - #[test] - fn regular_account_cannot_get_unwrapped_ccc() { - let mut state = get_temp_state(); - - let (sender, sender_public, _) = address(); - let (master_account, master_public, _) = address(); - let (regular_account, regular_public, _) = address(); - let type_of_wccc = H160::zero(); - let tracker = H256::random().into(); - let lock_script_hash = H160::from("0xb042ad154a3359d276835c903587ebafefea22af"); - let shard_id = 0; - set_top_level_state!(state, [ - (account: sender => balance: 123), - (account: master_account => balance: 456), - (regular_key: master_public => regular_public), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1), - (asset: (shard_id, tracker, 0) => { asset_type: type_of_wccc, quantity: 30, lock_script_hash: lock_script_hash }) - ]); - - let unwrap_ccc_tx = unwrap_ccc!( - asset_transfer_input!(asset_out_point!(tracker, 0, type_of_wccc, 30), vec![0x01]), - regular_account - ); - let tx = transaction!(seq: 0, fee: 11, unwrap_ccc_tx); - assert_eq!( - Err(RuntimeError::InvalidTransferDestination.into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 123)), - (account: master_account => (seq: 0, balance: 456, key: regular_public)) - ]); - } - #[test] fn use_owner_balance_when_signed_with_regular_key() { let mut state = get_temp_state(); @@ -1523,18 +1016,6 @@ mod tests_tx { check_top_level_state!(state, [ (account: sender => (seq: 1, balance: 10, key: *key)) ]); - - let tx = transaction!(seq: 1, fee: 5, Action::CreateShard { users: vec![] }); - - assert_eq!( - Ok(()), - state.apply(&tx, &H256::random().into(), regular_keypair.public(), &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 2, balance: 15 - 5 - 5)), - (shard: 0 => owners: vec![sender], users: vec![]) - ]); } #[test] @@ -1616,114 +1097,6 @@ mod tests_tx { ]); } - #[test] - fn pass_approver_check_using_a_regular_key() { - let (sender, sender_public, _) = address(); - let (_, regular_public, _) = address(); - - let shard_id = 0x0; - let mint_tracker = Tracker::from(H256::random()); - let mut state = get_temp_state(); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("0xb042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let asset_type = Blake::blake(*mint_tracker); - - set_top_level_state!(state, [ - (account: sender => balance: 25), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1), - (regular_key: sender_public => regular_public), - (scheme: (shard_id, asset_type) => { supply: amount, metadata: metadata, approver: Some(sender) }), - (asset: (shard_id, mint_tracker, 0) => { asset_type: asset_type, quantity: amount, lock_script_hash: lock_script_hash }) - ]); - - let transfer = transfer_asset!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![(lock_script_hash, vec![vec![1]], asset_type, 30)] - ); - let transfer_tx = transaction!(seq: 0, fee: 11, transfer); - - assert_eq!( - Ok(()), - state.apply(&transfer_tx, &H256::random().into(), ®ular_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 25 - 11)) - ]); - } - - - #[test] - fn pass_approver_check_using_a_regular_key_with_approval() { - let (sender, sender_public, _) = address(); - let (_, regular_public, regular_private) = address(); - - let shard_id = 0x0; - let mint_tracker = Tracker::from(H256::random()); - let mut state = get_temp_state(); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("0xb042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let asset_type = Blake::blake(*mint_tracker); - - set_top_level_state!(state, [ - (account: sender => balance: 25), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1), - (regular_key: sender_public => regular_public), - (scheme: (shard_id, asset_type) => { supply: amount, metadata: metadata, approver: Some(sender) }), - (asset: (shard_id, mint_tracker, 0) => { asset_type: asset_type, quantity: amount, lock_script_hash: lock_script_hash }) - ]); - - let transfer = transfer_asset!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![(lock_script_hash, vec![vec![1]], asset_type, 30)] - ); - let approval = sign(®ular_private, &transfer.tracker().unwrap()).unwrap(); - let transfer = transfer_asset!( - inputs: asset_transfer_inputs![(asset_out_point!(mint_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![(lock_script_hash, vec![vec![1]], asset_type, 30)], - approvals: vec![approval] - ); - let transfer_tx = transaction!(seq: 0, fee: 11, transfer); - - assert_eq!( - Ok(()), - state.apply(&transfer_tx, &H256::random().into(), ®ular_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 25 - 11)) - ]); - } - - #[test] - fn use_deleted_regular_key_as_owner_key() { - let (sender, sender_public, _) = address(); - let (regular_address, regular_public, _) = address(); - let (_, regular_public2, _) = address(); - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 20), - (regular_key: sender_public => regular_public), - (regular_key: sender_public => regular_public2), - (account: regular_address => balance: 20) - ]); - - assert_eq!(Ok(false), state.regular_account_exists_and_not_null(®ular_public)); - - let tx = transaction!(fee: 5, Action::CreateShard { users: vec![] }); - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), ®ular_public, &get_test_client(), 0, 0, 0)); - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 20)), - (account: regular_address => (seq: 1, balance: 20 - 5)), - (shard: 0 => owners: vec![regular_address], users: vec![]) - ]); - } - #[test] fn fail_when_someone_sends_some_ccc_to_an_address_which_used_as_a_regular_key() { let (sender, sender_public, _) = address(); @@ -1800,399 +1173,17 @@ mod tests_tx { } #[test] - fn mint_permissioned_asset() { - let (sender, sender_public, _) = address(); - - let shard_id = 0x0; + fn store_and_remove() { + let (sender, sender_public, sender_private) = address(); let mut state = get_temp_state(); - let approver = Address::random(); set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: approver => seq: 1), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) + (account: sender => balance: 20) ]); - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let amount = 30; - let transaction = mint_asset!( - Box::new(asset_mint_output!(lock_script_hash, parameters, amount)), - metadata.clone(), - approver: approver - ); - let transaction_tracker = transaction.tracker().unwrap(); - let asset_type = Blake::blake(*transaction_tracker); - let tx = transaction!(fee: 11, transaction); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 11)), - (scheme: (shard_id, asset_type) => { metadata: metadata, supply: amount, approver: approver }), - (asset: (transaction_tracker, 0, shard_id) => { asset_type: asset_type, quantity: amount }) - ]); - } - - #[test] - fn mint_infinite_permissioned_asset() { - let (sender, sender_public, _) = address(); - - let shard_id = 0; - - let mut state = get_temp_state(); - let approver = Address::random(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: approver => seq: 1), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let transaction = mint_asset!( - Box::new(asset_mint_output!(lock_script_hash, parameters: parameters)), - metadata.clone(), - approver: approver - ); - let transaction_tracker = transaction.tracker().unwrap(); - let asset_type = Blake::blake(*transaction_tracker); - let tx = transaction!(fee: 5, transaction); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 5)), - (scheme: (shard_id, asset_type) => { metadata: metadata, supply: ::std::u64::MAX, approver: approver }), - (asset: (transaction_tracker, 0, shard_id) => { asset_type: asset_type, quantity: ::std::u64::MAX }) - ]); - } - - #[test] - fn mint_and_transfer_in_different_transaction() { - let (sender, sender_public, _) = address(); - - let shard_id = 0x00; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 120), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let mint = mint_asset!(Box::new(asset_mint_output!(lock_script_hash, supply: amount)), metadata.clone()); - let mint_tracker = mint.tracker().unwrap(); - let mint_tx = transaction!(fee: 20, mint); - let asset_type = Blake::blake(*mint_tracker); - - assert_eq!(Ok(()), state.apply(&mint_tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 120 - 20)), - (scheme: (shard_id, asset_type) => { metadata: metadata.clone(), supply: 30 }), - (asset: (mint_tracker, 0, shard_id) => { asset_type: asset_type, quantity: 30 }) - ]); - - let random_lock_script_hash = H160::random(); - let transfer = transfer_asset!( - inputs: vec![asset_transfer_input!(asset_out_point!(mint_tracker, 0, asset_type, 30), vec![0x30, 0x01])], - vec![ - asset_transfer_output!(lock_script_hash, vec![vec![1]], asset_type, 10), - asset_transfer_output!(lock_script_hash, asset_type, 5), - asset_transfer_output!(random_lock_script_hash, asset_type, 15), - ] - ); - let transfer_tracker = transfer.tracker().unwrap(); - - state.shard_root(shard_id).unwrap().unwrap(); - - let transfer_tx = transaction!(seq: 1, fee: 30, transfer); - - assert_eq!( - Ok(()), - state.apply(&transfer_tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 2, balance: 120 - 20 - 30)), - (scheme: (shard_id, asset_type) => { metadata: metadata, supply: 30 }), - (asset: (mint_tracker, 0, shard_id)), - (asset: (transfer_tracker, 0, shard_id) => { asset_type: asset_type, quantity: 10 }), - (asset: (transfer_tracker, 1, shard_id) => { asset_type: asset_type, quantity: 5 }), - (asset: (transfer_tracker, 2, shard_id) => { asset_type: asset_type, quantity: 15 }) - ]); - } - - #[test] - fn cannot_mint_twice_in_different_transaction() { - let (sender, sender_public, _) = address(); - - let shard_id = 0x0; - - let mut state = get_temp_state(); - let approver = Address::random(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: approver => seq: 1), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let amount = 30; - let transaction = mint_asset!( - Box::new(asset_mint_output!(lock_script_hash, parameters, amount)), - metadata, - approver: approver - ); - let tx = transaction!(fee: 11, transaction.clone()); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 11)) - ]); - - let transaction_tracker = transaction.tracker().unwrap(); - let tx = transaction!(seq: 1, fee: 11, transaction); - assert_eq!( - Err(RuntimeError::AssetSchemeDuplicated { - tracker: transaction_tracker, - shard_id - } - .into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 11)) - ]); - } - - #[test] - fn wrap_and_unwrap_ccc() { - let (sender, sender_public, _) = address(); - let (receiver, ..) = address(); - - let shard_id = 0x0; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let lock_script_hash = H160::from("ca5d3fa0a6887285ef6aa85cb12960a2b6706e00"); - let quantity = 30; - - let tx = transaction!(fee: 11, wrap_ccc!(lock_script_hash, quantity)); - let tx_hash = tx.hash(); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - let asset_type = H160::zero(); - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 11 - 30)), - (account: receiver), - (asset: (Tracker::from(*tx_hash), 0, 0) => { asset_type: asset_type, quantity: quantity }) - ]); - - let unwrap_ccc_tx = unwrap_ccc!( - asset_transfer_input!(asset_out_point!(Tracker::from(*tx_hash), 0, asset_type, 30), vec![0x01]), - receiver - ); - let tx = transaction!(seq: 1, fee: 11, unwrap_ccc_tx); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - check_top_level_state!(state, [ - (account: sender => (seq: 2, balance: 100 - 11 - 30 - 11)), - (account: receiver => (seq: 0, balance: 30)), - (asset: (Tracker::from(*tx_hash), 0, 0)) - ]); - } - - #[test] - fn wrap_and_failed_unwrap() { - let (sender, sender_public, _) = address(); - let (receiver, ..) = address(); - - let shard_id = 0x0; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let lock_script_hash = H160::from("ca5d3fa0a6887285ef6aa85cb12960a2b6706e00"); - let quantity = 30; - - let tx = transaction!(fee: 11, wrap_ccc!(lock_script_hash, quantity)); - let tx_hash = tx.hash(); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - let asset_type = H160::zero(); - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 11 - 30)), - (account: receiver), - (asset: (Tracker::from(*tx_hash), 0, 0) => { asset_type: asset_type, quantity: quantity }) - ]); - - let failed_lock_script = vec![0x02]; - let unwrap_ccc_tx = unwrap_ccc!( - asset_transfer_input!( - asset_out_point!(Tracker::from(*tx_hash), 0, asset_type, 30), - failed_lock_script.clone() - ), - receiver - ); - let tx = transaction!(seq: 1, fee: 11, unwrap_ccc_tx); - - assert_eq!( - Err(RuntimeError::ScriptHashMismatch(Mismatch { - expected: lock_script_hash, - found: Blake::blake(&failed_lock_script), - }) - .into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 11 - 30)), - (account: receiver), - (asset: (Tracker::from(*tx_hash), 0, 0) => { asset_type: asset_type, quantity: quantity }) - ]); - } - - #[test] - fn wrap_ccc_with_insufficient_balance() { - let (sender, sender_public, _) = address(); - let shard_id = 0; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 20), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let lock_script_hash = H160::from("ca5d3fa0a6887285ef6aa85cb12960a2b6706e00"); - let quantity = 30; - - let tx = transaction!(fee: 11, wrap_ccc!(lock_script_hash, quantity)); - - assert_eq!( - Err(RuntimeError::InsufficientBalance { - address: sender, - balance: 9, - cost: 30, - } - .into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 20)) - ]); - } - - #[test] - #[allow(clippy::cognitive_complexity)] - fn wrap_ccc_and_transfer_and_unwrap_ccc() { - let (sender, sender_public, _) = address(); - - let shard_id = 0x0; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let quantity = 30; - - let tx = transaction!(fee: 11, wrap_ccc!(lock_script_hash, quantity)); - let tx_hash = tx.hash(); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - let asset_type = H160::zero(); - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 30 - 11)), - (asset: (Tracker::from(*tx_hash), 0, 0) => { asset_type: asset_type, quantity: quantity }) - ]); - - let lock_script_hash_burn = H160::from("ca5d3fa0a6887285ef6aa85cb12960a2b6706e00"); - let random_lock_script_hash = H160::random(); - let transfer_tx = transfer_asset!( - inputs: asset_transfer_inputs![(asset_out_point!(Tracker::from(*tx_hash), 0, asset_type, 30), vec![0x30, 0x01])], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type, 10), - (lock_script_hash_burn, asset_type, 5), - (random_lock_script_hash, asset_type, 15), - ] - ); - let transfer_tx_tracker = transfer_tx.tracker().unwrap(); - - let tx = transaction!(seq: 1, fee: 11, transfer_tx); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - check_top_level_state!(state, [ - (account: sender => (seq: 2, balance: 100 - 30 - 11 - 11)), - (asset: (Tracker::from(*tx_hash), 0, 0)), - (asset: (transfer_tx_tracker, 0, 0) => { asset_type: asset_type, quantity: 10 }), - (asset: (transfer_tx_tracker, 1, 0) => { asset_type: asset_type, quantity: 5 }), - (asset: (transfer_tx_tracker, 2, 0) => { asset_type: asset_type, quantity: 15 }) - ]); - - let unwrap_ccc_tx = unwrap_ccc!( - asset_transfer_input!(asset_out_point!(transfer_tx_tracker, 1, asset_type, 5), vec![0x01]), - sender - ); - let tx = transaction!(seq: 2, fee: 11, unwrap_ccc_tx); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - check_top_level_state!(state, [ - (account: sender => (seq: 3, balance: 100 - 30 - 11 - 11 - 11 + 5)), - (asset: (transfer_tx_tracker, 0, 0) => { asset_type: asset_type, quantity: 10 }), - (asset: (transfer_tx_tracker, 1, 0)), - (asset: (transfer_tx_tracker, 2, 0) => { asset_type: asset_type, quantity: 15 }) - ]); - } - - #[test] - fn store_and_remove() { - let (sender, sender_public, sender_private) = address(); - let shard_id = 0; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 20), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let content = "CodeChain".to_string(); - let content_hash = Blake::blake(content.rlp_bytes()); - let signature = sign(&sender_private, &content_hash).unwrap(); + let content = "CodeChain".to_string(); + let content_hash = Blake::blake(content.rlp_bytes()); + let signature = sign(&sender_private, &content_hash).unwrap(); let store_tx = transaction!(fee: 10, store!(content.clone(), sender, signature)); let dummy_signed_hash = TxHash::from(H256::random()); @@ -2221,13 +1212,10 @@ mod tests_tx { #[test] fn store_with_wrong_signature() { let (sender, sender_public, _) = address(); - let shard_id = 0; let mut state = get_temp_state(); set_top_level_state!(state, [ - (account: sender => balance: 20), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) + (account: sender => balance: 20) ]); let content = "CodeChain".to_string(); @@ -2264,13 +1252,10 @@ mod tests_tx { #[test] fn remove_on_nothing() { let (sender, sender_public, sender_private) = address(); - let shard_id = 0; let mut state = get_temp_state(); set_top_level_state!(state, [ - (account: sender => balance: 20), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) + (account: sender => balance: 20) ]); let hash = TxHash::from(H256::random()); @@ -2286,1000 +1271,4 @@ mod tests_tx { (account: sender => (seq: 0, balance: 20)) ]); } - - #[test] - fn get_invalid_shard_root() { - let state = get_temp_state(); - - let shard_id = 3; - check_top_level_state!(state, [(shard: shard_id)]); - } - - #[test] - fn get_asset_in_invalid_shard() { - let state = get_temp_state(); - - let shard_id = 3; - check_top_level_state!(state, [ - (asset: (Tracker::from(H256::random()), 0, shard_id)) - ]); - } - - - #[test] - fn get_asset_scheme_in_invalid_shard() { - let state = get_temp_state(); - - let shard_id = 3; - check_top_level_state!(state, [(scheme: (shard_id, H160::random()))]); - } - - #[test] - #[allow(clippy::cognitive_complexity)] - fn apply_create_shard() { - let mut state = get_temp_state(); - let (sender, sender_public, _) = address(); - let users = vec![Address::random(), Address::random(), Address::random()]; - set_top_level_state!(state, [ - (account: users[0] => seq: 1), - (account: users[1] => seq: 1), - (account: users[2] => seq: 1), - (account: sender => balance: 20) - ]); - - let tx1 = transaction!(fee: 5, Action::CreateShard { users: vec![] }); - let tx2 = transaction!(seq: 1, fee: 5, Action::CreateShard { users: users.clone() }); - let invalid_hash = TxHash::from(H256::random()); - let signed_hash1 = TxHash::from(H256::random()); - let signed_hash2 = TxHash::from(H256::random()); - - assert_eq!(Ok(None), state.shard_id_by_hash(&invalid_hash)); - assert_eq!(Ok(None), state.shard_id_by_hash(&signed_hash1)); - assert_eq!(Ok(None), state.shard_id_by_hash(&signed_hash2)); - - assert_eq!(Ok(()), state.apply(&tx1, &signed_hash1, &sender_public, &get_test_client(), 0, 0, 0)); - - assert_eq!(Ok(None), state.shard_id_by_hash(&invalid_hash)); - assert_eq!(Ok(Some(0)), state.shard_id_by_hash(&signed_hash1)); - assert_eq!(Ok(None), state.shard_id_by_hash(&signed_hash2)); - - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 20 - 5)), - (shard: 0 => owners: [sender]), - (shard: 1) - ]); - - assert_eq!(Ok(()), state.apply(&tx2, &signed_hash2, &sender_public, &get_test_client(), 0, 0, 0)); - assert_eq!(Ok(None), state.shard_id_by_hash(&invalid_hash)); - assert_eq!(Ok(Some(0)), state.shard_id_by_hash(&signed_hash1)); - assert_eq!(Ok(Some(1)), state.shard_id_by_hash(&signed_hash2)); - - check_top_level_state!(state, [ - (account: sender => (seq: 2, balance: 20 - 5 - 5)), - (shard: 0 => owners: vec![sender], users: vec![]), - (shard: 1 => owners: vec![sender], users: users), - (shard: 2) - ]); - } - - #[test] - #[allow(clippy::cognitive_complexity)] - fn apply_create_shard_when_there_are_default_shards() { - let mut state = get_temp_state(); - let (sender, sender_public, _) = address(); - let shard_owner0 = address().0; - let shard_owner1 = address().0; - let shard_user = Address::random(); - - set_top_level_state!(state, [ - (account: shard_owner0 => seq: 1), - (account: shard_owner1 => seq: 1), - (account: shard_user => seq: 1), - (shard: 0 => owners: [shard_owner0]), - (shard: 1 => owners: [shard_owner1]), - (metadata: shards: 2), - (account: sender => balance: 20) - ]); - - let tx1 = transaction!(fee: 5, Action::CreateShard { users: vec![shard_user] }); - let invalid_hash = TxHash::from(H256::random()); - let signed_hash1 = TxHash::from(H256::random()); - let signed_hash2 = TxHash::from(H256::random()); - - assert_eq!(Ok(None), state.shard_id_by_hash(&invalid_hash)); - assert_eq!(Ok(None), state.shard_id_by_hash(&signed_hash1)); - assert_eq!(Ok(None), state.shard_id_by_hash(&signed_hash2)); - - assert_eq!(Ok(()), state.apply(&tx1, &signed_hash1, &sender_public, &get_test_client(), 0, 0, 0)); - - assert_eq!(Ok(None), state.shard_id_by_hash(&invalid_hash)); - assert_eq!(Ok(Some(2)), state.shard_id_by_hash(&signed_hash1)); - assert_eq!(Ok(None), state.shard_id_by_hash(&signed_hash2)); - - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 20 - 5)), - (shard: 0 => owners: [shard_owner0]), - (shard: 1 => owners: vec![shard_owner1]), - (shard: 2 => owners: vec![sender], users: vec![shard_user]), - (shard: 3) - ]); - - let tx2 = transaction!(seq: 1, fee: 5, Action::CreateShard { users: vec![] }); - assert_eq!(Ok(()), state.apply(&tx2, &signed_hash2, &sender_public, &get_test_client(), 0, 0, 0)); - assert_eq!(Ok(None), state.shard_id_by_hash(&invalid_hash)); - assert_eq!(Ok(Some(2)), state.shard_id_by_hash(&signed_hash1)); - assert_eq!(Ok(Some(3)), state.shard_id_by_hash(&signed_hash2)); - - check_top_level_state!(state, [ - (account: sender => (seq: 2, balance: 20 - 5 - 5)), - (shard: 0 => owners: [shard_owner0]), - (shard: 1 => owners: [shard_owner1]), - (shard: 2 => owners: vec![sender], users: vec![shard_user]), - (shard: 3 => owners: vec![sender], users: vec![]), - (shard: 4) - ]); - } - - #[test] - fn get_asset_in_invalid_shard2() { - let mut state = get_temp_state(); - let (sender, sender_public, _) = address(); - set_top_level_state!(state, [ - (account: sender => balance: 20) - ]); - - let tx = transaction!(fee: 5, Action::CreateShard { users: vec![] }); - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - let invalid_shard_id = 3; - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 20 - 5)), - (shard: 0 => owners: vec![sender], users: vec![]), - (asset: (Tracker::from(H256::random()), 0, invalid_shard_id)) - ]); - } - - #[test] - fn get_asset_scheme_in_invalid_shard2() { - let mut state = get_temp_state(); - let (sender, sender_public, _) = address(); - let users = vec![Address::random(), Address::random()]; - set_top_level_state!(state, [ - (account: users[0] => seq: 1), - (account: users[1] => seq: 1), - (account: sender => balance: 20) - ]); - - let tx = transaction!(fee: 5, Action::CreateShard { users: users.clone() }); - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - let invalid_shard_id = 3; - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 20 - 5)), - (shard: 0 => owners: vec![sender], users: users), - (asset: (Tracker::from(H256::random()), 0, invalid_shard_id)) - ]); - } - - #[test] - fn mint_asset_on_invalid_shard_must_fail() { - let mut state = get_temp_state(); - let (sender, sender_public, _) = address(); - let approver = Address::random(); - set_top_level_state!(state, [ - (account: approver => seq: 1), - (account: sender => balance: 100) - ]); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::random(); - let parameters = vec![]; - let amount = 30; - let transaction = mint_asset!( - Box::new(asset_mint_output!(lock_script_hash, parameters, amount)), - metadata, - approver: approver - ); - let tx = transaction!(fee: 11, transaction); - - assert_eq!( - Err(RuntimeError::InvalidShardId(0).into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 100)) - ]); - } - - #[test] - fn transfer_on_invalid_tx_must_fail() { - let (sender, sender_public, _) = address(); - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 120) - ]); - - let shard_id = 100; - - let asset_type = H160::zero(); - let transfer = transfer_asset!( - inputs: - asset_transfer_inputs![(asset_out_point!(Tracker::from(H256::random()), 0, asset_type, shard_id, 30), vec![ - 0x30, 0x01 - ])], - asset_transfer_outputs![ - (H160::random(), vec![vec![1]], asset_type, shard_id, 10), - (H160::random(), vec![], asset_type, shard_id, 5), - (H160::random(), vec![], asset_type, shard_id, 15), - ] - ); - - let tx = transaction!(fee: 30, transfer); - - assert_eq!( - Err(RuntimeError::InvalidShardId(100).into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 120)) - ]); - } - - #[test] - fn set_shard_owners() { - let (sender, sender_public, _) = address(); - - let shard_id = 0; - - let mut state = get_temp_state(); - let owners = vec![Address::random(), Address::random(), sender]; - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: owners[0] => balance: 100), - (account: owners[1] => balance: 100), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let tx = transaction!(fee: 5, set_shard_owners!(owners.clone())); - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 5)), - (shard: 0 => owners: owners) - ]); - } - - #[test] - fn new_owners_must_contain_sender() { - let (sender, sender_public, _) = address(); - - let shard_id = 0; - - let mut state = get_temp_state(); - let owners = vec![Address::random(), Address::random()]; - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: owners[0] => seq: 1), - (account: owners[0] => seq: 1), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let tx = transaction!(fee: 5, set_shard_owners!(owners)); - assert_eq!( - Err(RuntimeError::NewOwnersMustContainSender.into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 100)), - (shard: 0 => owners: [sender]) - ]); - } - - #[test] - fn only_owner_can_set_owners() { - let (original_owner, ..) = address(); - - let shard_id = 0; - - let mut state = get_temp_state(); - let (sender, sender_public, _) = address(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: original_owner => seq: 1), - (shard: shard_id => owners: [original_owner]), - (metadata: shards: 1) - ]); - - let owners = vec![Address::random(), Address::random(), sender]; - let tx = transaction!(fee: 5, set_shard_owners!(owners)); - - assert_eq!( - Err(RuntimeError::InsufficientPermission.into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 100)), - (shard: 0 => owners: [original_owner]) - ]); - } - - #[test] - fn set_shard_owners_fail_on_invalid_shard_id() { - let (sender, sender_public, _) = address(); - let shard_id = 0; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1) - ]); - - let invalid_shard_id = 0xF; - let owners = vec![Address::random(), Address::random(), sender]; - let tx = transaction!(fee: 5, set_shard_owners!(shard_id: invalid_shard_id, owners)); - - assert_eq!( - Err(RuntimeError::InvalidShardId(invalid_shard_id).into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 100)), - (shard: 0 => owners: [sender]), - (shard: invalid_shard_id) - ]); - } - - #[test] - fn user_cannot_set_owners() { - let (original_owner, ..) = address(); - let (sender, sender_public, _) = address(); - let shard_id = 0; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: original_owner => seq: 1), - (shard: shard_id => owners: [original_owner], users: [sender]), - (metadata: shards: 1) - ]); - - let owners = vec![Address::random(), Address::random(), sender]; - - let tx = transaction!(fee: 5, set_shard_owners!(owners)); - assert_eq!( - Err(StateError::Runtime(RuntimeError::InsufficientPermission)), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 100)), - (shard: 0 => owners: [original_owner]) - ]); - } - - - #[test] - fn user_can_mint() { - let (original_owner, ..) = address(); - let (sender, sender_public, _) = address(); - let shard_id = 0x00; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: original_owner => seq: 1), - (shard: shard_id => owners: [original_owner], users: [sender]), - (metadata: shards: 1) - ]); - - let metadata = "metadata".to_string(); - let lock_script_hash = H160::from("b042ad154a3359d276835c903587ebafefea22af"); - let amount = 30; - let parameters = vec![]; - - let mint = mint_asset!(Box::new(asset_mint_output!(lock_script_hash, parameters, amount)), metadata.clone()); - let mint_tracker = mint.tracker().unwrap(); - let asset_type = Blake::blake(*mint_tracker); - - let tx = transaction!(fee: 20, mint); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 20)), - (scheme: (shard_id, asset_type) => { metadata: metadata, supply: amount }), - (asset: (mint_tracker, 0, shard_id) => { asset_type: asset_type, quantity: amount }) - ]); - } - - #[test] - fn set_shard_users() { - let (sender, sender_public, _) = address(); - let old_users = vec![Address::random(), Address::random(), Address::random()]; - let shard_id = 0; - - let mut state = get_temp_state(); - let new_users = vec![Address::random(), Address::random(), sender]; - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: old_users[0] => seq: 1), - (account: old_users[1] => seq: 1), - (account: old_users[2] => seq: 1), - (account: new_users[0] => seq: 1), - (account: new_users[1] => seq: 1), - (shard: shard_id => owners: [sender], users: old_users), - (metadata: shards: 1) - ]); - - let tx = transaction!(fee: 5, set_shard_users!(new_users)); - - assert_eq!(Ok(()), state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0)); - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 100 - 5)) - ]); - } - - - #[test] - fn user_cannot_set_shard_users() { - let (sender, sender_public, _) = address(); - let owners = vec![Address::random(), Address::random(), Address::random()]; - let old_users = vec![Address::random(), Address::random(), Address::random(), sender]; - let shard_id = 0; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: old_users[0] => seq: 1), - (account: old_users[1] => seq: 1), - (account: old_users[2] => seq: 1), - (account: owners[0] => seq: 1), - (account: owners[1] => seq: 1), - (account: owners[2] => seq: 1), - (shard: shard_id => owners: owners.clone(), users: old_users.clone()), - (metadata: shards: 1) - ]); - - let new_users = vec![Address::random(), Address::random(), sender]; - let tx = transaction!(fee: 5, set_shard_users!(new_users)); - - assert_eq!( - Err(RuntimeError::InsufficientPermission.into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 100)), - (shard: 0 => owners: owners, users: old_users) - ]); - } - - #[test] - fn transfer_failed_if_the_input_amount_is_not_valid() { - let shard_id = 0; - - let mint_tracker1 = Tracker::from(H256::random()); - let mint_tracker2 = Tracker::from(H256::random()); - let asset_type1 = Blake::blake(*mint_tracker1); - let asset_type2 = Blake::blake(*mint_tracker2); - - let lock_script_hash = H160::from("0xb042ad154a3359d276835c903587ebafefea22af"); - - let (sender, signer_public, _) = address(); - - let mut state = get_temp_state(); - let owner0 = address().0; - set_top_level_state!(state, [ - (account: sender => balance: 25), - (account: owner0 => seq: 1), - (shard: shard_id => owners: [owner0]), - (metadata: shards: 1), - (scheme: (shard_id, asset_type1) => { supply: 10, metadata: format!("asset on shard {}", shard_id) }), - (scheme: (shard_id, asset_type2) => { supply: 20, metadata: format!("asset on shard {}", shard_id) }), - (asset: (shard_id, mint_tracker1, 0) => { asset_type: asset_type1, quantity: 10, lock_script_hash: lock_script_hash }), - (asset: (shard_id, mint_tracker2, 0) => { asset_type: asset_type2, quantity: 20, lock_script_hash: lock_script_hash }) - ]); - - let transfer = transfer_asset!( - inputs: - asset_transfer_inputs![ - (asset_out_point!(mint_tracker1, 0, asset_type1, shard_id, 10), vec![0x30, 0x01]), - (asset_out_point!(mint_tracker2, 0, asset_type2, shard_id, 10), vec![0x30, 0x01]) - ], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type1, shard_id, 10), - (lock_script_hash, vec![vec![1]], asset_type2, shard_id, 10) - ] - ); - let transfer_tracker = transfer.tracker().unwrap(); - let transfer_tx = transaction!(seq: 0, fee: 11, transfer); - - assert_eq!( - Err(RuntimeError::InvalidAssetQuantity { - shard_id, - tracker: mint_tracker2, - index: 0, - expected: 20, - got: 10, - } - .into()), - state.apply(&transfer_tx, &H256::random().into(), &signer_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 25)), - (scheme: (shard_id, asset_type1) => { supply: 10 }), - (scheme: (shard_id, asset_type2) => { supply: 20 }), - (asset: (mint_tracker1, 0, shard_id) => { asset_type: asset_type1, quantity: 10 }), - (asset: (mint_tracker2, 0, shard_id) => { asset_type: asset_type2, quantity: 20 }), - (asset: (transfer_tracker, 0, shard_id)), - (asset: (transfer_tracker, 1, shard_id)) - ]); - } - - #[test] - #[allow(clippy::cognitive_complexity)] - fn multi_shard_transfer() { - let shard3 = 3; - let shard4 = 4; - - let mint_tracker3 = Tracker::from(H256::random()); - let mint_tracker4 = Tracker::from(H256::random()); - let asset_type3 = Blake::blake(*mint_tracker3); - let asset_type4 = Blake::blake(*mint_tracker4); - let lock_script_hash = H160::from("0xb042ad154a3359d276835c903587ebafefea22af"); - - let (sender, signer_public, _) = address(); - - let mut state = get_temp_state(); - let owner0 = address().0; - let owner1 = address().0; - let owner2 = address().0; - let owner3 = address().0; - let owner4 = address().0; - set_top_level_state!(state, [ - (account: sender => balance: 25), - (account: owner0 => seq: 1), - (account: owner1 => seq: 1), - (account: owner2 => seq: 1), - (account: owner3 => seq: 1), - (account: owner4 => seq: 1), - (shard: 0 => owners: [owner0]), - (shard: 1 => owners: [owner1]), - (shard: 2 => owners: [owner2]), - (shard: shard3 => owners: [owner3]), - (shard: shard4 => owners: [owner4]), - (metadata: shards: 5), - (scheme: (shard3, asset_type3) => { supply: 10, metadata: "asset on shard 3".to_string() }), - (scheme: (shard4, asset_type4) => { supply: 20, metadata: "asset on shard 4".to_string() }), - (asset: (shard3, mint_tracker3, 0) => { asset_type: asset_type3, quantity: 10, lock_script_hash: lock_script_hash }), - (asset: (shard4, mint_tracker4, 0) => { asset_type: asset_type4, quantity: 20, lock_script_hash: lock_script_hash }) - ]); - - let transfer = transfer_asset!( - inputs: - asset_transfer_inputs![ - (asset_out_point!(mint_tracker3, 0, asset_type3, shard3, 10), vec![0x30, 0x01]), - (asset_out_point!(mint_tracker4, 0, asset_type4, shard4, 20), vec![0x30, 0x01]) - ], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type3, shard3, 10), - (lock_script_hash, vec![vec![1]], asset_type4, shard4, 20) - ] - ); - let transfer_tracker = transfer.tracker().unwrap(); - let transfer_tx = transaction!(seq: 0, fee: 11, transfer); - - assert_eq!( - Ok(()), - state.apply(&transfer_tx, &H256::random().into(), &signer_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 25 - 11)), - (scheme: (shard3, asset_type3) => { supply: 10 }), - (scheme: (shard4, asset_type4) => { supply: 20 }), - (asset: (mint_tracker3, 0, shard3)), - (asset: (mint_tracker4, 0, shard4)), - (asset: (transfer_tracker, 0, shard3) => { asset_type: asset_type3, quantity: 10 }), - (asset: (transfer_tracker, 1, shard3)), - (asset: (transfer_tracker, 0, shard4)), - (asset: (transfer_tracker, 1, shard4) => { asset_type: asset_type4, quantity: 20 }) - ]); - } - - #[test] - #[allow(clippy::cognitive_complexity)] - fn multi_shard_transfer_in_cross_order() { - let shard3 = 3; - let shard4 = 4; - - let mint_tracker3 = Tracker::from(H256::random()); - let mint_tracker4 = Tracker::from(H256::random()); - let asset_type3 = Blake::blake(*mint_tracker3); - let asset_type4 = Blake::blake(*mint_tracker4); - let lock_script_hash = H160::from("0xb042ad154a3359d276835c903587ebafefea22af"); - - let (sender, signer_public, _) = address(); - - let mut state = get_temp_state(); - let owner0 = address().0; - let owner1 = address().0; - let owner2 = address().0; - let owner3 = address().0; - let owner4 = address().0; - set_top_level_state!(state, [ - (account: sender => balance: 25), - (account: owner0 => seq: 1), - (account: owner1 => seq: 1), - (account: owner2 => seq: 1), - (account: owner3 => seq: 1), - (account: owner4 => seq: 1), - (shard: 0 => owners: [owner0]), - (shard: 1 => owners: [owner1]), - (shard: 2 => owners: [owner2]), - (shard: shard3 => owners: [owner3]), - (shard: shard4 => owners: [owner4]), - (metadata: shards: 5), - (scheme: (shard3, asset_type3) => { supply: 10, metadata: "asset on shard 3".to_string() }), - (scheme: (shard4, asset_type4) => { supply: 20, metadata: "asset on shard 4".to_string() }), - (asset: (shard3, mint_tracker3, 0) => { asset_type: asset_type3, quantity: 10, lock_script_hash: lock_script_hash }), - (asset: (shard4, mint_tracker4, 0) => { asset_type: asset_type4, quantity: 20, lock_script_hash: lock_script_hash }) - ]); - - let transfer = transfer_asset!( - inputs: - asset_transfer_inputs![ - (asset_out_point!(mint_tracker4, 0, asset_type4, shard4, 20), vec![0x30, 0x01]), - (asset_out_point!(mint_tracker3, 0, asset_type3, shard3, 10), vec![0x30, 0x01]) - ], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type4, shard4, 20), - (lock_script_hash, vec![vec![1]], asset_type3, shard3, 10) - ] - ); - let transfer_tracker = transfer.tracker().unwrap(); - let transfer_tx = transaction!(seq: 0, fee: 11, transfer); - - assert_eq!( - Ok(()), - state.apply(&transfer_tx, &H256::random().into(), &signer_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 1, balance: 25 - 11)), - (scheme: (shard3, asset_type3) => { supply: 10 }), - (scheme: (shard4, asset_type4) => { supply: 20 }), - (asset: (mint_tracker3, 0, shard3)), - (asset: (mint_tracker4, 0, shard4)), - (asset: (transfer_tracker, 0, shard3)), - (asset: (transfer_tracker, 1, shard3) => { asset_type: asset_type3, quantity: 10 }), - (asset: (transfer_tracker, 0, shard4) => { asset_type: asset_type4, quantity: 20 }), - (asset: (transfer_tracker, 1, shard4)) - ]); - } - - #[test] - #[allow(clippy::cognitive_complexity)] - fn multi_shard_transfer_failed_if_the_shard_id_of_input_is_not_valid() { - let shard3 = 3; - let shard4 = 4; - - let mint_tracker3 = Tracker::from(H256::random()); - let mint_tracker4 = Tracker::from(H256::random()); - let asset_type3 = Blake::blake(*mint_tracker3); - let asset_type4 = Blake::blake(*mint_tracker4); - let lock_script_hash = H160::from("0xb042ad154a3359d276835c903587ebafefea22af"); - - let (sender, signer_public, _) = address(); - - let mut state = get_temp_state(); - let owner0 = address().0; - let owner1 = address().0; - let owner2 = address().0; - let owner3 = address().0; - let owner4 = address().0; - set_top_level_state!(state, [ - (account: sender => balance: 25), - (account: owner0 => seq: 1), - (account: owner1 => seq: 1), - (account: owner2 => seq: 1), - (account: owner3 => seq: 1), - (account: owner4 => seq: 1), - (shard: 0 => owners: [owner0]), - (shard: 1 => owners: [owner1]), - (shard: 2 => owners: [owner2]), - (shard: shard3 => owners: [owner3]), - (shard: shard4 => owners: [owner4]), - (metadata: shards: 5), - (scheme: (shard3, asset_type3) => { supply: 10, metadata: "asset on shard 3".to_string() }), - (scheme: (shard4, asset_type4) => { supply: 20, metadata: "asset on shard 4".to_string() }), - (asset: (shard3, mint_tracker3, 0) => { asset_type: asset_type3, quantity: 10, lock_script_hash: lock_script_hash }), - (asset: (shard4, mint_tracker4, 0) => { asset_type: asset_type4, quantity: 20, lock_script_hash: lock_script_hash }) - ]); - - let transfer = transfer_asset!( - inputs: - asset_transfer_inputs![ - (asset_out_point!(mint_tracker3, 0, asset_type3, shard3, 10), vec![0x30, 0x01]), - (asset_out_point!(mint_tracker4, 0, asset_type4, shard3, 20), vec![0x30, 0x01]) - ], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type3, shard3, 10), - (lock_script_hash, vec![vec![1]], asset_type4, shard3, 20) - ] - ); - let transfer_tracker = transfer.tracker().unwrap(); - let transfer_tx = transaction!(seq: 0, fee: 11, transfer); - - assert_eq!( - Err(RuntimeError::AssetSchemeNotFound { - asset_type: asset_type4, - shard_id: shard3, - } - .into()), - state.apply(&transfer_tx, &H256::random().into(), &signer_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 25)), - (scheme: (shard3, asset_type3) => { supply: 10 }), - (scheme: (shard4, asset_type4) => { supply: 20 }), - (asset: (mint_tracker3, 0, shard3) => { asset_type: asset_type3, quantity: 10 }), - (asset: (mint_tracker4, 0, shard4) => { asset_type: asset_type4, quantity: 20 }), - (asset: (transfer_tracker, 0, shard3)), - (asset: (transfer_tracker, 1, shard3)), - (asset: (transfer_tracker, 0, shard4)), - (asset: (transfer_tracker, 1, shard4)) - ]); - } - - #[test] - #[allow(clippy::cognitive_complexity)] - fn multi_shard_transfer_failed_if_the_input_amount_is_not_valid() { - let shard3 = 3; - let shard4 = 4; - - let mint_tracker3 = Tracker::from(H256::random()); - let mint_tracker4 = Tracker::from(H256::random()); - let asset_type3 = Blake::blake(*mint_tracker3); - let asset_type4 = Blake::blake(*mint_tracker4); - let lock_script_hash = H160::from("0xb042ad154a3359d276835c903587ebafefea22af"); - - let (sender, signer_public, _) = address(); - - let mut state = get_temp_state(); - let owner0 = address().0; - let owner1 = address().0; - let owner2 = address().0; - let owner3 = address().0; - let owner4 = address().0; - set_top_level_state!(state, [ - (account: sender => balance: 25), - (account: owner0 => seq: 1), - (account: owner1 => seq: 1), - (account: owner2 => seq: 1), - (account: owner3 => seq: 1), - (account: owner4 => seq: 1), - (shard: 0 => owners: [owner0]), - (shard: 1 => owners: [owner1]), - (shard: 2 => owners: [owner2]), - (shard: shard3 => owners: [owner3]), - (shard: shard4 => owners: [owner4]), - (metadata: shards: 5), - (scheme: (shard3, asset_type3) => { supply: 10, metadata: "asset on shard 3".to_string() }), - (scheme: (shard4, asset_type4) => { supply: 20, metadata: "asset on shard 4".to_string() }), - (asset: (shard3, mint_tracker3, 0) => { asset_type: asset_type3, quantity: 10, lock_script_hash: lock_script_hash }), - (asset: (shard4, mint_tracker4, 0) => { asset_type: asset_type4, quantity: 20, lock_script_hash: lock_script_hash }) - ]); - - let transfer = transfer_asset!( - inputs: - asset_transfer_inputs![ - (asset_out_point!(mint_tracker3, 0, asset_type3, shard3, 10), vec![0x30, 0x01]), - (asset_out_point!(mint_tracker4, 0, asset_type4, shard4, 10), vec![0x30, 0x01]) - ], - asset_transfer_outputs![ - (lock_script_hash, vec![vec![1]], asset_type3, shard3, 10), - (lock_script_hash, vec![vec![1]], asset_type4, shard4, 10) - ] - ); - let transfer_tracker = transfer.tracker().unwrap(); - let transfer_tx = transaction!(seq: 0, fee: 11, transfer); - - assert_eq!( - Err(RuntimeError::InvalidAssetQuantity { - shard_id: shard4, - tracker: mint_tracker4, - index: 0, - expected: 20, - got: 10, - } - .into()), - state.apply(&transfer_tx, &H256::random().into(), &signer_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 25)), - (scheme: (shard3, asset_type3) => { supply: 10 }), - (scheme: (shard4, asset_type4) => { supply: 20 }), - (asset: (transfer_tracker, 0, shard3)), - (asset: (transfer_tracker, 1, shard3)), - (asset: (transfer_tracker, 0, shard4)), - (asset: (transfer_tracker, 1, shard4)), - (asset: (mint_tracker3, 0, shard3) => { asset_type: asset_type3, quantity: 10 }), - (asset: (mint_tracker4, 0, shard4) => { asset_type: asset_type4, quantity: 20 }) - ]); - } - - #[test] - fn cannot_create_a_shard_that_user_is_a_regular_account() { - let (sender, sender_public, _) = address(); - let (regular_account, regular_public, _) = address(); - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (metadata: shards: 0), - (account: sender => balance: 25), - (regular_key: sender_public => regular_public) - ]); - - let tx = transaction!(fee: 10, Action::CreateShard { users: vec![regular_account] }); - - assert_eq!( - Err(RuntimeError::NonActiveAccount { - address: regular_account, - name: "shard user".to_string(), - } - .into()), - state.apply(&tx, &H256::random().into(), ®ular_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 25)) - ]); - } - - #[test] - fn regular_account_cannot_be_shard_user() { - let (sender, sender_public, _) = address(); - let (regular_account, regular_public, _) = address(); - - let shard_id = 0; - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 25), - (shard: shard_id => owners: [sender], users: []), - (metadata: shards: 1), - (regular_key: sender_public => regular_public) - ]); - - let tx = transaction!(fee: 10, Action::SetShardUsers { users: vec![regular_account], shard_id }); - - assert_eq!( - Err(RuntimeError::NonActiveAccount { - address: regular_account, - name: "shard user".to_string(), - } - .into()), - state.apply(&tx, &H256::random().into(), ®ular_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 25)) - ]); - } - - #[test] - fn regular_account_cannot_be_shard_owner() { - let (sender, sender_public, _) = address(); - let (regular_account, regular_public, _) = address(); - - let shard_id = 0; - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 25), - (shard: shard_id => owners: [sender], users: []), - (metadata: shards: 1), - (regular_key: sender_public => regular_public) - ]); - - let tx = transaction!(fee: 10, Action::SetShardOwners { owners: vec![regular_account, sender], shard_id }); - - assert_eq!( - Err(RuntimeError::NonActiveAccount { - address: regular_account, - name: "shard owner".to_string(), - } - .into()), - state.apply(&tx, &H256::random().into(), ®ular_public, &get_test_client(), 0, 0, 0) - ); - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 25)) - ]); - } - - #[test] - fn regular_account_cannot_be_approver() { - let (sender, sender_public, _) = address(); - let (master_account, master_public, _) = address(); - let (regular_account, regular_public, _) = address(); - - let shard_id = 0x0; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: master_account => seq: 1), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1), - (regular_key: master_public => regular_public) - ]); - - let transaction = mint_asset!( - Box::new(asset_mint_output!(H160::random(), vec![], 30)), - "metadata".to_string(), - approver: regular_account - ); - let transaction_tracker = transaction.tracker().unwrap(); - let asset_type = Blake::blake(*transaction_tracker); - let tx = transaction!(fee: 11, transaction); - - assert_eq!( - Err(RuntimeError::NonActiveAccount { - address: regular_account, - name: "approver of asset".to_string(), - } - .into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 100)), - (scheme: (shard_id, asset_type)), - (asset: (transaction_tracker, 0, shard_id)) - ]); - } - - - #[test] - fn regular_account_cannot_be_registrar() { - let (sender, sender_public, _) = address(); - let (master_account, master_public, _) = address(); - let (regular_account, regular_public, _) = address(); - - let shard_id = 0x0; - - let mut state = get_temp_state(); - set_top_level_state!(state, [ - (account: sender => balance: 100), - (account: master_account => seq: 1), - (shard: shard_id => owners: [sender]), - (metadata: shards: 1), - (regular_key: master_public => regular_public) - ]); - - let transaction = mint_asset!( - Box::new(asset_mint_output!(H160::random(), vec![], 30)), - "metadata".to_string(), - registrar: regular_account - ); - let transaction_tracker = transaction.tracker().unwrap(); - let asset_type = Blake::blake(*transaction_tracker); - let tx = transaction!(fee: 11, transaction); - - assert_eq!( - Err(RuntimeError::NonActiveAccount { - address: regular_account, - name: "registrar of asset".to_string(), - } - .into()), - state.apply(&tx, &H256::random().into(), &sender_public, &get_test_client(), 0, 0, 0) - ); - - check_top_level_state!(state, [ - (account: sender => (seq: 0, balance: 100)), - (scheme: (shard_id, asset_type)), - (asset: (transaction_tracker, 0, shard_id)) - ]); - } } diff --git a/state/src/item/address.rs b/state/src/item/address.rs index 662b7f9487..2805f00693 100644 --- a/state/src/item/address.rs +++ b/state/src/item/address.rs @@ -23,31 +23,10 @@ macro_rules! define_address_constructor { $name(hash) } }; - (SHARD, $name:ident, $prefix:expr) => { - fn from_hash_with_shard_id>(input_hash: T, index: u64, shard_id: ::ctypes::ShardId) -> Self { - let mut hash: ::primitives::H256 = - ::ccrypto::Blake::blake_with_key(&input_hash, &::primitives::H128::from(index)); - hash[0..2].copy_from_slice(&[$prefix, 0]); - - debug_assert_eq!(::std::mem::size_of::(), ::std::mem::size_of::<::ctypes::ShardId>()); - let shard_id_bytes: [u8; 2] = shard_id.to_be_bytes(); - hash[2..4].copy_from_slice(&shard_id_bytes); - - $name(hash) - } - }; } macro_rules! define_id_getter { - (TOP) => { - }; - (SHARD) => { - pub fn shard_id(&self) -> ::ctypes::ShardId { - debug_assert_eq!(::std::mem::size_of::(), ::std::mem::size_of::()); - let shard_id_bytes: [u8; 2] = [self.0[2], self.0[3]]; - ::ctypes::ShardId::from_be_bytes(shard_id_bytes) - } - }; + (TOP) => {}; } macro_rules! impl_address { diff --git a/state/src/item/asset.rs b/state/src/item/asset.rs deleted file mode 100644 index 59846dba32..0000000000 --- a/state/src/item/asset.rs +++ /dev/null @@ -1,259 +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 . - -use ctypes::{ShardId, Tracker}; -use primitives::{Bytes, H160, H256}; -use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; - -use crate::CacheableItem; - -#[derive(Clone, Debug, PartialEq, RlpEncodable, RlpDecodable)] -pub struct Asset { - asset_type: H160, - quantity: u64, -} - -impl Asset { - pub fn new(asset_type: H160, quantity: u64) -> Self { - Self { - asset_type, - quantity, - } - } - - pub fn asset_type(&self) -> &H160 { - &self.asset_type - } - - pub fn quantity(&self) -> u64 { - self.quantity - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct OwnedAsset { - asset: Asset, - lock_script_hash: H160, - parameters: Vec, -} - -impl OwnedAsset { - pub fn new(asset_type: H160, lock_script_hash: H160, parameters: Vec, quantity: u64) -> Self { - Self { - asset: Asset { - asset_type, - quantity, - }, - lock_script_hash, - parameters, - } - } - - pub fn asset_type(&self) -> &H160 { - &self.asset.asset_type() - } - - pub fn lock_script_hash(&self) -> &H160 { - &self.lock_script_hash - } - - pub fn parameters(&self) -> &Vec { - &self.parameters - } - - pub fn quantity(&self) -> u64 { - self.asset.quantity() - } -} - -impl Default for OwnedAsset { - fn default() -> Self { - Self { - asset: Asset { - asset_type: H160::zero(), - quantity: 0, - }, - lock_script_hash: H160::zero(), - parameters: vec![], - } - } -} - -impl CacheableItem for OwnedAsset { - type Address = OwnedAssetAddress; - - fn is_null(&self) -> bool { - self.asset.quantity() == 0 - } -} - -const PREFIX: u8 = super::OWNED_ASSET_PREFIX; - -impl Encodable for OwnedAsset { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(6) - .append(&PREFIX) - .append(self.asset.asset_type()) - .append(&self.asset.quantity()) - .append(&self.lock_script_hash) - .append(&self.parameters) - // NOTE: The order_hash field removed. - .append(&Option::::None); - } -} - -impl Decodable for OwnedAsset { - fn decode(rlp: &Rlp) -> Result { - let item_count = rlp.item_count()?; - if rlp.item_count()? != 6 { - return Err(DecoderError::RlpInvalidLength { - expected: 6, - got: item_count, - }) - } - - let prefix = rlp.val_at::(0)?; - if PREFIX != prefix { - cdebug!(STATE, "{} is not an expected prefix for asset", prefix); - return Err(DecoderError::Custom("Unexpected prefix")) - } - let order_hash = rlp.val_at::>(5)?; - if let Some(h) = order_hash { - cdebug!(STATE, "order_hash must be None but Some({}) is given", h); - return Err(DecoderError::Custom("order_hash must be None")) - } - Ok(Self { - asset: Asset { - asset_type: rlp.val_at(1)?, - quantity: rlp.val_at(2)?, - }, - lock_script_hash: rlp.val_at(3)?, - parameters: rlp.val_at(4)?, - }) - } -} - -#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct OwnedAssetAddress(H256); - -impl_address!(SHARD, OwnedAssetAddress, PREFIX); - -impl OwnedAssetAddress { - pub fn new(tracker: Tracker, index: usize, shard_id: ShardId) -> Self { - debug_assert_eq!(::std::mem::size_of::(), ::std::mem::size_of::()); - let index = index as u64; - - Self::from_hash_with_shard_id(*tracker, index, shard_id) - } -} - -#[cfg(test)] -mod tests { - use rlp::rlp_encode_and_decode_test; - - use super::*; - - #[test] - fn asset_from_address() { - let tracker = { - let mut address; - 'address: loop { - address = H256::random(); - if address[0] == PREFIX { - continue - } - for a in address.iter().take(8).skip(1) { - if *a == 0 { - continue 'address - } - } - break - } - address.into() - }; - let shard_id = 0xBEEF; - let address1 = OwnedAssetAddress::new(tracker, 0, shard_id); - let address2 = OwnedAssetAddress::new(tracker, 1, shard_id); - assert_ne!(address1, address2); - assert_eq!(address1[0..2], [PREFIX, 0]); - assert_eq!(address1[2..4], [0xBE, 0xEF]); // shard id - assert_eq!(address2[0..2], [PREFIX, 0]); - assert_eq!(address2[2..4], [0xBE, 0xEF]); // shard id - } - - #[test] - fn parse_fail_return_none() { - let hash = { - let mut hash; - loop { - hash = H256::random(); - if hash[0] == PREFIX { - continue - } - for h in hash.iter().take(6).skip(1) { - if *h == 0 { - continue - } - } - break - } - hash - }; - let address = OwnedAssetAddress::from_hash(hash); - assert!(address.is_none()); - } - - #[test] - fn parse_return_some() { - let hash = { - let mut hash = H256::random(); - hash[0..6].copy_from_slice(&[PREFIX, 0, 0, 0, 0, 0]); - hash - }; - let address = OwnedAssetAddress::from_hash(hash); - assert_eq!(Some(OwnedAssetAddress(hash)), address); - } - - #[test] - fn shard_id() { - let origin = H256::random().into(); - let shard_id = 0xCAA; - let asset_address = OwnedAssetAddress::new(origin, 2, shard_id); - assert_eq!(shard_id, asset_address.shard_id()); - } - - #[test] - fn shard_id_from_hash() { - let hash = { - let mut hash = H256::random(); - hash[0] = PREFIX; - hash[1] = 0; - hash - }; - assert_eq!(::std::mem::size_of::(), ::std::mem::size_of::()); - let shard_id = (ShardId::from(hash[2]) << 8) + ShardId::from(hash[3]); - let asset_address = OwnedAssetAddress::from_hash(hash).unwrap(); - assert_eq!(shard_id, asset_address.shard_id()); - } - - #[test] - fn encode_and_decode_asset() { - rlp_encode_and_decode_test!(Asset { - asset_type: H160::random(), - quantity: 0, - }); - } -} diff --git a/state/src/item/asset_scheme.rs b/state/src/item/asset_scheme.rs deleted file mode 100644 index f03090d71e..0000000000 --- a/state/src/item/asset_scheme.rs +++ /dev/null @@ -1,271 +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 . - -use ccrypto::Blake; -use ckey::Address; -use ctypes::errors::RuntimeError; -use ctypes::{ShardId, Tracker}; -use primitives::{H160, H256}; -use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; - -use super::asset::Asset; -use crate::CacheableItem; - -#[derive(Clone, Debug, PartialEq)] -pub struct AssetScheme { - metadata: String, - supply: u64, - approver: Option
, - registrar: Option
, - allowed_script_hashes: Vec, - pool: Vec, - seq: usize, -} - -impl AssetScheme { - pub fn new( - metadata: String, - supply: u64, - approver: Option
, - registrar: Option
, - allowed_script_hashes: Vec, - ) -> Self { - Self { - metadata, - supply, - approver, - registrar, - allowed_script_hashes, - pool: Vec::new(), - seq: 0, - } - } - - pub fn new_with_pool( - metadata: String, - supply: u64, - approver: Option
, - registrar: Option
, - allowed_script_hashes: Vec, - pool: Vec, - ) -> Self { - Self { - metadata, - supply, - approver, - registrar, - allowed_script_hashes, - pool, - seq: 0, - } - } - - pub fn metadata(&self) -> &String { - &self.metadata - } - - pub fn supply(&self) -> u64 { - self.supply - } - - pub fn approver(&self) -> &Option
{ - &self.approver - } - - pub fn registrar(&self) -> &Option
{ - &self.registrar - } - - pub fn allowed_script_hashes(&self) -> &[H160] { - &self.allowed_script_hashes - } - - pub fn seq(&self) -> usize { - self.seq - } - - pub fn is_permissioned(&self) -> bool { - self.approver.is_some() - } - - pub fn is_regulated(&self) -> bool { - self.registrar.is_some() - } - - pub fn is_allowed_script_hash(&self, lock_script_hash: &H160) -> bool { - let allowed_hashes = self.allowed_script_hashes(); - allowed_hashes.is_empty() || allowed_hashes.contains(lock_script_hash) - } - - pub fn pool(&self) -> &[Asset] { - &self.pool - } - - pub fn change_data( - &mut self, - metadata: String, - approver: Option
, - registrar: Option
, - allowed_script_hashes: Vec, - ) { - self.metadata = metadata; - self.approver = approver; - self.registrar = registrar; - self.allowed_script_hashes = allowed_script_hashes; - } - - pub fn increase_supply(&mut self, quantity: u64) -> Result { - let headroom = std::u64::MAX - self.supply; - if quantity > headroom { - return Err(RuntimeError::AssetSupplyOverflow) - } - let previous = self.supply; - self.supply += quantity; - Ok(previous) - } - - pub fn increase_seq(&mut self) { - self.seq += 1; - } - - pub fn reduce_supply(&mut self, quantity: u64) -> u64 { - assert!(self.supply >= quantity, "AssetScheme supply shouldn't be depleted"); - let previous = self.supply; - self.supply -= quantity; - previous - } -} - -const PREFIX: u8 = super::ASSET_SCHEME_PREFIX; - -impl Default for AssetScheme { - fn default() -> Self { - Self::new("".to_string(), 0, None, None, Vec::new()) - } -} - -impl Encodable for AssetScheme { - fn rlp_append(&self, s: &mut RlpStream) { - if self.seq == 0 { - s.begin_list(7); - } else { - s.begin_list(8); - } - s.append(&PREFIX) - .append(&self.metadata) - .append(&self.supply) - .append(&self.approver) - .append(&self.registrar) - .append_list(&self.allowed_script_hashes) - .append_list(&self.pool); - if self.seq != 0 { - s.append(&self.seq); - } - } -} - -impl Decodable for AssetScheme { - fn decode(rlp: &Rlp) -> Result { - let seq = match rlp.item_count()? { - 7 => 0, - 8 => rlp.val_at(7)?, - item_count => { - return Err(DecoderError::RlpInvalidLength { - got: item_count, - expected: 7, - }) - } - }; - - let prefix = rlp.val_at::(0)?; - if PREFIX != prefix { - cdebug!(STATE, "{} is not an expected prefix for asset scheme", prefix); - return Err(DecoderError::Custom("Unexpected prefix")) - } - Ok(Self { - metadata: rlp.val_at(1)?, - supply: rlp.val_at(2)?, - approver: rlp.val_at(3)?, - registrar: rlp.val_at(4)?, - allowed_script_hashes: rlp.list_at(5)?, - pool: rlp.list_at(6)?, - seq, - }) - } -} - -#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct AssetSchemeAddress(H256); - -impl_address!(SHARD, AssetSchemeAddress, PREFIX); - -impl AssetSchemeAddress { - pub fn new(asset_type: H160, shard_id: ShardId) -> Self { - let index = ::std::u64::MAX; - - Self::from_hash_with_shard_id(asset_type, index, shard_id) - } - - pub fn new_from_tracker(tracker: Tracker, shard_id: ShardId) -> Self { - let asset_type = Blake::blake(*tracker); - Self::new(asset_type, shard_id) - } -} - -impl CacheableItem for AssetScheme { - type Address = AssetSchemeAddress; - - fn is_null(&self) -> bool { - self.supply == 0 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn asset_from_address() { - let origin = H160::random(); - let shard_id = 0xBEE; - let asset_address = AssetSchemeAddress::new(origin, shard_id); - let hash: H256 = asset_address.into(); - assert_eq!(hash[0..2], [PREFIX, 0]); - assert_eq!(hash[2..4], [0x0B, 0xEE]); // shard id - } - - #[test] - fn shard_id() { - let origin = H160::random(); - let shard_id = 0xCAA; - let asset_scheme_address = AssetSchemeAddress::new(origin, shard_id); - assert_eq!(shard_id, asset_scheme_address.shard_id()); - } - - #[test] - fn shard_id_from_hash() { - let hash = { - let mut hash = H256::random(); - hash[0] = PREFIX; - hash[1] = 0; - hash - }; - assert_eq!(::std::mem::size_of::(), ::std::mem::size_of::()); - let shard_id = (ShardId::from(hash[2]) << 8) + ShardId::from(hash[3]); - let asset_scheme_address = AssetSchemeAddress::from_hash(hash).unwrap(); - assert_eq!(shard_id, asset_scheme_address.shard_id()); - } -} diff --git a/state/src/item/metadata.rs b/state/src/item/metadata.rs index 6ad74076b3..c8f00af45a 100644 --- a/state/src/item/metadata.rs +++ b/state/src/item/metadata.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 ctypes::{CommonParams, ShardId, TxHash}; +use ctypes::{CommonParams, TxHash}; use primitives::H256; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; @@ -28,8 +28,6 @@ struct TermMetadata { #[derive(Clone, Debug, PartialEq)] pub struct Metadata { - number_of_shards: ShardId, - number_of_initial_shards: ShardId, hashes: Vec, term: TermMetadata, seq: u64, @@ -37,10 +35,8 @@ pub struct Metadata { } impl Metadata { - pub fn new(number_of_shards: ShardId) -> Self { + pub fn new() -> Self { Self { - number_of_shards, - number_of_initial_shards: number_of_shards, hashes: vec![], term: Default::default(), seq: 0, @@ -48,35 +44,6 @@ impl Metadata { } } - pub fn number_of_shards(&self) -> &ShardId { - &self.number_of_shards - } - - pub fn add_shard(&mut self, tx_hash: TxHash) -> ShardId { - let r = self.number_of_shards; - self.number_of_shards += 1; - self.hashes.push(tx_hash); - r - } - - #[cfg(test)] - pub fn set_number_of_shards(&mut self, number_of_shards: ShardId) { - assert!(self.number_of_shards <= number_of_shards); - assert_eq!(0, self.hashes.len()); - self.number_of_shards = number_of_shards; - self.number_of_initial_shards = number_of_shards; - } - - pub fn shard_id_by_hash(&self, tx_hash: &TxHash) -> Option { - debug_assert_eq!(::std::mem::size_of::(), ::std::mem::size_of::<::ctypes::ShardId>()); - assert!(self.hashes.len() < ::std::u16::MAX as usize); - self.hashes.iter().enumerate().find(|(_index, hash)| tx_hash == *hash).map(|(index, _)| { - let index = index as ShardId + self.number_of_initial_shards; - assert!(index < self.number_of_shards); - index - }) - } - pub fn seq(&self) -> u64 { self.seq } @@ -110,15 +77,16 @@ impl Metadata { impl Default for Metadata { fn default() -> Self { - Self::new(0) + Self::new() } } impl CacheableItem for Metadata { type Address = MetadataAddress; + // FIXME: I'm not sure of it. fn is_null(&self) -> bool { - self.number_of_shards == 0 + self.hashes.is_empty() && self.seq == 0 } } @@ -126,7 +94,7 @@ const PREFIX: u8 = super::METADATA_PREFIX; impl Encodable for Metadata { fn rlp_append(&self, s: &mut RlpStream) { - const INITIAL_LEN: usize = 4; + const INITIAL_LEN: usize = 2; const TERM_LEN: usize = 2; const PARAMS_LEN: usize = 2; let mut len = INITIAL_LEN; @@ -143,11 +111,7 @@ impl Encodable for Metadata { } len += PARAMS_LEN; } - s.begin_list(len) - .append(&PREFIX) - .append(&self.number_of_shards) - .append(&self.number_of_initial_shards) - .append_list(&self.hashes); + s.begin_list(len).append(&PREFIX).append_list(&self.hashes); if term_changed { s.append(&self.term.last_term_finished_block_num).append(&self.term.current_term_id); } @@ -165,27 +129,27 @@ impl Encodable for Metadata { impl Decodable for Metadata { fn decode(rlp: &Rlp) -> Result { let (term, seq, params) = match rlp.item_count()? { - 4 => (TermMetadata::default(), 0, None), - 6 => ( + 2 => (TermMetadata::default(), 0, None), + 4 => ( TermMetadata { - last_term_finished_block_num: rlp.val_at(4)?, - current_term_id: rlp.val_at(5)?, + last_term_finished_block_num: rlp.val_at(2)?, + current_term_id: rlp.val_at(3)?, }, 0, None, ), - 8 => ( + 6 => ( TermMetadata { - last_term_finished_block_num: rlp.val_at(4)?, - current_term_id: rlp.val_at(5)?, + last_term_finished_block_num: rlp.val_at(2)?, + current_term_id: rlp.val_at(3)?, }, - rlp.val_at(6)?, - Some(rlp.val_at(7)?), + rlp.val_at(4)?, + Some(rlp.val_at(5)?), ), item_count => { return Err(DecoderError::RlpInvalidLength { got: item_count, - expected: 4, + expected: 2, }) } }; @@ -195,9 +159,7 @@ impl Decodable for Metadata { return Err(DecoderError::Custom("Unexpected prefix")) } Ok(Self { - number_of_shards: rlp.val_at(1)?, - number_of_initial_shards: rlp.val_at(2)?, - hashes: rlp.list_at(3)?, + hashes: rlp.list_at(1)?, term, seq, params, @@ -260,23 +222,19 @@ mod tests { #[test] fn check_backward_compatibility() { let metadata = Metadata { - number_of_shards: 10, - number_of_initial_shards: 1, hashes: vec![], term: Default::default(), seq: 0, params: None, }; - let mut rlp = RlpStream::new_list(4); - rlp.append(&PREFIX).append(&10u16).append(&1u16).append_list::(&[]); + let mut rlp = RlpStream::new_list(2); + rlp.append(&PREFIX).append_list::(&[]); assert_eq!(metadata.rlp_bytes(), rlp.drain()); } #[test] fn metadata_without_term_with_seq() { let metadata = Metadata { - number_of_shards: 10, - number_of_initial_shards: 1, hashes: vec![], term: Default::default(), seq: 3, @@ -288,8 +246,6 @@ mod tests { #[test] fn metadata_with_term_without_seq() { let metadata = Metadata { - number_of_shards: 10, - number_of_initial_shards: 1, hashes: vec![], term: TermMetadata { last_term_finished_block_num: 1, @@ -304,8 +260,6 @@ mod tests { #[test] fn metadata_with_term_and_seq() { let metadata = Metadata { - number_of_shards: 10, - number_of_initial_shards: 1, hashes: vec![], term: TermMetadata { last_term_finished_block_num: 1, diff --git a/state/src/item/mod.rs b/state/src/item/mod.rs index 6eb88c9a7b..26eb41ab8c 100644 --- a/state/src/item/mod.rs +++ b/state/src/item/mod.rs @@ -19,17 +19,11 @@ mod address; pub mod account; pub mod action_data; -pub mod asset; -pub mod asset_scheme; pub mod metadata; pub mod regular_account; -pub mod shard; pub mod text; -const OWNED_ASSET_PREFIX: u8 = b'A'; const ADDRESS_PREFIX: u8 = b'C'; -const SHARD_PREFIX: u8 = b'H'; const METADATA_PREFIX: u8 = b'M'; const REGULAR_ACCOUNT_PREFIX: u8 = b'R'; -const ASSET_SCHEME_PREFIX: u8 = b'S'; const TEXT_PREFIX: u8 = b'T'; diff --git a/state/src/item/shard.rs b/state/src/item/shard.rs deleted file mode 100644 index a56b4921af..0000000000 --- a/state/src/item/shard.rs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2018 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 ccrypto::BLAKE_NULL_RLP; -use ckey::Address; -use ctypes::ShardId; -use primitives::H256; -use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; - -use crate::CacheableItem; - -#[derive(Clone, Debug)] -pub struct Shard { - root: H256, - owners: Vec
, - users: Vec
, -} - -impl Shard { - pub fn new(shard_root: H256, owners: Vec
, users: Vec
) -> Self { - Self { - root: shard_root, - owners, - users, - } - } - - pub fn root(&self) -> &H256 { - &self.root - } - - pub fn set_root(&mut self, root: H256) { - self.root = root; - } - - pub fn owners(&self) -> &[Address] { - debug_assert_ne!(Vec::
::new(), self.owners); - &self.owners - } - - pub fn set_owners(&mut self, owners: Vec
) { - debug_assert_ne!(Vec::
::new(), owners); - self.owners = owners; - } - - pub fn users(&self) -> &[Address] { - &self.users - } - - pub fn set_users(&mut self, users: Vec
) { - self.users = users; - } -} - -impl Default for Shard { - fn default() -> Self { - Self::new(BLAKE_NULL_RLP, vec![], vec![]) - } -} - -impl CacheableItem for Shard { - type Address = ShardAddress; - - fn is_null(&self) -> bool { - self.root == BLAKE_NULL_RLP - } -} - -const PREFIX: u8 = super::SHARD_PREFIX; - -impl Encodable for Shard { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(4).append(&PREFIX).append(&self.root).append_list(&self.owners).append_list(&self.users); - } -} - -impl Decodable for Shard { - fn decode(rlp: &Rlp) -> Result { - let item_count = rlp.item_count()?; - if item_count != 4 { - return Err(DecoderError::RlpInvalidLength { - expected: 4, - got: item_count, - }) - } - let prefix = rlp.val_at::(0)?; - if PREFIX != prefix { - cdebug!(STATE, "{} is not an expected prefix for asset", prefix); - return Err(DecoderError::Custom("Unexpected prefix")) - } - Ok(Self { - root: rlp.val_at(1)?, - owners: rlp.list_at(2)?, - users: rlp.list_at(3)?, - }) - } -} - -#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct ShardAddress(H256); - -impl_address!(TOP, ShardAddress, PREFIX); - -impl ShardAddress { - pub fn new(shard_id: ShardId) -> Self { - Self::from_transaction_hash(H256::from_slice(b"shard"), shard_id.into()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn different_shard_id_makes_different_address() { - let address1 = ShardAddress::new(0); - let address2 = ShardAddress::new(1); - assert_ne!(address1, address2); - assert_eq!(address1[0], PREFIX); - assert_eq!(address2[0], PREFIX); - } - - #[test] - fn parse_fail_return_none() { - let hash = { - let mut hash; - loop { - hash = H256::random(); - if hash[0] == PREFIX { - continue - } - break - } - hash - }; - let address = ShardAddress::from_hash(hash); - assert!(address.is_none()); - } - - #[test] - fn parse_return_some() { - let hash = { - let mut hash = H256::random(); - hash[0] = PREFIX; - hash - }; - let address = ShardAddress::from_hash(hash); - assert_eq!(Some(ShardAddress(hash)), address); - } -} diff --git a/state/src/lib.rs b/state/src/lib.rs index e940524ec5..46964e6d36 100644 --- a/state/src/lib.rs +++ b/state/src/lib.rs @@ -21,7 +21,6 @@ extern crate codechain_merkle as cmerkle; extern crate codechain_logger as clogger; extern crate codechain_key as ckey; extern crate codechain_types as ctypes; -extern crate codechain_vm as cvm; extern crate kvdb; extern crate kvdb_memorydb; extern crate lru_cache; @@ -50,16 +49,13 @@ 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::impls::{ShardLevelState, TopLevelState}; +pub use crate::impls::TopLevelState; pub use crate::item::account::Account; pub use crate::item::action_data::ActionData; -pub use crate::item::asset::{Asset, OwnedAsset, OwnedAssetAddress}; -pub use crate::item::asset_scheme::{AssetScheme, AssetSchemeAddress}; pub use crate::item::metadata::{Metadata, MetadataAddress}; pub use crate::item::regular_account::{RegularAccount, RegularAccountAddress}; -pub use crate::item::shard::{Shard, ShardAddress}; pub use crate::item::text::Text; -pub use crate::traits::{ShardState, ShardStateView, StateWithCache, TopState, TopStateView}; +pub use crate::traits::{StateWithCache, TopState, TopStateView}; use crate::cache::CacheableItem; diff --git a/state/src/tests.rs b/state/src/tests.rs index 00c7a04d11..291ad68a35 100644 --- a/state/src/tests.rs +++ b/state/src/tests.rs @@ -19,29 +19,17 @@ pub mod helpers { use cdb::AsHashDB; use cmerkle::{TrieFactory, TrieMut}; - use ctypes::{BlockNumber, Tracker}; - use cvm::ChainTimeInfo; + use kvdb::KeyValueDB; use kvdb_memorydb; use primitives::H256; use rlp::Encodable; - use crate::impls::TopLevelState; use crate::{FindActionHandler, Metadata, MetadataAddress, StateDB}; pub struct TestClient {} - impl ChainTimeInfo for TestClient { - fn transaction_block_age(&self, _: &Tracker, _parent_block_number: BlockNumber) -> Option { - Some(0) - } - - fn transaction_time_age(&self, _: &Tracker, _parent_block_timestamp: u64) -> Option { - Some(0) - } - } - impl FindActionHandler for TestClient {} pub fn get_memory_db() -> Arc { @@ -83,7 +71,7 @@ pub mod helpers { // init trie and reset root too null { let mut t = TrieFactory::create(db.as_hashdb_mut(), &mut root); - t.insert(&*MetadataAddress::new(), &Metadata::new(1).rlp_bytes()).unwrap(); + t.insert(&*MetadataAddress::new(), &Metadata::new().rlp_bytes()).unwrap(); } diff --git a/state/src/traits.rs b/state/src/traits.rs index 40d94688f7..e622563bdc 100644 --- a/state/src/traits.rs +++ b/state/src/traits.rs @@ -16,15 +16,10 @@ use ckey::{public_to_address, Address, Public, Signature}; use cmerkle::Result as TrieResult; -use ctypes::transaction::ShardTransaction; -use ctypes::{BlockNumber, CommonParams, ShardId, Tracker, TxHash}; -use cvm::ChainTimeInfo; -use primitives::{Bytes, H160, H256}; +use ctypes::{CommonParams, TxHash}; +use primitives::{Bytes, H256}; -use crate::{ - Account, ActionData, AssetScheme, CacheableItem, Metadata, OwnedAsset, RegularAccount, Shard, StateDB, StateResult, - Text, -}; +use crate::{Account, ActionData, CacheableItem, Metadata, RegularAccount, StateDB, StateResult, Text}; pub trait TopStateView { @@ -84,70 +79,11 @@ pub trait TopStateView { fn metadata(&self) -> TrieResult>; - fn number_of_shards(&self) -> TrieResult { - Ok(*self.metadata()?.expect("Metadata must exist").number_of_shards()) - } - - fn shard_id_by_hash(&self, tx_hash: &TxHash) -> TrieResult> { - Ok(self.metadata()?.and_then(|metadata| metadata.shard_id_by_hash(tx_hash))) - } - - fn shard(&self, shard_id: ShardId) -> TrieResult>; - fn shard_state<'db>(&'db self, shard_id: ShardId) -> TrieResult>>; - - fn shard_root(&self, shard_id: ShardId) -> TrieResult> { - Ok(self.shard(shard_id)?.map(|shard| *shard.root())) - } - - fn shard_owners(&self, shard_id: ShardId) -> TrieResult>> { - Ok(self.shard(shard_id)?.map(|shard| shard.owners().to_vec())) - } - - fn shard_users(&self, shard_id: ShardId) -> TrieResult>> { - Ok(self.shard(shard_id)?.map(|shard| shard.users().to_vec())) - } - - /// Get the asset scheme. - fn asset_scheme(&self, shard_id: ShardId, asset_type: H160) -> TrieResult> { - match self.shard_state(shard_id)? { - None => Ok(None), - Some(state) => state.asset_scheme(asset_type), - } - } - - /// Get the asset. - fn asset(&self, shard_id: ShardId, tracker: Tracker, index: usize) -> TrieResult> { - match self.shard_state(shard_id)? { - None => Ok(None), - Some(state) => state.asset(tracker, index), - } - } - fn text(&self, key: &H256) -> TrieResult>; fn action_data(&self, key: &H256) -> TrieResult>; } -pub trait ShardStateView { - /// Get the asset scheme. - fn asset_scheme(&self, asset_type: H160) -> TrieResult>; - /// Get the asset. - fn asset(&self, tracker: Tracker, index: usize) -> TrieResult>; -} - -pub trait ShardState { - fn apply( - &mut self, - transaction: &ShardTransaction, - sender: &Address, - shard_owners: &[Address], - approvers: &[Address], - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, - ) -> StateResult<()>; -} - pub trait TopState { /// Remove an existing account. fn kill_account(&mut self, account: &Address); @@ -166,14 +102,6 @@ pub trait TopState { /// Set the regular key of account `owner_public` fn set_regular_key(&mut self, owner_public: &Public, key: &Public) -> StateResult<()>; - fn create_shard(&mut self, fee_payer: &Address, tx_hash: TxHash, users: Vec
) -> StateResult<()>; - fn change_shard_owners(&mut self, shard_id: ShardId, owners: &[Address], sender: &Address) -> StateResult<()>; - fn change_shard_users(&mut self, shard_id: ShardId, users: &[Address], sender: &Address) -> StateResult<()>; - - fn set_shard_root(&mut self, shard_id: ShardId, new_root: H256) -> StateResult<()>; - fn set_shard_owners(&mut self, shard_id: ShardId, new_owners: Vec
) -> StateResult<()>; - fn set_shard_users(&mut self, shard_id: ShardId, new_users: Vec
) -> StateResult<()>; - fn store_text(&mut self, key: &TxHash, text: Text, sig: &Signature) -> StateResult<()>; fn remove_text(&mut self, key: &TxHash, sig: &Signature) -> StateResult<()>; From e1f1bb7e15c037b89654ae1fd6f3923aeabf8bd6 Mon Sep 17 00:00:00 2001 From: Park Juhyung Date: Fri, 20 Dec 2019 18:25:55 +0900 Subject: [PATCH 5/6] Remove tracker and vm --- Cargo.lock | 14 - Cargo.toml | 2 - core/Cargo.toml | 1 - core/src/block.rs | 9 +- core/src/blockchain/blockchain.rs | 12 +- core/src/blockchain/body_db.rs | 149 +-- core/src/blockchain/extras.rs | 233 +---- core/src/blockchain/invoice_db.rs | 93 +- core/src/blockchain/mod.rs | 2 +- core/src/client/client.rs | 84 +- core/src/client/importer.rs | 33 +- core/src/client/mod.rs | 33 +- core/src/client/test_client.rs | 27 +- core/src/codechain_machine.rs | 131 +-- core/src/consensus/stake/action_data.rs | 2 - core/src/consensus/tendermint/engine.rs | 7 +- .../consensus/tendermint/vote_collector.rs | 1 - core/src/invoice.rs | 3 +- core/src/lib.rs | 4 +- core/src/miner/mem_pool.rs | 204 +--- core/src/miner/mem_pool_types.rs | 41 - core/src/miner/miner.rs | 124 +-- core/src/miner/mod.rs | 14 +- core/src/scheme/mod.rs | 1 - core/src/scheme/pod_shard_metadata.rs | 43 - core/src/scheme/pod_state.rs | 31 - core/src/scheme/scheme.rs | 18 +- core/src/transaction.rs | 42 +- core/src/verification/canon_verifier.rs | 3 +- core/src/verification/noop_verifier.rs | 3 +- core/src/verification/verification.rs | 29 +- core/src/verification/verifier.rs | 2 - foundry/config/mod.rs | 4 - json/src/scheme/mod.rs | 4 +- json/src/scheme/scheme.rs | 5 +- json/src/scheme/shard.rs | 96 -- json/src/scheme/state.rs | 3 +- rpc/src/v1/errors.rs | 9 - rpc/src/v1/impls/chain.rs | 45 +- rpc/src/v1/impls/mempool.rs | 11 +- rpc/src/v1/traits/chain.rs | 18 +- rpc/src/v1/traits/mempool.rs | 6 +- rpc/src/v1/types/action.rs | 650 +----------- rpc/src/v1/types/asset.rs | 34 - rpc/src/v1/types/asset_input.rs | 85 -- rpc/src/v1/types/asset_output.rs | 90 -- rpc/src/v1/types/asset_scheme.rs | 34 - rpc/src/v1/types/mod.rs | 12 +- rpc/src/v1/types/transaction.rs | 8 +- state/src/impls/top_level.rs | 4 - sync/src/block/message/response.rs | 24 - sync/src/transaction/message.rs | 21 - types/src/block_hash.rs | 17 - types/src/errors/runtime_error.rs | 245 +---- types/src/errors/syntax_error.rs | 48 - types/src/lib.rs | 5 - types/src/tracker.rs | 109 -- types/src/transaction/action.rs | 895 +--------------- types/src/transaction/asset_out_point.rs | 29 - types/src/transaction/input.rs | 27 - types/src/transaction/mod.rs | 10 - types/src/transaction/output.rs | 35 - types/src/transaction/partial_hashing.rs | 29 - types/src/transaction/shard.rs | 966 ------------------ types/src/transaction/transaction.rs | 25 +- types/src/tx_hash.rs | 17 - types/src/util/mod.rs | 1 - types/src/util/tag.rs | 136 --- vm/Cargo.toml | 17 - vm/src/decoder.rs | 179 ---- vm/src/executor.rs | 519 ---------- vm/src/instruction.rs | 82 -- vm/src/lib.rs | 33 - vm/src/opcode.rs | 40 - vm/tests/chk_multi_sig.rs | 752 -------------- vm/tests/chk_sig.rs | 545 ---------- vm/tests/common/mod.rs | 48 - vm/tests/executor.rs | 924 ----------------- 78 files changed, 163 insertions(+), 8128 deletions(-) delete mode 100644 core/src/scheme/pod_shard_metadata.rs delete mode 100644 json/src/scheme/shard.rs delete mode 100644 rpc/src/v1/types/asset.rs delete mode 100644 rpc/src/v1/types/asset_input.rs delete mode 100644 rpc/src/v1/types/asset_output.rs delete mode 100644 rpc/src/v1/types/asset_scheme.rs delete mode 100644 types/src/tracker.rs delete mode 100644 types/src/transaction/asset_out_point.rs delete mode 100644 types/src/transaction/input.rs delete mode 100644 types/src/transaction/output.rs delete mode 100644 types/src/transaction/partial_hashing.rs delete mode 100644 types/src/transaction/shard.rs delete mode 100644 types/src/util/tag.rs delete mode 100644 vm/Cargo.toml delete mode 100644 vm/src/decoder.rs delete mode 100644 vm/src/executor.rs delete mode 100644 vm/src/instruction.rs delete mode 100644 vm/src/lib.rs delete mode 100644 vm/src/opcode.rs delete mode 100644 vm/tests/chk_multi_sig.rs delete mode 100644 vm/tests/chk_sig.rs delete mode 100644 vm/tests/common/mod.rs delete mode 100644 vm/tests/executor.rs diff --git a/Cargo.lock b/Cargo.lock index 67df2ceaeb..53f0e5f54a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -265,7 +265,6 @@ dependencies = [ "codechain-stratum", "codechain-timer", "codechain-types", - "codechain-vm", "crossbeam-channel", "cuckoo", "hyper 0.10.0-a.0", @@ -582,18 +581,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "codechain-vm" -version = "0.1.0" -dependencies = [ - "codechain-crypto", - "codechain-key", - "codechain-types", - "primitives", - "rlp", - "secp256k1", -] - [[package]] name = "colored" version = "1.6.0" @@ -967,7 +954,6 @@ dependencies = [ "codechain-sync", "codechain-timer", "codechain-types", - "codechain-vm", "ctrlc", "env_logger 0.5.10", "fdlimit", diff --git a/Cargo.toml b/Cargo.toml index 27e729fc0d..c682bf15f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,6 @@ codechain-state = { path = "state" } codechain-sync = { path = "sync" } codechain-timer = { path = "util/timer" } codechain-types = { path = "types" } -codechain-vm = { path = "vm" } codechain-stratum = { path = "stratum" } ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" } fdlimit = "0.1" @@ -74,5 +73,4 @@ members = [ "rpc", "sync", "types", - "vm", ] diff --git a/core/Cargo.toml b/core/Cargo.toml index d08eb40d6d..b680c93ba7 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -18,7 +18,6 @@ codechain-state = { path = "../state" } codechain-timer = { path = "../util/timer" } codechain-types = { path = "../types" } codechain-stratum = { path = "../stratum" } -codechain-vm = { path = "../vm" } crossbeam-channel = "0.3" cuckoo = { git = "https://github.com/CodeChain-io/rust-cuckoo.git", rev = "280cab9c" } hyper = { git = "https://github.com/paritytech/hyper", default-features = false } diff --git a/core/src/block.rs b/core/src/block.rs index 9a6584d090..024d45007f 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -24,7 +24,6 @@ use ctypes::errors::HistoryError; use ctypes::header::{Header, Seal}; use ctypes::util::unexpected::Mismatch; use ctypes::{BlockNumber, CommonParams, TxHash}; -use cvm::ChainTimeInfo; use primitives::{Bytes, H256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; @@ -151,7 +150,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, @@ -164,7 +163,6 @@ impl<'x> OpenBlock<'x> { } let hash = tx.hash(); - let tracker = tx.tracker(); let error = match self.block.state.apply( &tx, &hash, @@ -183,7 +181,6 @@ impl<'x> OpenBlock<'x> { }; self.block.invoices.push(Invoice { hash, - tracker, error: error.clone().map(|err| err.to_string()), }); @@ -194,7 +191,7 @@ impl<'x> OpenBlock<'x> { } /// Push transactions onto the block. - pub fn push_transactions( + pub fn push_transactions( &mut self, transactions: &[SignedTransaction], client: &C, @@ -481,7 +478,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/blockchain/blockchain.rs b/core/src/blockchain/blockchain.rs index 0ed70027f2..4ea40ccc3a 100644 --- a/core/src/blockchain/blockchain.rs +++ b/core/src/blockchain/blockchain.rs @@ -16,7 +16,7 @@ use std::sync::Arc; -use ctypes::{BlockHash, BlockNumber, Tracker, TxHash}; +use ctypes::{BlockHash, BlockNumber, TxHash}; use kvdb::{DBTransaction, KeyValueDB}; use parking_lot::RwLock; use primitives::H256; @@ -141,7 +141,7 @@ impl BlockChain { self.body_db.insert_body(batch, &new_block); self.body_db.update_best_block(batch, &best_block_changed); for invoice in invoices { - self.invoice_db.insert_invoice(batch, invoice.hash, invoice.tracker, invoice.error); + self.invoice_db.insert_invoice(batch, invoice.hash, invoice.error); } if let Some(best_block_hash) = best_block_changed.new_best_hash() { @@ -415,10 +415,6 @@ impl BodyProvider for BlockChain { self.body_db.transaction_address(hash) } - fn transaction_address_by_tracker(&self, tracker: &Tracker) -> Option { - self.body_db.transaction_address_by_tracker(tracker) - } - fn block_body(&self, hash: &BlockHash) -> Option { self.body_db.block_body(hash) } @@ -430,10 +426,6 @@ impl InvoiceProvider for BlockChain { self.invoice_db.is_known_error_hint(hash) } - fn error_hints_by_tracker(&self, tracker: &Tracker) -> Vec<(TxHash, Option)> { - self.invoice_db.error_hints_by_tracker(tracker) - } - fn error_hint(&self, hash: &TxHash) -> Option { self.invoice_db.error_hint(hash) } diff --git a/core/src/blockchain/body_db.rs b/core/src/blockchain/body_db.rs index 365b5b3532..d9af236d96 100644 --- a/core/src/blockchain/body_db.rs +++ b/core/src/blockchain/body_db.rs @@ -14,11 +14,11 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::mem; use std::sync::Arc; -use ctypes::{BlockHash, Tracker, TxHash}; +use ctypes::{BlockHash, TxHash}; use kvdb::{DBTransaction, KeyValueDB}; use lru_cache::LruCache; use parking_lot::{Mutex, RwLock}; @@ -27,10 +27,10 @@ use rlp::RlpStream; use rlp_compress::{blocks_swapper, compress, decompress}; use super::block_info::BestBlockChanged; -use super::extras::{TransactionAddress, TransactionAddresses}; +use super::extras::TransactionAddress; use crate::db::{self, CacheUpdatePolicy, Readable, Writable}; +use crate::encoded; use crate::views::BlockView; -use crate::{encoded, UnverifiedTransaction}; const BODY_CACHE_SIZE: usize = 1000; @@ -40,14 +40,9 @@ pub struct BodyDB { address_by_hash_cache: RwLock>, pending_addresses_by_hash: RwLock>>, - addresses_by_tracker_cache: Mutex>, - pending_addresses_by_tracker: Mutex>>, - db: Arc, } -type TrackerAndAddress = (Tracker, TransactionAddresses); - impl BodyDB { /// Create new instance of blockchain from given Genesis. pub fn new(genesis: &BlockView, db: Arc) -> Self { @@ -56,9 +51,6 @@ impl BodyDB { address_by_hash_cache: RwLock::new(HashMap::new()), pending_addresses_by_hash: RwLock::new(HashMap::new()), - addresses_by_tracker_cache: Default::default(), - pending_addresses_by_tracker: Default::default(), - db, }; @@ -91,19 +83,12 @@ impl BodyDB { pub fn update_best_block(&self, batch: &mut DBTransaction, best_block_changed: &BestBlockChanged) { let mut pending_addresses_by_hash = self.pending_addresses_by_hash.write(); - let mut pending_addresses_by_tracker = self.pending_addresses_by_tracker.lock(); batch.extend_with_option_cache( db::COL_EXTRA, &mut *pending_addresses_by_hash, self.new_transaction_address_entries(best_block_changed), CacheUpdatePolicy::Overwrite, ); - batch.extend_with_option_cache( - db::COL_EXTRA, - &mut *pending_addresses_by_tracker, - self.new_transaction_addresses_entries(best_block_changed), - CacheUpdatePolicy::Overwrite, - ); } /// Apply pending insertion updates @@ -111,9 +96,6 @@ impl BodyDB { let mut address_by_hash_cache = self.address_by_hash_cache.write(); let mut pending_addresses_by_hash = self.pending_addresses_by_hash.write(); - let mut addresses_by_tracker_cache = self.addresses_by_tracker_cache.lock(); - let mut pending_addresses_by_tracker = self.pending_addresses_by_tracker.lock(); - let new_txs_by_hash = mem::replace(&mut *pending_addresses_by_hash, HashMap::new()); let (retracted_txs, enacted_txs) = new_txs_by_hash.into_iter().partition::, _>(|&(_, ref value)| value.is_none()); @@ -124,17 +106,6 @@ impl BodyDB { for hash in retracted_txs.keys() { address_by_hash_cache.remove(hash); } - - let new_txs_by_tracker = mem::replace(&mut *pending_addresses_by_tracker, HashMap::new()); - let (removed_transactions, added_transactions) = - new_txs_by_tracker.into_iter().partition::, _>(|&(_, ref value)| value.is_none()); - - addresses_by_tracker_cache - .extend(added_transactions.into_iter().map(|(k, v)| (k, v.expect("Transactions were partitioned; qed")))); - - for hash in removed_transactions.keys() { - addresses_by_tracker_cache.remove(hash); - } } /// This function returns modified transaction addresses. @@ -182,93 +153,6 @@ impl BodyDB { } } - fn new_transaction_addresses_entries( - &self, - best_block_changed: &BestBlockChanged, - ) -> HashMap> { - let block_hash = if let Some(best_block_hash) = best_block_changed.new_best_hash() { - best_block_hash - } else { - return HashMap::new() - }; - let block = match best_block_changed.best_block() { - Some(block) => block, - None => return HashMap::new(), - }; - - let (removed, added): ( - Box>, - Box>, - ) = match best_block_changed { - BestBlockChanged::CanonChainAppended { - .. - } => ( - Box::new(::std::iter::empty()), - Box::new(tracker_and_addresses_entries(block_hash, block.transactions())), - ), - BestBlockChanged::BranchBecomingCanonChain { - ref tree_route, - .. - } => { - let enacted = tree_route - .enacted - .iter() - .flat_map(|hash| { - let body = self.block_body(hash).expect("Enacted block must be in database."); - tracker_and_addresses_entries(*hash, body.transactions()) - }) - .chain(tracker_and_addresses_entries(block_hash, block.transactions())); - - let retracted = tree_route.retracted.iter().flat_map(|hash| { - let body = self.block_body(hash).expect("Retracted block must be in database."); - tracker_and_addresses_entries(*hash, body.transactions()) - }); - - (Box::new(retracted), Box::new(enacted)) - } - BestBlockChanged::None => return Default::default(), - }; - - let mut added_addresses: HashMap = Default::default(); - let mut removed_addresses: HashMap = Default::default(); - let mut trackers: HashSet = Default::default(); - for (tracker, address) in added { - trackers.insert(tracker); - *added_addresses.entry(tracker).or_insert_with(Default::default) += address; - } - for (tracker, address) in removed { - trackers.insert(tracker); - *removed_addresses.entry(tracker).or_insert_with(Default::default) += address; - } - let mut inserted_address: HashMap = Default::default(); - for tracker in trackers.into_iter() { - let address: TransactionAddresses = self.db.read(db::COL_EXTRA, &tracker).unwrap_or_default(); - inserted_address.insert(tracker, address); - } - - for (tracker, removed_address) in removed_addresses.into_iter() { - *inserted_address - .get_mut(&tracker) - .expect("inserted addresses are sum of added_addresses and removed_addresses") -= removed_address; - } - for (tracker, added_address) in added_addresses.into_iter() { - *inserted_address - .get_mut(&tracker) - .expect("inserted addresses are sum of added_addresses and removed_addresses") += added_address; - } - - inserted_address - .into_iter() - .map(|(hash, address)| { - if address.is_empty() { - (hash, None) - } else { - (hash, Some(address)) - } - }) - .collect() - } - /// Create a block body from a block. pub fn block_to_body(block: &BlockView) -> Bytes { let mut body = RlpStream::new_list(1); @@ -286,8 +170,6 @@ pub trait BodyProvider { /// Get the address of transaction with given hash. fn transaction_address(&self, hash: &TxHash) -> Option; - fn transaction_address_by_tracker(&self, tracker: &Tracker) -> Option; - /// Get the block body (transactions). fn block_body(&self, hash: &BlockHash) -> Option; } @@ -303,12 +185,6 @@ impl BodyProvider for BodyDB { Some(result) } - fn transaction_address_by_tracker(&self, tracker: &Tracker) -> Option { - let addresses = - self.db.read_with_cache(db::COL_EXTRA, &mut *self.addresses_by_tracker_cache.lock(), tracker)?; - addresses.into_iter().next() - } - /// Get block body data fn block_body(&self, hash: &BlockHash) -> Option { // Check cache first @@ -345,20 +221,3 @@ fn tx_hash_and_address_entries( ) }) } - -fn tracker_and_addresses_entries( - block_hash: BlockHash, - tx_hashes: impl IntoIterator, -) -> impl Iterator { - tx_hashes.into_iter().enumerate().filter_map(move |(index, tx)| { - tx.tracker().map(|tracker| { - ( - tracker, - TransactionAddresses::new(TransactionAddress { - block_hash, - index, - }), - ) - }) - }) -} diff --git a/core/src/blockchain/extras.rs b/core/src/blockchain/extras.rs index 8eaef5d2a7..00a373c75a 100644 --- a/core/src/blockchain/extras.rs +++ b/core/src/blockchain/extras.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::ops::{Add, AddAssign, Deref, Sub, SubAssign}; +use std::ops::Deref; -use ctypes::{BlockHash, BlockNumber, Tracker, TxHash}; +use ctypes::{BlockHash, BlockNumber, TxHash}; use primitives::{H256, H264, U256}; use crate::db::Key; @@ -31,8 +31,7 @@ enum ExtrasIndex { BlockHash = 1, /// Transaction address index TransactionAddress = 2, - /// Transaction addresses index - TransactionAddresses = 3, + // (Reserved) = 3, // (Reserved) = 4, // (Reserved) = 5, } @@ -54,7 +53,6 @@ impl Deref for BlockNumberKey { } } - impl Key for BlockNumber { type Target = BlockNumberKey; @@ -85,14 +83,6 @@ impl Key for TxHash { } } -impl Key for Tracker { - type Target = H264; - - fn key(&self) -> H264 { - with_index(self, ExtrasIndex::TransactionAddresses) - } -} - /// Familial details concerning a block #[derive(Debug, Clone, RlpEncodable, RlpDecodable)] pub struct BlockDetails { @@ -118,220 +108,3 @@ impl From for TransactionId { TransactionId::Location(addr.block_hash.into(), addr.index) } } - -/// Represents address of certain transaction that has the same tracker -#[derive(Debug, Default, PartialEq, Clone, RlpEncodableWrapper, RlpDecodableWrapper)] -pub struct TransactionAddresses { - addresses: Vec, -} - -impl TransactionAddresses { - pub fn new(address: TransactionAddress) -> Self { - Self { - addresses: vec![address], - } - } - - pub fn is_empty(&self) -> bool { - self.addresses.is_empty() - } -} - -impl IntoIterator for TransactionAddresses { - type Item = TransactionAddress; - type IntoIter = ::std::vec::IntoIter<::Item>; - - fn into_iter(self) -> ::IntoIter { - self.addresses.into_iter() - } -} - -impl Add for TransactionAddresses { - type Output = Self; - - fn add(self, rhs: Self) -> ::Output { - let mut s = self; - s += rhs; - s - } -} - -impl AddAssign for TransactionAddresses { - fn add_assign(&mut self, rhs: Self) { - // FIXME: Please fix this O(n*m) algorithm - let new_addresses: Vec<_> = rhs.into_iter().filter(|addr| !self.addresses.contains(addr)).collect(); - self.addresses.extend(new_addresses); - } -} - -impl Sub for TransactionAddresses { - type Output = Self; - - fn sub(self, rhs: Self) -> ::Output { - let mut s = self; - s -= rhs; - s - } -} - -impl SubAssign for TransactionAddresses { - fn sub_assign(&mut self, rhs: Self) { - // FIXME: Please fix this O(n*m) algorithm - self.addresses.retain(|addr| !rhs.addresses.contains(addr)); - self.addresses.shrink_to_fit(); - } -} - -#[cfg(test)] -mod tests { - use rlp::rlp_encode_and_decode_test; - - use super::*; - - #[test] - fn encode_and_decode_transaction_address_with_single_address() { - rlp_encode_and_decode_test!(TransactionAddresses::new(TransactionAddress { - block_hash: H256::random().into(), - index: 0, - })); - } - - #[test] - fn encode_and_decode_transaction_address_without_address() { - rlp_encode_and_decode_test!(TransactionAddresses::default()); - } - - #[test] - fn encode_and_decode_transaction_address_with_multiple_addresses() { - rlp_encode_and_decode_test!(TransactionAddresses { - addresses: vec![ - TransactionAddress { - block_hash: H256::random().into(), - index: 0, - }, - TransactionAddress { - block_hash: H256::random().into(), - index: 3, - }, - TransactionAddress { - block_hash: H256::random().into(), - index: 1, - }, - ], - }); - } - - #[test] - fn add() { - let t1 = TransactionAddresses { - addresses: vec![TransactionAddress { - block_hash: H256::zero().into(), - index: 0, - }], - }; - let t2 = TransactionAddresses { - addresses: vec![TransactionAddress { - block_hash: H256::from(1).into(), - index: 0, - }], - }; - assert_eq!( - vec![ - TransactionAddress { - block_hash: H256::zero().into(), - index: 0, - }, - TransactionAddress { - block_hash: H256::from(1).into(), - index: 0, - } - ], - (t1 + t2).addresses - ); - } - - #[test] - fn do_not_add_duplicated_item() { - let t1 = TransactionAddresses { - addresses: vec![TransactionAddress { - block_hash: H256::zero().into(), - index: 0, - }], - }; - let t2 = TransactionAddresses { - addresses: vec![TransactionAddress { - block_hash: H256::zero().into(), - index: 0, - }], - }; - assert_eq!( - vec![TransactionAddress { - block_hash: H256::zero().into(), - index: 0, - },], - (t1 + t2).addresses - ); - } - - #[test] - fn remove() { - let t1 = TransactionAddresses { - addresses: vec![ - TransactionAddress { - block_hash: H256::zero().into(), - index: 0, - }, - TransactionAddress { - block_hash: H256::from(1).into(), - index: 0, - }, - TransactionAddress { - block_hash: H256::from(2).into(), - index: 0, - }, - ], - }; - let t2 = TransactionAddresses { - addresses: vec![TransactionAddress { - block_hash: H256::from(1).into(), - index: 0, - }], - }; - assert_eq!( - vec![ - TransactionAddress { - block_hash: H256::zero().into(), - index: 0, - }, - TransactionAddress { - block_hash: H256::from(2).into(), - index: 0, - } - ], - (t1 - t2).addresses - ); - } - - #[test] - fn remove_dont_touch_unmatched_item() { - let t1 = TransactionAddresses { - addresses: vec![TransactionAddress { - block_hash: H256::zero().into(), - index: 0, - }], - }; - let t2 = TransactionAddresses { - addresses: vec![TransactionAddress { - block_hash: H256::from(1).into(), - index: 0, - }], - }; - assert_eq!( - vec![TransactionAddress { - block_hash: H256::zero().into(), - index: 0, - },], - (t1 - t2).addresses - ); - } -} diff --git a/core/src/blockchain/invoice_db.rs b/core/src/blockchain/invoice_db.rs index fa296f8133..1f6c661792 100644 --- a/core/src/blockchain/invoice_db.rs +++ b/core/src/blockchain/invoice_db.rs @@ -15,14 +15,12 @@ // along with this program. If not, see . use std::collections::HashMap; -use std::ops::{Deref, DerefMut}; use std::sync::Arc; -use ctypes::{Tracker, TxHash}; +use ctypes::TxHash; use kvdb::{DBTransaction, KeyValueDB}; use parking_lot::RwLock; use primitives::{H256, H264}; -use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; use crate::db::{self, CacheUpdatePolicy, Key, Readable, Writable}; @@ -30,8 +28,6 @@ use crate::db::{self, CacheUpdatePolicy, Key, Readable, Writable}; /// /// **Does not do input data verification.** pub struct InvoiceDB { - // tracker -> transaction hashe + error hint - tracker_cache: RwLock>, // transaction hash -> error hint hash_cache: RwLock>>, @@ -42,7 +38,6 @@ impl InvoiceDB { /// Create new instance of blockchain from given Genesis. pub fn new(db: Arc) -> Self { Self { - tracker_cache: Default::default(), hash_cache: Default::default(), db, @@ -52,27 +47,13 @@ impl InvoiceDB { /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. - pub fn insert_invoice( - &self, - batch: &mut DBTransaction, - hash: TxHash, - tracker: Option, - error_hint: Option, - ) { + pub fn insert_invoice(&self, batch: &mut DBTransaction, hash: TxHash, error_hint: Option) { if self.is_known_error_hint(&hash) { return } - let mut hashes_cache = self.tracker_cache.write(); let mut hint_cache = self.hash_cache.write(); - if let Some(tracker) = tracker { - let mut hashes = - self.db.read_with_cache(db::COL_ERROR_HINT, &mut *hashes_cache, &tracker).unwrap_or_default(); - hashes.push((hash, error_hint.clone())); - batch.write_with_cache(db::COL_ERROR_HINT, &mut *hashes_cache, tracker, hashes, CacheUpdatePolicy::Remove) - } - batch.write_with_cache(db::COL_ERROR_HINT, &mut *hint_cache, hash, error_hint, CacheUpdatePolicy::Remove); } } @@ -82,9 +63,6 @@ pub trait InvoiceProvider { /// Returns true if invoices for given hash is known fn is_known_error_hint(&self, hash: &TxHash) -> bool; - /// Get error hints - fn error_hints_by_tracker(&self, tracker: &Tracker) -> Vec<(TxHash, Option)>; - /// Get error hint fn error_hint(&self, hash: &TxHash) -> Option; } @@ -94,71 +72,12 @@ impl InvoiceProvider for InvoiceDB { self.db.exists_with_cache(db::COL_ERROR_HINT, &self.hash_cache, hash) } - fn error_hints_by_tracker(&self, tracker: &Tracker) -> Vec<(TxHash, Option)> { - self.db - .read_with_cache(db::COL_ERROR_HINT, &mut *self.tracker_cache.write(), tracker) - .map(|hashes| (*hashes).clone()) - .unwrap_or_default() - } - fn error_hint(&self, hash: &TxHash) -> Option { self.db.read_with_cache(db::COL_ERROR_HINT, &mut *self.hash_cache.write(), hash)? } } -#[derive(Clone, Default)] -pub struct TrackerInvoices(Vec<(TxHash, Option)>); - -impl Encodable for TrackerInvoices { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(self.len() * 2); - for (hash, error) in self.iter() { - s.append(hash); - s.append(error); - } - } -} - -impl Decodable for TrackerInvoices { - fn decode(rlp: &Rlp) -> Result { - let item_count = rlp.item_count()?; - if item_count % 2 == 1 { - return Err(DecoderError::RlpInvalidLength { - expected: item_count + 1, - got: item_count, - }) - } - let mut vec = Vec::with_capacity(item_count / 2); - // TODO: Optimzie the below code - for i in 0..(item_count / 2) { - vec.push((rlp.val_at(i * 2)?, rlp.val_at(i * 2 + 1)?)); - } - Ok(vec.into()) - } -} - -impl From)>> for TrackerInvoices { - fn from(f: Vec<(TxHash, Option)>) -> Self { - TrackerInvoices(f) - } -} - -impl Deref for TrackerInvoices { - type Target = Vec<(TxHash, Option)>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for TrackerInvoices { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - enum ErrorHintIndex { - TrackerToHashes = 0, HashToHint = 1, } @@ -176,14 +95,6 @@ impl Key> for TxHash { } } -impl Key for Tracker { - type Target = H264; - - fn key(&self) -> H264 { - with_index(self, ErrorHintIndex::TrackerToHashes) - } -} - fn with_index(hash: &H256, i: ErrorHintIndex) -> H264 { let mut result = H264::default(); result[0] = i as u8; diff --git a/core/src/blockchain/mod.rs b/core/src/blockchain/mod.rs index f2f5302978..9442d12b18 100644 --- a/core/src/blockchain/mod.rs +++ b/core/src/blockchain/mod.rs @@ -25,7 +25,7 @@ mod route; pub use self::blockchain::{BlockChain, BlockProvider}; pub use self::body_db::BodyProvider; -pub use self::extras::{BlockDetails, TransactionAddress, TransactionAddresses}; +pub use self::extras::{BlockDetails, TransactionAddress}; pub use self::headerchain::HeaderProvider; pub use self::invoice_db::InvoiceProvider; pub use self::route::ImportRoute; diff --git a/core/src/client/client.rs b/core/src/client/client.rs index 2e31912c62..dd09e2b9c3 100644 --- a/core/src/client/client.rs +++ b/core/src/client/client.rs @@ -25,9 +25,7 @@ use cmerkle::Result as TrieResult; use cnetwork::NodeId; use cstate::{ActionHandler, FindActionHandler, StateDB, Text, TopLevelState, TopStateView}; use ctimer::{TimeoutHandler, TimerApi, TimerScheduleError, TimerToken}; -use ctypes::transaction::{AssetTransferInput, PartialHashing}; -use ctypes::{BlockHash, BlockNumber, CommonParams, Tracker, TxHash}; -use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig}; +use ctypes::{BlockHash, BlockNumber, CommonParams, TxHash}; use kvdb::{DBTransaction, KeyValueDB}; use parking_lot::{Mutex, RwLock, RwLockReadGuard}; use primitives::{Bytes, U256}; @@ -36,8 +34,8 @@ use rlp::Rlp; use super::importer::Importer; use super::{ AccountData, BlockChainClient, BlockChainInfo, BlockChainTrait, BlockProducer, ChainNotify, ClientConfig, - DatabaseClient, EngineClient, EngineInfo, Error as ClientError, ExecuteClient, ImportBlock, ImportResult, - MiningBlockChainClient, StateInfo, StateOrBlock, TextClient, + DatabaseClient, EngineClient, EngineInfo, ImportBlock, ImportResult, MiningBlockChainClient, StateInfo, + StateOrBlock, TextClient, }; use crate::block::{ClosedBlock, IsBlock, OpenBlock, SealedBlock}; use crate::blockchain::{BlockChain, BlockProvider, BodyProvider, HeaderProvider, InvoiceProvider, TransactionAddress}; @@ -231,10 +229,6 @@ impl Client { } } - fn transaction_addresses(&self, tracker: &Tracker) -> Option { - self.block_chain().transaction_address_by_tracker(tracker) - } - /// Import transactions from the IO queue pub fn import_queued_transactions(&self, transactions: &[Bytes], peer_id: NodeId) -> usize { ctrace!(EXTERNAL_TX, "Importing queued"); @@ -355,52 +349,6 @@ impl TextClient for Client { } } -impl ExecuteClient for Client { - fn execute_vm( - &self, - tx: &dyn PartialHashing, - inputs: &[AssetTransferInput], - params: &[Vec], - indices: &[usize], - ) -> Result, ClientError> { - let mut results = Vec::with_capacity(indices.len()); - for (i, index) in indices.iter().enumerate() { - let input = inputs.get(*index); - let param = params.get(i); - let result = match (input, param) { - (Some(input), Some(param)) => { - let lock_script = decode(&input.lock_script); - let unlock_script = decode(&input.unlock_script); - match (lock_script, unlock_script) { - (Ok(lock_script), Ok(unlock_script)) => { - match execute( - &unlock_script, - ¶m, - &lock_script, - tx, - VMConfig::default(), - &input, - false, - self, - self.best_block_header().number(), - self.best_block_header().timestamp(), - ) { - Ok(ScriptResult::Burnt) => "burnt".to_string(), - Ok(ScriptResult::Unlocked) => "unlocked".to_string(), - _ => "failed".to_string(), - } - } - _ => "invalid".to_string(), - } - } - _ => "invalid".to_string(), - }; - results.push(result); - } - Ok(results) - } -} - impl StateInfo for Client { fn state_at(&self, id: BlockId) -> Option { self.block_header(&id).and_then(|header| { @@ -546,10 +494,6 @@ impl BlockChainTrait for Client { fn transaction_block(&self, id: &TransactionId) -> Option { self.transaction_address(id).map(|addr| addr.block_hash) } - - fn transaction_header(&self, tracker: &Tracker) -> Option { - self.transaction_addresses(tracker).map(|addr| addr.block_hash).and_then(|hash| self.block_header(&hash.into())) - } } impl ImportBlock for Client { @@ -628,7 +572,6 @@ impl ImportBlock for Client { } } - impl BlockChainClient for Client { fn queue_info(&self) -> BlockQueueInfo { self.importer.block_queue.queue_info() @@ -709,17 +652,6 @@ impl BlockChainClient for Client { let chain = self.block_chain(); chain.error_hint(hash) } - - fn transaction_by_tracker(&self, tracker: &Tracker) -> Option { - let chain = self.block_chain(); - let address = self.transaction_addresses(tracker); - address.and_then(|address| chain.transaction(&address)) - } - - fn error_hints_by_tracker(&self, tracker: &Tracker) -> Vec<(TxHash, Option)> { - let chain = self.block_chain(); - chain.error_hints_by_tracker(tracker) - } } impl TermInfo for Client { @@ -814,16 +746,6 @@ impl MiningBlockChainClient for Client { } } -impl ChainTimeInfo for Client { - fn transaction_block_age(&self, tracker: &Tracker, parent_block_number: BlockNumber) -> Option { - self.transaction_block_number(tracker).map(|block_number| parent_block_number - block_number) - } - - fn transaction_time_age(&self, tracker: &Tracker, parent_timestamp: u64) -> Option { - self.transaction_block_timestamp(tracker).map(|block_timestamp| parent_timestamp - block_timestamp) - } -} - impl FindActionHandler for Client { fn find_action_handler_for(&self, id: u64) -> Option<&dyn ActionHandler> { self.engine.find_action_handler_for(id) diff --git a/core/src/client/importer.rs b/core/src/client/importer.rs index 8400fc7c36..0389b7f552 100644 --- a/core/src/client/importer.rs +++ b/core/src/client/importer.rs @@ -237,29 +237,15 @@ impl Importer { let common_params = client.common_params(parent.hash().into()).unwrap(); // Verify Block Family - self.verifier - .verify_block_family( - &block.bytes, - header, - &parent, - engine, - Some(verification::FullFamilyParams { - block_bytes: &block.bytes, - transactions: &block.transactions, - block_provider: &*chain, - client, - }), - &common_params, - ) - .map_err(|e| { - cwarn!( - CLIENT, - "Stage 3 block verification failed for #{} ({})\nError: {:?}", - header.number(), - header.hash(), - e - ); - })?; + self.verifier.verify_block_family(&block.bytes, header, &parent, engine, &common_params).map_err(|e| { + cwarn!( + CLIENT, + "Stage 3 block verification failed for #{} ({})\nError: {:?}", + header.number(), + header.hash(), + e + ); + })?; self.verifier.verify_block_external(header, engine).map_err(|e| { cwarn!( @@ -271,7 +257,6 @@ impl Importer { ); })?; - // Enact Verified Block let db = client.state_db().read().clone(&parent.state_root()); diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index 49d713323a..2fbaff1837 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -36,9 +36,7 @@ use ckey::{Address, NetworkId, PlatformAddress, Public}; use cmerkle::Result as TrieResult; use cnetwork::NodeId; use cstate::{FindActionHandler, Text, TopLevelState, TopStateView}; -use ctypes::transaction::{AssetTransferInput, PartialHashing}; -use ctypes::{BlockHash, BlockNumber, CommonParams, Tracker, TxHash}; -use cvm::ChainTimeInfo; +use ctypes::{BlockHash, BlockNumber, CommonParams, TxHash}; use kvdb::KeyValueDB; use primitives::{Bytes, U256}; @@ -74,16 +72,6 @@ pub trait BlockChainTrait { /// Get the hash of block that contains the transaction, if any. fn transaction_block(&self, id: &TransactionId) -> Option; - - fn transaction_header(&self, tracker: &Tracker) -> Option; - - fn transaction_block_number(&self, tracker: &Tracker) -> Option { - self.transaction_header(tracker).map(|header| header.number()) - } - - fn transaction_block_timestamp(&self, tracker: &Tracker) -> Option { - self.transaction_header(tracker).map(|header| header.timestamp()) - } } pub trait EngineInfo: Send + Sync { @@ -161,7 +149,6 @@ pub trait AccountData { } } - /// State information to be used during client query pub enum StateOrBlock { /// State to be used, may be pending @@ -201,7 +188,7 @@ pub trait ImportBlock { } /// Blockchain database client. Owns and manages a blockchain and a block queue. -pub trait BlockChainClient: Sync + Send + AccountData + BlockChainTrait + ImportBlock + ChainTimeInfo { +pub trait BlockChainClient: Sync + Send + AccountData + BlockChainTrait + ImportBlock { /// Get block queue information. fn queue_info(&self) -> BlockQueueInfo; @@ -230,7 +217,6 @@ pub trait BlockChainClient: Sync + Send + AccountData + BlockChainTrait + Import /// Get block status by block header hash. fn block_status(&self, id: &BlockId) -> BlockStatus; - /// Get block total score. fn block_total_score(&self, id: &BlockId) -> Option; @@ -242,11 +228,6 @@ pub trait BlockChainClient: Sync + Send + AccountData + BlockChainTrait + Import /// Get invoice with given hash. fn error_hint(&self, hash: &TxHash) -> Option; - - /// Get the transaction with given tracker. - fn transaction_by_tracker(&self, tracker: &Tracker) -> Option; - - fn error_hints_by_tracker(&self, tracker: &Tracker) -> Vec<(TxHash, Option)>; } /// Result of import block operation. @@ -292,16 +273,6 @@ pub trait TextClient { fn get_text(&self, tx_hash: TxHash, id: BlockId) -> TrieResult>; } -pub trait ExecuteClient: ChainTimeInfo { - fn execute_vm( - &self, - tx: &dyn PartialHashing, - inputs: &[AssetTransferInput], - params: &[Vec], - indices: &[usize], - ) -> Result, Error>; -} - pub trait StateInfo { /// Attempt to get a copy of a specific block's final state. /// diff --git a/core/src/client/test_client.rs b/core/src/client/test_client.rs index e07083ca61..aa448f424f 100644 --- a/core/src/client/test_client.rs +++ b/core/src/client/test_client.rs @@ -44,8 +44,7 @@ use cstate::tests::helpers::empty_top_state; use cstate::{FindActionHandler, StateDB, TopLevelState}; use ctimer::{TimeoutHandler, TimerToken}; use ctypes::transaction::{Action, Transaction}; -use ctypes::{BlockHash, BlockNumber, CommonParams, Header as BlockHeader, Tracker, TxHash}; -use cvm::ChainTimeInfo; +use ctypes::{BlockHash, BlockNumber, CommonParams, Header as BlockHeader, TxHash}; use kvdb::KeyValueDB; use kvdb_memorydb; use parking_lot::RwLock; @@ -456,10 +455,6 @@ impl BlockChainTrait for TestBlockChainClient { fn transaction_block(&self, _id: &TransactionId) -> Option { None // Simple default. } - - fn transaction_header(&self, _tracker: &Tracker) -> Option { - None - } } impl ImportBlock for TestBlockChainClient { @@ -518,7 +513,6 @@ impl ImportBlock for TestBlockChainClient { fn set_max_timer(&self) {} } - impl BlockChainClient for TestBlockChainClient { fn queue_info(&self) -> QueueInfo { QueueInfo { @@ -550,7 +544,6 @@ impl BlockChainClient for TestBlockChainClient { self.miner.count_pending_transactions(range) } - fn is_pending_queue_empty(&self) -> bool { self.miner.status().transactions_in_pending_queue == 0 } @@ -594,30 +587,12 @@ impl BlockChainClient for TestBlockChainClient { fn error_hint(&self, _hash: &TxHash) -> Option { unimplemented!(); } - - fn transaction_by_tracker(&self, _: &Tracker) -> Option { - unimplemented!(); - } - - fn error_hints_by_tracker(&self, _: &Tracker) -> Vec<(TxHash, Option)> { - unimplemented!(); - } } impl TimeoutHandler for TestBlockChainClient { fn on_timeout(&self, _token: TimerToken) {} } -impl ChainTimeInfo for TestBlockChainClient { - fn transaction_block_age(&self, _: &Tracker, _parent_block_number: BlockNumber) -> Option { - Some(0) - } - - fn transaction_time_age(&self, _: &Tracker, _parent_timestamp: u64) -> Option { - Some(0) - } -} - impl FindActionHandler for TestBlockChainClient {} impl super::EngineClient for TestBlockChainClient { diff --git a/core/src/codechain_machine.rs b/core/src/codechain_machine.rs index 9d10dcf0aa..b4e1157178 100644 --- a/core/src/codechain_machine.rs +++ b/core/src/codechain_machine.rs @@ -17,12 +17,11 @@ use ckey::Address; use cstate::{StateError, TopState, TopStateView}; -use ctypes::errors::{HistoryError, SyntaxError}; -use ctypes::transaction::{Action, AssetTransferInput, Timelock}; +use ctypes::errors::SyntaxError; +use ctypes::transaction::Action; use ctypes::{CommonParams, Header}; use crate::block::{ExecutedBlock, IsBlock}; -use crate::client::BlockChainTrait; use crate::error::Error; use crate::transaction::{SignedTransaction, UnverifiedTransaction}; @@ -67,146 +66,20 @@ impl CodeChainMachine { Ok(SignedTransaction::try_new(p)?) } - /// Does verification of the transaction against the parent state. - pub fn verify_transaction( - &self, - tx: &SignedTransaction, - header: &Header, - client: &C, - verify_timelock: bool, - ) -> Result<(), Error> { - if let Action::TransferAsset { - inputs, - expiration, - .. - } = &tx.action - { - Self::verify_transaction_expiration(&expiration, header)?; - if verify_timelock { - Self::verify_transfer_timelock(inputs, header, client)?; - } - } - // FIXME: Filter transactions. - Ok(()) - } - /// Populate a header's fields based on its parent's header. /// Usually implements the chain scoring rule based on weight. pub fn populate_from_parent(&self, header: &mut Header, parent: &Header) { header.set_score(*parent.score()); } - fn verify_transaction_expiration(expiration: &Option, header: &Header) -> Result<(), Error> { - if expiration.is_none() { - return Ok(()) - } - let expiration = expiration.unwrap(); - - if expiration < header.timestamp() { - return Err(HistoryError::TransferExpired { - expiration, - timestamp: header.timestamp(), - } - .into()) - } - Ok(()) - } - - fn verify_transfer_timelock( - inputs: &[AssetTransferInput], - header: &Header, - client: &C, - ) -> Result<(), Error> { - for input in inputs { - if let Some(timelock) = input.timelock { - match timelock { - Timelock::Block(value) if value > header.number() => { - return Err(HistoryError::Timelocked { - timelock, - remaining_time: value - header.number(), - } - .into()) - } - Timelock::BlockAge(value) => { - let absolute = client.transaction_block_number(&input.prev_out.tracker).ok_or_else(|| { - Error::History(HistoryError::Timelocked { - timelock, - remaining_time: u64::max_value(), - }) - })? + value; - if absolute > header.number() { - return Err(HistoryError::Timelocked { - timelock, - remaining_time: absolute - header.number(), - } - .into()) - } - } - Timelock::Time(value) if value > header.timestamp() => { - return Err(HistoryError::Timelocked { - timelock, - remaining_time: value - header.timestamp(), - } - .into()) - } - Timelock::TimeAge(value) => { - let absolute = - client.transaction_block_timestamp(&input.prev_out.tracker).ok_or_else(|| { - Error::History(HistoryError::Timelocked { - timelock, - remaining_time: u64::max_value(), - }) - })? + value; - if absolute > header.timestamp() { - return Err(HistoryError::Timelocked { - timelock, - remaining_time: absolute - header.timestamp(), - } - .into()) - } - } - _ => (), - } - } - } - Ok(()) - } - pub fn min_cost(params: &CommonParams, action: &Action) -> u64 { match action { - Action::MintAsset { - .. - } => params.min_asset_mint_cost(), - Action::TransferAsset { - .. - } => params.min_asset_transfer_cost(), - Action::ChangeAssetScheme { - .. - } => params.min_asset_scheme_change_cost(), - Action::IncreaseAssetSupply { - .. - } => params.min_asset_supply_increase_cost(), - Action::UnwrapCCC { - .. - } => params.min_asset_unwrap_ccc_cost(), Action::Pay { .. } => params.min_pay_transaction_cost(), Action::SetRegularKey { .. } => params.min_set_regular_key_transaction_cost(), - Action::CreateShard { - .. - } => params.min_create_shard_transaction_cost(), - Action::SetShardOwners { - .. - } => params.min_set_shard_owners_transaction_cost(), - Action::SetShardUsers { - .. - } => params.min_set_shard_users_transaction_cost(), - Action::WrapCCC { - .. - } => params.min_wrap_ccc_transaction_cost(), Action::Custom { .. } => params.min_custom_transaction_cost(), diff --git a/core/src/consensus/stake/action_data.rs b/core/src/consensus/stake/action_data.rs index acc1add3b3..9717015238 100644 --- a/core/src/consensus/stake/action_data.rs +++ b/core/src/consensus/stake/action_data.rs @@ -138,7 +138,6 @@ impl Stakeholders { Ok(result) } - #[cfg(test)] pub fn contains(&self, address: &Address) -> bool { self.0.contains(address) @@ -334,7 +333,6 @@ impl Validators { Ok(Self(result)) } - pub fn save_to_state(&self, state: &mut TopLevelState) -> StateResult<()> { let key = &*VALIDATORS_KEY; if !self.is_empty() { diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index dbfbf86198..3474e5d18c 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -295,7 +295,6 @@ impl ConsensusEngine for Tendermint { header.parent_hash() } - fn can_change_canon_chain( &self, _new_header_hash: BlockHash, @@ -314,11 +313,13 @@ impl ConsensusEngine for Tendermint { let client = self.client().ok_or(EngineError::CannotOpenBlock)?; let block_hash = match block_number { None => { - client.block_header(&BlockId::Latest).expect("latest block must exist").hash() // the latest block + client.block_header(&BlockId::Latest).expect("latest block must exist").hash() + // the latest block } Some(block_number) => { assert_ne!(0, block_number); - client.block_header(&(block_number - 1).into()).ok_or(EngineError::CannotOpenBlock)?.hash() // the parent of the given block number + client.block_header(&(block_number - 1).into()).ok_or(EngineError::CannotOpenBlock)?.hash() + // the parent of the given block number } }; Ok(Some(self.validators.addresses(&block_hash))) diff --git a/core/src/consensus/tendermint/vote_collector.rs b/core/src/consensus/tendermint/vote_collector.rs index f96216fa66..73b2537820 100644 --- a/core/src/consensus/tendermint/vote_collector.rs +++ b/core/src/consensus/tendermint/vote_collector.rs @@ -169,7 +169,6 @@ impl VoteCollector { .unwrap_or_default() } - /// Returns the first signature and the index of its signer for a given round and hash if exists. pub fn round_signature(&self, round: &VoteStep, block_hash: &BlockHash) -> Option { self.votes diff --git a/core/src/invoice.rs b/core/src/invoice.rs index c36e1303ae..c76ce8075c 100644 --- a/core/src/invoice.rs +++ b/core/src/invoice.rs @@ -14,11 +14,10 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use ctypes::{Tracker, TxHash}; +use ctypes::TxHash; #[derive(Clone, Debug, PartialEq)] pub struct Invoice { - pub tracker: Option, pub hash: TxHash, pub error: Option, } diff --git a/core/src/lib.rs b/core/src/lib.rs index 185389b896..15d2c8a312 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -30,7 +30,6 @@ extern crate codechain_state as cstate; extern crate codechain_stratum as cstratum; extern crate codechain_timer as ctimer; extern crate codechain_types as ctypes; -extern crate codechain_vm as cvm; extern crate crossbeam_channel; extern crate cuckoo; extern crate kvdb; @@ -84,8 +83,7 @@ pub use crate::account_provider::{AccountProvider, Error as AccountProviderError pub use crate::block::Block; pub use crate::client::{ AccountData, BlockChainClient, BlockChainTrait, ChainNotify, Client, ClientConfig, DatabaseClient, EngineClient, - EngineInfo, ExecuteClient, ImportBlock, MiningBlockChainClient, StateInfo, TermInfo, TestBlockChainClient, - TextClient, + EngineInfo, ImportBlock, MiningBlockChainClient, StateInfo, TermInfo, TestBlockChainClient, TextClient, }; pub use crate::consensus::{EngineType, TimeGapParams}; pub use crate::db::{COL_STATE, NUM_COLUMNS}; diff --git a/core/src/miner/mem_pool.rs b/core/src/miner/mem_pool.rs index 42c22fe87f..95a4d4313f 100644 --- a/core/src/miner/mem_pool.rs +++ b/core/src/miner/mem_pool.rs @@ -395,14 +395,6 @@ impl MemPool { .filter(|&(_, ref item)| !item.origin.is_local()) .map(|(hash, item)| (hash, item, current_block_number.saturating_sub(item.inserted_block_number))) .filter_map(|(hash, item, time_diff)| { - // FIXME: In PoW, current_timestamp can be roll-backed. - // In that case, transactions which are removed in here can be recovered. - if let Some(expiration) = item.expiration() { - if expiration < current_timestamp { - return Some(*hash) - } - } - if time_diff > max_block_number { return Some(*hash) } @@ -576,7 +568,6 @@ impl MemPool { self.move_queue(public, next_seq, new_next_seq, QueueTag::Current); } - if new_next_seq <= first_seq { self.next_seqs.remove(&public); } else { @@ -878,12 +869,7 @@ impl MemPool { /// Returns top transactions whose timestamp are in the given range from the pool ordered by priority. // FIXME: current_timestamp should be `u64`, not `Option`. // FIXME: if range_contains becomes stable, use range.contains instead of inequality. - pub fn top_transactions( - &self, - size_limit: usize, - current_timestamp: Option, - range: Range, - ) -> PendingSignedTransactions { + pub fn top_transactions(&self, size_limit: usize, range: Range) -> PendingSignedTransactions { let mut current_size: usize = 0; let pending_items: Vec<_> = self .current @@ -894,14 +880,6 @@ impl MemPool { .get(&t.hash) .expect("All transactions in `current` and `future` are always included in `by_hash`") }) - .filter(|t| { - if let Some(expiration) = t.expiration() { - if let Some(timestamp) = current_timestamp { - return expiration >= timestamp - } - } - true - }) .filter(|t| range.contains(&t.inserted_timestamp)) .take_while(|t| { let encoded_byte_array = rlp::encode(&t.tx); @@ -953,11 +931,6 @@ impl MemPool { self.current.queue.iter().any(|tx| tx.origin.is_local()) } - /// Returns Some(true) if the given transaction is local and None for not found. - pub fn is_local_transaction(&self, tx_hash: TxHash) -> Option { - self.by_hash.get(&tx_hash).map(|found_item| found_item.origin.is_local()) - } - /// Checks the given timelock with the current time/timestamp. fn should_wait_timelock(timelock: &TxTimelock, best_block_number: BlockNumber, best_block_timestamp: u64) -> bool { if let Some(block_number) = timelock.block { @@ -974,15 +947,13 @@ impl MemPool { } } - #[cfg(test)] pub mod test { use std::cmp::Ordering; use crate::client::{AccountData, TestBlockChainClient}; use ckey::{Generator, KeyPair, Random}; - use ctypes::transaction::{Action, AssetMintOutput, Transaction}; - use primitives::H160; + use ctypes::transaction::{Action, Transaction}; use super::*; use rlp::rlp_encode_and_decode_test; @@ -1226,69 +1197,6 @@ pub mod test { ); } - #[test] - fn mint_transaction_does_not_increase_cost() { - let shard_id = 0xCCC; - - let fee = 100; - let tx = Transaction { - seq: 0, - fee, - network_id: "tc".into(), - action: Action::MintAsset { - network_id: "tc".into(), - shard_id, - metadata: "Metadata".to_string(), - output: Box::new(AssetMintOutput { - lock_script_hash: H160::zero(), - parameters: vec![], - supply: ::std::u64::MAX, - }), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - approvals: vec![], - }, - }; - let timelock = TxTimelock { - block: None, - timestamp: None, - }; - let keypair = Random.generate().unwrap(); - let signed = SignedTransaction::new_with_sign(tx, keypair.private()); - let item = MemPoolItem::new(signed, TxOrigin::Local, 0, 0, 0, timelock); - - assert_eq!(fee, item.cost()); - } - - #[test] - fn transfer_transaction_does_not_increase_cost() { - let fee = 100; - let tx = Transaction { - seq: 0, - fee, - network_id: "tc".into(), - action: Action::TransferAsset { - network_id: "tc".into(), - burns: vec![], - inputs: vec![], - outputs: vec![], - metadata: "".into(), - approvals: vec![], - expiration: None, - }, - }; - let timelock = TxTimelock { - block: None, - timestamp: None, - }; - let keypair = Random.generate().unwrap(); - let signed = SignedTransaction::new_with_sign(tx, keypair.private()); - let item = MemPoolItem::new(signed, TxOrigin::Local, 0, 0, 0, timelock); - - assert_eq!(fee, item.cost()); - } - #[test] fn pay_transaction_increases_cost() { let fee = 100; @@ -1314,44 +1222,6 @@ pub mod test { assert_eq!(fee + quantity, item.cost()); } - #[test] - fn fee_per_byte_order_simple() { - let order1 = create_transaction_order(1_000_000_000, 100); - let order2 = create_transaction_order(1_500_000_000, 300); - assert!( - order1.fee_per_byte > order2.fee_per_byte, - "{} must be larger than {}", - order1.fee_per_byte, - order2.fee_per_byte - ); - assert_eq!(Ordering::Greater, order1.cmp(&order2)); - } - - #[test] - fn fee_per_byte_order_sort() { - let factors: Vec> = vec![ - vec![4, 9], // 19607 - vec![2, 9], // 9803 - vec![2, 6], // 11494 - vec![10, 10], // 46728 - vec![2, 8], // 10309 - ]; - let mut orders: Vec = Vec::new(); - for factor in factors { - let fee = 1_000_000 * (factor[0] as u64); - orders.push(create_transaction_order(fee, 10 * factor[1])); - } - - let prev_orders = orders.clone(); - orders.sort_unstable(); - let sorted_orders = orders; - assert_eq!(prev_orders[1], sorted_orders[0]); - assert_eq!(prev_orders[4], sorted_orders[1]); - assert_eq!(prev_orders[2], sorted_orders[2]); - assert_eq!(prev_orders[0], sorted_orders[3]); - assert_eq!(prev_orders[3], sorted_orders[4]); - } - #[test] fn txorigin_encode_and_decode() { rlp_encode_and_decode_test!(TxOrigin::External); @@ -1384,38 +1254,6 @@ pub mod test { rlp_encode_and_decode_test!(signed); } - #[test] - fn mempool_item_encode_and_decode() { - let keypair = Random.generate().unwrap(); - let tx = Transaction { - seq: 0, - fee: 10, - network_id: "tc".into(), - action: Action::MintAsset { - network_id: "tc".into(), - shard_id: 0, - metadata: String::from_utf8(vec![b'a'; 1]).unwrap(), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - output: Box::new(AssetMintOutput { - lock_script_hash: H160::zero(), - parameters: vec![], - supply: ::std::u64::MAX, - }), - approvals: vec![], - }, - }; - let timelock = TxTimelock { - block: None, - timestamp: None, - }; - let signed = SignedTransaction::new_with_sign(tx, keypair.private()); - let item = MemPoolItem::new(signed, TxOrigin::Local, 0, 0, 0, timelock); - - rlp_encode_and_decode_test!(item); - } - #[test] fn db_backup_and_recover() { //setup test_client @@ -1522,36 +1360,6 @@ pub mod test { MemPoolInput::new(signed, TxOrigin::Local, timelock) } - fn create_transaction_order(fee: u64, transaction_count: usize) -> TransactionOrder { - let keypair = Random.generate().unwrap(); - let tx = Transaction { - seq: 0, - fee, - network_id: "tc".into(), - action: Action::MintAsset { - network_id: "tc".into(), - shard_id: 0, - metadata: String::from_utf8(vec![b'a'; transaction_count]).unwrap(), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - output: Box::new(AssetMintOutput { - lock_script_hash: H160::zero(), - parameters: vec![], - supply: ::std::u64::MAX, - }), - approvals: vec![], - }, - }; - let timelock = TxTimelock { - block: None, - timestamp: None, - }; - let signed = SignedTransaction::new_with_sign(tx, keypair.private()); - let item = MemPoolItem::new(signed, TxOrigin::Local, 0, 0, 0, timelock); - TransactionOrder::for_transaction(&item, 0) - } - fn abbreviated_mempool_add( test_client: &TestBlockChainClient, mem_pool: &mut MemPool, @@ -1627,7 +1435,7 @@ pub mod test { create_signed_pay_with_fee(1, 140, keypair), create_signed_pay_with_fee(2, 160, keypair) ], - mem_pool.top_transactions(std::usize::MAX, None, 0..std::u64::MAX).transactions + mem_pool.top_transactions(std::usize::MAX, 0..std::u64::MAX).transactions ); assert_eq!(Vec::::default(), mem_pool.future_transactions()); @@ -1686,7 +1494,7 @@ pub mod test { assert_eq!( vec![create_signed_pay_with_fee(0, 200, keypair), create_signed_pay_with_fee(1, 160, keypair)], - mem_pool.top_transactions(std::usize::MAX, None, 0..std::u64::MAX).transactions + mem_pool.top_transactions(std::usize::MAX, 0..std::u64::MAX).transactions ); assert_eq!(Vec::::default(), mem_pool.future_transactions()); @@ -1737,7 +1545,7 @@ pub mod test { assert_eq!( vec![create_signed_pay(0, keypair), create_signed_pay(1, keypair), create_signed_pay(2, keypair),], - mem_pool.top_transactions(std::usize::MAX, None, 0..std::u64::MAX).transactions + mem_pool.top_transactions(std::usize::MAX, 0..std::u64::MAX).transactions ); assert_eq!(Vec::::default(), mem_pool.future_transactions()); @@ -1753,7 +1561,7 @@ pub mod test { assert_eq!( vec![create_signed_pay(0, keypair),], - mem_pool.top_transactions(std::usize::MAX, None, 0..std::u64::MAX).transactions + mem_pool.top_transactions(std::usize::MAX, 0..std::u64::MAX).transactions ); assert_eq!(vec![create_signed_pay(2, keypair),], mem_pool.future_transactions()); diff --git a/core/src/miner/mem_pool_types.rs b/core/src/miner/mem_pool_types.rs index 6311cd7dcb..e69e1dc7b2 100644 --- a/core/src/miner/mem_pool_types.rs +++ b/core/src/miner/mem_pool_types.rs @@ -255,23 +255,9 @@ impl MemPoolItem { quantity, .. } => self.tx.fee + *quantity, - Action::WrapCCC { - quantity, - .. - } => self.tx.fee + *quantity, _ => self.tx.fee, } } - - pub fn expiration(&self) -> Option { - match &self.tx.action { - Action::TransferAsset { - expiration, - .. - } => *expiration, - _ => None, - } - } } #[derive(Clone, Copy, Debug, PartialEq)] @@ -496,39 +482,12 @@ impl MemPoolFees { } pub fn min_cost(&self, action: &Action) -> u64 { match action { - Action::MintAsset { - .. - } => self.min_asset_mint_cost, - Action::TransferAsset { - .. - } => self.min_asset_transfer_cost, - Action::ChangeAssetScheme { - .. - } => self.min_asset_scheme_change_cost, - Action::IncreaseAssetSupply { - .. - } => self.min_asset_supply_increase_cost, - Action::UnwrapCCC { - .. - } => self.min_asset_unwrap_ccc_cost, Action::Pay { .. } => self.min_pay_transaction_cost, Action::SetRegularKey { .. } => self.min_set_regular_key_transaction_cost, - Action::CreateShard { - .. - } => self.min_create_shard_transaction_cost, - Action::SetShardOwners { - .. - } => self.min_set_shard_owners_transaction_cost, - Action::SetShardUsers { - .. - } => self.min_set_shard_users_transaction_cost, - Action::WrapCCC { - .. - } => self.min_wrap_ccc_transaction_cost, Action::Custom { .. } => self.min_custom_transaction_cost, diff --git a/core/src/miner/miner.rs b/core/src/miner/miner.rs index 08a2ba0a99..c06beb523f 100644 --- a/core/src/miner/miner.rs +++ b/core/src/miner/miner.rs @@ -24,10 +24,9 @@ use std::time::{Duration, Instant}; use ckey::{public_to_address, Address, Password, PlatformAddress, Public}; use cstate::{FindActionHandler, TopLevelState}; -use ctypes::errors::{HistoryError, RuntimeError}; -use ctypes::transaction::{Action, IncompleteTransaction, Timelock}; +use ctypes::errors::HistoryError; +use ctypes::transaction::{Action, IncompleteTransaction}; use ctypes::{BlockHash, BlockNumber, Header, TxHash}; -use cvm::ChainTimeInfo; use kvdb::KeyValueDB; use parking_lot::{Mutex, RwLock}; use primitives::{Bytes, H256}; @@ -77,7 +76,6 @@ pub struct MinerOptions { /// then `new_fee > old_fee + old_fee >> mem_pool_fee_bump_shift` should be satisfied to replace. /// Local transactions ignore this option. pub mem_pool_fee_bump_shift: usize, - pub allow_create_shard: bool, /// How many historical work packages can we store before running out? pub work_queue_size: usize, /// Minimum fees configured by the machine. @@ -97,7 +95,6 @@ impl Default for MinerOptions { mem_pool_size: 8192, mem_pool_memory_limit: Some(2 * 1024 * 1024), mem_pool_fee_bump_shift: 3, - allow_create_shard: false, work_queue_size: 20, mem_pool_fees: Default::default(), } @@ -327,17 +324,6 @@ impl Miner { e })?; - // This check goes here because verify_transaction takes SignedTransaction parameter - self.engine.machine().verify_transaction(&tx, &fake_header, client, false).map_err(|e| { - match e { - Error::Syntax(_) if !origin.is_local() && !immune_users.contains(&signer_address) => { - self.malicious_users.write().insert(signer_address); - } - _ => {} - } - e - })?; - let timelock = self.calculate_timelock(&tx, client)?; let tx_hash = tx.hash(); @@ -381,48 +367,14 @@ impl Miner { results } - fn calculate_timelock(&self, tx: &SignedTransaction, client: &C) -> Result { - let mut max_block = None; - let mut max_timestamp = None; - if let Action::TransferAsset { - inputs, - .. - } = &tx.action - { - for input in inputs { - if let Some(timelock) = input.timelock { - let (is_block_number, value) = match timelock { - Timelock::Block(value) => (true, value), - Timelock::BlockAge(value) => ( - true, - client.transaction_block_number(&input.prev_out.tracker).ok_or_else(|| { - Error::History(HistoryError::Timelocked { - timelock, - remaining_time: u64::max_value(), - }) - })? + value, - ), - Timelock::Time(value) => (false, value), - Timelock::TimeAge(value) => ( - false, - client.transaction_block_timestamp(&input.prev_out.tracker).ok_or_else(|| { - Error::History(HistoryError::Timelocked { - timelock, - remaining_time: u64::max_value(), - }) - })? + value, - ), - }; - if is_block_number { - if max_block.is_none() || max_block.expect("The previous guard ensures") < value { - max_block = Some(value); - } - } else if max_timestamp.is_none() || max_timestamp.expect("The previous guard ensures") < value { - max_timestamp = Some(value); - } - } - } - }; + fn calculate_timelock( + &self, + _tx: &SignedTransaction, + _client: &C, + ) -> Result { + let max_block = None; + let max_timestamp = None; + Ok(TxTimelock { block: max_block, timestamp: max_timestamp, @@ -478,9 +430,7 @@ impl Miner { } /// Prepares new block for sealing including top transactions from queue. - fn prepare_block< - C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo, - >( + fn prepare_block( &self, parent_block_id: BlockId, chain: &C, @@ -503,9 +453,7 @@ impl Miner { // NOTE: This lock should be acquired after `prepare_open_block` to prevent deadlock let mem_pool = self.mem_pool.read(); - let transactions = mem_pool - .top_transactions(max_body_size, Some(open_block.header().timestamp()), DEFAULT_RANGE) - .transactions; + let transactions = mem_pool.top_transactions(max_body_size, DEFAULT_RANGE).transactions; (transactions, open_block, last_work_hash, block_number) }; @@ -534,7 +482,7 @@ impl Miner { let tx_total = transactions.len(); let mut invalid_tx_users = HashSet::new(); - let immune_users = self.immune_users.read(); + let _immune_users = self.immune_users.read(); for tx in transactions { let signer_public = tx.signer_public(); let signer_address = public_to_address(&signer_public); @@ -554,31 +502,13 @@ impl Miner { let hash = tx.hash(); let start = Instant::now(); - // Check whether transaction type is allowed for sender let result = - self.engine.machine().verify_transaction(&tx, open_block.header(), chain, true).and_then(|_| { - open_block.push_transaction(tx, None, chain, parent_header.number(), parent_header.timestamp()) - }); + open_block.push_transaction(tx, None, chain, parent_header.number(), parent_header.timestamp()); match result { // already have transaction - ignore Err(Error::History(HistoryError::TransactionAlreadyImported)) => {} Err(e) => { - match e { - Error::Runtime(RuntimeError::AssetSupplyOverflow) - | Error::Runtime(RuntimeError::InvalidScript) => { - if !self - .mem_pool - .read() - .is_local_transaction(hash) - .expect("The tx is clearly fetched from the mempool") - && !immune_users.contains(&signer_address) - { - self.malicious_users.write().insert(signer_address); - } - } - _ => {} - } invalid_tx_users.insert(signer_public); invalid_transactions.push(hash); cinfo!( @@ -690,15 +620,7 @@ impl Miner { }) } - fn is_allowed_transaction(&self, action: &Action) -> bool { - if let Action::CreateShard { - .. - } = action - { - if !self.options.allow_create_shard { - return false - } - } + fn is_allowed_transaction(&self, _action: &Action) -> bool { true } } @@ -812,7 +734,7 @@ impl MinerService for Miner { } fn prepare_work_sealing< - C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo, + C: AccountData + BlockChainTrait + BlockProducer + EngineInfo + FindActionHandler + TermInfo, >( &self, client: &C, @@ -864,14 +786,8 @@ impl MinerService for Miner { fn update_sealing(&self, chain: &C, parent_block: BlockId, allow_empty_block: bool) where - C: AccountData - + BlockChainTrait - + BlockProducer - + EngineInfo - + ImportBlock - + ChainTimeInfo - + FindActionHandler - + TermInfo, { + C: AccountData + BlockChainTrait + BlockProducer + EngineInfo + ImportBlock + FindActionHandler + TermInfo, + { ctrace!(MINER, "update_sealing: preparing a block"); let parent_block_number = chain.block_header(&parent_block).expect("Parent is always exist").number(); @@ -953,7 +869,7 @@ impl MinerService for Miner { fn map_sealing_work(&self, client: &C, f: F) -> Option where - C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo, + C: AccountData + BlockChainTrait + BlockProducer + EngineInfo + FindActionHandler + TermInfo, F: FnOnce(&ClosedBlock) -> T, { ctrace!(MINER, "map_sealing_work: entering"); self.prepare_work_sealing(client); @@ -1082,7 +998,7 @@ impl MinerService for Miner { fn ready_transactions(&self, range: Range) -> PendingSignedTransactions { // FIXME: Update the body size when the common params are updated let max_body_size = self.engine.machine().genesis_common_params().max_body_size(); - self.mem_pool.read().top_transactions(max_body_size, None, range) + self.mem_pool.read().top_transactions(max_body_size, range) } fn count_pending_transactions(&self, range: Range) -> usize { diff --git a/core/src/miner/mod.rs b/core/src/miner/mod.rs index c732644a68..caa90679fc 100644 --- a/core/src/miner/mod.rs +++ b/core/src/miner/mod.rs @@ -29,7 +29,6 @@ use ckey::{Address, Password, PlatformAddress}; use cstate::{FindActionHandler, TopStateView}; use ctypes::transaction::IncompleteTransaction; use ctypes::{BlockHash, TxHash}; -use cvm::ChainTimeInfo; use primitives::Bytes; pub use self::mem_pool_types::MemPoolFees; @@ -88,19 +87,12 @@ pub trait MinerService: Send + Sync { /// Returns true if we had to prepare new pending block. fn prepare_work_sealing(&self, _: &C) -> bool where - C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo; + C: AccountData + BlockChainTrait + BlockProducer + EngineInfo + FindActionHandler + TermInfo; /// 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 - + ChainTimeInfo - + EngineInfo - + FindActionHandler - + TermInfo; + C: AccountData + BlockChainTrait + BlockProducer + ImportBlock + EngineInfo + FindActionHandler + TermInfo; /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. @@ -109,7 +101,7 @@ pub trait MinerService: Send + Sync { /// Get the sealing work package and if `Some`, apply some transform. fn map_sealing_work(&self, client: &C, f: F) -> Option where - C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo, + C: AccountData + BlockChainTrait + BlockProducer + EngineInfo + FindActionHandler + TermInfo, F: FnOnce(&ClosedBlock) -> T, Self: Sized; diff --git a/core/src/scheme/mod.rs b/core/src/scheme/mod.rs index e5fe849499..06ab3a455e 100644 --- a/core/src/scheme/mod.rs +++ b/core/src/scheme/mod.rs @@ -16,7 +16,6 @@ mod genesis; mod pod_account; -mod pod_shard_metadata; mod pod_state; #[cfg_attr(feature = "cargo-clippy", allow(clippy::module_inception))] mod scheme; diff --git a/core/src/scheme/pod_shard_metadata.rs b/core/src/scheme/pod_shard_metadata.rs deleted file mode 100644 index d9c8f9345a..0000000000 --- a/core/src/scheme/pod_shard_metadata.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2018 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 std::fmt; - -use cjson; -use ckey::{Address, PlatformAddress}; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct PodShardMetadata { - pub owners: Vec
, - pub users: Vec
, - pub seq: u64, -} - -impl From for PodShardMetadata { - fn from(s: cjson::scheme::Shard) -> Self { - Self { - seq: s.seq.map(Into::into).unwrap_or(0), - owners: s.owners.into_iter().map(PlatformAddress::into_address).collect(), - users: s.users.unwrap_or_else(Vec::new).into_iter().map(PlatformAddress::into_address).collect(), - } - } -} - -impl fmt::Display for PodShardMetadata { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "(#seq={}; owners={:#?}; users={:#?})", self.seq, self.owners, self.users) - } -} diff --git a/core/src/scheme/pod_state.rs b/core/src/scheme/pod_state.rs index ba884eb731..79cedf81d0 100644 --- a/core/src/scheme/pod_state.rs +++ b/core/src/scheme/pod_state.rs @@ -20,10 +20,8 @@ use std::ops::Deref; use cjson; use ckey::Address; -use ctypes::ShardId; use super::pod_account::PodAccount; -use super::pod_shard_metadata::PodShardMetadata; /// State of all accounts in the system expressed in Plain Old Data. #[derive(Debug, Clone, PartialEq, Eq, Default)] @@ -56,32 +54,3 @@ impl fmt::Display for PodAccounts { Ok(()) } } - - -/// State of all accounts in the system expressed in Plain Old Data. -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct PodShards(BTreeMap); - -impl Deref for PodShards { - type Target = BTreeMap; - - fn deref(&self) -> &::Target { - &self.0 - } -} - -impl From for PodShards { - fn from(s: cjson::scheme::Shards) -> PodShards { - let shards = s.into_iter().map(|(shard_id, shard)| (shard_id, shard.into())).collect(); - PodShards(shards) - } -} - -impl fmt::Display for PodShards { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for (shard_id, shard) in &self.0 { - writeln!(f, "{}: {}", shard_id, shard)?; - } - Ok(()) - } -} diff --git a/core/src/scheme/scheme.rs b/core/src/scheme/scheme.rs index 7c386c480b..f54a5985fd 100644 --- a/core/src/scheme/scheme.rs +++ b/core/src/scheme/scheme.rs @@ -22,7 +22,7 @@ use cdb::{AsHashDB, HashDB}; use cjson; use ckey::Address; use cmerkle::{TrieFactory, TrieMut}; -use cstate::{StateDB, StateResult, StateWithCache, TopLevelState}; +use cstate::{Metadata, MetadataAddress, StateDB, StateResult, StateWithCache, TopLevelState}; use ctypes::errors::SyntaxError; use ctypes::{BlockHash, CommonParams, Header}; use parking_lot::RwLock; @@ -112,6 +112,7 @@ impl Scheme { fn initialize_state(&self, db: StateDB) -> Result { let root = BLAKE_NULL_RLP; let (db, root) = self.initialize_accounts(db, root)?; + let (db, root) = self.initialize_metadata(db, root)?; let (db, root) = self.initialize_action_handlers(db, root)?; *self.state_root_memo.write() = root; @@ -133,6 +134,21 @@ impl Scheme { Ok((db, root)) } + fn initialize_metadata(&self, mut db: DB, mut root: H256) -> StateResult<(DB, H256)> { + { + let global_metadata = Metadata::new(); + + let mut t = TrieFactory::from_existing(db.as_hashdb_mut(), &mut root)?; + let address = MetadataAddress::new(); + + let r = t.insert(&*address, &global_metadata.rlp_bytes()); + debug_assert_eq!(Ok(None), r); + r?; + } + + 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)?; diff --git a/core/src/transaction.rs b/core/src/transaction.rs index 804b27a4e6..bd499eb34f 100644 --- a/core/src/transaction.rs +++ b/core/src/transaction.rs @@ -17,7 +17,7 @@ use std::ops::Deref; use ccrypto::blake256; -use ckey::{self, public_to_address, recover, sign, Private, Public, Signature}; +use ckey::{self, recover, sign, Private, Public, Signature}; use ctypes::errors::SyntaxError; use ctypes::transaction::Transaction; use ctypes::{BlockHash, BlockNumber, CommonParams, TxHash}; @@ -132,7 +132,7 @@ impl UnverifiedTransaction { /// Verify basic signature params. Does not attempt signer recovery. pub fn verify_basic(&self) -> Result<(), SyntaxError> { - self.action.verify() + Ok(()) } /// Verify transactiosn with the common params. Does not attempt signer recovery. @@ -160,7 +160,6 @@ pub struct PendingSignedTransactions { pub last_timestamp: Option, } - impl rlp::Encodable for SignedTransaction { fn rlp_append(&self, s: &mut RlpStream) { self.tx.rlp_append_sealed_transaction(s) @@ -197,8 +196,7 @@ impl SignedTransaction { /// Try to verify transaction and recover public. pub fn try_new(tx: UnverifiedTransaction) -> Result { let signer_public = tx.recover_public()?; - let signer = public_to_address(&signer_public); - tx.action.verify_with_signer_address(&signer)?; + let _signer = public_to_address(&signer_public); Ok(SignedTransaction { tx, signer_public, @@ -274,23 +272,6 @@ mod tests { use super::*; - #[test] - fn unverified_transaction_rlp() { - rlp_encode_and_decode_test!(UnverifiedTransaction { - unsigned: Transaction { - seq: 0, - fee: 10, - action: Action::CreateShard { - users: vec![Address::random(), Address::random()] - }, - network_id: "tc".into(), - }, - sig: Signature::default(), - hash: H256::default().into(), - } - .compute_hash()); - } - #[test] fn encode_and_decode_pay_transaction() { rlp_encode_and_decode_test!(UnverifiedTransaction { @@ -325,21 +306,4 @@ mod tests { } .compute_hash()); } - - #[test] - fn encode_and_decode_create_shard_transaction() { - rlp_encode_and_decode_test!(UnverifiedTransaction { - unsigned: Transaction { - seq: 30, - fee: 40, - network_id: "tc".into(), - action: Action::CreateShard { - users: vec![] - }, - }, - sig: Signature::default(), - hash: H256::default().into(), - } - .compute_hash()); - } } diff --git a/core/src/verification/canon_verifier.rs b/core/src/verification/canon_verifier.rs index 295ed45769..afa881be84 100644 --- a/core/src/verification/canon_verifier.rs +++ b/core/src/verification/canon_verifier.rs @@ -32,10 +32,9 @@ impl Verifier for CanonVerifier { header: &Header, parent: &Header, engine: &dyn CodeChainEngine, - do_full: Option>, common_params: &CommonParams, ) -> Result<(), Error> { - verification::verify_block_family(block, header, parent, engine, do_full, common_params) + verification::verify_block_family(block, header, parent, engine, common_params) } fn verify_block_final(&self, expected: &Header, got: &Header) -> Result<(), Error> { diff --git a/core/src/verification/noop_verifier.rs b/core/src/verification/noop_verifier.rs index 8c93d2e1a9..cbbeaa69cf 100644 --- a/core/src/verification/noop_verifier.rs +++ b/core/src/verification/noop_verifier.rs @@ -16,7 +16,7 @@ use ctypes::{CommonParams, Header}; -use super::{verification, Verifier}; +use super::Verifier; use crate::client::BlockChainTrait; use crate::consensus::CodeChainEngine; use crate::error::Error; @@ -31,7 +31,6 @@ impl Verifier for NoopVerifier { _: &Header, _t: &Header, _: &dyn CodeChainEngine, - _: Option>, _common_params: &CommonParams, ) -> Result<(), Error> { Ok(()) diff --git a/core/src/verification/verification.rs b/core/src/verification/verification.rs index 5ad32138f6..e72f5d6aab 100644 --- a/core/src/verification/verification.rs +++ b/core/src/verification/verification.rs @@ -22,8 +22,6 @@ use ctypes::{BlockNumber, CommonParams, Header}; use primitives::{Bytes, H256}; use rlp::Rlp; -use crate::blockchain::BlockProvider; -use crate::client::BlockChainTrait; use crate::codechain_machine::CodeChainMachine; use crate::consensus::CodeChainEngine; use crate::error::{BlockError, Error}; @@ -179,28 +177,12 @@ pub fn verify_block_seal( }) } -/// Parameters for full verification of block family -pub struct FullFamilyParams<'a, C: BlockChainTrait + 'a> { - /// Serialized block bytes - pub block_bytes: &'a [u8], - - /// Signed transactions - pub transactions: &'a [SignedTransaction], - - /// Block provider to use during verification - pub block_provider: &'a dyn BlockProvider, - - /// Engine client to use during verification - pub client: &'a C, -} - /// Phase 3 verification. Check block information against parent and uncles. -pub fn verify_block_family( +pub fn verify_block_family( block: &[u8], header: &Header, parent: &Header, engine: &dyn CodeChainEngine, - do_full: Option>, common_params: &CommonParams, ) -> Result<(), Error> { verify_block_with_params(header, block, engine, common_params)?; @@ -210,15 +192,6 @@ pub fn verify_block_family( verify_transactions_root(block, header.transactions_root(), *parent.transactions_root())?; engine.verify_block_family(&header, &parent)?; - let params = match do_full { - Some(x) => x, - None => return Ok(()), - }; - - for tx in params.transactions { - engine.machine().verify_transaction(tx, header, params.client, true)?; - } - Ok(()) } diff --git a/core/src/verification/verifier.rs b/core/src/verification/verifier.rs index 6917d0e4cb..825ab2a5c7 100644 --- a/core/src/verification/verifier.rs +++ b/core/src/verification/verifier.rs @@ -16,7 +16,6 @@ use ctypes::{CommonParams, Header}; -use super::verification; use crate::client::BlockChainTrait; use crate::consensus::CodeChainEngine; use crate::error::Error; @@ -32,7 +31,6 @@ where header: &Header, parent: &Header, engine: &dyn CodeChainEngine, - do_full: Option>, common_params: &CommonParams, ) -> Result<(), Error>; diff --git a/foundry/config/mod.rs b/foundry/config/mod.rs index e4ea5538d6..c07468fab9 100644 --- a/foundry/config/mod.rs +++ b/foundry/config/mod.rs @@ -99,7 +99,6 @@ impl Config { mem_size => Some(mem_size * 1024 * 1024), }, mem_pool_fee_bump_shift: self.mining.mem_pool_fee_bump_shift.unwrap(), - allow_create_shard: self.mining.allow_create_shard.unwrap_or(false), new_work_notify: self.mining.notify_work.clone().unwrap(), force_sealing: self.mining.force_sealing.unwrap(), reseal_on_own_transaction, @@ -508,9 +507,6 @@ impl Mining { if let Some(mem_pool_size) = matches.value_of("mem-pool-size") { self.mem_pool_size = Some(mem_pool_size.parse().map_err(|_| "Invalid size")?); } - if matches.is_present("allow-create-shard") { - self.allow_create_shard = Some(true) - } if let Some(notify_work) = matches.values_of("notify-work") { self.notify_work = Some(notify_work.map(|a| a.into()).collect()); } diff --git a/json/src/scheme/mod.rs b/json/src/scheme/mod.rs index 0587d487c6..fe504a06fa 100644 --- a/json/src/scheme/mod.rs +++ b/json/src/scheme/mod.rs @@ -24,7 +24,6 @@ mod params; #[cfg_attr(feature = "cargo-clippy", allow(clippy::module_inception))] mod scheme; mod seal; -mod shard; mod simple_poa; mod solo; mod state; @@ -39,8 +38,7 @@ pub use self::null_engine::{NullEngine, NullEngineParams}; pub use self::params::Params; pub use self::scheme::Scheme; pub use self::seal::{Seal, TendermintSeal}; -pub use self::shard::Shard; pub use self::simple_poa::{SimplePoA, SimplePoAParams}; pub use self::solo::{Solo, SoloParams}; -pub use self::state::{Accounts, Shards}; +pub use self::state::Accounts; pub use self::tendermint::{Tendermint, TendermintParams}; diff --git a/json/src/scheme/scheme.rs b/json/src/scheme/scheme.rs index b48eefedfc..4259791cd3 100644 --- a/json/src/scheme/scheme.rs +++ b/json/src/scheme/scheme.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::{Accounts, Engine, Genesis, Params, Shards}; +use super::{Accounts, Engine, Genesis, Params}; use serde_json; use serde_json::Error; use std::io::Read; @@ -35,7 +35,6 @@ pub struct Scheme { pub genesis: Genesis, /// Genesis state. pub accounts: Accounts, - pub shards: Shards, /// Boot nodes. pub nodes: Option>, } @@ -122,8 +121,6 @@ mod tests { "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqvxf40sk": { "balance": "1", "seq": "1048576" }, "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqszkma5z": { "balance": "1", "seq": "1048576" }, "tccq8txq9uafdg8y2de9m2tdkhsfsj3m9nluq94hyan": { "balance": "1606938044258990275541962092341162602522202993782792835301376", "seq": "1048576" } - }, - "shards": { } }"#; let _deserialized: Scheme = serde_json::from_str(s).unwrap(); diff --git a/json/src/scheme/shard.rs b/json/src/scheme/shard.rs deleted file mode 100644 index 8129221ab6..0000000000 --- a/json/src/scheme/shard.rs +++ /dev/null @@ -1,96 +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 . - -use ckey::PlatformAddress; - -use crate::uint::Uint; - -#[derive(Debug, PartialEq, Deserialize)] -pub struct Shard { - pub seq: Option, - pub owners: Vec, - pub users: Option>, -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use ckey::PlatformAddress; - use serde_json; - - use super::*; - - #[test] - fn shard_deserialization() { - let s = r#"{ - "seq": 0, - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"] - }"#; - let shard: Shard = serde_json::from_str(s).unwrap(); - assert_eq!( - Shard { - seq: Some(0.into()), - owners: vec![PlatformAddress::from_str("tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u").unwrap()], - users: None, - }, - shard - ); - } - - #[test] - fn shard_with_non_zero_seq_deserialization() { - let s = r#"{ - "seq": 100, - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"], - "users": ["tccq8txq9uafdg8y2de9m2tdkhsfsj3m9nluq94hyan"] - }"#; - let shard: Shard = serde_json::from_str(s).unwrap(); - assert_eq!( - Shard { - seq: Some(100.into()), - owners: vec![PlatformAddress::from_str("tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u").unwrap()], - users: Some(vec![PlatformAddress::from_str("tccq8txq9uafdg8y2de9m2tdkhsfsj3m9nluq94hyan").unwrap()]), - }, - shard - ); - } - - - #[test] - fn deserialization_of_empty_shard_fails() { - let s = r#"{ - }"#; - let result: Result = serde_json::from_str(s); - assert!(result.is_err()); - } - - #[test] - fn shard_without_seq_deserialization() { - let s = r#"{ - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"] - }"#; - let shard: Shard = serde_json::from_str(s).unwrap(); - assert_eq!( - Shard { - seq: None, - owners: vec![PlatformAddress::from_str("tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u").unwrap()], - users: None, - }, - shard - ); - } -} diff --git a/json/src/scheme/state.rs b/json/src/scheme/state.rs index 674639048b..2b43a924eb 100644 --- a/json/src/scheme/state.rs +++ b/json/src/scheme/state.rs @@ -18,7 +18,6 @@ use std::collections::BTreeMap; use ckey::PlatformAddress; -use super::{Account, Shard}; +use super::Account; pub type Accounts = BTreeMap; -pub type Shards = BTreeMap; diff --git a/rpc/src/v1/errors.rs b/rpc/src/v1/errors.rs index c979967187..cc6009d244 100644 --- a/rpc/src/v1/errors.rs +++ b/rpc/src/v1/errors.rs @@ -68,7 +68,6 @@ mod codes { pub const WRONG_PASSWORD: i64 = -32043; pub const NO_SUCH_ACCOUNT: i64 = -32044; pub const NOT_UNLOCKED: i64 = -32045; - pub const TRANSFER_ONLY_IN_EXECUTE_VM: i64 = -32046; pub const STATE_NOT_EXIST: i64 = -32048; pub const ACTION_DATA_HANDLER_NOT_FOUND: i64 = -32049; pub const UNKNOWN_ERROR: i64 = -32099; @@ -261,14 +260,6 @@ pub fn network_control(error: &NetworkControlError) -> Error { } } -pub fn transfer_only() -> Error { - Error { - code: ErrorCode::ServerError(codes::TRANSFER_ONLY_IN_EXECUTE_VM), - message: "chain_executeVM() only accepts AssetTransfer transactions.".into(), - data: None, - } -} - pub fn state_not_exist() -> Error { Error { code: ErrorCode::ServerError(codes::STATE_NOT_EXIST), diff --git a/rpc/src/v1/impls/chain.rs b/rpc/src/v1/impls/chain.rs index 79a6862c41..7b7f3b78c2 100644 --- a/rpc/src/v1/impls/chain.rs +++ b/rpc/src/v1/impls/chain.rs @@ -14,33 +14,30 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::convert::TryInto; use std::sync::Arc; -use ccore::{AccountData, BlockId, EngineInfo, ExecuteClient, MiningBlockChainClient, TermInfo, TextClient}; +use ccore::{AccountData, BlockId, EngineInfo, MiningBlockChainClient, TermInfo, TextClient}; use cjson::scheme::Params; use cjson::uint::Uint; use ckey::{public_to_address, NetworkId, PlatformAddress, Public}; use cstate::FindActionHandler; -use ctypes::transaction::{Action, ShardTransaction as ShardTransactionType}; -use ctypes::{BlockHash, BlockNumber, Tracker, TxHash}; -use primitives::Bytes as BytesArray; +use ctypes::{BlockHash, BlockNumber, TxHash}; use jsonrpc_core::Result; use super::super::errors; use super::super::traits::Chain; -use super::super::types::{Block, BlockNumberAndHash, Text, Transaction, UnsignedTransaction}; +use super::super::types::{Block, BlockNumberAndHash, Text, Transaction}; pub struct ChainClient where - C: MiningBlockChainClient + ExecuteClient + EngineInfo, { + C: MiningBlockChainClient + EngineInfo, { client: Arc, } impl ChainClient where - C: MiningBlockChainClient + AccountData + ExecuteClient + EngineInfo + TextClient, + C: MiningBlockChainClient + AccountData + EngineInfo + TextClient, { pub fn new(client: Arc) -> Self { ChainClient { @@ -51,14 +48,7 @@ where impl Chain for ChainClient where - C: MiningBlockChainClient - + AccountData - + ExecuteClient - + EngineInfo - + FindActionHandler - + TextClient - + TermInfo - + 'static, + C: MiningBlockChainClient + AccountData + EngineInfo + FindActionHandler + TextClient + TermInfo + 'static, { fn get_transaction(&self, transaction_hash: TxHash) -> Result> { let id = transaction_hash.into(); @@ -81,10 +71,6 @@ where self.contains_transaction(transaction_hash) } - fn get_transaction_by_tracker(&self, tracker: Tracker) -> Result> { - Ok(self.client.transaction_by_tracker(&tracker).map(From::from)) - } - fn get_text(&self, transaction_hash: TxHash, block_number: Option) -> Result> { if block_number == Some(0) { return Ok(None) @@ -236,23 +222,4 @@ where fn get_possible_authors(&self, block_number: Option) -> Result>> { Ok(self.client.possible_authors(block_number).map_err(errors::core)?) } - - fn execute_vm( - &self, - tx: UnsignedTransaction, - params: Vec>, - indices: Vec, - ) -> Result> { - let action = tx.action.try_into().map_err(errors::conversion)?; - if let Action::TransferAsset { - inputs, - .. - } = &action - { - let transaction = Option::::from(action.clone()).unwrap(); - Ok(self.client.execute_vm(&transaction, inputs, ¶ms, &indices).map_err(errors::core)?) - } else { - Err(errors::transfer_only()) - } - } } diff --git a/rpc/src/v1/impls/mempool.rs b/rpc/src/v1/impls/mempool.rs index ed021f1c8d..2cbaaa8efa 100644 --- a/rpc/src/v1/impls/mempool.rs +++ b/rpc/src/v1/impls/mempool.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use ccore::{BlockChainClient, MiningBlockChainClient, SignedTransaction}; use cjson::bytes::Bytes; use ckey::{Address, PlatformAddress}; -use ctypes::{Tracker, TxHash}; +use ctypes::TxHash; use rlp::Rlp; use jsonrpc_core::Result; @@ -59,15 +59,6 @@ where .map(Into::into) } - fn get_transaction_results_by_tracker(&self, tracker: Tracker) -> Result> { - Ok(self - .client - .error_hints_by_tracker(&tracker) - .into_iter() - .map(|(_hash, error_hint)| error_hint.is_none()) - .collect()) - } - fn get_error_hint(&self, transaction_hash: TxHash) -> Result> { Ok(self.client.error_hint(&transaction_hash)) } diff --git a/rpc/src/v1/traits/chain.rs b/rpc/src/v1/traits/chain.rs index 1aac70608d..ad64543b5e 100644 --- a/rpc/src/v1/traits/chain.rs +++ b/rpc/src/v1/traits/chain.rs @@ -17,12 +17,11 @@ use cjson::scheme::Params; use cjson::uint::Uint; use ckey::{NetworkId, PlatformAddress, Public}; -use ctypes::{BlockHash, BlockNumber, Tracker, TxHash}; -use primitives::Bytes as BytesArray; +use ctypes::{BlockHash, BlockNumber, TxHash}; use jsonrpc_core::Result; -use super::super::types::{Block, BlockNumberAndHash, Text, Transaction, UnsignedTransaction}; +use super::super::types::{Block, BlockNumberAndHash, Text, Transaction}; #[rpc(server)] pub trait Chain { @@ -41,10 +40,6 @@ pub trait Chain { #[rpc(name = "chain_containTransaction")] fn contain_transaction(&self, transaction_hash: TxHash) -> Result; - /// Gets transaction with given transaction tracker. - #[rpc(name = "chain_getTransactionByTracker")] - fn get_transaction_by_tracker(&self, tracker: Tracker) -> Result>; - /// Gets text with given transaction hash. #[rpc(name = "chain_getText")] fn get_text(&self, transaction_hash: TxHash, block_number: Option) -> Result>; @@ -120,13 +115,4 @@ pub trait Chain { /// Return the valid block authors #[rpc(name = "chain_getPossibleAuthors")] fn get_possible_authors(&self, block_number: Option) -> Result>>; - - /// Execute AssetTransfer transaction inputs in VM - #[rpc(name = "chain_executeVM")] - fn execute_vm( - &self, - tx: UnsignedTransaction, - params: Vec>, - indices: Vec, - ) -> Result>; } diff --git a/rpc/src/v1/traits/mempool.rs b/rpc/src/v1/traits/mempool.rs index b7726306b0..72532742d4 100644 --- a/rpc/src/v1/traits/mempool.rs +++ b/rpc/src/v1/traits/mempool.rs @@ -16,7 +16,7 @@ use cjson::bytes::Bytes; use ckey::PlatformAddress; -use ctypes::{Tracker, TxHash}; +use ctypes::TxHash; use jsonrpc_core::Result; use super::super::types::PendingTransactions; @@ -27,10 +27,6 @@ pub trait Mempool { #[rpc(name = "mempool_sendSignedTransaction")] fn send_signed_transaction(&self, raw: Bytes) -> Result; - /// Gets transaction results with given transaction tracker. - #[rpc(name = "mempool_getTransactionResultsByTracker")] - fn get_transaction_results_by_tracker(&self, tracker: Tracker) -> Result>; - /// Gets a hint to find out why the transaction failed. #[rpc(name = "mempool_getErrorHint")] fn get_error_hint(&self, transaction_hash: TxHash) -> Result>; diff --git a/rpc/src/v1/types/action.rs b/rpc/src/v1/types/action.rs index 25343e937a..054c15bd9b 100644 --- a/rpc/src/v1/types/action.rs +++ b/rpc/src/v1/types/action.rs @@ -18,184 +18,15 @@ use std::convert::TryFrom; use cjson::uint::Uint; use ckey::{NetworkId, PlatformAddress, Public, Signature}; -use ctypes::transaction::{Action as ActionType, AssetMintOutput as AssetMintOutputType}; -use ctypes::{ShardId, Tracker, TxHash}; -use primitives::{Bytes, H160}; -use rustc_serialize::hex::{FromHex, ToHex}; +use ctypes::transaction::Action as ActionType; +use ctypes::TxHash; +use primitives::Bytes; use super::super::errors::ConversionError; -use super::{AssetMintOutput, AssetTransferInput, AssetTransferOutput}; -#[derive(Debug, Deserialize, PartialEq)] +#[derive(Debug, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase", tag = "type")] pub enum Action { - #[serde(rename_all = "camelCase")] - MintAsset { - network_id: NetworkId, - shard_id: ShardId, - metadata: String, - approver: Option, - registrar: Option, - allowed_script_hashes: Vec, - - output: Box, - - approvals: Vec, - }, - #[serde(rename_all = "camelCase")] - TransferAsset { - network_id: NetworkId, - burns: Vec, - inputs: Vec, - outputs: Vec, - - metadata: String, - approvals: Vec, - expiration: Option, - }, - #[serde(rename_all = "camelCase")] - ChangeAssetScheme { - network_id: NetworkId, - shard_id: ShardId, - asset_type: H160, - seq: u64, - metadata: String, - approver: Option, - registrar: Option, - allowed_script_hashes: Vec, - - approvals: Vec, - }, - #[serde(rename_all = "camelCase")] - IncreaseAssetSupply { - network_id: NetworkId, - shard_id: ShardId, - asset_type: H160, - seq: u64, - output: Box, - - approvals: Vec, - }, - #[serde(rename_all = "camelCase")] - UnwrapCCC { - network_id: NetworkId, - burn: AssetTransferInput, - receiver: PlatformAddress, - }, - Pay { - receiver: PlatformAddress, - quantity: Uint, - }, - SetRegularKey { - key: Public, - }, - CreateShard { - users: Vec, - }, - #[serde(rename_all = "camelCase")] - SetShardOwners { - shard_id: ShardId, - owners: Vec, - }, - #[serde(rename_all = "camelCase")] - SetShardUsers { - shard_id: ShardId, - users: Vec, - }, - #[serde(rename_all = "camelCase")] - WrapCCC { - shard_id: ShardId, - lock_script_hash: H160, - parameters: Vec, - quantity: Uint, - payer: PlatformAddress, - }, - Store { - content: String, - certifier: PlatformAddress, - signature: Signature, - }, - Remove { - hash: TxHash, - signature: Signature, - }, - #[serde(rename_all = "camelCase")] - Custom { - handler_id: Uint, - bytes: Bytes, - }, -} - -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase", tag = "type")] -pub enum ActionWithTracker { - #[serde(rename_all = "camelCase")] - MintAsset { - network_id: NetworkId, - shard_id: ShardId, - metadata: String, - approver: Option, - registrar: Option, - allowed_script_hashes: Vec, - - output: Box, - - approvals: Vec, - - tracker: Tracker, - }, - #[serde(rename_all = "camelCase")] - TransferAsset { - network_id: NetworkId, - burns: Vec, - inputs: Vec, - outputs: Vec, - // NOTE: The orders field is removed in the core but it remains to - // support the old version of the SDK - orders: Vec<()>, - - metadata: String, - approvals: Vec, - expiration: Option, - - tracker: Tracker, - }, - #[serde(rename_all = "camelCase")] - ChangeAssetScheme { - network_id: NetworkId, - shard_id: ShardId, - asset_type: H160, - seq: u64, - metadata: String, - approver: Option, - registrar: Option, - allowed_script_hashes: Vec, - - approvals: Vec, - - tracker: Tracker, - }, - #[serde(rename_all = "camelCase")] - IncreaseAssetSupply { - network_id: NetworkId, - shard_id: ShardId, - asset_type: H160, - seq: u64, - output: Box, - - approvals: Vec, - - tracker: Tracker, - }, - - #[serde(rename_all = "camelCase")] - UnwrapCCC { - network_id: NetworkId, - burn: Box, - receiver: PlatformAddress, - - tracker: Tracker, - }, Pay { receiver: PlatformAddress, quantity: Uint, @@ -203,27 +34,6 @@ pub enum ActionWithTracker { SetRegularKey { key: Public, }, - CreateShard { - users: Vec, - }, - #[serde(rename_all = "camelCase")] - SetShardOwners { - shard_id: ShardId, - owners: Vec, - }, - #[serde(rename_all = "camelCase")] - SetShardUsers { - shard_id: ShardId, - users: Vec, - }, - #[serde(rename_all = "camelCase")] - WrapCCC { - shard_id: ShardId, - lock_script_hash: H160, - parameters: Vec, - quantity: Uint, - payer: PlatformAddress, - }, Store { content: String, certifier: PlatformAddress, @@ -240,473 +50,87 @@ pub enum ActionWithTracker { }, } -impl ActionWithTracker { - pub fn from_core(from: ActionType, network_id: NetworkId) -> Self { - let tracker = from.tracker(); - match from { - ActionType::MintAsset { - network_id, - shard_id, - metadata, - approver, - registrar, - allowed_script_hashes, - - output, - approvals, - } => ActionWithTracker::MintAsset { - network_id, - shard_id, - metadata, - approver: approver.map(|approver| PlatformAddress::new_v1(network_id, approver)), - registrar: registrar.map(|registrar| PlatformAddress::new_v1(network_id, registrar)), - allowed_script_hashes, - output: Box::new((*output).into()), - approvals, - tracker: tracker.unwrap(), - }, - ActionType::TransferAsset { - network_id, - burns, - inputs, - outputs, - metadata, - approvals, - expiration, - } => ActionWithTracker::TransferAsset { - network_id, - burns: burns.into_iter().map(From::from).collect(), - inputs: inputs.into_iter().map(From::from).collect(), - outputs: outputs.into_iter().map(From::from).collect(), - orders: vec![], - metadata, - approvals, - expiration: expiration.map(From::from), - tracker: tracker.unwrap(), - }, - ActionType::ChangeAssetScheme { - network_id, - shard_id, - asset_type, - seq, - metadata, - approver, - registrar, - allowed_script_hashes, - approvals, - } => ActionWithTracker::ChangeAssetScheme { - network_id, - shard_id, - asset_type, - seq: seq as u64, - metadata, - approver: approver.map(|approver| PlatformAddress::new_v1(network_id, approver)), - registrar: registrar.map(|registrar| PlatformAddress::new_v1(network_id, registrar)), - allowed_script_hashes, - approvals, - tracker: tracker.unwrap(), - }, - ActionType::IncreaseAssetSupply { - network_id, - shard_id, - asset_type, - seq, - output, - approvals, - } => ActionWithTracker::IncreaseAssetSupply { - network_id, - shard_id, - asset_type, - seq: seq as u64, - output: Box::new((*output).into()), - approvals, - tracker: tracker.unwrap(), - }, - ActionType::UnwrapCCC { - network_id, - burn, - receiver, - } => ActionWithTracker::UnwrapCCC { - network_id, - burn: Box::new(burn.into()), - receiver: PlatformAddress::new_v1(network_id, receiver), - tracker: tracker.unwrap(), - }, - ActionType::Pay { +impl TryFrom for ActionType { + type Error = ConversionError; + fn try_from(from: Action) -> Result { + Ok(match from { + Action::Pay { receiver, quantity, - } => ActionWithTracker::Pay { - receiver: PlatformAddress::new_v1(network_id, receiver), + } => ActionType::Pay { + receiver: receiver.try_into_address()?, quantity: quantity.into(), }, - ActionType::SetRegularKey { + Action::SetRegularKey { key, - } => ActionWithTracker::SetRegularKey { + } => ActionType::SetRegularKey { key, }, - ActionType::CreateShard { - users, - } => { - let users = users.into_iter().map(|user| PlatformAddress::new_v1(network_id, user)).collect(); - ActionWithTracker::CreateShard { - users, - } - } - ActionType::SetShardOwners { - shard_id, - owners, - } => ActionWithTracker::SetShardOwners { - shard_id, - owners: owners.into_iter().map(|owner| PlatformAddress::new_v1(network_id, owner)).collect(), - }, - ActionType::SetShardUsers { - shard_id, - users, - } => ActionWithTracker::SetShardUsers { - shard_id, - users: users.into_iter().map(|user| PlatformAddress::new_v1(network_id, user)).collect(), - }, - ActionType::WrapCCC { - shard_id, - lock_script_hash, - parameters, - quantity, - payer, - } => { - let parameters = parameters.into_iter().map(|param| param.to_hex()).collect(); - let payer = PlatformAddress::new_v1(network_id, payer); - ActionWithTracker::WrapCCC { - shard_id, - lock_script_hash, - parameters, - quantity: quantity.into(), - payer, - } - } - ActionType::Store { + Action::Store { content, certifier, signature, - } => ActionWithTracker::Store { + } => ActionType::Store { content, - certifier: PlatformAddress::new_v1(network_id, certifier), + certifier: certifier.try_into_address()?, signature, }, - ActionType::Remove { + Action::Remove { hash, signature, - } => ActionWithTracker::Remove { + } => ActionType::Remove { hash, signature, }, - ActionType::Custom { + Action::Custom { handler_id, bytes, - } => ActionWithTracker::Custom { + } => ActionType::Custom { handler_id: handler_id.into(), bytes, }, - } + }) } } -impl TryFrom for ActionType { - type Error = ConversionError; - fn try_from(from: Action) -> Result { - Ok(match from { - Action::MintAsset { - network_id, - shard_id, - metadata, - approver, - registrar, - allowed_script_hashes, - output, - approvals, - } => { - let approver = match approver { - Some(approver) => Some(approver.try_into_address()?), - None => None, - }; - let registrar = match registrar { - Some(registrar) => Some(registrar.try_into_address()?), - None => None, - }; - let output_content = AssetMintOutputType::try_from(*output)?; - ActionType::MintAsset { - network_id, - shard_id, - metadata, - approver, - registrar, - allowed_script_hashes, - output: Box::new(output_content), - approvals, - } - } - Action::TransferAsset { - network_id, - burns, - inputs, - outputs, - - metadata, - approvals, - expiration, - } => { - let outputs = outputs.into_iter().map(TryFrom::try_from).collect::>()?; - ActionType::TransferAsset { - network_id, - burns: burns.into_iter().map(From::from).collect(), - inputs: inputs.into_iter().map(From::from).collect(), - outputs, - metadata, - approvals, - expiration: expiration.map(From::from), - } - } - Action::ChangeAssetScheme { - network_id, - shard_id, - asset_type, - seq, - metadata, - approver, - registrar, - allowed_script_hashes, - - approvals, - } => { - let approver = match approver { - Some(approver) => Some(approver.try_into_address()?), - None => None, - }; - let registrar = match registrar { - Some(registrar) => Some(registrar.try_into_address()?), - None => None, - }; - ActionType::ChangeAssetScheme { - network_id, - shard_id, - asset_type, - seq: seq as usize, - metadata, - approver, - registrar, - allowed_script_hashes, - approvals, - } - } - Action::IncreaseAssetSupply { - network_id, - shard_id, - asset_type, - seq, - output, - approvals, - } => { - let output_content = AssetMintOutputType::try_from(*output)?; - ActionType::IncreaseAssetSupply { - network_id, - shard_id, - seq: seq as usize, - asset_type, - output: Box::new(output_content), - approvals, - } - } - Action::UnwrapCCC { - network_id, - burn, - receiver, - } => ActionType::UnwrapCCC { - network_id, - burn: burn.into(), - receiver: receiver.try_into_address()?, - }, - Action::Pay { +impl Action { + pub fn from_core(from: ActionType, network_id: NetworkId) -> Self { + match from { + ActionType::Pay { receiver, quantity, - } => ActionType::Pay { - receiver: receiver.try_into_address()?, + } => Action::Pay { + receiver: PlatformAddress::new_v1(network_id, receiver), quantity: quantity.into(), }, - Action::SetRegularKey { + ActionType::SetRegularKey { key, - } => ActionType::SetRegularKey { + } => Action::SetRegularKey { key, }, - Action::CreateShard { - users, - } => { - let users = users.into_iter().map(PlatformAddress::try_into_address).collect::>()?; - ActionType::CreateShard { - users, - } - } - Action::SetShardOwners { - shard_id, - owners, - } => { - let owners: Result<_, _> = owners.into_iter().map(PlatformAddress::try_into_address).collect(); - ActionType::SetShardOwners { - shard_id, - owners: owners?, - } - } - Action::SetShardUsers { - shard_id, - users, - } => { - let users: Result<_, _> = users.into_iter().map(PlatformAddress::try_into_address).collect(); - ActionType::SetShardUsers { - shard_id, - users: users?, - } - } - Action::WrapCCC { - shard_id, - lock_script_hash, - parameters, - quantity, - payer, - } => { - let parameters = parameters.into_iter().map(|param| param.from_hex()).collect::>()?; - ActionType::WrapCCC { - shard_id, - lock_script_hash, - parameters, - quantity: quantity.into(), - payer: payer.try_into_address()?, - } - } - Action::Store { + ActionType::Store { content, certifier, signature, - } => ActionType::Store { + } => Action::Store { content, - certifier: certifier.try_into_address()?, + certifier: PlatformAddress::new_v1(network_id, certifier), signature, }, - Action::Remove { + ActionType::Remove { hash, signature, - } => ActionType::Remove { + } => Action::Remove { hash, signature, }, - Action::Custom { + ActionType::Custom { handler_id, bytes, - } => ActionType::Custom { + } => Action::Custom { handler_id: handler_id.into(), bytes, }, - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use serde_json::{from_str, to_string}; - - #[test] - fn serialize_metadata_with_single_quotations() { - let mint = ActionWithTracker::MintAsset { - network_id: "ab".into(), - shard_id: 0, - metadata: "string with 'a single quotation'".to_string(), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - - output: AssetMintOutput { - lock_script_hash: Default::default(), - parameters: vec![], - supply: 1.into(), - } - .into(), - - approvals: vec![], - tracker: Default::default(), - }; - let s = to_string(&mint).unwrap(); - let expected = r#"{"type":"mintAsset","networkId":"ab","shardId":0,"metadata":"string with 'a single quotation'","approver":null,"registrar":null,"allowedScriptHashes":[],"output":{"lockScriptHash":"0x0000000000000000000000000000000000000000","parameters":[],"supply":"0x1"},"approvals":[],"tracker":"0x0000000000000000000000000000000000000000000000000000000000000000"}"#; - assert_eq!(&s, expected); - } - - #[test] - fn parse_metadata_with_single_quotations() { - let input = r#"{"type":"mintAsset","networkId":"ab","shardId":0,"metadata":"string with 'a single quotation'","approver":null,"registrar":null,"allowedScriptHashes":[],"output":{"lockScriptHash":"0x0000000000000000000000000000000000000000","parameters":[],"supply":"0x1"},"approvals":[]}"#; - let mint = from_str(input).unwrap(); - let expected = Action::MintAsset { - network_id: "ab".into(), - shard_id: 0, - metadata: "string with 'a single quotation'".to_string(), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - - output: AssetMintOutput { - lock_script_hash: Default::default(), - parameters: vec![], - supply: 1.into(), - } - .into(), - - approvals: vec![], - }; - assert_eq!(expected, mint); - } - - #[test] - fn parse_metadata_with_apostrophe() { - let input = r#"{"type":"mintAsset","networkId":"ab","shardId":0,"metadata":"string with 'an apostrophe’","approver":null,"registrar":null,"allowedScriptHashes":[],"output":{"lockScriptHash":"0x0000000000000000000000000000000000000000","parameters":[],"supply":"0x1"},"approvals":[]}"#; - let mint = from_str(input).unwrap(); - let expected = Action::MintAsset { - network_id: "ab".into(), - shard_id: 0, - metadata: "string with 'an apostrophe’".to_string(), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - - output: AssetMintOutput { - lock_script_hash: Default::default(), - parameters: vec![], - supply: 1.into(), - } - .into(), - - approvals: vec![], - }; - assert_eq!(expected, mint); - } - - #[test] - fn serialize_metadata_with_apostrophe() { - let mint = ActionWithTracker::MintAsset { - network_id: "ab".into(), - shard_id: 0, - metadata: "string with 'an apostrophe’".to_string(), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - - output: AssetMintOutput { - lock_script_hash: Default::default(), - parameters: vec![], - supply: 1.into(), - } - .into(), - - approvals: vec![], - tracker: Default::default(), - }; - let s = to_string(&mint).unwrap(); - let expected = r#"{"type":"mintAsset","networkId":"ab","shardId":0,"metadata":"string with 'an apostrophe’","approver":null,"registrar":null,"allowedScriptHashes":[],"output":{"lockScriptHash":"0x0000000000000000000000000000000000000000","parameters":[],"supply":"0x1"},"approvals":[],"tracker":"0x0000000000000000000000000000000000000000000000000000000000000000"}"#; - assert_eq!(&s, expected); + } } } diff --git a/rpc/src/v1/types/asset.rs b/rpc/src/v1/types/asset.rs deleted file mode 100644 index 63e2244480..0000000000 --- a/rpc/src/v1/types/asset.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 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 . - -use cjson::uint::Uint; -use primitives::H160; - -#[derive(Clone, Debug, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Asset { - asset_type: H160, - quantity: Uint, -} - -#[derive(Clone, Debug, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct OwnedAsset { - #[serde(flatten)] - asset: Asset, - lock_script_hash: H160, - parameters: Vec, -} diff --git a/rpc/src/v1/types/asset_input.rs b/rpc/src/v1/types/asset_input.rs deleted file mode 100644 index 65fba8832c..0000000000 --- a/rpc/src/v1/types/asset_input.rs +++ /dev/null @@ -1,85 +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 . - -use cjson::uint::Uint; -use ctypes::transaction::{AssetOutPoint as AssetOutPointType, AssetTransferInput as AssetTransferInputType, Timelock}; -use ctypes::{ShardId, Tracker}; -use primitives::{Bytes, H160}; - -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct AssetOutPoint { - pub tracker: Tracker, - pub index: usize, - pub asset_type: H160, - pub shard_id: ShardId, - pub quantity: Uint, -} - -impl From for AssetOutPoint { - fn from(from: AssetOutPointType) -> Self { - AssetOutPoint { - tracker: from.tracker, - index: from.index, - asset_type: from.asset_type, - shard_id: from.shard_id, - quantity: from.quantity.into(), - } - } -} - -impl From for AssetOutPointType { - fn from(from: AssetOutPoint) -> Self { - AssetOutPointType { - tracker: from.tracker, - index: from.index, - asset_type: from.asset_type, - shard_id: from.shard_id, - quantity: from.quantity.into(), - } - } -} - -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct AssetTransferInput { - pub prev_out: AssetOutPoint, - pub timelock: Option, - pub lock_script: Bytes, - pub unlock_script: Bytes, -} - -impl From for AssetTransferInput { - fn from(from: AssetTransferInputType) -> Self { - AssetTransferInput { - prev_out: from.prev_out.into(), - timelock: from.timelock, - lock_script: from.lock_script, - unlock_script: from.unlock_script, - } - } -} - -impl From for AssetTransferInputType { - fn from(from: AssetTransferInput) -> Self { - AssetTransferInputType { - prev_out: from.prev_out.into(), - timelock: from.timelock, - lock_script: from.lock_script, - unlock_script: from.unlock_script, - } - } -} diff --git a/rpc/src/v1/types/asset_output.rs b/rpc/src/v1/types/asset_output.rs deleted file mode 100644 index d8780f8b2a..0000000000 --- a/rpc/src/v1/types/asset_output.rs +++ /dev/null @@ -1,90 +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 . -extern crate rustc_serialize; - -use std::convert::TryFrom; -use std::iter::FromIterator; -use std::ops::Deref; - -use cjson::uint::Uint; -use ctypes::transaction::{AssetMintOutput as AssetMintOutputType, AssetTransferOutput as AssetTransferOutputType}; -use ctypes::ShardId; -use primitives::H160; -use rustc_serialize::hex::{FromHex, FromHexError, ToHex}; - -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct AssetTransferOutput { - pub lock_script_hash: H160, - pub parameters: Vec, - pub asset_type: H160, - pub shard_id: ShardId, - pub quantity: Uint, -} - -impl From for AssetTransferOutput { - fn from(from: AssetTransferOutputType) -> Self { - AssetTransferOutput { - lock_script_hash: from.lock_script_hash, - parameters: from.parameters.iter().map(Deref::deref).map(<[u8]>::to_hex).collect(), - asset_type: from.asset_type, - shard_id: from.shard_id, - quantity: from.quantity.into(), - } - } -} - -impl TryFrom for AssetTransferOutputType { - type Error = FromHexError; - fn try_from(from: AssetTransferOutput) -> Result { - Ok(AssetTransferOutputType { - lock_script_hash: from.lock_script_hash, - parameters: Result::from_iter(from.parameters.iter().map(Deref::deref).map(FromHex::from_hex))?, - asset_type: from.asset_type, - shard_id: from.shard_id, - quantity: from.quantity.into(), - }) - } -} - -#[derive(Debug, Deserialize, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct AssetMintOutput { - pub lock_script_hash: H160, - pub parameters: Vec, - pub supply: Uint, -} - -impl From for AssetMintOutput { - fn from(from: AssetMintOutputType) -> Self { - AssetMintOutput { - lock_script_hash: from.lock_script_hash, - parameters: from.parameters.iter().map(Deref::deref).map(<[u8]>::to_hex).collect(), - supply: from.supply.into(), - } - } -} - -impl TryFrom for AssetMintOutputType { - type Error = FromHexError; - fn try_from(from: AssetMintOutput) -> Result { - Ok(AssetMintOutputType { - lock_script_hash: from.lock_script_hash, - parameters: Result::from_iter(from.parameters.iter().map(Deref::deref).map(FromHex::from_hex))?, - supply: from.supply.into(), - }) - } -} diff --git a/rpc/src/v1/types/asset_scheme.rs b/rpc/src/v1/types/asset_scheme.rs deleted file mode 100644 index 9a9e6fa74a..0000000000 --- a/rpc/src/v1/types/asset_scheme.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 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 . - -use cjson::uint::Uint; -use ckey::PlatformAddress; - -use primitives::H160; - -use super::Asset; - -#[derive(Clone, Debug, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct AssetScheme { - metadata: String, - supply: Uint, - approver: Option, - registrar: Option, - allowed_script_hashes: Vec, - pool: Vec, - seq: u64, -} diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 412c049f4f..ee243e43cc 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -15,23 +15,13 @@ // along with this program. If not, see . mod action; -mod asset; -mod asset_input; -mod asset_output; -mod asset_scheme; mod block; mod text; mod transaction; mod unsigned_transaction; mod work; -use self::asset::Asset; -use self::asset_input::AssetTransferInput; -use self::asset_output::{AssetMintOutput, AssetTransferOutput}; - -pub use self::action::{Action, ActionWithTracker}; -pub use self::asset::OwnedAsset; -pub use self::asset_scheme::AssetScheme; +pub use self::action::Action; pub use self::block::Block; pub use self::block::BlockNumberAndHash; pub use self::text::Text; diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 1586d256f9..1a6933f530 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -19,7 +19,7 @@ use cjson::uint::Uint; use ckey::{NetworkId, Signature}; use ctypes::{BlockHash, TxHash}; -use super::ActionWithTracker; +use super::Action; #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] @@ -31,7 +31,7 @@ pub struct Transaction { pub seq: u64, pub fee: Uint, pub network_id: NetworkId, - pub action: ActionWithTracker, + pub action: Action, pub hash: TxHash, pub sig: Signature, } @@ -64,7 +64,7 @@ impl From for Transaction { seq: p.seq, fee: p.fee.into(), network_id: p.network_id, - action: ActionWithTracker::from_core(p.action.clone(), p.network_id), + action: Action::from_core(p.action.clone(), p.network_id), hash: p.hash(), sig, } @@ -82,7 +82,7 @@ impl From for Transaction { seq: p.seq, fee: p.fee.into(), network_id: p.network_id, - action: ActionWithTracker::from_core(p.action.clone(), p.network_id), + action: Action::from_core(p.action.clone(), p.network_id), hash: p.hash(), sig, } diff --git a/state/src/impls/top_level.rs b/state/src/impls/top_level.rs index 3e2d50a670..b35b28ea96 100644 --- a/state/src/impls/top_level.rs +++ b/state/src/impls/top_level.rs @@ -319,10 +319,6 @@ impl TopLevelState { handler.execute(bytes, self, fee_payer, signer_public)?; Ok(()) } - _ => { - // FIXME: Transactions related to Assets will be removed - Ok(()) - } } } diff --git a/sync/src/block/message/response.rs b/sync/src/block/message/response.rs index f6a16f2f97..69fd5065cc 100644 --- a/sync/src/block/message/response.rs +++ b/sync/src/block/message/response.rs @@ -140,9 +140,6 @@ impl ResponseMessage { mod tests { use rlp::{Encodable, Rlp}; - use ccore::UnverifiedTransaction; - use ckey::{Address, Signature}; - use ctypes::transaction::{Action, Transaction}; use ctypes::Header; use super::ResponseMessage; @@ -163,27 +160,6 @@ mod tests { assert_eq!(message, decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); } - #[test] - fn bodies_message_rlp() { - let message = ResponseMessage::Bodies(vec![vec![]]); - assert_eq!(message, decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); - - let tx = UnverifiedTransaction::new( - Transaction { - seq: 0, - fee: 10, - action: Action::CreateShard { - users: vec![Address::random(), Address::random()], - }, - network_id: "tc".into(), - }, - Signature::default(), - ); - - let message = ResponseMessage::Bodies(vec![vec![tx]]); - assert_eq!(message, decode_bytes(message.message_id(), message.rlp_bytes().as_ref())); - } - #[test] fn state_head_message_rlp() { let message = ResponseMessage::StateHead(vec![]); diff --git a/sync/src/transaction/message.rs b/sync/src/transaction/message.rs index c16a1b614f..5c93add414 100644 --- a/sync/src/transaction/message.rs +++ b/sync/src/transaction/message.rs @@ -65,31 +65,10 @@ impl Decodable for Message { mod tests { use rlp::rlp_encode_and_decode_test; - use ccore::UnverifiedTransaction; - use ckey::{Address, Signature}; - use ctypes::transaction::{Action, Transaction}; - use super::Message; #[test] fn transactions_message_rlp() { rlp_encode_and_decode_test!(Message::Transactions(Vec::new())); } - - #[test] - fn transactions_message_rlp_with_tx() { - let tx = UnverifiedTransaction::new( - Transaction { - seq: 0, - fee: 10, - action: Action::CreateShard { - users: vec![Address::random(), Address::random()], - }, - network_id: "tc".into(), - }, - Signature::default(), - ); - - rlp_encode_and_decode_test!(Message::Transactions(vec![tx])); - } } diff --git a/types/src/block_hash.rs b/types/src/block_hash.rs index 43bb03c144..a8058ee587 100644 --- a/types/src/block_hash.rs +++ b/types/src/block_hash.rs @@ -59,27 +59,10 @@ impl Decodable for BlockHash { #[cfg(test)] mod tests { - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; - use rlp::{self, rlp_encode_and_decode_test}; use super::*; - #[test] - fn hash_of_block_hash_and_h256_are_the_same() { - let h256 = H256::random(); - let block_hash = BlockHash(h256); - - let mut hasher_of_h256 = DefaultHasher::new(); - let mut hasher_of_tracker = DefaultHasher::new(); - - h256.hash(&mut hasher_of_h256); - block_hash.hash(&mut hasher_of_tracker); - - assert_eq!(hasher_of_h256.finish(), hasher_of_tracker.finish()); - } - #[test] fn rlp_of_block_hash_can_be_decoded_to_h256() { let h256 = H256::random(); diff --git a/types/src/errors/runtime_error.rs b/types/src/errors/runtime_error.rs index 3349d5ae6a..f75bbdff06 100644 --- a/types/src/errors/runtime_error.rs +++ b/types/src/errors/runtime_error.rs @@ -17,47 +17,15 @@ use std::fmt::{Display, Formatter, Result as FormatResult}; use ckey::Address; -use primitives::H160; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; use super::TaggedRlp; use crate::util::unexpected::Mismatch; -use crate::{ShardId, Tracker}; #[derive(Debug, PartialEq, Clone, Eq, Serialize)] #[serde(tag = "type", content = "content")] pub enum Error { - /// Desired input asset not found - AssetNotFound { - shard_id: ShardId, - tracker: Tracker, - index: usize, - }, - AssetSchemeDuplicated { - tracker: Tracker, - shard_id: ShardId, - }, - /// Desired input asset scheme not found - AssetSchemeNotFound { - asset_type: H160, - shard_id: ShardId, - }, - InvalidSeqOfAssetScheme { - asset_type: H160, - shard_id: ShardId, - expected: usize, - actual: usize, - }, - AssetSupplyOverflow, - CannotBurnRegulatedAsset, FailedToHandleCustomAction(String), - /// Script execution result is `Fail` - FailedToUnlock { - shard_id: ShardId, - tracker: Tracker, - index: usize, - reason: UnlockFailureReason, - }, /// Sender doesn't have enough funds to pay for this Transaction InsufficientBalance { address: Address, @@ -67,31 +35,12 @@ pub enum Error { cost: u64, }, InsufficientPermission, - InvalidAssetQuantity { - shard_id: ShardId, - tracker: Tracker, - index: usize, - expected: u64, - got: u64, - }, - /// AssetType error other than format. - UnexpectedAssetType { - index: usize, - mismatch: Mismatch, - }, - /// Failed to decode script. - InvalidScript, /// Returned when transaction seq does not match state seq InvalidSeq(Mismatch), - InvalidShardId(ShardId), InvalidTransferDestination, - NewOwnersMustContainSender, NotApproved(Address), RegularKeyAlreadyInUse, RegularKeyAlreadyInUseAsPlatformAccount, - /// Script hash does not match with provided lock script - ScriptHashMismatch(Mismatch), - ScriptNotAllowed(H160), TextNotExist, /// Remove Text error TextVerificationFail(String), @@ -109,36 +58,16 @@ pub enum Error { }, } -const ERROR_ID_ASSET_NOT_FOUND: u8 = 1; -const ERROR_ID_ASSET_SCHEME_DUPLICATED: u8 = 2; -const ERROR_ID_ASSET_SCHEME_NOT_FOUND: u8 = 3; -const ERROR_ID_CANNOT_BURN_REGULATED_ASSET: u8 = 4; -/// Deprecated -//const ERROR_ID_CANNOT_COMPOSE_REGULATED_ASSET: u8 = 5; -const ERROR_ID_FAILED_TO_UNLOCK: u8 = 6; -const ERROR_ID_INVALID_SEQ_OF_ASSET_SCHEME: u8 = 7; const ERROR_ID_INSUFFICIENT_BALANCE: u8 = 8; const ERROR_ID_INSUFFICIENT_PERMISSION: u8 = 9; -const ERROR_ID_INVALID_ASSET_QUANTITY: u8 = 10; -const ERROR_ID_UNEXPECTED_ASSET_TYPE: u8 = 11; -/// Deprecated -//const ERROR_ID_INVALID_DECOMPOSED_INPUT: u8 = 13; -/// Deprecated -//const ERROR_ID_INVALID_DECOMPOSED_OUTPUT: u8 = 14; -const ERROR_ID_INVALID_SHARD_ID: u8 = 15; const ERROR_ID_INVALID_TRANSFER_DESTINATION: u8 = 16; -const ERROR_ID_NEW_OWNERS_MUST_CONTAIN_SENDER: u8 = 17; const ERROR_ID_NOT_APPROVED: u8 = 18; const ERROR_ID_REGULAR_KEY_ALREADY_IN_USE: u8 = 19; const ERROR_ID_REGULAR_KEY_ALREADY_IN_USE_AS_PLATFORM: u8 = 20; -const ERROR_ID_SCRIPT_HASH_MISMATCH: u8 = 21; -const ERROR_ID_SCRIPT_NOT_ALLOWED: u8 = 22; const ERROR_ID_TEXT_NOT_EXIST: u8 = 23; const ERROR_ID_TEXT_VERIFICATION_FAIL: u8 = 24; const ERROR_ID_CANNOT_USE_MASTER_KEY: u8 = 25; -const ERROR_ID_INVALID_SCRIPT: u8 = 27; const ERROR_ID_INVALID_SEQ: u8 = 28; -const ERROR_ID_ASSET_SUPPLY_OVERFLOW: u8 = 29; const ERROR_ID_NON_ACTIVE_ACCOUNT: u8 = 30; const ERROR_ID_FAILED_TO_HANDLE_CUSTOM_ACTION: u8 = 31; const ERROR_ID_SIGNATURE_OF_INVALID_ACCOUNT: u8 = 32; @@ -151,28 +80,14 @@ impl TaggedRlp for RlpHelper { fn length_of(tag: u8) -> Result { Ok(match tag { - ERROR_ID_ASSET_NOT_FOUND => 4, - ERROR_ID_ASSET_SCHEME_DUPLICATED => 3, - ERROR_ID_ASSET_SCHEME_NOT_FOUND => 3, - ERROR_ID_INVALID_SEQ_OF_ASSET_SCHEME => 5, - ERROR_ID_ASSET_SUPPLY_OVERFLOW => 1, - ERROR_ID_CANNOT_BURN_REGULATED_ASSET => 1, ERROR_ID_FAILED_TO_HANDLE_CUSTOM_ACTION => 2, - ERROR_ID_FAILED_TO_UNLOCK => 5, ERROR_ID_INSUFFICIENT_BALANCE => 4, ERROR_ID_INSUFFICIENT_PERMISSION => 1, - ERROR_ID_INVALID_ASSET_QUANTITY => 6, - ERROR_ID_UNEXPECTED_ASSET_TYPE => 3, - ERROR_ID_INVALID_SCRIPT => 1, ERROR_ID_INVALID_SEQ => 2, - ERROR_ID_INVALID_SHARD_ID => 2, ERROR_ID_INVALID_TRANSFER_DESTINATION => 1, - ERROR_ID_NEW_OWNERS_MUST_CONTAIN_SENDER => 1, ERROR_ID_NOT_APPROVED => 2, ERROR_ID_REGULAR_KEY_ALREADY_IN_USE => 1, ERROR_ID_REGULAR_KEY_ALREADY_IN_USE_AS_PLATFORM => 1, - ERROR_ID_SCRIPT_HASH_MISMATCH => 2, - ERROR_ID_SCRIPT_NOT_ALLOWED => 2, ERROR_ID_TEXT_NOT_EXIST => 1, ERROR_ID_TEXT_VERIFICATION_FAIL => 2, ERROR_ID_CANNOT_USE_MASTER_KEY => 1, @@ -188,44 +103,9 @@ impl TaggedRlp for RlpHelper { impl Encodable for Error { fn rlp_append(&self, s: &mut RlpStream) { match self { - Error::AssetNotFound { - shard_id, - tracker, - index, - } => RlpHelper::new_tagged_list(s, ERROR_ID_ASSET_NOT_FOUND).append(shard_id).append(tracker).append(index), - Error::AssetSchemeDuplicated { - tracker, - shard_id, - } => RlpHelper::new_tagged_list(s, ERROR_ID_ASSET_SCHEME_DUPLICATED).append(tracker).append(shard_id), - Error::AssetSchemeNotFound { - asset_type, - shard_id, - } => RlpHelper::new_tagged_list(s, ERROR_ID_ASSET_SCHEME_NOT_FOUND).append(asset_type).append(shard_id), - Error::InvalidSeqOfAssetScheme { - asset_type, - shard_id, - expected, - actual, - } => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_SEQ_OF_ASSET_SCHEME) - .append(asset_type) - .append(shard_id) - .append(expected) - .append(actual), - Error::AssetSupplyOverflow => RlpHelper::new_tagged_list(s, ERROR_ID_ASSET_SUPPLY_OVERFLOW), - Error::CannotBurnRegulatedAsset => RlpHelper::new_tagged_list(s, ERROR_ID_CANNOT_BURN_REGULATED_ASSET), Error::FailedToHandleCustomAction(detail) => { RlpHelper::new_tagged_list(s, ERROR_ID_FAILED_TO_HANDLE_CUSTOM_ACTION).append(detail) } - Error::FailedToUnlock { - shard_id, - tracker, - index, - reason, - } => RlpHelper::new_tagged_list(s, ERROR_ID_FAILED_TO_UNLOCK) - .append(shard_id) - .append(tracker) - .append(index) - .append(reason), Error::InsufficientBalance { address, balance, @@ -235,38 +115,13 @@ impl Encodable for Error { .append(balance) .append(cost), Error::InsufficientPermission => RlpHelper::new_tagged_list(s, ERROR_ID_INSUFFICIENT_PERMISSION), - Error::InvalidAssetQuantity { - shard_id, - tracker, - index, - expected, - got, - } => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ASSET_QUANTITY) - .append(shard_id) - .append(tracker) - .append(index) - .append(expected) - .append(got), - Error::UnexpectedAssetType { - index, - mismatch, - } => RlpHelper::new_tagged_list(s, ERROR_ID_UNEXPECTED_ASSET_TYPE).append(index).append(mismatch), - Error::InvalidScript => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_SCRIPT), Error::InvalidSeq(mismatch) => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_SEQ).append(mismatch), - Error::InvalidShardId(shard_id) => { - RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_SHARD_ID).append(shard_id) - } Error::InvalidTransferDestination => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_TRANSFER_DESTINATION), - Error::NewOwnersMustContainSender => RlpHelper::new_tagged_list(s, ERROR_ID_NEW_OWNERS_MUST_CONTAIN_SENDER), Error::NotApproved(address) => RlpHelper::new_tagged_list(s, ERROR_ID_NOT_APPROVED).append(address), Error::RegularKeyAlreadyInUse => RlpHelper::new_tagged_list(s, ERROR_ID_REGULAR_KEY_ALREADY_IN_USE), Error::RegularKeyAlreadyInUseAsPlatformAccount => { RlpHelper::new_tagged_list(s, ERROR_ID_REGULAR_KEY_ALREADY_IN_USE_AS_PLATFORM) } - Error::ScriptHashMismatch(mismatch) => { - RlpHelper::new_tagged_list(s, ERROR_ID_SCRIPT_HASH_MISMATCH).append(mismatch) - } - Error::ScriptNotAllowed(hash) => RlpHelper::new_tagged_list(s, ERROR_ID_SCRIPT_NOT_ALLOWED).append(hash), Error::TextNotExist => RlpHelper::new_tagged_list(s, ERROR_ID_TEXT_NOT_EXIST), Error::TextVerificationFail(err) => { RlpHelper::new_tagged_list(s, ERROR_ID_TEXT_VERIFICATION_FAIL).append(err) @@ -295,61 +150,18 @@ impl Decodable for Error { fn decode(rlp: &Rlp) -> Result { let tag = rlp.val_at::(0)?; let error = match tag { - ERROR_ID_ASSET_NOT_FOUND => Error::AssetNotFound { - shard_id: rlp.val_at(1)?, - tracker: rlp.val_at(2)?, - index: rlp.val_at(3)?, - }, - ERROR_ID_ASSET_SCHEME_DUPLICATED => Error::AssetSchemeDuplicated { - tracker: rlp.val_at(1)?, - shard_id: rlp.val_at(2)?, - }, - ERROR_ID_ASSET_SCHEME_NOT_FOUND => Error::AssetSchemeNotFound { - asset_type: rlp.val_at(1)?, - shard_id: rlp.val_at(2)?, - }, - ERROR_ID_INVALID_SEQ_OF_ASSET_SCHEME => Error::InvalidSeqOfAssetScheme { - asset_type: rlp.val_at(1)?, - shard_id: rlp.val_at(2)?, - expected: rlp.val_at(3)?, - actual: rlp.val_at(4)?, - }, - ERROR_ID_ASSET_SUPPLY_OVERFLOW => Error::AssetSupplyOverflow, - ERROR_ID_CANNOT_BURN_REGULATED_ASSET => Error::CannotBurnRegulatedAsset, ERROR_ID_FAILED_TO_HANDLE_CUSTOM_ACTION => Error::FailedToHandleCustomAction(rlp.val_at(1)?), - ERROR_ID_FAILED_TO_UNLOCK => Error::FailedToUnlock { - shard_id: rlp.val_at(1)?, - tracker: rlp.val_at(2)?, - index: rlp.val_at(3)?, - reason: rlp.val_at(4)?, - }, ERROR_ID_INSUFFICIENT_BALANCE => Error::InsufficientBalance { address: rlp.val_at(1)?, balance: rlp.val_at(2)?, cost: rlp.val_at(3)?, }, ERROR_ID_INSUFFICIENT_PERMISSION => Error::InsufficientPermission, - ERROR_ID_INVALID_ASSET_QUANTITY => Error::InvalidAssetQuantity { - shard_id: rlp.val_at(1)?, - tracker: rlp.val_at(2)?, - index: rlp.val_at(3)?, - expected: rlp.val_at(4)?, - got: rlp.val_at(5)?, - }, - ERROR_ID_UNEXPECTED_ASSET_TYPE => Error::UnexpectedAssetType { - index: rlp.val_at(1)?, - mismatch: rlp.val_at(2)?, - }, - ERROR_ID_INVALID_SCRIPT => Error::InvalidScript, ERROR_ID_INVALID_SEQ => Error::InvalidSeq(rlp.val_at(1)?), - ERROR_ID_INVALID_SHARD_ID => Error::InvalidShardId(rlp.val_at(1)?), ERROR_ID_INVALID_TRANSFER_DESTINATION => Error::InvalidTransferDestination, - ERROR_ID_NEW_OWNERS_MUST_CONTAIN_SENDER => Error::NewOwnersMustContainSender, ERROR_ID_NOT_APPROVED => Error::NotApproved(rlp.val_at(1)?), ERROR_ID_REGULAR_KEY_ALREADY_IN_USE => Error::RegularKeyAlreadyInUse, ERROR_ID_REGULAR_KEY_ALREADY_IN_USE_AS_PLATFORM => Error::RegularKeyAlreadyInUseAsPlatformAccount, - ERROR_ID_SCRIPT_HASH_MISMATCH => Error::ScriptHashMismatch(rlp.val_at(1)?), - ERROR_ID_SCRIPT_NOT_ALLOWED => Error::ScriptNotAllowed(rlp.val_at(1)?), ERROR_ID_TEXT_NOT_EXIST => Error::TextNotExist, ERROR_ID_TEXT_VERIFICATION_FAIL => Error::TextVerificationFail(rlp.val_at(1)?), ERROR_ID_CANNOT_USE_MASTER_KEY => Error::CannotUseMasterKey, @@ -376,76 +188,37 @@ impl Decodable for Error { impl Display for Error { fn fmt(&self, f: &mut Formatter) -> FormatResult { match self { - Error::AssetNotFound { shard_id, tracker, index } => write!(f, "Asset not found: {}:{}:{}", shard_id, tracker, index), - Error::AssetSchemeDuplicated { tracker, shard_id} => write!(f, "Asset scheme already exists: {}:{}", shard_id, tracker), - Error::AssetSchemeNotFound { - asset_type, - shard_id, - } => write!(f, "Asset scheme not found: {}:{}", asset_type, shard_id), - Error::InvalidSeqOfAssetScheme { - asset_type, - shard_id, - expected, - actual, - } => write!(f, "Already used seq of asset scheme {}:{}. expected: {}, actual: {}", asset_type, shard_id, expected, actual), - Error::AssetSupplyOverflow => write!(f, "Asset supply should not be overflowed"), - Error::CannotBurnRegulatedAsset => write!(f, "Cannot burn the regulated asset"), Error::FailedToHandleCustomAction(detail) => write!(f, "Cannot handle custom action: {}", detail), - Error::FailedToUnlock { - shard_id, - tracker, - index, - reason, - } => write!(f, "Failed to unlock asset {}:{}:{}, reason: {}", shard_id, tracker, index, reason), Error::InsufficientBalance { address, balance, cost, } => write!(f, "{} has only {:?} but it must be larger than {:?}", address, balance, cost), Error::InsufficientPermission => write!(f, "Sender doesn't have a permission"), - Error::InvalidAssetQuantity { - shard_id, - tracker, - index, - expected, - got, - } => write!( - f, - "AssetTransfer must consume input asset completely. The quantity of asset({}:{}:{}) must be {}, but {}.", - shard_id, tracker, index, expected, got - ), - Error::UnexpectedAssetType{index, mismatch} => write!(f, "{}th input has an unexpected asset type: {}", index, mismatch), - Error::InvalidScript => write!(f, "Failed to decode script"), Error::InvalidSeq(mismatch) => write!(f, "Invalid transaction seq {}", mismatch), - Error::InvalidShardId(shard_id) => write!(f, "{} is an invalid shard id", shard_id), Error::InvalidTransferDestination => write!(f, "Transfer receiver is not valid account"), - Error::NewOwnersMustContainSender => write!(f, "New owners must contain the sender"), Error::NotApproved(address) => write!(f, "{} should approve it.", address), Error::RegularKeyAlreadyInUse => write!(f, "The regular key is already registered to another account"), Error::RegularKeyAlreadyInUseAsPlatformAccount => { write!(f, "The regular key is already used as a platform account") } - Error::ScriptHashMismatch(mismatch) => { - write!(f, "Expected script with hash {}, but got {}", mismatch.expected, mismatch.found) - } - Error::ScriptNotAllowed(hash) => write!(f, "Output lock script hash is not allowed : {}", hash), Error::TextNotExist => write!(f, "The text does not exist"), Error::TextVerificationFail(err) => write!(f, "Text verification has failed: {}", err), Error::CannotUseMasterKey => { write!(f, "Cannot use the master key because a regular key is already registered") } Error::NonActiveAccount { - name, address, - } => { - write!(f, "Non active account({}) cannot be {}", address, name) + name, + address, + } => write!(f, "Non active account({}) cannot be {}", address, name), + Error::SignatureOfInvalidAccount(address) => { + write!(f, "Signature of invalid account({}) received", address) } - Error::SignatureOfInvalidAccount(address) => - write!(f, "Signature of invalid account({}) received", address), - Error::InsufficientStakes(mismatch) => - write!(f, "Insufficient stakes: {}", mismatch), + Error::InsufficientStakes(mismatch) => write!(f, "Insufficient stakes: {}", mismatch), Error::InvalidValidatorIndex { - idx, parent_height, - } => write!(f, "The validator index {} is invalid at the parent hash {}", idx, parent_height), + idx, + parent_height, + } => write!(f, "The validator index {} is invalid at the parent hash {}", idx, parent_height), } } } diff --git a/types/src/errors/syntax_error.rs b/types/src/errors/syntax_error.rs index 182fada270..bcd7b57576 100644 --- a/types/src/errors/syntax_error.rs +++ b/types/src/errors/syntax_error.rs @@ -17,21 +17,13 @@ use std::fmt::{Display, Formatter, Result as FormatResult}; use ckey::NetworkId; -use primitives::H160; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; use super::TaggedRlp; -use crate::{ShardId, Tracker}; #[derive(Debug, PartialEq, Clone, Eq, Serialize)] #[serde(tag = "type", content = "content")] pub enum Error { - /// There are burn/inputs that shares same previous output - DuplicatedPreviousOutput { - tracker: Tracker, - index: usize, - }, - EmptyShardOwners(ShardId), /// Returned when the sum of the transaction's inputs is different from the sum of outputs. InconsistentTransactionInOut, /// Transaction's fee is below currently set minimal fee requirement. @@ -41,8 +33,6 @@ pub enum Error { /// Transaction fee got: u64, }, - /// AssetType format error - InvalidAssetType(H160), InvalidCustomAction(String), /// Invalid network ID given. InvalidNetworkId(NetworkId), @@ -54,19 +44,14 @@ pub enum Error { TransactionIsTooBig, /// Returned when the quantity of either input or output is 0. ZeroQuantity, - CannotChangeWcccAssetScheme, DisabledTransaction, - InvalidSignerOfWrapCCC, } -const ERORR_ID_DUPLICATED_PREVIOUS_OUTPUT: u8 = 1; /// Deprecated //const ERROR_ID_EMPTY_INPUT: u8 = 2; //const ERROR_ID_EMPTY_OUTPUT: u8 = 3; -const ERROR_ID_EMPTY_SHARD_OWNERS: u8 = 4; const ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT: u8 = 5; const ERROR_ID_INSUFFICIENT_FEE: u8 = 7; -const ERROR_ID_INVALID_ASSET_TYPE: u8 = 8; /// Deprecated //const ERROR_ID_INVALID_COMPOSED_OUTPUT_AMOUNT: u8 = 9; //const ERROR_ID_INVALID_DECOMPOSED_INPUT_AMOUNT: u8 = 10; @@ -77,7 +62,6 @@ const ERROR_ID_TEXT_CONTENT_TOO_BIG: u8 = 24; const ERROR_ID_TOO_MANY_OUTPUTS: u8 = 26; const ERROR_ID_TX_IS_TOO_BIG: u8 = 27; const ERROR_ID_ZERO_QUANTITY: u8 = 28; -const ERROR_ID_CANNOT_CHANGE_WCCC_ASSET_SCHEME: u8 = 29; const ERROR_ID_DISABLED_TRANSACTION: u8 = 30; const ERROR_ID_INVALID_SIGNER_OF_WRAP_CCC: u8 = 31; const ERROR_ID_INVALID_CUSTOM_ACTION: u8 = 32; @@ -88,11 +72,8 @@ impl TaggedRlp for RlpHelper { fn length_of(tag: u8) -> Result { Ok(match tag { - ERORR_ID_DUPLICATED_PREVIOUS_OUTPUT => 3, - ERROR_ID_EMPTY_SHARD_OWNERS => 2, ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT => 1, ERROR_ID_INSUFFICIENT_FEE => 3, - ERROR_ID_INVALID_ASSET_TYPE => 2, ERROR_ID_INVALID_CUSTOM_ACTION => 2, ERROR_ID_INVALID_NETWORK_ID => 2, ERROR_ID_INVALID_APPROVAL => 2, @@ -101,7 +82,6 @@ impl TaggedRlp for RlpHelper { ERROR_ID_TOO_MANY_OUTPUTS => 2, ERROR_ID_TX_IS_TOO_BIG => 1, ERROR_ID_ZERO_QUANTITY => 1, - ERROR_ID_CANNOT_CHANGE_WCCC_ASSET_SCHEME => 1, ERROR_ID_DISABLED_TRANSACTION => 1, ERROR_ID_INVALID_SIGNER_OF_WRAP_CCC => 1, _ => return Err(DecoderError::Custom("Invalid SyntaxError")), @@ -112,13 +92,6 @@ impl TaggedRlp for RlpHelper { impl Encodable for Error { fn rlp_append(&self, s: &mut RlpStream) { match self { - Error::DuplicatedPreviousOutput { - tracker, - index, - } => RlpHelper::new_tagged_list(s, ERORR_ID_DUPLICATED_PREVIOUS_OUTPUT).append(tracker).append(index), - Error::EmptyShardOwners(shard_id) => { - RlpHelper::new_tagged_list(s, ERROR_ID_EMPTY_SHARD_OWNERS).append(shard_id) - } Error::InconsistentTransactionInOut => { RlpHelper::new_tagged_list(s, ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT) } @@ -126,7 +99,6 @@ impl Encodable for Error { minimal, got, } => RlpHelper::new_tagged_list(s, ERROR_ID_INSUFFICIENT_FEE).append(minimal).append(got), - Error::InvalidAssetType(addr) => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_ASSET_TYPE).append(addr), Error::InvalidCustomAction(err) => { RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_CUSTOM_ACTION).append(err) } @@ -139,11 +111,7 @@ impl Encodable for Error { Error::TooManyOutputs(num) => RlpHelper::new_tagged_list(s, ERROR_ID_TOO_MANY_OUTPUTS).append(num), Error::TransactionIsTooBig => RlpHelper::new_tagged_list(s, ERROR_ID_TX_IS_TOO_BIG), Error::ZeroQuantity => RlpHelper::new_tagged_list(s, ERROR_ID_ZERO_QUANTITY), - Error::CannotChangeWcccAssetScheme => { - RlpHelper::new_tagged_list(s, ERROR_ID_CANNOT_CHANGE_WCCC_ASSET_SCHEME) - } Error::DisabledTransaction => RlpHelper::new_tagged_list(s, ERROR_ID_DISABLED_TRANSACTION), - Error::InvalidSignerOfWrapCCC => RlpHelper::new_tagged_list(s, ERROR_ID_INVALID_SIGNER_OF_WRAP_CCC), }; } } @@ -152,17 +120,11 @@ impl Decodable for Error { fn decode(rlp: &Rlp) -> Result { let tag = rlp.val_at::(0)?; let error = match tag { - ERORR_ID_DUPLICATED_PREVIOUS_OUTPUT => Error::DuplicatedPreviousOutput { - tracker: rlp.val_at(1)?, - index: rlp.val_at(2)?, - }, - ERROR_ID_EMPTY_SHARD_OWNERS => Error::EmptyShardOwners(rlp.val_at(1)?), ERROR_ID_INCONSISTENT_TRANSACTION_IN_OUT => Error::InconsistentTransactionInOut, ERROR_ID_INSUFFICIENT_FEE => Error::InsufficientFee { minimal: rlp.val_at(1)?, got: rlp.val_at(2)?, }, - ERROR_ID_INVALID_ASSET_TYPE => Error::InvalidAssetType(rlp.val_at(1)?), ERROR_ID_INVALID_CUSTOM_ACTION => Error::InvalidCustomAction(rlp.val_at(1)?), ERROR_ID_INVALID_NETWORK_ID => Error::InvalidNetworkId(rlp.val_at(1)?), ERROR_ID_INVALID_APPROVAL => Error::InvalidApproval(rlp.val_at(1)?), @@ -171,9 +133,7 @@ impl Decodable for Error { ERROR_ID_TOO_MANY_OUTPUTS => Error::TooManyOutputs(rlp.val_at(1)?), ERROR_ID_TX_IS_TOO_BIG => Error::TransactionIsTooBig, ERROR_ID_ZERO_QUANTITY => Error::ZeroQuantity, - ERROR_ID_CANNOT_CHANGE_WCCC_ASSET_SCHEME => Error::CannotChangeWcccAssetScheme, ERROR_ID_DISABLED_TRANSACTION => Error::DisabledTransaction, - ERROR_ID_INVALID_SIGNER_OF_WRAP_CCC => Error::InvalidSignerOfWrapCCC, _ => return Err(DecoderError::Custom("Invalid SyntaxError")), }; RlpHelper::check_size(rlp, tag)?; @@ -184,11 +144,6 @@ impl Decodable for Error { impl Display for Error { fn fmt(&self, f: &mut Formatter) -> FormatResult { match self { - Error::DuplicatedPreviousOutput { - tracker, - index, - } => write!(f, "The previous output of inputs/burns are duplicated: ({}, {})", tracker, index), - Error::EmptyShardOwners(shard_id) => write!(f, "Shard({}) must have at least one owner", shard_id), Error::InconsistentTransactionInOut => { write!(f, "The sum of the transaction's inputs is different from the sum of the transaction's outputs") } @@ -196,7 +151,6 @@ impl Display for Error { minimal, got, } => write!(f, "Insufficient fee. Min={}, Given={}", minimal, got), - Error::InvalidAssetType(addr) => write!(f, "Asset type is invalid: {}", addr), Error::InvalidCustomAction(err) => write!(f, "Invalid custom action: {}", err), Error::InvalidNetworkId(network_id) => write!(f, "{} is an invalid network id", network_id), Error::InvalidApproval(err) => write!(f, "Transaction has an invalid approval :{}", err), @@ -205,9 +159,7 @@ impl Display for Error { Error::TooManyOutputs(num) => write!(f, "The number of outputs is {}. It should be 126 or less.", num), Error::TransactionIsTooBig => write!(f, "Transaction size exceeded the body size limit"), Error::ZeroQuantity => write!(f, "A quantity cannot be 0"), - Error::CannotChangeWcccAssetScheme => write!(f, "Cannot change the asset scheme of WCCC"), Error::DisabledTransaction => write!(f, "Used the disabled transaction"), - Error::InvalidSignerOfWrapCCC => write!(f, "The signer of WrapCCC must be matched"), } } } diff --git a/types/src/lib.rs b/types/src/lib.rs index 05e9fbf1c4..18e5a50d51 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -19,8 +19,6 @@ extern crate codechain_json as cjson; extern crate codechain_key as ckey; extern crate primitives; extern crate rlp; -#[macro_use] -extern crate rlp_derive; extern crate serde; #[macro_use] extern crate serde_derive; @@ -29,7 +27,6 @@ extern crate serde_json; mod block_hash; mod common_params; -mod tracker; mod tx_hash; pub mod errors; @@ -38,10 +35,8 @@ pub mod transaction; pub mod util; pub type BlockNumber = u64; -pub type ShardId = u16; pub use block_hash::BlockHash; pub use common_params::CommonParams; pub use header::Header; -pub use tracker::Tracker; pub use tx_hash::TxHash; diff --git a/types/src/tracker.rs b/types/src/tracker.rs deleted file mode 100644 index ba764d4e78..0000000000 --- a/types/src/tracker.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 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 . - - -use std::fmt::{self, Display, Formatter}; -use std::ops::Deref; - -use primitives::H256; -use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; - - -#[derive(Clone, Copy, Default, Eq, Hash, PartialEq, Debug, Deserialize, Serialize)] -pub struct Tracker(H256); - -impl From for Tracker { - fn from(h: H256) -> Self { - Self(h) - } -} - -impl Deref for Tracker { - type Target = H256; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for Tracker { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { - self.0.fmt(f) - } -} - -impl Encodable for Tracker { - fn rlp_append(&self, s: &mut RlpStream) { - self.0.rlp_append(s); - } -} - -impl Decodable for Tracker { - fn decode(rlp: &Rlp) -> Result { - Ok(H256::decode(rlp)?.into()) - } -} - -#[cfg(test)] -mod tests { - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; - - use rlp::{self, rlp_encode_and_decode_test}; - - use super::*; - - #[test] - fn hash_of_tracker_and_h256_are_the_same() { - let h256 = H256::random(); - let tracker = Tracker(h256); - - let mut hasher_of_h256 = DefaultHasher::new(); - let mut hasher_of_tracker = DefaultHasher::new(); - - h256.hash(&mut hasher_of_h256); - tracker.hash(&mut hasher_of_tracker); - - assert_eq!(hasher_of_h256.finish(), hasher_of_tracker.finish()); - } - - #[test] - fn rlp_of_tracker_can_be_decoded_to_h256() { - let h256 = H256::random(); - let tracker = Tracker(h256); - - let encoded = rlp::encode(&tracker); - let decoded = rlp::decode(&*encoded).unwrap(); - - assert_eq!(h256, decoded); - } - - #[test] - fn rlp_of_h256_can_be_decoded_to_tracker() { - let h256 = H256::random(); - - let encoded = rlp::encode(&h256); - let decoded = rlp::decode(&*encoded).unwrap(); - - let tracker = Tracker(h256); - assert_eq!(tracker, decoded); - } - - #[test] - fn rlp() { - rlp_encode_and_decode_test!(Tracker(H256::random())); - } -} diff --git a/types/src/transaction/action.rs b/types/src/transaction/action.rs index 9b35fa2723..26688bbcbc 100644 --- a/types/src/transaction/action.rs +++ b/types/src/transaction/action.rs @@ -14,82 +14,22 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::collections::{HashMap, HashSet}; - use ccrypto::Blake; -use ckey::{recover, Address, NetworkId, Public, Signature}; -use primitives::{Bytes, H160, H256}; +use ckey::{Address, Public, Signature}; +use primitives::{Bytes, H256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; use crate::errors::SyntaxError; -use crate::transaction::{AssetMintOutput, AssetTransferInput, AssetTransferOutput, ShardTransaction}; -use crate::{CommonParams, ShardId, Tracker, TxHash}; +use crate::{CommonParams, TxHash}; const PAY: u8 = 0x02; const SET_REGULAR_KEY: u8 = 0x03; -const CREATE_SHARD: u8 = 0x04; -const SET_SHARD_OWNERS: u8 = 0x05; -const SET_SHARD_USERS: u8 = 0x06; -const WRAP_CCC: u8 = 0x07; const STORE: u8 = 0x08; const REMOVE: u8 = 0x09; -const UNWRAP_CCC: u8 = 0x11; -const MINT_ASSET: u8 = 0x13; -const TRANSFER_ASSET: u8 = 0x14; -const CHANGE_ASSET_SCHEME: u8 = 0x15; -// Derepcated -//const COMPOSE_ASSET: u8 = 0x16; -// Derepcated -//const DECOMPOSE_ASSET: u8 = 0x17; -const INCREASE_ASSET_SUPPLY: u8 = 0x18; - const CUSTOM: u8 = 0xFF; #[derive(Debug, Clone, PartialEq, Eq)] pub enum Action { - MintAsset { - network_id: NetworkId, - shard_id: ShardId, - metadata: String, - approver: Option
, - registrar: Option
, - allowed_script_hashes: Vec, - output: Box, - approvals: Vec, - }, - TransferAsset { - network_id: NetworkId, - burns: Vec, - inputs: Vec, - outputs: Vec, - metadata: String, - approvals: Vec, - expiration: Option, - }, - ChangeAssetScheme { - network_id: NetworkId, - shard_id: ShardId, - asset_type: H160, - seq: usize, - metadata: String, - approver: Option
, - registrar: Option
, - allowed_script_hashes: Vec, - approvals: Vec, - }, - IncreaseAssetSupply { - network_id: NetworkId, - shard_id: ShardId, - asset_type: H160, - seq: usize, - output: Box, - approvals: Vec, - }, - UnwrapCCC { - network_id: NetworkId, - burn: AssetTransferInput, - receiver: Address, - }, Pay { receiver: Address, /// Transferred quantity. @@ -98,24 +38,6 @@ pub enum Action { SetRegularKey { key: Public, }, - CreateShard { - users: Vec
, - }, - SetShardOwners { - shard_id: ShardId, - owners: Vec
, - }, - SetShardUsers { - shard_id: ShardId, - users: Vec
, - }, - WrapCCC { - shard_id: ShardId, - lock_script_hash: H160, - parameters: Vec, - quantity: u64, - payer: Address, - }, Custom { handler_id: u64, bytes: Bytes, @@ -137,418 +59,24 @@ impl Action { Blake::blake(rlp) } - pub fn asset_transaction(&self) -> Option { - match self { - Action::MintAsset { - .. - } - | Action::TransferAsset { - .. - } - | Action::ChangeAssetScheme { - .. - } - | Action::IncreaseAssetSupply { - .. - } - | Action::UnwrapCCC { - .. - } => self.clone().into(), - _ => None, - } - } - - pub fn tracker(&self) -> Option { - self.asset_transaction().map(|tx| tx.tracker()) - } - - pub fn verify(&self) -> Result<(), SyntaxError> { - match self { - Action::MintAsset { - output, - .. - } => { - if output.supply == 0 { - return Err(SyntaxError::ZeroQuantity) - } - } - Action::TransferAsset { - burns, - inputs, - outputs, - .. - } => { - if outputs.len() > 512 { - return Err(SyntaxError::TooManyOutputs(outputs.len())) - } - if !is_input_and_output_consistent(inputs, outputs) { - return Err(SyntaxError::InconsistentTransactionInOut) - } - if burns.iter().any(|burn| burn.prev_out.quantity == 0) { - return Err(SyntaxError::ZeroQuantity) - } - if inputs.iter().any(|input| input.prev_out.quantity == 0) { - return Err(SyntaxError::ZeroQuantity) - } - check_duplication_in_prev_out(burns, inputs)?; - - if outputs.iter().any(|output| output.quantity == 0) { - return Err(SyntaxError::ZeroQuantity) - } - } - Action::ChangeAssetScheme { - asset_type, - .. - } => { - if asset_type.is_zero() { - return Err(SyntaxError::CannotChangeWcccAssetScheme) - } - } - Action::IncreaseAssetSupply { - asset_type, - output, - .. - } => { - if output.supply == 0 { - return Err(SyntaxError::ZeroQuantity) - } - if asset_type.is_zero() { - return Err(SyntaxError::CannotChangeWcccAssetScheme) - } - } - Action::UnwrapCCC { - burn, - .. - } => { - if burn.prev_out.quantity == 0 { - return Err(SyntaxError::ZeroQuantity) - } - if !burn.prev_out.asset_type.is_zero() { - return Err(SyntaxError::InvalidAssetType(burn.prev_out.asset_type)) - } - } - Action::WrapCCC { - quantity, - .. - } => { - if *quantity == 0 { - return Err(SyntaxError::ZeroQuantity) - } - } - Action::Store { - .. - } => {} - _ => {} - } - Ok(()) - } - pub fn verify_with_params(&self, common_params: &CommonParams) -> Result<(), SyntaxError> { - if let Some(network_id) = self.network_id() { - let system_network_id = common_params.network_id(); - if network_id != system_network_id { - return Err(SyntaxError::InvalidNetworkId(network_id)) - } - } - - match self { - Action::MintAsset { - metadata, - .. - } => { - let max_asset_scheme_metadata_size = common_params.max_asset_scheme_metadata_size(); - if metadata.len() > max_asset_scheme_metadata_size { - return Err(SyntaxError::MetadataTooBig) - } - } - Action::TransferAsset { - metadata, - .. - } => { - let max_transfer_metadata_size = common_params.max_transfer_metadata_size(); - if metadata.len() > max_transfer_metadata_size { - return Err(SyntaxError::MetadataTooBig) - } - } - Action::ChangeAssetScheme { - metadata, - .. - } => { - let max_asset_scheme_metadata_size = common_params.max_asset_scheme_metadata_size(); - if metadata.len() > max_asset_scheme_metadata_size { - return Err(SyntaxError::MetadataTooBig) - } - } - Action::IncreaseAssetSupply { - .. - } => {} - Action::UnwrapCCC { - .. - } => {} - Action::WrapCCC { - .. - } => {} - Action::Store { - content, - .. - } => { - let max_text_size = common_params.max_text_content_size(); - if content.len() > max_text_size { - return Err(SyntaxError::TextContentTooBig) - } - } - _ => {} - } - Ok(()) - } - - pub fn verify_with_signer_address(&self, signer: &Address) -> Result<(), SyntaxError> { - if let Action::WrapCCC { - payer, + if let Action::Store { + content, .. } = self { - if payer != signer { - return Err(SyntaxError::InvalidSignerOfWrapCCC) - } - } - if let Some(approvals) = self.approvals() { - let tracker = self.tracker().unwrap(); - - for approval in approvals { - recover(approval, &tracker).map_err(|err| SyntaxError::InvalidApproval(err.to_string()))?; + let max_text_size = common_params.max_text_content_size(); + if content.len() > max_text_size { + return Err(SyntaxError::TextContentTooBig) } } Ok(()) } - - fn approvals(&self) -> Option<&[Signature]> { - match self { - Action::MintAsset { - approvals, - .. - } - | Action::TransferAsset { - approvals, - .. - } - | Action::ChangeAssetScheme { - approvals, - .. - } - | Action::IncreaseAssetSupply { - approvals, - .. - } => Some(approvals), - _ => None, - } - } - - fn network_id(&self) -> Option { - match self { - Action::MintAsset { - network_id, - .. - } - | Action::TransferAsset { - network_id, - .. - } - | Action::ChangeAssetScheme { - network_id, - .. - } - | Action::IncreaseAssetSupply { - network_id, - .. - } - | Action::UnwrapCCC { - network_id, - .. - } => Some(*network_id), - _ => None, - } - } -} - -impl From for Option { - fn from(action: Action) -> Self { - match action { - Action::MintAsset { - network_id, - shard_id, - metadata, - approver, - registrar, - allowed_script_hashes, - output, - .. - } => Some(ShardTransaction::MintAsset { - network_id, - shard_id, - metadata, - approver, - registrar, - allowed_script_hashes, - output: *output, - }), - Action::TransferAsset { - network_id, - burns, - inputs, - outputs, - .. - } => Some(ShardTransaction::TransferAsset { - network_id, - burns, - inputs, - outputs, - }), - Action::ChangeAssetScheme { - network_id, - shard_id, - asset_type, - seq, - metadata, - approver, - registrar, - allowed_script_hashes, - .. - } => Some(ShardTransaction::ChangeAssetScheme { - network_id, - shard_id, - asset_type, - seq, - metadata, - approver, - registrar, - allowed_script_hashes, - }), - Action::IncreaseAssetSupply { - network_id, - shard_id, - asset_type, - seq, - output, - .. - } => Some(ShardTransaction::IncreaseAssetSupply { - network_id, - shard_id, - asset_type, - seq, - output: *output, - }), - Action::UnwrapCCC { - network_id, - burn, - receiver, - } => Some(ShardTransaction::UnwrapCCC { - network_id, - burn, - receiver, - }), - _ => None, - } - } } impl Encodable for Action { fn rlp_append(&self, s: &mut RlpStream) { match self { - Action::MintAsset { - network_id, - shard_id, - metadata, - approver, - registrar, - allowed_script_hashes, - output, - approvals, - } => { - s.begin_list(11) - .append(&MINT_ASSET) - .append(network_id) - .append(shard_id) - .append(metadata) - .append(&output.lock_script_hash) - .append(&output.parameters) - .append(&output.supply) - .append(approver) - .append(registrar) - .append_list(allowed_script_hashes) - .append_list(approvals); - } - Action::TransferAsset { - network_id, - burns, - inputs, - outputs, - metadata, - approvals, - expiration, - } => { - let empty: Vec = vec![]; - s.begin_list(9) - .append(&TRANSFER_ASSET) - .append(network_id) - .append_list(burns) - .append_list(inputs) - .append_list(outputs) - // NOTE: The orders field removed. - .append_list(&empty) - .append(metadata) - .append_list(approvals) - .append(expiration); - } - Action::ChangeAssetScheme { - network_id, - shard_id, - asset_type, - seq, - metadata, - approver, - registrar, - allowed_script_hashes, - approvals, - } => { - s.begin_list(10) - .append(&CHANGE_ASSET_SCHEME) - .append(network_id) - .append(shard_id) - .append(asset_type) - .append(seq) - .append(metadata) - .append(approver) - .append(registrar) - .append_list(allowed_script_hashes) - .append_list(approvals); - } - Action::IncreaseAssetSupply { - network_id, - shard_id, - asset_type, - seq, - output, - approvals, - } => { - s.begin_list(9) - .append(&INCREASE_ASSET_SUPPLY) - .append(network_id) - .append(shard_id) - .append(asset_type) - .append(seq) - .append(&output.lock_script_hash) - .append(&output.parameters) - .append(&output.supply) - .append_list(approvals); - } - Action::UnwrapCCC { - network_id, - burn, - receiver, - } => { - s.begin_list(4).append(&UNWRAP_CCC).append(network_id).append(burn).append(receiver); - } Action::Pay { receiver, quantity, @@ -565,46 +93,6 @@ impl Encodable for Action { s.append(&SET_REGULAR_KEY); s.append(key); } - Action::CreateShard { - users, - } => { - s.begin_list(2); - s.append(&CREATE_SHARD); - s.append_list(users); - } - Action::SetShardOwners { - shard_id, - owners, - } => { - s.begin_list(3); - s.append(&SET_SHARD_OWNERS); - s.append(shard_id); - s.append_list(owners); - } - Action::SetShardUsers { - shard_id, - users, - } => { - s.begin_list(3); - s.append(&SET_SHARD_USERS); - s.append(shard_id); - s.append_list(users); - } - Action::WrapCCC { - shard_id, - lock_script_hash, - parameters, - quantity, - payer, - } => { - s.begin_list(6); - s.append(&WRAP_CCC); - s.append(shard_id); - s.append(lock_script_hash); - s.append(parameters); - s.append(quantity); - s.append(payer); - } Action::Store { content, certifier, @@ -641,102 +129,6 @@ impl Encodable for Action { impl Decodable for Action { fn decode(rlp: &Rlp) -> Result { match rlp.val_at(0)? { - MINT_ASSET => { - let item_count = rlp.item_count()?; - if item_count != 11 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 11, - }) - } - Ok(Action::MintAsset { - network_id: rlp.val_at(1)?, - shard_id: rlp.val_at(2)?, - metadata: rlp.val_at(3)?, - output: Box::new(AssetMintOutput { - lock_script_hash: rlp.val_at(4)?, - parameters: rlp.val_at(5)?, - supply: rlp.val_at(6)?, - }), - approver: rlp.val_at(7)?, - registrar: rlp.val_at(8)?, - allowed_script_hashes: rlp.list_at(9)?, - approvals: rlp.list_at(10)?, - }) - } - TRANSFER_ASSET => { - let item_count = rlp.item_count()?; - if item_count != 9 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 9, - }) - } - Ok(Action::TransferAsset { - network_id: rlp.val_at(1)?, - burns: rlp.list_at(2)?, - inputs: rlp.list_at(3)?, - outputs: rlp.list_at(4)?, - metadata: rlp.val_at(6)?, - approvals: rlp.list_at(7)?, - expiration: rlp.val_at(8)?, - }) - } - CHANGE_ASSET_SCHEME => { - let item_count = rlp.item_count()?; - if item_count != 10 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 10, - }) - } - Ok(Action::ChangeAssetScheme { - network_id: rlp.val_at(1)?, - shard_id: rlp.val_at(2)?, - asset_type: rlp.val_at(3)?, - seq: rlp.val_at(4)?, - metadata: rlp.val_at(5)?, - approver: rlp.val_at(6)?, - registrar: rlp.val_at(7)?, - allowed_script_hashes: rlp.list_at(8)?, - approvals: rlp.list_at(9)?, - }) - } - INCREASE_ASSET_SUPPLY => { - let item_count = rlp.item_count()?; - if item_count != 9 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 9, - }) - } - Ok(Action::IncreaseAssetSupply { - network_id: rlp.val_at(1)?, - shard_id: rlp.val_at(2)?, - asset_type: rlp.val_at(3)?, - seq: rlp.val_at(4)?, - output: Box::new(AssetMintOutput { - lock_script_hash: rlp.val_at(5)?, - parameters: rlp.val_at(6)?, - supply: rlp.val_at(7)?, - }), - approvals: rlp.list_at(8)?, - }) - } - UNWRAP_CCC => { - let item_count = rlp.item_count()?; - if item_count != 4 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 4, - }) - } - Ok(Action::UnwrapCCC { - network_id: rlp.val_at(1)?, - burn: rlp.val_at(2)?, - receiver: rlp.val_at(3)?, - }) - } PAY => { let item_count = rlp.item_count()?; if item_count != 3 { @@ -762,60 +154,6 @@ impl Decodable for Action { key: rlp.val_at(1)?, }) } - CREATE_SHARD => { - let item_count = rlp.item_count()?; - if item_count != 2 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 2, - }) - } - Ok(Action::CreateShard { - users: rlp.list_at(1)?, - }) - } - SET_SHARD_OWNERS => { - let item_count = rlp.item_count()?; - if item_count != 3 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 3, - }) - } - Ok(Action::SetShardOwners { - shard_id: rlp.val_at(1)?, - owners: rlp.list_at(2)?, - }) - } - SET_SHARD_USERS => { - let item_count = rlp.item_count()?; - if item_count != 3 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 3, - }) - } - Ok(Action::SetShardUsers { - shard_id: rlp.val_at(1)?, - users: rlp.list_at(2)?, - }) - } - WRAP_CCC => { - let item_count = rlp.item_count()?; - if item_count != 6 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 6, - }) - } - Ok(Action::WrapCCC { - shard_id: rlp.val_at(1)?, - lock_script_hash: rlp.val_at(2)?, - parameters: rlp.val_at(3)?, - quantity: rlp.val_at(4)?, - payer: rlp.val_at(5)?, - }) - } STORE => { let item_count = rlp.item_count()?; if item_count != 4 { @@ -861,145 +199,11 @@ impl Decodable for Action { } } -fn is_input_and_output_consistent(inputs: &[AssetTransferInput], outputs: &[AssetTransferOutput]) -> bool { - let mut sum: HashMap<(H160, ShardId), u128> = HashMap::new(); - - for input in inputs { - let shard_asset_type = (input.prev_out.asset_type, input.prev_out.shard_id); - let quantity = u128::from(input.prev_out.quantity); - *sum.entry(shard_asset_type).or_insert_with(Default::default) += quantity; - } - for output in outputs { - let shard_asset_type = (output.asset_type, output.shard_id); - let quantity = u128::from(output.quantity); - let current_quantity = if let Some(current_quantity) = sum.get(&shard_asset_type) { - if *current_quantity < quantity { - return false - } - *current_quantity - } else { - return false - }; - let t = sum.insert(shard_asset_type, current_quantity - quantity); - debug_assert!(t.is_some()); - } - - sum.iter().all(|(_, sum)| *sum == 0) -} - -fn check_duplication_in_prev_out( - burns: &[AssetTransferInput], - inputs: &[AssetTransferInput], -) -> Result<(), SyntaxError> { - let mut prev_out_set = HashSet::new(); - for input in inputs.iter().chain(burns) { - let prev_out = (input.prev_out.tracker, input.prev_out.index); - if !prev_out_set.insert(prev_out) { - return Err(SyntaxError::DuplicatedPreviousOutput { - tracker: input.prev_out.tracker, - index: input.prev_out.index, - }) - } - } - Ok(()) -} - #[cfg(test)] mod tests { use rlp::rlp_encode_and_decode_test; use super::*; - use crate::transaction::AssetOutPoint; - - #[test] - fn encode_and_decode_mint_asset() { - rlp_encode_and_decode_test!(Action::MintAsset { - network_id: "tc".into(), - shard_id: 0xc, - metadata: "mint test".to_string(), - output: Box::new(AssetMintOutput { - lock_script_hash: H160::random(), - parameters: vec![], - supply: 10000, - }), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - approvals: vec![Signature::random(), Signature::random(), Signature::random(), Signature::random()], - }); - } - - #[test] - fn encode_and_decode_mint_asset_with_parameters() { - rlp_encode_and_decode_test!(Action::MintAsset { - network_id: "tc".into(), - shard_id: 3, - metadata: "mint test".to_string(), - output: Box::new(AssetMintOutput { - lock_script_hash: H160::random(), - parameters: vec![vec![1, 2, 3], vec![4, 5, 6], vec![0, 7]], - supply: 10000, - }), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - approvals: vec![Signature::random()], - }); - } - - #[test] - fn encode_and_decode_mint_with_single_quotation() { - rlp_encode_and_decode_test!(Action::MintAsset { - network_id: "tc".into(), - shard_id: 3, - metadata: "metadata has a single quotation(')".to_string(), - output: Box::new(AssetMintOutput { - lock_script_hash: H160::random(), - parameters: vec![vec![1, 2, 3], vec![4, 5, 6], vec![0, 7]], - supply: 10000, - }), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - approvals: vec![Signature::random()], - }); - } - - #[test] - fn encode_and_decode_mint_with_apostrophe() { - rlp_encode_and_decode_test!(Action::MintAsset { - network_id: "tc".into(), - shard_id: 3, - metadata: "metadata has an apostrophe(’)".to_string(), - output: Box::new(AssetMintOutput { - lock_script_hash: H160::random(), - parameters: vec![vec![1, 2, 3], vec![4, 5, 6], vec![0, 7]], - supply: 10000, - }), - approver: None, - registrar: None, - allowed_script_hashes: vec![], - approvals: vec![Signature::random()], - }); - } - - #[test] - fn encode_and_decode_transfer_asset() { - let burns = vec![]; - let inputs = vec![]; - let outputs = vec![]; - let network_id = "tc".into(); - let metadata = "".into(); - rlp_encode_and_decode_test!(Action::TransferAsset { - network_id, - burns, - inputs, - outputs, - metadata, - approvals: vec![Signature::random(), Signature::random()], - expiration: Some(10), - }); - } #[test] fn encode_and_decode_pay_action() { @@ -1009,22 +213,6 @@ mod tests { }); } - #[test] - fn encode_and_decode_set_shard_owners() { - rlp_encode_and_decode_test!(Action::SetShardOwners { - shard_id: 1, - owners: vec![Address::random(), Address::random()], - }); - } - - #[test] - fn encode_and_decode_set_shard_users() { - rlp_encode_and_decode_test!(Action::SetShardUsers { - shard_id: 1, - users: vec![Address::random(), Address::random()], - }); - } - #[test] fn encode_and_decode_store() { rlp_encode_and_decode_test!(Action::Store { @@ -1041,71 +229,4 @@ mod tests { signature: Signature::random(), }); } - - #[test] - fn encode_and_decode_change_asset_scheme_action() { - rlp_encode_and_decode_test!(Action::ChangeAssetScheme { - network_id: "ab".into(), - shard_id: 1, - asset_type: H160::random(), - seq: 0, - metadata: "some asset scheme metadata".to_string(), - approver: Some(Address::random()), - registrar: Some(Address::random()), - allowed_script_hashes: vec![H160::random(), H160::random(), H160::random()], - approvals: vec![], - }); - } - - #[test] - fn verify_unwrap_ccc_transaction_should_fail() { - let tx_zero_quantity = Action::UnwrapCCC { - network_id: NetworkId::default(), - burn: AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::zero(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - receiver: Address::random(), - }; - assert_eq!(tx_zero_quantity.verify(), Err(SyntaxError::ZeroQuantity)); - - let invalid_asset_type = H160::random(); - let tx_invalid_asset_type = Action::UnwrapCCC { - network_id: NetworkId::default(), - burn: AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: invalid_asset_type, - shard_id: 0, - quantity: 1, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - receiver: Address::random(), - }; - assert_eq!(tx_invalid_asset_type.verify(), Err(SyntaxError::InvalidAssetType(invalid_asset_type))); - } - - #[test] - fn verify_wrap_ccc_transaction_should_fail() { - let tx_zero_quantity = Action::WrapCCC { - shard_id: 0, - lock_script_hash: H160::random(), - parameters: vec![], - quantity: 0, - payer: Address::random(), - }; - assert_eq!(tx_zero_quantity.verify(), Err(SyntaxError::ZeroQuantity)); - } } diff --git a/types/src/transaction/asset_out_point.rs b/types/src/transaction/asset_out_point.rs deleted file mode 100644 index be72d0ce14..0000000000 --- a/types/src/transaction/asset_out_point.rs +++ /dev/null @@ -1,29 +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 . - -use primitives::H160; - -use crate::ShardId; -use crate::Tracker; - -#[derive(Debug, Clone, Eq, PartialEq, RlpDecodable, RlpEncodable)] -pub struct AssetOutPoint { - pub tracker: Tracker, - pub index: usize, - pub asset_type: H160, - pub shard_id: ShardId, - pub quantity: u64, -} diff --git a/types/src/transaction/input.rs b/types/src/transaction/input.rs deleted file mode 100644 index d49d27387f..0000000000 --- a/types/src/transaction/input.rs +++ /dev/null @@ -1,27 +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 . - -use primitives::Bytes; - -use super::{AssetOutPoint, Timelock}; - -#[derive(Debug, Clone, Eq, PartialEq, RlpDecodable, RlpEncodable)] -pub struct AssetTransferInput { - pub prev_out: AssetOutPoint, - pub timelock: Option, - pub lock_script: Bytes, - pub unlock_script: Bytes, -} diff --git a/types/src/transaction/mod.rs b/types/src/transaction/mod.rs index acbbaa748d..0a1a0a1c5a 100644 --- a/types/src/transaction/mod.rs +++ b/types/src/transaction/mod.rs @@ -15,22 +15,12 @@ // along with this program. If not, see . mod action; -mod asset_out_point; mod incomplete_transaction; -mod input; -mod output; -mod partial_hashing; -mod shard; mod timelock; #[cfg_attr(feature = "cargo-clippy", allow(clippy::module_inception))] mod transaction; pub use self::action::Action; -pub use self::asset_out_point::AssetOutPoint; pub use self::incomplete_transaction::IncompleteTransaction; -pub use self::input::AssetTransferInput; -pub use self::output::{AssetMintOutput, AssetTransferOutput}; -pub use self::partial_hashing::{HashingError, PartialHashing}; -pub use self::shard::{AssetWrapCCCOutput, ShardTransaction}; pub use self::timelock::Timelock; pub use self::transaction::Transaction; diff --git a/types/src/transaction/output.rs b/types/src/transaction/output.rs deleted file mode 100644 index 4adbac51bc..0000000000 --- a/types/src/transaction/output.rs +++ /dev/null @@ -1,35 +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 . - -use primitives::{Bytes, H160}; - -use crate::ShardId; - -#[derive(Debug, Clone, Eq, PartialEq, RlpDecodable, RlpEncodable)] -pub struct AssetTransferOutput { - pub lock_script_hash: H160, - pub parameters: Vec, - pub asset_type: H160, - pub shard_id: ShardId, - pub quantity: u64, -} - -#[derive(Default, Debug, Clone, PartialEq, Eq)] -pub struct AssetMintOutput { - pub lock_script_hash: H160, - pub parameters: Vec, - pub supply: u64, -} diff --git a/types/src/transaction/partial_hashing.rs b/types/src/transaction/partial_hashing.rs deleted file mode 100644 index a83843d412..0000000000 --- a/types/src/transaction/partial_hashing.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2018 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 primitives::H256; - -use super::AssetTransferInput; -use crate::util::tag::Tag; - -pub trait PartialHashing { - fn hash_partially(&self, tag: Tag, cur: &AssetTransferInput, burn: bool) -> Result; -} - -#[derive(Debug, PartialEq)] -pub enum HashingError { - InvalidFilter, -} diff --git a/types/src/transaction/shard.rs b/types/src/transaction/shard.rs deleted file mode 100644 index 2dbf27a0cf..0000000000 --- a/types/src/transaction/shard.rs +++ /dev/null @@ -1,966 +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 . - -use ccrypto::{blake128, blake256, blake256_with_key}; -use ckey::{Address, NetworkId}; -use primitives::{Bytes, H160, H256}; -use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; - -use super::{AssetMintOutput, AssetTransferInput, AssetTransferOutput, HashingError, PartialHashing}; -use crate::util::tag::Tag; -use crate::{ShardId, Tracker, TxHash}; - -/// Shard Transaction type. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ShardTransaction { - MintAsset { - network_id: NetworkId, - shard_id: ShardId, - metadata: String, - approver: Option
, - registrar: Option
, - allowed_script_hashes: Vec, - output: AssetMintOutput, - }, - TransferAsset { - network_id: NetworkId, - burns: Vec, - inputs: Vec, - outputs: Vec, - }, - ChangeAssetScheme { - network_id: NetworkId, - shard_id: ShardId, - asset_type: H160, - seq: usize, - metadata: String, - approver: Option
, - registrar: Option
, - allowed_script_hashes: Vec, - }, - IncreaseAssetSupply { - network_id: NetworkId, - shard_id: ShardId, - asset_type: H160, - seq: usize, - output: AssetMintOutput, - }, - UnwrapCCC { - network_id: NetworkId, - burn: AssetTransferInput, - receiver: Address, - }, - WrapCCC { - network_id: NetworkId, - shard_id: ShardId, - tx_hash: TxHash, - output: AssetWrapCCCOutput, - }, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct AssetWrapCCCOutput { - pub lock_script_hash: H160, - pub parameters: Vec, - pub quantity: u64, -} - -impl ShardTransaction { - pub fn tracker(&self) -> Tracker { - if let ShardTransaction::WrapCCC { - tx_hash, - .. - } = self - { - return (**tx_hash).into() - } - blake256(&*self.rlp_bytes()).into() - } - - pub fn network_id(&self) -> NetworkId { - match self { - ShardTransaction::TransferAsset { - network_id, - .. - } - | ShardTransaction::MintAsset { - network_id, - .. - } - | ShardTransaction::IncreaseAssetSupply { - network_id, - .. - } - | ShardTransaction::ChangeAssetScheme { - network_id, - .. - } - | ShardTransaction::UnwrapCCC { - network_id, - .. - } - | ShardTransaction::WrapCCC { - network_id, - .. - } => *network_id, - } - } - - pub fn related_shards(&self) -> Vec { - match self { - ShardTransaction::TransferAsset { - burns, - inputs, - .. - } => { - let mut shards: Vec = burns - .iter() - .map(|v| v.prev_out.shard_id) - .chain(inputs.iter().map(|v| v.prev_out.shard_id)) - .collect(); - shards.sort_unstable(); - shards.dedup(); - shards - } - ShardTransaction::MintAsset { - shard_id, - .. - } => vec![*shard_id], - ShardTransaction::IncreaseAssetSupply { - shard_id, - .. - } => vec![*shard_id], - ShardTransaction::ChangeAssetScheme { - shard_id, - .. - } => vec![*shard_id], - ShardTransaction::UnwrapCCC { - burn, - .. - } => vec![burn.prev_out.shard_id], - ShardTransaction::WrapCCC { - shard_id, - .. - } => vec![*shard_id], - } - } - - fn is_valid_output_index(&self, index: usize) -> bool { - match self { - ShardTransaction::MintAsset { - .. - } => index == 0, - ShardTransaction::TransferAsset { - outputs, - .. - } => index < outputs.len(), - ShardTransaction::IncreaseAssetSupply { - .. - } => index == 0, - ShardTransaction::ChangeAssetScheme { - .. - } => false, - ShardTransaction::UnwrapCCC { - .. - } => false, - ShardTransaction::WrapCCC { - .. - } => index == 0, - } - } - - pub fn is_valid_shard_id_index(&self, index: usize, id: ShardId) -> bool { - if !self.is_valid_output_index(index) { - return false - } - match self { - ShardTransaction::MintAsset { - shard_id, - .. - } => &id == shard_id, - ShardTransaction::TransferAsset { - outputs, - .. - } => id == outputs[index].shard_id, - ShardTransaction::IncreaseAssetSupply { - shard_id, - .. - } => &id == shard_id, - ShardTransaction::ChangeAssetScheme { - .. - } => unreachable!("AssetSchemeChange doesn't have a valid index"), - ShardTransaction::UnwrapCCC { - .. - } => unreachable!("UnwrapCCC doesn't have a valid index"), - ShardTransaction::WrapCCC { - shard_id, - .. - } => &id == shard_id, - } - } -} - -fn apply_bitmask_to_output( - mut bitmask: Vec, - outputs: &[AssetTransferOutput], - mut result: Vec, -) -> Result, HashingError> { - let mut index = 0; - let output_len = outputs.len(); - - while let Some(e) = bitmask.pop() { - let mut filter = e; - for i in 0..8 { - if (8 * index + i) == output_len as usize { - return Ok(result) - } - - if (filter & 0x1) == 1 { - result.push(outputs[8 * index + i].clone()); - } - - filter >>= 1; - } - index += 1; - } - Ok(result) -} - -fn apply_input_scheme( - inputs: &[AssetTransferInput], - is_sign_all: bool, - is_sign_single: bool, - cur: &AssetTransferInput, -) -> Vec { - if is_sign_all { - return inputs - .iter() - .map(|input| AssetTransferInput { - prev_out: input.prev_out.clone(), - timelock: input.timelock, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }) - .collect() - } - - if is_sign_single { - return vec![AssetTransferInput { - prev_out: cur.prev_out.clone(), - timelock: cur.timelock, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }] - } - - Vec::new() -} - -impl PartialHashing for ShardTransaction { - fn hash_partially(&self, tag: Tag, cur: &AssetTransferInput, is_burn: bool) -> Result { - match self { - ShardTransaction::TransferAsset { - network_id, - burns, - inputs, - outputs, - } => { - let new_burns = apply_input_scheme(burns, tag.sign_all_inputs, is_burn, cur); - let new_inputs = apply_input_scheme(inputs, tag.sign_all_inputs, !is_burn, cur); - - let new_outputs = if tag.sign_all_outputs { - outputs.clone() - } else { - apply_bitmask_to_output(tag.filter.clone(), &outputs, Vec::new())? - }; - - Ok(blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: *network_id, - burns: new_burns, - inputs: new_inputs, - outputs: new_outputs, - } - .rlp_bytes(), - &blake128(tag.get_tag()), - )) - } - ShardTransaction::UnwrapCCC { - network_id, - burn, - receiver, - } => { - if !tag.sign_all_inputs || !tag.sign_all_outputs { - return Err(HashingError::InvalidFilter) - } - - Ok(blake256_with_key( - &ShardTransaction::UnwrapCCC { - network_id: *network_id, - burn: AssetTransferInput { - prev_out: burn.prev_out.clone(), - timelock: burn.timelock, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }, - receiver: *receiver, - } - .rlp_bytes(), - &blake128(tag.get_tag()), - )) - } - _ => unreachable!(), - } - } -} - -type TransactionId = u8; -const ASSET_UNWRAP_CCC_ID: TransactionId = 0x11; -const ASSET_MINT_ID: TransactionId = 0x13; -const ASSET_TRANSFER_ID: TransactionId = 0x14; -const ASSET_SCHEME_CHANGE_ID: TransactionId = 0x15; -/// Deprecated -//const ASSET_COMPOSE_ID: TransactionId = 0x16; -/// Deprecated -//const ASSET_DECOMPOSE_ID: TransactionId = 0x17; -const ASSET_INCREASE_SUPPLY_ID: TransactionId = 0x18; - -impl Decodable for ShardTransaction { - fn decode(d: &Rlp) -> Result { - match d.val_at(0)? { - ASSET_MINT_ID => { - let item_count = d.item_count()?; - if item_count != 10 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 10, - }) - } - Ok(ShardTransaction::MintAsset { - network_id: d.val_at(1)?, - shard_id: d.val_at(2)?, - metadata: d.val_at(3)?, - output: AssetMintOutput { - lock_script_hash: d.val_at(4)?, - parameters: d.val_at(5)?, - supply: d.val_at(6)?, - }, - approver: d.val_at(7)?, - registrar: d.val_at(8)?, - allowed_script_hashes: d.list_at(9)?, - }) - } - ASSET_TRANSFER_ID => { - let item_count = d.item_count()?; - if item_count != 6 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 6, - }) - } - let orders = d.list_at::(5)?; - if !orders.is_empty() { - return Err(DecoderError::Custom("orders must be an empty list")) - } - Ok(ShardTransaction::TransferAsset { - network_id: d.val_at(1)?, - burns: d.list_at(2)?, - inputs: d.list_at(3)?, - outputs: d.list_at(4)?, - }) - } - ASSET_SCHEME_CHANGE_ID => { - let item_count = d.item_count()?; - if item_count != 9 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 9, - }) - } - Ok(ShardTransaction::ChangeAssetScheme { - network_id: d.val_at(1)?, - shard_id: d.val_at(2)?, - asset_type: d.val_at(3)?, - seq: d.val_at(4)?, - metadata: d.val_at(5)?, - approver: d.val_at(6)?, - registrar: d.val_at(7)?, - allowed_script_hashes: d.list_at(8)?, - }) - } - ASSET_INCREASE_SUPPLY_ID => { - let item_count = d.item_count()?; - if item_count != 8 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 8, - }) - } - Ok(ShardTransaction::IncreaseAssetSupply { - network_id: d.val_at(1)?, - shard_id: d.val_at(2)?, - asset_type: d.val_at(3)?, - seq: d.val_at(4)?, - output: AssetMintOutput { - lock_script_hash: d.val_at(5)?, - parameters: d.val_at(6)?, - supply: d.val_at(7)?, - }, - }) - } - ASSET_UNWRAP_CCC_ID => { - let item_count = d.item_count()?; - if item_count != 4 { - return Err(DecoderError::RlpIncorrectListLen { - got: item_count, - expected: 4, - }) - } - Ok(ShardTransaction::UnwrapCCC { - network_id: d.val_at(1)?, - burn: d.val_at(2)?, - receiver: d.val_at(3)?, - }) - } - _ => Err(DecoderError::Custom("Unexpected transaction")), - } - } -} - -impl Encodable for ShardTransaction { - fn rlp_append(&self, s: &mut RlpStream) { - match self { - ShardTransaction::MintAsset { - network_id, - shard_id, - metadata, - output: - AssetMintOutput { - lock_script_hash, - parameters, - supply, - }, - approver, - registrar, - allowed_script_hashes, - } => { - s.begin_list(10) - .append(&ASSET_MINT_ID) - .append(network_id) - .append(shard_id) - .append(metadata) - .append(lock_script_hash) - .append(parameters) - .append(supply) - .append(approver) - .append(registrar) - .append_list(allowed_script_hashes); - } - ShardTransaction::TransferAsset { - network_id, - burns, - inputs, - outputs, - } => { - let empty: Vec = vec![]; - s.begin_list(6) - .append(&ASSET_TRANSFER_ID) - .append(network_id) - .append_list(burns) - .append_list(inputs) - .append_list(outputs) - // NOTE: The orders field removed. - .append_list(&empty); - } - ShardTransaction::ChangeAssetScheme { - network_id, - shard_id, - asset_type, - seq, - metadata, - approver, - registrar, - allowed_script_hashes, - } => { - s.begin_list(9) - .append(&ASSET_SCHEME_CHANGE_ID) - .append(network_id) - .append(shard_id) - .append(asset_type) - .append(seq) - .append(metadata) - .append(approver) - .append(registrar) - .append_list(allowed_script_hashes); - } - ShardTransaction::IncreaseAssetSupply { - network_id, - shard_id, - asset_type, - seq, - output: - AssetMintOutput { - lock_script_hash, - parameters, - supply, - }, - } => { - s.begin_list(8) - .append(&ASSET_INCREASE_SUPPLY_ID) - .append(network_id) - .append(shard_id) - .append(asset_type) - .append(seq) - .append(lock_script_hash) - .append(parameters) - .append(supply); - } - ShardTransaction::UnwrapCCC { - network_id, - burn, - receiver, - } => { - s.begin_list(4).append(&ASSET_UNWRAP_CCC_ID).append(network_id).append(burn).append(receiver); - } - ShardTransaction::WrapCCC { - .. - } => { - unreachable!("No reason to get a RLP encoding of WrapCCC"); - } - }; - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - - use rlp::rlp_encode_and_decode_test; - - use super::super::AssetOutPoint; - use super::*; - - #[test] - fn _is_input_and_output_consistent() { - let asset_type = H160::random(); - let quantity = 100; - - assert!(is_input_and_output_consistent( - &[AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random().into(), - index: 0, - asset_type, - shard_id: 0, - quantity, - }, - timelock: None, - lock_script: vec![], - unlock_script: vec![], - }], - &[AssetTransferOutput { - lock_script_hash: H160::random(), - parameters: vec![], - asset_type, - shard_id: 0, - quantity, - }] - )); - } - - #[test] - fn multiple_asset_is_input_and_output_consistent() { - let asset_type1 = H160::random(); - let asset_type2 = { - let mut asset_type = H160::random(); - while asset_type == asset_type1 { - asset_type = H160::random(); - } - asset_type - }; - let quantity1 = 100; - let quantity2 = 200; - - assert!(is_input_and_output_consistent( - &[ - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random().into(), - index: 0, - asset_type: asset_type1, - shard_id: 0, - quantity: quantity1, - }, - timelock: None, - lock_script: vec![], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random().into(), - index: 0, - asset_type: asset_type2, - shard_id: 0, - quantity: quantity2, - }, - timelock: None, - lock_script: vec![], - unlock_script: vec![], - }, - ], - &[ - AssetTransferOutput { - lock_script_hash: H160::random(), - parameters: vec![], - asset_type: asset_type1, - shard_id: 0, - quantity: quantity1, - }, - AssetTransferOutput { - lock_script_hash: H160::random(), - parameters: vec![], - asset_type: asset_type2, - shard_id: 0, - quantity: quantity2, - }, - ] - )); - } - - #[test] - fn multiple_asset_different_order_is_input_and_output_consistent() { - let asset_type1 = H160::random(); - let asset_type2 = { - let mut asset_type = H160::random(); - while asset_type == asset_type1 { - asset_type = H160::random(); - } - asset_type - }; - let quantity1 = 100; - let quantity2 = 200; - - assert!(is_input_and_output_consistent( - &[ - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random().into(), - index: 0, - asset_type: asset_type1, - shard_id: 0, - quantity: quantity1, - }, - timelock: None, - lock_script: vec![], - unlock_script: vec![], - }, - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random().into(), - index: 0, - asset_type: asset_type2, - shard_id: 0, - quantity: quantity2, - }, - timelock: None, - lock_script: vec![], - unlock_script: vec![], - }, - ], - &[ - AssetTransferOutput { - lock_script_hash: H160::random(), - parameters: vec![], - asset_type: asset_type2, - shard_id: 0, - quantity: quantity2, - }, - AssetTransferOutput { - lock_script_hash: H160::random(), - parameters: vec![], - asset_type: asset_type1, - shard_id: 0, - quantity: quantity1, - }, - ] - )); - } - - #[test] - fn empty_is_input_and_output_consistent() { - assert!(is_input_and_output_consistent(&[], &[])); - } - - #[test] - fn fail_if_output_has_more_asset() { - let asset_type = H160::random(); - let output_quantity = 100; - assert!(!is_input_and_output_consistent(&[], &[AssetTransferOutput { - lock_script_hash: H160::random(), - parameters: vec![], - asset_type, - shard_id: 0, - quantity: output_quantity, - }])); - } - - #[test] - fn fail_if_input_has_more_asset() { - let asset_type = H160::random(); - let input_quantity = 100; - - assert!(!is_input_and_output_consistent( - &[AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random().into(), - index: 0, - asset_type, - shard_id: 0, - quantity: input_quantity, - }, - timelock: None, - lock_script: vec![], - unlock_script: vec![], - }], - &[] - )); - } - - #[test] - fn fail_if_input_is_larger_than_output() { - let asset_type = H160::random(); - let input_quantity = 100; - let output_quantity = 80; - - assert!(!is_input_and_output_consistent( - &[AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random().into(), - index: 0, - asset_type, - shard_id: 0, - quantity: input_quantity, - }, - timelock: None, - lock_script: vec![], - unlock_script: vec![], - }], - &[AssetTransferOutput { - lock_script_hash: H160::random(), - parameters: vec![], - asset_type, - shard_id: 0, - quantity: output_quantity, - }] - )); - } - - #[test] - fn fail_if_input_is_smaller_than_output() { - let asset_type = H160::random(); - let input_quantity = 80; - let output_quantity = 100; - - assert!(!is_input_and_output_consistent( - &[AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random().into(), - index: 0, - asset_type, - shard_id: 0, - quantity: input_quantity, - }, - timelock: None, - lock_script: vec![], - unlock_script: vec![], - }], - &[AssetTransferOutput { - lock_script_hash: H160::random(), - parameters: vec![], - asset_type, - shard_id: 0, - quantity: output_quantity, - }] - )); - } - - #[test] - fn encode_and_decode_unwrapccc_transaction() { - let tx = ShardTransaction::UnwrapCCC { - network_id: NetworkId::default(), - burn: AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::zero(), - shard_id: 0, - quantity: 30, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }, - receiver: Address::random(), - }; - rlp_encode_and_decode_test!(tx); - } - - #[test] - fn encode_and_decode_transfer_transaction_with_order() { - let tx = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: vec![], - inputs: vec![AssetTransferInput { - prev_out: AssetOutPoint { - tracker: H256::random().into(), - index: 0, - asset_type: H160::random(), - shard_id: 0, - quantity: 30, - }, - timelock: None, - lock_script: vec![0x30, 0x01], - unlock_script: vec![], - }], - outputs: vec![AssetTransferOutput { - lock_script_hash: H160::random(), - parameters: vec![vec![1]], - asset_type: H160::random(), - shard_id: 0, - quantity: 30, - }], - }; - rlp_encode_and_decode_test!(tx); - } - - #[test] - fn apply_long_filter() { - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let inputs: Vec = (0..100) - .map(|_| AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }) - .collect(); - let mut outputs: Vec = (0..100) - .map(|_| AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }) - .collect(); - - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: inputs.clone(), - outputs: outputs.clone(), - }; - let mut tag: Vec = vec![0b0000_1111 as u8]; - for _i in 0..12 { - tag.push(0b1111_1111 as u8); - } - tag.push(0b0011_0101); - assert_eq!( - transaction.hash_partially(Tag::try_new(tag.clone()).unwrap(), &input, false), - Ok(blake256_with_key(&transaction.rlp_bytes(), &blake128(&tag))) - ); - - // Sign except for last element - outputs.pop(); - let transaction_aux = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: inputs.clone(), - outputs: outputs.clone(), - }; - tag = vec![0b0000_0111 as u8]; - for _i in 0..12 { - tag.push(0b1111_1111 as u8); - } - tag.push(0b0011_0101); - assert_eq!( - transaction.hash_partially(Tag::try_new(tag.clone()).unwrap(), &input, false), - Ok(blake256_with_key(&transaction_aux.rlp_bytes(), &blake128(&tag))) - ); - - // Sign except for last two elements - outputs.pop(); - let transaction_aux = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs, - outputs, - }; - tag = vec![0b0000_0011 as u8]; - for _i in 0..12 { - tag.push(0b1111_1111 as u8); - } - tag.push(0b0011_0101); - assert_eq!( - transaction.hash_partially(Tag::try_new(tag.clone()).unwrap(), &input, false), - Ok(blake256_with_key(&transaction_aux.rlp_bytes(), &blake128(&tag))) - ); - } - - // FIXME: Remove it and reuse the same function declared in action.rs - fn is_input_and_output_consistent(inputs: &[AssetTransferInput], outputs: &[AssetTransferOutput]) -> bool { - let mut sum: HashMap = HashMap::new(); - - for input in inputs { - let asset_type = input.prev_out.asset_type; - let quantity = u128::from(input.prev_out.quantity); - *sum.entry(asset_type).or_insert_with(Default::default) += quantity; - } - for output in outputs { - let asset_type = output.asset_type; - let quantity = u128::from(output.quantity); - let current_quantity = if let Some(current_quantity) = sum.get(&asset_type) { - if *current_quantity < quantity { - return false - } - *current_quantity - } else { - return false - }; - let t = sum.insert(asset_type, current_quantity - quantity); - debug_assert!(t.is_some()); - } - - sum.iter().all(|(_, sum)| *sum == 0) - } -} diff --git a/types/src/transaction/transaction.rs b/types/src/transaction/transaction.rs index 57f57275d3..77afba1193 100644 --- a/types/src/transaction/transaction.rs +++ b/types/src/transaction/transaction.rs @@ -19,8 +19,7 @@ use ckey::NetworkId; use rlp::RlpStream; use super::Action; -use super::{AssetWrapCCCOutput, ShardTransaction}; -use crate::{Tracker, TxHash}; +use crate::TxHash; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Transaction { @@ -51,28 +50,6 @@ impl Transaction { blake256(stream.as_raw()).into() } - pub fn tracker(&self) -> Option { - let shard_tx = match self.action.clone() { - Action::WrapCCC { - shard_id, - lock_script_hash, - parameters, - quantity, - .. - } => Some(ShardTransaction::WrapCCC { - network_id: self.network_id, - shard_id, - tx_hash: self.hash(), - output: AssetWrapCCCOutput { - lock_script_hash, - parameters, - quantity, - }, - }), - other_actions => other_actions.into(), - }; - shard_tx.map(|t| t.tracker()) - } pub fn is_master_key_allowed(&self) -> bool { match self.action { Action::SetRegularKey { diff --git a/types/src/tx_hash.rs b/types/src/tx_hash.rs index 33c0d101ca..9a57ea0b59 100644 --- a/types/src/tx_hash.rs +++ b/types/src/tx_hash.rs @@ -59,27 +59,10 @@ impl Decodable for TxHash { #[cfg(test)] mod tests { - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; - use rlp::{self, rlp_encode_and_decode_test}; use super::*; - #[test] - fn hash_of_tx_hash_and_h256_are_the_same() { - let h256 = H256::random(); - let tx_hash = TxHash(h256); - - let mut hasher_of_h256 = DefaultHasher::new(); - let mut hasher_of_tracker = DefaultHasher::new(); - - h256.hash(&mut hasher_of_h256); - tx_hash.hash(&mut hasher_of_tracker); - - assert_eq!(hasher_of_h256.finish(), hasher_of_tracker.finish()); - } - #[test] fn rlp_of_tx_hash_can_be_decoded_to_h256() { let h256 = H256::random(); diff --git a/types/src/util/mod.rs b/types/src/util/mod.rs index 7652f11dbc..c729e83548 100644 --- a/types/src/util/mod.rs +++ b/types/src/util/mod.rs @@ -14,5 +14,4 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -pub mod tag; pub mod unexpected; diff --git a/types/src/util/tag.rs b/types/src/util/tag.rs deleted file mode 100644 index 4599576ea2..0000000000 --- a/types/src/util/tag.rs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2018 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::transaction::HashingError; - -#[derive(Debug, PartialEq)] -pub struct Tag { - pub sign_all_inputs: bool, - pub sign_all_outputs: bool, - pub filter_len: usize, - pub filter: Vec, - pub bitvec: Vec, -} - -impl Tag { - pub fn try_new(mut bitvec: Vec) -> Result { - let vec = bitvec.clone(); - let tag = bitvec.pop().ok_or(HashingError::InvalidFilter)?; - let sign_all_inputs = (tag & 0x1) == 1; - let sign_all_outputs = (tag >> 1 & 0x1) == 1; - let filter_len = (tag >> 2) as usize; - - let length = bitvec.len(); - if length != filter_len { - return Err(HashingError::InvalidFilter) - } - - // Check if the filter has trailing zero - if length != 0 && bitvec[0] == 0 { - return Err(HashingError::InvalidFilter) - } - - Ok(Tag { - sign_all_inputs, - sign_all_outputs, - filter_len, - filter: bitvec, - bitvec: vec, - }) - } - - pub fn get_tag(&self) -> &Vec { - &self.bitvec - } -} -#[cfg(test)] -mod tests { - use crate::transaction::HashingError; - use crate::util::tag::Tag; - #[test] - fn make_partial_signing_tag() { - let bitvec = vec![ - 0b1000_0000, - 0b0100_0000, - 0b0010_0000, - 0b0001_0000, - 0b0000_1000, - 0b0000_0100, - 0b0000_0010, - 0b0000_0001, - 0b0010_0001, - ]; - let tag = Tag::try_new(bitvec).unwrap(); - - assert_eq!(tag.sign_all_inputs, true); - assert_eq!(tag.sign_all_outputs, false); - assert_eq!(tag.filter_len, 8); - assert_eq!(tag.filter, vec![ - 0b1000_0000, - 0b0100_0000, - 0b0010_0000, - 0b0001_0000, - 0b0000_1000, - 0b0000_0100, - 0b0000_0010, - 0b0000_0001 - ]); - } - - #[test] - fn trailing_zero() { - let bitvec = vec![ - 0b0000_0000, - 0b0100_0000, - 0b0010_0000, - 0b0001_0000, - 0b0000_1000, - 0b0000_0100, - 0b0000_0010, - 0b0000_0001, - 0b0010_0001, - ]; - assert_eq!(Tag::try_new(bitvec), Err(HashingError::InvalidFilter)); - - let bitvec = vec![ - 0b0000_0100, - 0b0000_0000, - 0b0000_0000, - 0b0000_0000, - 0b0000_0000, - 0b0000_0000, - 0b0000_0000, - 0b0000_0000, - 0b0010_0001, - ]; - assert_ne!(Tag::try_new(bitvec), Err(HashingError::InvalidFilter)); - } - - #[test] - fn zero_length_filter() { - let bitvec = vec![0b0000_0001]; - assert_eq!( - Tag::try_new(bitvec), - Ok(Tag { - sign_all_inputs: true, - sign_all_outputs: false, - filter_len: 0, - filter: vec![], - bitvec: vec![0b0000_0001], - }) - ); - } -} diff --git a/vm/Cargo.toml b/vm/Cargo.toml deleted file mode 100644 index c3ee936994..0000000000 --- a/vm/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "codechain-vm" -version = "0.1.0" -authors = ["CodeChain Team "] -edition = "2018" - -[lib] - -[dependencies] -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } -codechain-key = { path = "../key" } -codechain-types = { path = "../types" } -primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } -rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } - -[dev-dependencies] -secp256k1 = { git = "https://github.com/CodeChain-io/rust-secp256k1.git", version = "0.6" } diff --git a/vm/src/decoder.rs b/vm/src/decoder.rs deleted file mode 100644 index d2f2f7a130..0000000000 --- a/vm/src/decoder.rs +++ /dev/null @@ -1,179 +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 . - -use crate::instruction::Instruction; -use crate::opcode; - -#[derive(Debug, PartialEq)] -pub enum DecoderError { - ScriptTooShort, - InvalidOpCode(u8), - InvalidImmediateValue(u8), -} - -pub fn decode(bytes: &[u8]) -> Result, DecoderError> { - let mut iter = bytes.iter(); - let mut result = Vec::new(); - while let Some(b) = iter.next() { - match *b { - opcode::NOP => result.push(Instruction::Nop), - opcode::BURN => result.push(Instruction::Burn), - opcode::SUCCESS => result.push(Instruction::Success), - opcode::FAIL => result.push(Instruction::Fail), - opcode::NOT => result.push(Instruction::Not), - opcode::EQ => result.push(Instruction::Eq), - opcode::JMP => { - let val = *iter.next().ok_or(DecoderError::ScriptTooShort)?; - result.push(Instruction::Jmp(val)); - } - opcode::JNZ => { - let val = *iter.next().ok_or(DecoderError::ScriptTooShort)?; - result.push(Instruction::Jnz(val)); - } - opcode::JZ => { - let val = *iter.next().ok_or(DecoderError::ScriptTooShort)?; - result.push(Instruction::Jz(val)); - } - opcode::PUSH => { - let val = *iter.next().ok_or(DecoderError::ScriptTooShort)?; - result.push(Instruction::Push(val)); - } - opcode::POP => result.push(Instruction::Pop), - opcode::PUSHB => { - let len = *iter.next().ok_or(DecoderError::ScriptTooShort)?; - // FIXME : optimize blob assignment - let mut blob = Vec::new(); - for _ in 0..len { - blob.push(*iter.next().ok_or(DecoderError::ScriptTooShort)?); - } - result.push(Instruction::PushB(blob)); - } - opcode::DUP => result.push(Instruction::Dup), - opcode::SWAP => result.push(Instruction::Swap), - opcode::COPY => { - let val = *iter.next().ok_or(DecoderError::ScriptTooShort)?; - result.push(Instruction::Copy(val)); - } - opcode::DROP => { - let val = *iter.next().ok_or(DecoderError::ScriptTooShort)?; - result.push(Instruction::Drop(val)); - } - opcode::CHKSIG => result.push(Instruction::ChkSig), - opcode::CHKMULTISIG => result.push(Instruction::ChkMultiSig), - opcode::BLAKE256 => result.push(Instruction::Blake256), - opcode::SHA256 => result.push(Instruction::Sha256), - opcode::RIPEMD160 => result.push(Instruction::Ripemd160), - opcode::KECCAK256 => result.push(Instruction::Keccak256), - opcode::BLAKE160 => result.push(Instruction::Blake160), - opcode::CHKTIMELOCK => { - let val = *iter.next().ok_or(DecoderError::ScriptTooShort)?; - if val < 1 || val > 4 { - return Err(DecoderError::InvalidImmediateValue(val)) - } - result.push(Instruction::ChkTimelock(val)); - } - invalid_opcode => return Err(DecoderError::InvalidOpCode(invalid_opcode)), - } - } - - Ok(result) -} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! test_no_argument_opcode { - ($opcode:ident, $instruction:ident) => { - #[test] - #[allow(non_snake_case)] - fn $instruction() { - assert_eq!(decode(&[opcode::$opcode]), Ok(vec![Instruction::$instruction])); - assert_eq!( - decode(&[opcode::$opcode, opcode::$opcode]), - Ok(vec![Instruction::$instruction, Instruction::$instruction]) - ); - } - }; - } - - macro_rules! test_one_argument_opcode { - ($opcode:ident, $instruction:ident) => { - #[test] - #[allow(non_snake_case)] - fn $instruction() { - assert_eq!(decode(&[opcode::$opcode]), Err(DecoderError::ScriptTooShort)); - assert_eq!(decode(&[opcode::$opcode, 0]), Ok(vec![Instruction::$instruction(0)])); - assert_eq!(decode(&[opcode::$opcode, 0, opcode::$opcode]), Err(DecoderError::ScriptTooShort)); - assert_eq!( - decode(&[opcode::$opcode, 0, opcode::$opcode, 1]), - Ok(vec![Instruction::$instruction(0), Instruction::$instruction(1)]) - ); - } - }; - } - - test_no_argument_opcode!(NOP, Nop); - test_no_argument_opcode!(BURN, Burn); - test_no_argument_opcode!(SUCCESS, Success); - test_no_argument_opcode!(FAIL, Fail); - test_no_argument_opcode!(NOT, Not); - test_no_argument_opcode!(EQ, Eq); - test_one_argument_opcode!(JMP, Jmp); - test_one_argument_opcode!(JNZ, Jnz); - test_one_argument_opcode!(JZ, Jz); - test_one_argument_opcode!(PUSH, Push); - test_no_argument_opcode!(POP, Pop); - test_no_argument_opcode!(DUP, Dup); - test_no_argument_opcode!(SWAP, Swap); - test_one_argument_opcode!(COPY, Copy); - test_one_argument_opcode!(DROP, Drop); - test_no_argument_opcode!(CHKSIG, ChkSig); - test_no_argument_opcode!(CHKMULTISIG, ChkMultiSig); - test_no_argument_opcode!(BLAKE256, Blake256); - test_no_argument_opcode!(SHA256, Sha256); - test_no_argument_opcode!(RIPEMD160, Ripemd160); - test_no_argument_opcode!(KECCAK256, Keccak256); - test_no_argument_opcode!(BLAKE160, Blake160); - - #[test] - #[allow(non_snake_case)] - fn PushB() { - let blobs: Vec<&[u8]> = vec![&[0xed, 0x11, 0xe7], &[0x8b, 0x0c, 0x92, 0x24, 0x3f]]; - assert_eq!( - decode([&[opcode::PUSHB, 3], &blobs[0][..], &[opcode::PUSHB, 5], &blobs[1][..]].concat().as_slice()), - Ok(vec![Instruction::PushB(blobs[0].to_vec()), Instruction::PushB(blobs[1].to_vec())]) - ); - assert_eq!(decode([&[opcode::PUSHB, 4], &blobs[0][..]].concat().as_slice()), Err(DecoderError::ScriptTooShort)); - } - - #[test] - #[allow(non_snake_case)] - fn ChkTimelock() { - assert_eq!(decode(&[opcode::CHKTIMELOCK]), Err(DecoderError::ScriptTooShort)); - assert_eq!(decode(&[opcode::CHKTIMELOCK, 0]), Err(DecoderError::InvalidImmediateValue(0))); - assert_eq!(decode(&[opcode::CHKTIMELOCK, 5]), Err(DecoderError::InvalidImmediateValue(5))); - assert_eq!(decode(&[opcode::CHKTIMELOCK, 1]), Ok(vec![Instruction::ChkTimelock(1)])); - assert_eq!(decode(&[opcode::CHKTIMELOCK, 2]), Ok(vec![Instruction::ChkTimelock(2)])); - assert_eq!(decode(&[opcode::CHKTIMELOCK, 3]), Ok(vec![Instruction::ChkTimelock(3)])); - assert_eq!(decode(&[opcode::CHKTIMELOCK, 4]), Ok(vec![Instruction::ChkTimelock(4)])); - assert_eq!(decode(&[opcode::CHKTIMELOCK, 1, opcode::CHKTIMELOCK]), Err(DecoderError::ScriptTooShort)); - assert_eq!( - decode(&[opcode::CHKTIMELOCK, 1, opcode::CHKTIMELOCK, 2]), - Ok(vec![Instruction::ChkTimelock(1), Instruction::ChkTimelock(2)]) - ); - } -} diff --git a/vm/src/executor.rs b/vm/src/executor.rs deleted file mode 100644 index 22a192fdfe..0000000000 --- a/vm/src/executor.rs +++ /dev/null @@ -1,519 +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 . - -use ccrypto::{blake256, keccak256, ripemd160, sha256, Blake}; -use ckey::{verify, Public, Signature, SIGNATURE_LENGTH}; -use ctypes::transaction::{AssetTransferInput, HashingError, PartialHashing}; -use ctypes::util::tag::Tag; -use ctypes::{BlockNumber, Tracker}; - -use primitives::{H160, H256}; - - -use crate::instruction::{has_expensive_opcodes, is_valid_unlock_script, Instruction}; - -const DEFAULT_MAX_MEMORY: usize = 1024; - -const TIMELOCK_TYPE_BLOCK: u8 = 0x01; -const TIMELOCK_TYPE_BLOCK_AGE: u8 = 0x02; -const TIMELOCK_TYPE_TIME: u8 = 0x03; -const TIMELOCK_TYPE_TIME_AGE: u8 = 0x04; - -pub struct Config { - pub max_memory: usize, -} - -impl Default for Config { - fn default() -> Self { - Self { - max_memory: DEFAULT_MAX_MEMORY, - } - } -} - -#[derive(Debug, PartialEq)] -pub enum ScriptResult { - Fail, - Unlocked, - Burnt, -} - -#[derive(Debug, PartialEq)] -pub enum RuntimeError { - OutOfMemory, - IndexOutOfBound, - StackUnderflow, - TypeMismatch, - InvalidFilter, - InvalidSigCount, - InvalidTimelockType, -} - -impl From for RuntimeError { - fn from(error: HashingError) -> Self { - match error { - HashingError::InvalidFilter => RuntimeError::InvalidFilter, - } - } -} - -#[derive(Clone)] -struct Item(Vec); - -impl Item { - fn len(&self) -> usize { - self.0.len() - } - - fn assert_len(self, len: usize) -> Result { - if self.len() == len { - Ok(self) - } else { - Err(RuntimeError::TypeMismatch) - } - } -} - -impl AsRef<[u8]> for Item { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl From for Item { - fn from(val: bool) -> Item { - if val { - Item(vec![1]) - } else { - Item(vec![]) - } - } -} - -impl From for bool { - fn from(item: Item) -> Self { - item.as_ref().iter().any(|b| b != &0) - } -} - -struct Stack { - stack: Vec, - memory_usage: usize, - config: Config, -} - -impl Stack { - fn new(config: Config) -> Self { - Self { - stack: Vec::new(), - memory_usage: 0, - config, - } - } - - /// Returns true if value is successfully pushed - fn push(&mut self, val: Item) -> Result<(), RuntimeError> { - if self.memory_usage + val.len() > self.config.max_memory { - Err(RuntimeError::OutOfMemory) - } else { - self.memory_usage += val.len(); - self.stack.push(val); - Ok(()) - } - } - - fn pop(&mut self) -> Result { - let item = self.stack.pop(); - self.memory_usage -= item.as_ref().map_or(0, Item::len); - item.ok_or(RuntimeError::StackUnderflow) - } - - fn len(&self) -> usize { - self.stack.len() - } - - fn get(&self, index: usize) -> Result { - self.stack.get(index).cloned().ok_or(RuntimeError::IndexOutOfBound) - } - - fn remove(&mut self, index: usize) -> Result { - if index < self.stack.len() { - let item = self.stack.remove(index); - self.memory_usage -= item.len(); - Ok(item) - } else { - Err(RuntimeError::IndexOutOfBound) - } - } -} - -pub fn execute( - unlock: &[Instruction], - params: &[Vec], - lock: &[Instruction], - tx: &dyn PartialHashing, - config: Config, - cur: &AssetTransferInput, - burn: bool, - client: &C, - parent_block_number: BlockNumber, - parent_block_timestamp: u64, -) -> Result -where - C: ChainTimeInfo, { - // FIXME: don't merge scripts - - if !is_valid_unlock_script(unlock) { - return Ok(ScriptResult::Fail) - } - - if has_expensive_opcodes(unlock) { - return Ok(ScriptResult::Fail) - } - - let param_scripts: Vec<_> = params.iter().map(|p| Instruction::PushB(p.clone())).rev().collect(); - let script = [unlock, ¶m_scripts, lock].concat(); - - let mut stack = Stack::new(config); - let mut pc = 0; - while pc < script.len() { - match &script[pc] { - Instruction::Nop => {} - Instruction::Burn => return Ok(ScriptResult::Burnt), - Instruction::Success => return Ok(ScriptResult::Unlocked), - Instruction::Fail => return Ok(ScriptResult::Fail), - Instruction::Not => { - let value: bool = stack.pop()?.into(); - stack.push(Item::from(!value))?; - } - Instruction::Eq => { - let first = stack.pop()?; - let second = stack.pop()?; - stack.push(Item::from(first.as_ref() == second.as_ref()))?; - } - Instruction::Jmp(val) => { - pc += *val as usize; - } - Instruction::Jnz(val) => { - if stack.pop()?.into() { - pc += *val as usize; - } - } - Instruction::Jz(val) => { - let condition: bool = stack.pop()?.into(); - if !condition { - pc += *val as usize; - } - } - Instruction::Push(val) => stack.push(Item(vec![*val]))?, - Instruction::Pop => { - stack.pop()?; - } - Instruction::PushB(blob) => stack.push(Item(blob.clone()))?, - Instruction::Dup => { - let top = stack.pop()?; - stack.push(top.clone())?; - stack.push(top)?; - } - Instruction::Swap => { - let first = stack.pop()?; - let second = stack.pop()?; - stack.push(first)?; - stack.push(second)?; - } - Instruction::Copy(index) => { - if stack.len() <= *index as usize { - return Err(RuntimeError::StackUnderflow) - } - let item = stack.get((stack.len() - 1) - *index as usize)?; - stack.push(item)? - } - Instruction::Drop(index) => { - stack.remove(*index as usize)?; - } - Instruction::ChkSig => { - let pubkey = Public::from_slice(stack.pop()?.assert_len(64)?.as_ref()); - let tag = Tag::try_new(stack.pop()?.as_ref().to_vec())?; - let tx_hash = tx.hash_partially(tag, cur, burn)?; - let signature = Signature::from(stack.pop()?.assert_len(SIGNATURE_LENGTH)?.as_ref()); - let result = match verify(&pubkey, &signature, &tx_hash) { - Ok(true) => 1, - _ => 0, - }; - stack.push(Item(vec![result]))?; - } - Instruction::ChkMultiSig => { - // Get n pubkey. If there are more than six pubkeys, return error. - let n = stack.pop()?.assert_len(1)?.as_ref()[0] as usize; - - let mut pubkey: Vec = Vec::with_capacity(n); - for _ in 0..n { - pubkey.push(Public::from_slice(stack.pop()?.assert_len(64)?.as_ref())); - } - - // Get m signature. If signatures are more than pubkeys, return error. - let m = stack.pop()?.assert_len(1)?.as_ref()[0] as usize; - if m > n || m == 0 || m > 6 { - return Err(RuntimeError::InvalidSigCount) - } - - let mut signatures: Vec = Vec::with_capacity(m); - for _ in 0..m { - signatures.push(Signature::from(stack.pop()?.assert_len(SIGNATURE_LENGTH)?.as_ref())); - } - - let tag = Tag::try_new(stack.pop()?.as_ref().to_vec())?; - let tx_hash = tx.hash_partially(tag, cur, burn)?; - - let result = if check_multi_sig(&tx_hash, pubkey, signatures) { - 1 - } else { - 0 - }; - stack.push(Item(vec![result]))?; - } - Instruction::Blake256 => { - let value = stack.pop()?; - stack.push(Item(blake256(value).to_vec()))?; - } - Instruction::Sha256 => { - let value = stack.pop()?; - stack.push(Item(sha256(value).to_vec()))?; - } - Instruction::Ripemd160 => { - let value = stack.pop()?; - stack.push(Item(ripemd160(value).to_vec()))?; - } - Instruction::Keccak256 => { - let value = stack.pop()?; - stack.push(Item(keccak256(value).to_vec()))?; - } - Instruction::Blake160 => { - let value = stack.pop()?; - stack.push(Item(H160::blake(value).to_vec()))?; - } - Instruction::ChkTimelock(timelock_type) => { - let value_item = stack.pop()?; - let value = read_u64(value_item)?; - match *timelock_type { - TIMELOCK_TYPE_BLOCK => { - stack.push(Item::from(parent_block_number >= value))?; - } - TIMELOCK_TYPE_BLOCK_AGE => { - stack.push(Item::from( - client - .transaction_block_age(&cur.prev_out.tracker, parent_block_number) - .map_or(false, |age| age >= value), - ))?; - } - TIMELOCK_TYPE_TIME => { - stack.push(Item::from(parent_block_timestamp >= value))?; - } - TIMELOCK_TYPE_TIME_AGE => { - stack.push(Item::from( - client - .transaction_time_age(&cur.prev_out.tracker, parent_block_timestamp) - .map_or(false, |age| age >= value), - ))?; - } - _ => return Err(RuntimeError::InvalidTimelockType), - } - } - } - pc += 1; - } - - let result = stack.pop()?; - if result.into() && stack.len() == 0 { - Ok(ScriptResult::Unlocked) - } else { - Ok(ScriptResult::Fail) - } -} - -fn read_u64(value_item: Item) -> Result { - if value_item.len() > 8 { - return Err(RuntimeError::TypeMismatch) - } - let mut value_bytes = [0u8; 8]; - value_bytes[(8 - value_item.len())..8].copy_from_slice(value_item.as_ref()); - Ok(u64::from_be_bytes(value_bytes)) -} - -#[inline] -fn check_multi_sig(tx_hash: &H256, mut pubkey: Vec, mut signatures: Vec) -> bool { - while let Some(sig) = signatures.pop() { - loop { - let public = match pubkey.pop() { - None => return false, - Some(public) => public, - }; - if verify(&public, &sig, &tx_hash) == Ok(true) { - break - } - } - } - true -} - -pub trait ChainTimeInfo { - /// Get the block height of the transaction. - fn transaction_block_age(&self, tracker: &Tracker, parent_block_number: BlockNumber) -> Option; - - /// Get the how many seconds elapsed since transaction is confirmed, according to block timestamp. - fn transaction_time_age(&self, tracker: &Tracker, parent_timestamp: u64) -> Option; -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn convert_true() { - let item: Item = true.into(); - assert_eq!(vec![1], item.as_ref()); - let result: bool = item.into(); - assert!(result); - } - - #[test] - fn convert_false() { - let item: Item = false.into(); - assert_eq!(Vec::::new(), item.as_ref()); - let result: bool = item.into(); - assert!(!result); - } - - #[test] - fn false_if_all_bit_is_zero() { - let item = Item(vec![0, 0, 0, 0, 0, 0, 0]); - let result: bool = item.into(); - assert!(!result); - } - - #[test] - fn true_if_at_least_one_bit_is_not_zero() { - let item = Item(vec![0, 0, 0, 1, 0, 0, 0]); - let result: bool = item.into(); - assert!(result); - } - - #[test] - fn read_0_0_0_0_0_0_0_1() { - assert_eq!(Ok(0x0000_0000_0000_0001), read_u64(Item(vec![0, 0, 0, 0, 0, 0, 0, 1]))); - } - - #[test] - fn read_1() { - assert_eq!(Ok(0x01), read_u64(Item(vec![1]))); - } - - #[test] - fn read_f() { - assert_eq!(Ok(0x0f), read_u64(Item(vec![0xf]))) - } - - #[test] - fn read_1_0() { - assert_eq!(Ok(0x0100), read_u64(Item(vec![1, 0]))); - } - - #[test] - fn read_1_0_0() { - assert_eq!(Ok(0x0001_0000), read_u64(Item(vec![1, 0, 0]))); - } - - #[test] - fn read_1_0_0_0() { - assert_eq!(Ok(0x0100_0000), read_u64(Item(vec![1, 0, 0, 0]))); - } - - - #[test] - fn read_1_0_0_0_0_0_0_0() { - assert_eq!(Ok(0x0100_0000_0000_0000), read_u64(Item(vec![1, 0, 0, 0, 0, 0, 0, 0]))); - } - - #[test] - fn read_1_0_0_0_0_0_1_0() { - assert_eq!(Ok(0x0100_0000_0000_0100), read_u64(Item(vec![1, 0, 0, 0, 0, 0, 1, 0]))); - } -} - -#[cfg(test)] -mod tests_check_multi_sig { - use ckey::{sign, Generator, Random}; - - use super::*; - - #[test] - fn valid_2_of_3_110() { - let key_pair1 = Random.generate().unwrap(); - let key_pair2 = Random.generate().unwrap(); - let key_pair3 = Random.generate().unwrap(); - let pubkey1 = *key_pair1.public(); - let pubkey2 = *key_pair2.public(); - let pubkey3 = *key_pair3.public(); - let message = H256::random(); - let signature1 = sign(key_pair1.private(), &message).unwrap(); - let signature2 = sign(key_pair2.private(), &message).unwrap(); - - assert!(check_multi_sig(&message, vec![pubkey1, pubkey2, pubkey3], vec![signature1, signature2])); - } - - #[test] - fn valid_2_of_3_101() { - let key_pair1 = Random.generate().unwrap(); - let key_pair2 = Random.generate().unwrap(); - let key_pair3 = Random.generate().unwrap(); - let pubkey1 = *key_pair1.public(); - let pubkey2 = *key_pair2.public(); - let pubkey3 = *key_pair3.public(); - let message = H256::random(); - let signature1 = sign(key_pair1.private(), &message).unwrap(); - let signature3 = sign(key_pair3.private(), &message).unwrap(); - - assert!(check_multi_sig(&message, vec![pubkey1, pubkey2, pubkey3], vec![signature1, signature3])); - } - - #[test] - fn valid_2_of_3_011() { - let key_pair1 = Random.generate().unwrap(); - let key_pair2 = Random.generate().unwrap(); - let key_pair3 = Random.generate().unwrap(); - let pubkey1 = *key_pair1.public(); - let pubkey2 = *key_pair2.public(); - let pubkey3 = *key_pair3.public(); - let message = H256::random(); - let signature2 = sign(key_pair2.private(), &message).unwrap(); - let signature3 = sign(key_pair3.private(), &message).unwrap(); - - assert!(check_multi_sig(&message, vec![pubkey1, pubkey2, pubkey3], vec![signature2, signature3])); - } - - #[test] - fn invalid_2_of_2_if_order_is_different() { - let key_pair1 = Random.generate().unwrap(); - let key_pair2 = Random.generate().unwrap(); - let pubkey1 = *key_pair1.public(); - let pubkey2 = *key_pair2.public(); - let message = H256::random(); - let signature1 = sign(key_pair1.private(), &message).unwrap(); - let signature2 = sign(key_pair2.private(), &message).unwrap(); - - assert!(!check_multi_sig(&message, vec![pubkey2, pubkey1], vec![signature1, signature2])); - } -} diff --git a/vm/src/instruction.rs b/vm/src/instruction.rs deleted file mode 100644 index e727d93dac..0000000000 --- a/vm/src/instruction.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2018 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 . - -#[derive(Clone, Debug, PartialEq)] -pub enum Instruction { - Nop, - Burn, - Success, - Fail, - Not, - Eq, - Jmp(u8), - Jnz(u8), - Jz(u8), - Push(u8), - Pop, - PushB(Vec), - Dup, - Swap, - Copy(u8), - Drop(u8), - ChkSig, - ChkMultiSig, - Blake256, - Sha256, - Ripemd160, - Keccak256, - Blake160, - ChkTimelock(u8), -} - -pub fn is_valid_unlock_script(instrs: &[Instruction]) -> bool { - instrs.iter().all(|instr| match instr { - Instruction::Push(_) => true, - Instruction::PushB(_) => true, - _ => false, - }) -} - -pub fn has_expensive_opcodes(instrs: &[Instruction]) -> bool { - let count = - instrs.iter().filter(|instr| instr == &&Instruction::ChkSig || instr == &&Instruction::ChkMultiSig).count(); - count >= 6 -} - -#[test] -fn script_with_more_than_six_chksig_opcodes() { - let expensive_script = vec![ - Instruction::ChkSig, - Instruction::ChkSig, - Instruction::ChkSig, - Instruction::ChkMultiSig, - Instruction::ChkMultiSig, - Instruction::ChkMultiSig, - ]; - assert_eq!(has_expensive_opcodes(&expensive_script), true); -} - -#[test] -fn script_with_less_than_six_chksig_opcodes() { - let unexpensive_script = vec![ - Instruction::ChkSig, - Instruction::ChkSig, - Instruction::ChkSig, - Instruction::ChkMultiSig, - Instruction::ChkMultiSig, - ]; - assert_eq!(has_expensive_opcodes(&unexpensive_script), false); -} diff --git a/vm/src/lib.rs b/vm/src/lib.rs deleted file mode 100644 index 3555733e49..0000000000 --- a/vm/src/lib.rs +++ /dev/null @@ -1,33 +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 . - -extern crate codechain_crypto as ccrypto; -extern crate codechain_key as ckey; -extern crate codechain_types as ctypes; -extern crate primitives; - -extern crate rlp; -#[cfg(test)] -extern crate secp256k1; - -mod decoder; -mod executor; -mod instruction; -mod opcode; - -pub use crate::decoder::{decode, DecoderError}; -pub use crate::executor::{execute, ChainTimeInfo, Config as VMConfig, RuntimeError, ScriptResult}; -pub use crate::instruction::Instruction; diff --git a/vm/src/opcode.rs b/vm/src/opcode.rs deleted file mode 100644 index c789272b82..0000000000 --- a/vm/src/opcode.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018 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 . - -pub const NOP: u8 = 0x00; -pub const BURN: u8 = 0x01; -pub const SUCCESS: u8 = 0x02; -pub const FAIL: u8 = 0x03; -pub const NOT: u8 = 0x10; -pub const EQ: u8 = 0x11; -pub const JMP: u8 = 0x20; -pub const JNZ: u8 = 0x21; -pub const JZ: u8 = 0x22; -pub const PUSH: u8 = 0x30; -pub const POP: u8 = 0x31; -pub const PUSHB: u8 = 0x32; -pub const DUP: u8 = 0x33; -pub const SWAP: u8 = 0x34; -pub const COPY: u8 = 0x35; -pub const DROP: u8 = 0x36; -pub const CHKSIG: u8 = 0x80; -pub const CHKMULTISIG: u8 = 0x81; -pub const BLAKE256: u8 = 0x90; -pub const SHA256: u8 = 0x91; -pub const RIPEMD160: u8 = 0x92; -pub const KECCAK256: u8 = 0x93; -pub const BLAKE160: u8 = 0x94; -pub const CHKTIMELOCK: u8 = 0xb0; diff --git a/vm/tests/chk_multi_sig.rs b/vm/tests/chk_multi_sig.rs deleted file mode 100644 index 29ba62be0a..0000000000 --- a/vm/tests/chk_multi_sig.rs +++ /dev/null @@ -1,752 +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 . - -extern crate codechain_crypto as ccrypto; -extern crate codechain_key as ckey; -extern crate codechain_types as ctypes; -extern crate codechain_vm as cvm; -extern crate primitives; -extern crate rlp; -extern crate secp256k1; - -mod common; - -use ccrypto::{blake128, blake256_with_key}; -use ckey::{sign, KeyPair, NetworkId, Private}; -use ctypes::transaction::{AssetOutPoint, AssetTransferInput, ShardTransaction}; -use primitives::H160; -use rlp::Encodable; -use secp256k1::key::{MINUS_ONE_KEY, ONE_KEY, TWO_KEY}; - -use cvm::Instruction; -use cvm::{execute, RuntimeError, ScriptResult, VMConfig}; - -use common::TestClient; - -#[test] -fn valid_multi_sig_0_of_2() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - - let unlock_script = vec![Instruction::PushB(vec![0b11 as u8])]; - let lock_script = vec![ - Instruction::PushB(vec![0]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(vec![2]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Err(RuntimeError::InvalidSigCount) - ); -} - -#[test] -fn valid_multi_sig_1_of_2() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - - let unlock_script = vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature1)]; - let lock_script = vec![ - Instruction::PushB(vec![1]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(vec![2]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn valid_multi_sig_2_of_2() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - let signature2 = sign(keypair2.private(), &message).unwrap().to_vec(); - - let unlock_script = - vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature1), Instruction::PushB(signature2)]; - let lock_script = vec![ - Instruction::PushB(vec![2]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(vec![2]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn nvalid_multi_sig_2_of_2_duplicated() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - - let unlock_script = vec![ - Instruction::PushB(vec![0b11 as u8]), - Instruction::PushB(signature1.clone()), - Instruction::PushB(signature1), - ]; - let lock_script = vec![ - Instruction::PushB(vec![2]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(vec![2]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); -} - -#[test] -fn valid_multi_sig_2_of_3_110() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let keypair3 = KeyPair::from_private(Private::from(TWO_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let pubkey3 = <&[u8]>::from(keypair3.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - let signature2 = sign(keypair2.private(), &message).unwrap().to_vec(); - - let unlock_script = - vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature1), Instruction::PushB(signature2)]; - let lock_script = vec![ - Instruction::PushB(vec![2]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(pubkey3), - Instruction::PushB(vec![3]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn valid_multi_sig_2_of_3_101() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let keypair3 = KeyPair::from_private(Private::from(TWO_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let pubkey3 = <&[u8]>::from(keypair3.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - let signature3 = sign(keypair3.private(), &message).unwrap().to_vec(); - - let unlock_script = - vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature1), Instruction::PushB(signature3)]; - let lock_script = vec![ - Instruction::PushB(vec![2]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(pubkey3), - Instruction::PushB(vec![3]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn valid_multi_sig_2_of_3_011() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let keypair3 = KeyPair::from_private(Private::from(TWO_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let pubkey3 = <&[u8]>::from(keypair3.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature2 = sign(keypair2.private(), &message).unwrap().to_vec(); - let signature3 = sign(keypair3.private(), &message).unwrap().to_vec(); - - let unlock_script = - vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature2), Instruction::PushB(signature3)]; - let lock_script = vec![ - Instruction::PushB(vec![2]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(pubkey3), - Instruction::PushB(vec![3]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn invalid_multi_sig_1_of_2() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: "aa".into(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - - let unlock_script = vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature1)]; - let lock_script = vec![ - Instruction::PushB(vec![1]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(vec![2]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); -} - - -#[test] -fn invalid_multi_sig_2_of_2() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: "aa".into(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - let signature2 = sign(keypair2.private(), &message).unwrap().to_vec(); - - let unlock_script = - vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature1), Instruction::PushB(signature2)]; - let lock_script = vec![ - Instruction::PushB(vec![2]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(vec![2]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); -} - -#[test] -fn invalid_multi_sig_2_of_2_with_1_invalid_sig() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let message1 = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let message2 = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: "aa".into(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message1).unwrap().to_vec(); - let signature2 = sign(keypair2.private(), &message2).unwrap().to_vec(); - - let unlock_script = - vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature1), Instruction::PushB(signature2)]; - let lock_script = vec![ - Instruction::PushB(vec![2]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(vec![2]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); -} - -#[test] -fn invalid_multi_sig_with_less_sig_than_m() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - - let unlock_script = vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature1)]; - let lock_script = vec![ - Instruction::PushB(vec![2]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(vec![2]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Err(RuntimeError::TypeMismatch) - ); -} - -#[test] -fn invalid_multi_sig_with_more_sig_than_m() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let keypair2 = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let pubkey2 = <&[u8]>::from(keypair2.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - let signature2 = sign(keypair2.private(), &message).unwrap().to_vec(); - - let unlock_script = - vec![Instruction::PushB(vec![0b11 as u8]), Instruction::PushB(signature1), Instruction::PushB(signature2)]; - let lock_script = vec![ - Instruction::PushB(vec![1]), - Instruction::PushB(pubkey1), - Instruction::PushB(pubkey2), - Instruction::PushB(vec![2]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Err(RuntimeError::InvalidFilter) - ); -} - -#[test] -fn invalid_multi_sig_with_too_many_arg() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let outpoint = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair1 = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let pubkey1 = <&[u8]>::from(keypair1.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature1 = sign(keypair1.private(), &message).unwrap().to_vec(); - - let unlock_script = vec![ - Instruction::PushB(vec![0b11 as u8]), - Instruction::PushB(signature1.clone()), - Instruction::PushB(signature1.clone()), - Instruction::PushB(signature1.clone()), - Instruction::PushB(signature1.clone()), - Instruction::PushB(signature1.clone()), - Instruction::PushB(signature1.clone()), - Instruction::PushB(signature1), - ]; - let lock_script = vec![ - Instruction::PushB(vec![7]), - Instruction::PushB(pubkey1.clone()), - Instruction::PushB(pubkey1.clone()), - Instruction::PushB(pubkey1.clone()), - Instruction::PushB(pubkey1.clone()), - Instruction::PushB(pubkey1.clone()), - Instruction::PushB(pubkey1.clone()), - Instruction::PushB(pubkey1), - Instruction::PushB(vec![7]), - Instruction::ChkMultiSig, - ]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &outpoint, false, &client, 0, 0), - Err(RuntimeError::InvalidSigCount) - ); -} diff --git a/vm/tests/chk_sig.rs b/vm/tests/chk_sig.rs deleted file mode 100644 index 227dee3ab8..0000000000 --- a/vm/tests/chk_sig.rs +++ /dev/null @@ -1,545 +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 . - -extern crate codechain_crypto as ccrypto; -extern crate codechain_key as ckey; -extern crate codechain_types as ctypes; -extern crate codechain_vm as cvm; -extern crate primitives; -extern crate rlp; -extern crate secp256k1; - -mod common; - -use ccrypto::{blake128, blake256_with_key}; -use ckey::{sign, KeyPair, NetworkId, Private}; -use ctypes::transaction::{AssetOutPoint, AssetTransferInput, AssetTransferOutput, ShardTransaction}; -use primitives::H160; -use rlp::Encodable; -use secp256k1::key::{MINUS_ONE_KEY, ONE_KEY}; - -use cvm::Instruction; -use cvm::{execute, ScriptResult, VMConfig}; - -use common::TestClient; - -#[test] -fn valid_pay_to_public_key() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let pubkey = <&[u8]>::from(keypair.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature = sign(keypair.private(), &message).unwrap().to_vec(); - let unlock_script = vec![Instruction::PushB(signature), Instruction::PushB(vec![0b11 as u8])]; - let lock_script = vec![Instruction::PushB(pubkey), Instruction::ChkSig]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &input, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn invalid_pay_to_public_key() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let keypair = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let pubkey = <&[u8]>::from(keypair.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - - let invalid_keypair = KeyPair::from_private(Private::from(MINUS_ONE_KEY)).unwrap(); - let invalid_signature = sign(invalid_keypair.private(), &message).unwrap().to_vec(); - let unlock_script = vec![Instruction::PushB(invalid_signature), Instruction::PushB(vec![0b11 as u8])]; - let lock_script = vec![Instruction::PushB(pubkey), Instruction::ChkSig]; - - assert_eq!( - execute(&unlock_script[..], &[], &lock_script, &transaction, VMConfig::default(), &input, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); -} - -#[test] -fn sign_all_input_all_output() { - let client = TestClient::default(); - // Make input indexed 0 - let out0 = AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - let input0 = AssetTransferInput { - prev_out: out0, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - // Make input indexed 1 - let out1 = AssetOutPoint { - tracker: Default::default(), - index: 1, - asset_type: H160::default(), - shard_id: 0, - quantity: 1, - }; - let input1 = AssetTransferInput { - prev_out: out1, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - // Make output indexed 0 - let output0 = AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - // Make output indexed 1 - let output1 = AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 1, - }; - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone(), input1.clone()], - outputs: vec![output0.clone(), output1.clone()], - }; - - // Execute sciprt in input0 - let keypair = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let pubkey = <&[u8]>::from(keypair.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone(), input1], - outputs: vec![output0, output1], - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - - let signature = sign(keypair.private(), &message).unwrap().to_vec(); - let unlock_script = vec![Instruction::PushB(signature), Instruction::PushB(vec![0b11 as u8])]; - let lock_script = vec![Instruction::PushB(pubkey), Instruction::ChkSig]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &input0, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn sign_single_input_all_output() { - let client = TestClient::default(); - // Make input indexed 0 - let out0 = AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - let input0 = AssetTransferInput { - prev_out: out0, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - // Make input indexed 1 - let out1 = AssetOutPoint { - tracker: Default::default(), - index: 1, - asset_type: H160::default(), - shard_id: 0, - quantity: 1, - }; - let input1 = AssetTransferInput { - prev_out: out1, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - // Make output indexed 0 - let output0 = AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - // Make output indexed 1 - let output1 = AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 1, - }; - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone(), input1], - outputs: vec![output0.clone(), output1.clone()], - }; - - // Execute sciprt in input0 - let keypair = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let pubkey = <&[u8]>::from(keypair.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone()], - outputs: vec![output0, output1], - } - .rlp_bytes(), - &blake128(&[0b10 as u8]), - ); - let signature = sign(keypair.private(), &message).unwrap().to_vec(); - let unlock_script = vec![Instruction::PushB(signature), Instruction::PushB(vec![0b10 as u8])]; - let lock_script = vec![Instruction::PushB(pubkey), Instruction::ChkSig]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &input0, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn sign_all_input_partial_output() { - let client = TestClient::default(); - // Make input indexed 0 - let out0 = AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - let input0 = AssetTransferInput { - prev_out: out0, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - // Make input indexed 1 - let out1 = AssetOutPoint { - tracker: Default::default(), - index: 1, - asset_type: H160::default(), - shard_id: 0, - quantity: 1, - }; - let input1 = AssetTransferInput { - prev_out: out1, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - // Make output indexed 0 - let output0 = AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - // Make output indexed 1 - let output1 = AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 1, - }; - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone(), input1.clone()], - outputs: vec![output0.clone(), output1], - }; - - // Execute sciprt in input0 - let keypair = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let pubkey = <&[u8]>::from(keypair.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone(), input1], - outputs: vec![output0], - } - .rlp_bytes(), - &blake128(&[0b1, 0b0000_0101 as u8]), - ); - let signature = sign(keypair.private(), &message).unwrap().to_vec(); - let unlock_script = vec![Instruction::PushB(signature), Instruction::PushB(vec![0b1, 0b0000_0101 as u8])]; - let lock_script = vec![Instruction::PushB(pubkey), Instruction::ChkSig]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &input0, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn sign_single_input_partial_output() { - let client = TestClient::default(); - // Make input indexed 0 - let out0 = AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - let input0 = AssetTransferInput { - prev_out: out0, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - // Make input indexed 1 - let out1 = AssetOutPoint { - tracker: Default::default(), - index: 1, - asset_type: H160::default(), - shard_id: 0, - quantity: 1, - }; - let input1 = AssetTransferInput { - prev_out: out1, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - // Make output indexed 0 - let output0 = AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - // Make output indexed 1 - let output1 = AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 1, - }; - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone(), input1], - outputs: vec![output0.clone(), output1], - }; - - // Execute sciprt in input0 - let keypair = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let pubkey = <&[u8]>::from(keypair.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone()], - outputs: vec![output0], - } - .rlp_bytes(), - &blake128(&[0b1, 0b0000_0100 as u8]), - ); - let signature = sign(keypair.private(), &message).unwrap().to_vec(); - let unlock_script = vec![Instruction::PushB(signature), Instruction::PushB(vec![0b1, 0b0000_0100 as u8])]; - let lock_script = vec![Instruction::PushB(pubkey), Instruction::ChkSig]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &input0, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn distinguish_sign_single_input_with_sign_all() { - let client = TestClient::default(); - // Make input indexed 0 - let out0 = AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - let input0 = AssetTransferInput { - prev_out: out0, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - // Make output indexed 0 - let output0 = AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone()], - outputs: vec![output0.clone()], - }; - - // Execute sciprt in input0 - let keypair = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let pubkey = <&[u8]>::from(keypair.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone()], - outputs: vec![output0], - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature = sign(keypair.private(), &message).unwrap().to_vec(); - let unlock_script = vec![Instruction::PushB(signature), Instruction::PushB(vec![0b10 as u8])]; - let lock_script = vec![Instruction::PushB(pubkey), Instruction::ChkSig]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &input0, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); -} - - -#[test] -fn distinguish_sign_single_output_with_sign_all() { - let client = TestClient::default(); - // Make input indexed 0 - let out0 = AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - let input0 = AssetTransferInput { - prev_out: out0, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - // Make output indexed 0 - let output0 = AssetTransferOutput { - lock_script_hash: H160::default(), - parameters: Vec::new(), - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }; - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone()], - outputs: vec![output0.clone()], - }; - - // Execute sciprt in input0 - let keypair = KeyPair::from_private(Private::from(ONE_KEY)).unwrap(); - let pubkey = <&[u8]>::from(keypair.public()).to_vec(); - let message = blake256_with_key( - &ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: vec![input0.clone()], - outputs: vec![output0], - } - .rlp_bytes(), - &blake128(&[0b11 as u8]), - ); - let signature = sign(keypair.private(), &message).unwrap().to_vec(); - let unlock_script = vec![Instruction::PushB(signature), Instruction::PushB(vec![0b1, 0b0000_0101 as u8])]; - let lock_script = vec![Instruction::PushB(pubkey), Instruction::ChkSig]; - - assert_eq!( - execute(&unlock_script, &[], &lock_script, &transaction, VMConfig::default(), &input0, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); -} diff --git a/vm/tests/common/mod.rs b/vm/tests/common/mod.rs deleted file mode 100644 index 2ddc5dc9be..0000000000 --- a/vm/tests/common/mod.rs +++ /dev/null @@ -1,48 +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 . - -use ctypes::{BlockNumber, Tracker}; -use cvm::ChainTimeInfo; - -pub struct TestClient { - block_age: Option, - time_age: Option, -} - -impl TestClient { - pub fn new(block_age: Option, time_age: Option) -> Self { - TestClient { - block_age, - time_age, - } - } -} - -impl Default for TestClient { - fn default() -> Self { - Self::new(Some(0), Some(0)) - } -} - -impl ChainTimeInfo for TestClient { - fn transaction_block_age(&self, _: &Tracker, _parent_block_number: BlockNumber) -> Option { - self.block_age - } - - fn transaction_time_age(&self, _: &Tracker, _parent_timestamp: u64) -> Option { - self.time_age - } -} diff --git a/vm/tests/executor.rs b/vm/tests/executor.rs deleted file mode 100644 index 9ff0a9fa35..0000000000 --- a/vm/tests/executor.rs +++ /dev/null @@ -1,924 +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 . - -extern crate codechain_crypto as ccrypto; -extern crate codechain_key as ckey; -extern crate codechain_types as ctypes; -extern crate codechain_vm as cvm; -extern crate primitives; - -mod common; - -use ccrypto::{BLAKE_EMPTY, BLAKE_NULL_RLP}; -use ckey::NetworkId; -use ctypes::transaction::{AssetOutPoint, AssetTransferInput, ShardTransaction}; -use cvm::Instruction; -use cvm::{execute, RuntimeError, ScriptResult, VMConfig}; -use primitives::{H160, H256}; - -use common::TestClient; - -#[test] -fn simple_success() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - assert_eq!( - execute(&[], &[], &[Instruction::Push(1)], &transaction, VMConfig::default(), &input, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); - - assert_eq!( - execute(&[], &[], &[Instruction::Success], &transaction, VMConfig::default(), &input, false, &client, 0, 0), - Ok(ScriptResult::Unlocked) - ); -} - -#[test] -fn simple_failure() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - assert_eq!( - execute(&[Instruction::Push(0)], &[], &[], &transaction, VMConfig::default(), &input, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); - assert_eq!( - execute(&[], &[], &[Instruction::Fail], &transaction, VMConfig::default(), &input, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); -} - -#[test] -fn simple_burn() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - assert_eq!( - execute(&[], &[], &[Instruction::Burn], &transaction, VMConfig::default(), &input, false, &client, 0, 0), - Ok(ScriptResult::Burnt) - ); -} - -#[test] -fn underflow() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - assert_eq!( - execute(&[], &[], &[Instruction::Pop], &transaction, VMConfig::default(), &input, false, &client, 0, 0), - Err(RuntimeError::StackUnderflow) - ); -} - -#[test] -fn out_of_memory() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let config = VMConfig { - max_memory: 2, - }; - assert_eq!( - execute( - &[Instruction::Push(0), Instruction::Push(1), Instruction::Push(2)], - &[], - &[], - &transaction, - config, - &input, - false, - &client, - 0, - 0 - ), - Err(RuntimeError::OutOfMemory) - ); -} - -#[test] -fn invalid_unlock_script() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - assert_eq!( - execute(&[Instruction::Nop], &[], &[], &transaction, VMConfig::default(), &input, false, &client, 0, 0), - Ok(ScriptResult::Fail) - ); -} - -#[test] -fn conditional_burn() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let lock_script = vec![Instruction::Eq, Instruction::Dup, Instruction::Jnz(1), Instruction::Burn]; - assert_eq!( - execute( - &[Instruction::Push(0)], - &[vec![0]], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ); - assert_eq!( - execute( - &[Instruction::Push(0)], - &[vec![1]], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Burnt) - ); -} - -#[test] -fn _blake256() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - let lock_script = vec![Instruction::Blake256, Instruction::Eq]; - assert_eq!( - execute( - &[], - &[vec![], BLAKE_EMPTY.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ); - assert_eq!( - execute( - &[], - &[vec![], BLAKE_NULL_RLP.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ); - assert_eq!( - execute( - &[], - &[vec![0x80], BLAKE_NULL_RLP.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ); - assert_eq!( - execute( - &[], - &[vec![0x80], BLAKE_EMPTY.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ); -} - -#[test] -fn _ripemd160() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - const RIPEMD160_EMPTY: H160 = H160([ - 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28, 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, - 0x8d, 0x31, - ]); - const RIPEMD160_NULL_RLP: H160 = H160([ - 0xb4, 0x36, 0x44, 0x1e, 0x6b, 0xb8, 0x82, 0xfe, 0x0a, 0x0f, 0xa0, 0x32, 0x0c, 0xb2, 0xd9, 0x7d, 0x96, 0xb4, - 0xd1, 0xbc, - ]); - let lock_script = vec![Instruction::Ripemd160, Instruction::Eq]; - assert_eq!( - execute( - &[], - &[vec![], RIPEMD160_EMPTY.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ); - assert_eq!( - execute( - &[], - &[vec![], RIPEMD160_NULL_RLP.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ); - assert_eq!( - execute( - &[], - &[vec![0x80], RIPEMD160_NULL_RLP.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ); - assert_eq!( - execute( - &[], - &[vec![0x80], RIPEMD160_EMPTY.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ); -} - -#[test] -fn _sha256() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - const SHA256_EMPTY: H256 = H256([ - 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, - 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, - ]); - const SHA256_NULL_RLP: H256 = H256([ - 0x76, 0xbe, 0x8b, 0x52, 0x8d, 0x00, 0x75, 0xf7, 0xaa, 0xe9, 0x8d, 0x6f, 0xa5, 0x7a, 0x6d, 0x3c, 0x83, 0xae, - 0x48, 0x0a, 0x84, 0x69, 0xe6, 0x68, 0xd7, 0xb0, 0xaf, 0x96, 0x89, 0x95, 0xac, 0x71, - ]); - let lock_script = vec![Instruction::Sha256, Instruction::Eq]; - assert_eq!( - execute( - &[], - &[vec![], SHA256_EMPTY.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ); - assert_eq!( - execute( - &[], - &[vec![], SHA256_NULL_RLP.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ); - assert_eq!( - execute( - &[], - &[vec![0x80], SHA256_NULL_RLP.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ); - assert_eq!( - execute( - &[], - &[vec![0x80], SHA256_EMPTY.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ); -} - -#[test] -fn _keccak256() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - const KECCAK256_EMPTY: H256 = H256([ - 0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, - 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70, - ]); - const KECCAK256_NULL_RLP: H256 = H256([ - 0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, - 0xe0, 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x01, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21, - ]); - let lock_script = vec![Instruction::Keccak256, Instruction::Eq]; - assert_eq!( - execute( - &[], - &[vec![], KECCAK256_EMPTY.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ); - assert_eq!( - execute( - &[], - &[vec![], KECCAK256_NULL_RLP.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ); - assert_eq!( - execute( - &[], - &[vec![0x80], KECCAK256_NULL_RLP.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ); - assert_eq!( - execute( - &[], - &[vec![0x80], KECCAK256_EMPTY.to_vec()], - &lock_script, - &transaction, - VMConfig::default(), - &input, - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ); -} - -#[cfg(test)] -fn dummy_tx() -> ShardTransaction { - ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - } -} - -fn dummy_input() -> AssetTransferInput { - AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - } -} - -#[test] -fn timelock_invalid_type() { - assert_eq!( - execute( - &[], - &[], - &[Instruction::Push(0), Instruction::ChkTimelock(5)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &TestClient::default(), - 0, - 0 - ), - Err(RuntimeError::InvalidTimelockType) - ) -} - -#[test] -fn timelock_invalid_value() { - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![0, 0, 0, 0, 0, 0, 0, 0, 0]), Instruction::ChkTimelock(1)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &TestClient::default(), - 0, - 0 - ), - Err(RuntimeError::TypeMismatch) - ) -} - -#[test] -fn timelock_block_number_success() { - let client = TestClient::new(None, None); - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![10]), Instruction::ChkTimelock(1)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &client, - 10, - 0 - ), - Ok(ScriptResult::Unlocked) - ) -} - -#[test] -fn timelock_block_number_fail() { - let client = TestClient::new(None, None); - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![10]), Instruction::ChkTimelock(1)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &client, - 9, - 0 - ), - Ok(ScriptResult::Fail) - ) -} - -#[test] -fn timelock_block_timestamp_success() { - // 0x5BD02BF2, 2018-10-24T08:23:14+00:00 - let client = TestClient::new(None, None); - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![0x00, 0x5B, 0xD0, 0x2B, 0xF2]), Instruction::ChkTimelock(3)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &client, - 0, - 1_540_369_394 - ), - Ok(ScriptResult::Unlocked) - ) -} - -#[test] -fn timelock_block_timestamp_fail() { - // 0x5BD02BF1, 2018-10-24T08:23:13+00:00 - let client = TestClient::new(None, None); - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![0x00, 0x5B, 0xD0, 0x2B, 0xF2]), Instruction::ChkTimelock(3)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &client, - 0, - 1_540_369_393 - ), - Ok(ScriptResult::Fail) - ) -} - -#[test] -fn timelock_block_age_fail_due_to_none() { - let client = TestClient::new(None, None); - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![1]), Instruction::ChkTimelock(2)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ) -} - -#[test] -fn timelock_block_age_fail() { - let client = TestClient::new(Some(4), None); - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![5]), Instruction::ChkTimelock(2)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ) -} - -#[test] -fn timelock_block_age_success() { - let client = TestClient::new(Some(5), None); - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![5]), Instruction::ChkTimelock(2)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ) -} - -#[test] -fn timelock_time_age_fail_due_to_none() { - let client = TestClient::new(None, None); - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![0x27, 0x8D, 0x00]), Instruction::ChkTimelock(4)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ) -} - -#[test] -fn timelock_time_age_fail() { - // 0x278D00 seconds = 2592000 seconds = 30 days - let client = TestClient::new(None, Some(2_591_999)); - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![0x27, 0x8D, 0x00]), Instruction::ChkTimelock(4)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Fail) - ) -} - -#[test] -fn timelock_time_age_success() { - let client = TestClient::new(None, Some(2_592_000)); - assert_eq!( - execute( - &[], - &[], - &[Instruction::PushB(vec![0x27, 0x8D, 0x00]), Instruction::ChkTimelock(4)], - &dummy_tx(), - VMConfig::default(), - &dummy_input(), - false, - &client, - 0, - 0 - ), - Ok(ScriptResult::Unlocked) - ) -} - -#[test] -fn copy_stack_underflow() { - let client = TestClient::default(); - let transaction = ShardTransaction::TransferAsset { - network_id: NetworkId::default(), - burns: Vec::new(), - inputs: Vec::new(), - outputs: Vec::new(), - }; - let input = AssetTransferInput { - prev_out: AssetOutPoint { - tracker: Default::default(), - index: 0, - asset_type: H160::default(), - shard_id: 0, - quantity: 0, - }, - timelock: None, - lock_script: Vec::new(), - unlock_script: Vec::new(), - }; - assert_eq!( - execute(&[], &[], &[Instruction::Copy(1)], &transaction, VMConfig::default(), &input, false, &client, 0, 0), - Err(RuntimeError::StackUnderflow) - ); -} From 2f5b8606536cc9b0dcb820b2919a7cac89078ad5 Mon Sep 17 00:00:00 2001 From: Park Juhyung Date: Fri, 20 Dec 2019 19:02:39 +0900 Subject: [PATCH 6/6] Remove Asset related e2e tests --- core/src/transaction.rs | 1 - test/src/e2e.long/expiration.test.ts | 107 --- test/src/e2e.long/mempool.test.ts | 10 +- test/src/e2e.long/sync2.test.ts | 5 +- test/src/e2e.long/timelock.test.ts | 407 ---------- test/src/e2e/burn.test.ts | 158 ---- test/src/e2e/chain.test.ts | 265 ------- test/src/e2e/changeAssetScheme.test.ts | 156 ---- test/src/e2e/increaseAssetSupply.test.ts | 336 -------- test/src/e2e/mempool.test.ts | 86 +-- test/src/e2e/mintAsset.test.ts | 103 --- test/src/e2e/multisig.test.ts | 930 ----------------------- test/src/e2e/partialSignature.test.ts | 470 ------------ test/src/e2e/shard.test.ts | 462 ----------- test/src/e2e/transactionResult.test.ts | 185 ----- test/src/e2e/transferAsset.test.ts | 412 ---------- test/src/e2e/unwrap.test.ts | 228 ------ test/src/e2e/verification.test.ts | 483 +----------- test/src/e2e/wrap.test.ts | 234 ------ test/src/helper/error.ts | 20 - test/src/helper/spawn.ts | 182 +---- 21 files changed, 15 insertions(+), 5225 deletions(-) delete mode 100644 test/src/e2e.long/expiration.test.ts delete mode 100644 test/src/e2e.long/timelock.test.ts delete mode 100644 test/src/e2e/burn.test.ts delete mode 100644 test/src/e2e/changeAssetScheme.test.ts delete mode 100644 test/src/e2e/increaseAssetSupply.test.ts delete mode 100644 test/src/e2e/mintAsset.test.ts delete mode 100644 test/src/e2e/multisig.test.ts delete mode 100644 test/src/e2e/partialSignature.test.ts delete mode 100644 test/src/e2e/shard.test.ts delete mode 100644 test/src/e2e/transactionResult.test.ts delete mode 100644 test/src/e2e/transferAsset.test.ts delete mode 100644 test/src/e2e/unwrap.test.ts delete mode 100644 test/src/e2e/wrap.test.ts diff --git a/core/src/transaction.rs b/core/src/transaction.rs index bd499eb34f..80f3e348ba 100644 --- a/core/src/transaction.rs +++ b/core/src/transaction.rs @@ -196,7 +196,6 @@ impl SignedTransaction { /// Try to verify transaction and recover public. pub fn try_new(tx: UnverifiedTransaction) -> Result { let signer_public = tx.recover_public()?; - let _signer = public_to_address(&signer_public); Ok(SignedTransaction { tx, signer_public, diff --git a/test/src/e2e.long/expiration.test.ts b/test/src/e2e.long/expiration.test.ts deleted file mode 100644 index e0ce1db7ea..0000000000 --- a/test/src/e2e.long/expiration.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 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 { expect } from "chai"; -import { H256 } from "codechain-primitives"; -import "mocha"; -import { faucetAddress } from "../helper/constants"; -import { wait } from "../helper/promise"; -import CodeChain from "../helper/spawn"; - -describe("TransferAsset expiration test", function() { - let node: CodeChain; - const numTx = 5; - - beforeEach(async function() { - node = new CodeChain({ - argv: ["--force-sealing"] - }); - await node.start(); - }); - - describe(`Create ${numTx} transactions each expires in 1~${numTx} sec(s) after`, async function() { - let trackers: H256[] = []; - let startTime: number; - - beforeEach(async function() { - this.timeout(10_000); - - // 1. Create an asset for TransferAsset - let assets = []; - for (let i = 0; i < numTx; i++) { - const asset = await node.mintAsset({ supply: 1 }); - assets.push(asset); - } - - // 2. Stop sealing - await node.sdk.rpc.devel.stopSealing(); - - // 3. Send TransferAsset transactions (which should not processed) - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - startTime = Math.round(new Date().getTime() / 1000) + 5; - for (let i = 0; i < numTx; i++) { - const recipient = await node.createP2PKHAddress(); - const tx = node.sdk.core.createTransferAssetTransaction({ - expiration: startTime + numTx - i - }); - tx.addInputs(assets[i]); - tx.addOutputs({ - assetType: assets[i].assetType, - shardId: assets[i].shardId, - recipient, - quantity: 1 - }); - await node.signTransactionInput(tx, 0); - await node.sendAssetTransaction(tx, { - seq: seq + i - }); - - trackers.push(tx.tracker()); - } - }); - - it("then create block 1 sec after", async function() { - let prevBestBlockNum = await node.getBestBlockNumber(); - await wait(1_000); - await node.sdk.rpc.devel.startSealing(); - - await node.waitBlockNumber(prevBestBlockNum + 1); - let bestBlockNum = await node.getBestBlockNumber(); - let bestBlock = await node.sdk.rpc.chain.getBlock(bestBlockNum); - expect(bestBlock).not.to.be.null; - let bestBlockTimestamp = bestBlock!.timestamp; - - for (let i = 0; i < numTx; i++) { - const results = await node.sdk.rpc.chain.getTransactionResultsByTracker( - trackers[i] - ); - expect(results).not.to.be.null; - expect(results!.length).to.be.below(2); - - const isResultsEmpty = results!.length === 0; - const isExpired = bestBlockTimestamp > startTime + numTx - i; - expect(isResultsEmpty).to.be.equal(isExpired); - } - }).timeout(15_000); - }); - - afterEach(async function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - await node.clean(); - }); -}); diff --git a/test/src/e2e.long/mempool.test.ts b/test/src/e2e.long/mempool.test.ts index 6376394eeb..cb5a484233 100644 --- a/test/src/e2e.long/mempool.test.ts +++ b/test/src/e2e.long/mempool.test.ts @@ -19,6 +19,7 @@ import { SignedTransaction } from "codechain-sdk/lib/core/classes"; import "mocha"; import { wait } from "../helper/promise"; import CodeChain from "../helper/spawn"; +import {faucetAddress} from "../helper/constants"; describe("Memory pool size test", function() { let nodeA: CodeChain; @@ -164,7 +165,7 @@ describe("Memory pool memory limit test", function() { it("To self", async function() { for (let i = 0; i < sizeLimit; i++) { - await nodeA.mintAsset({ supply: 1, seq: i, awaitMint: false }); + await nodeA.pay(faucetAddress, 10, { seq: i }); } const pendingTransactions = await nodeA.sdk.rpc.chain.getPendingTransactions(); expect(pendingTransactions.transactions.length).to.equal(sizeLimit); @@ -195,12 +196,7 @@ describe("Memory pool memory limit test", function() { const minting = []; for (let i = 0; i < sizeLimit; i++) { minting.push( - nodeA.mintAsset({ - supply: mintSize, - seq: i, - metadata, - awaitMint: false - }) + nodeA.pay(faucetAddress, 10, { seq: i}) ); } await Promise.all(minting); diff --git a/test/src/e2e.long/sync2.test.ts b/test/src/e2e.long/sync2.test.ts index f63f821e25..8b892e7a23 100644 --- a/test/src/e2e.long/sync2.test.ts +++ b/test/src/e2e.long/sync2.test.ts @@ -162,9 +162,8 @@ describe("sync 2 nodes", function() { describe("A-B diverged with the same transaction", function() { describe("Both transaction success", function() { beforeEach(async function() { - const recipient = await nodeA.createP2PKHAddress(); - await nodeA.mintAsset({ supply: 10, recipient }); - await nodeB.mintAsset({ supply: 10, recipient }); + await nodeA.sendPayTx({ fee: 10 }); + await nodeB.sendPayTx({ fee: 10 }); expect(await nodeA.getBestBlockNumber()).to.equal( await nodeB.getBestBlockNumber() ); diff --git a/test/src/e2e.long/timelock.test.ts b/test/src/e2e.long/timelock.test.ts deleted file mode 100644 index 504b2716f9..0000000000 --- a/test/src/e2e.long/timelock.test.ts +++ /dev/null @@ -1,407 +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 { expect } from "chai"; -import { H256 } from "codechain-primitives/lib"; -import { Asset, AssetAddress, Timelock } from "codechain-sdk/lib/core/classes"; -import "mocha"; -import { wait } from "../helper/promise"; -import CodeChain from "../helper/spawn"; - -describe("Timelock", function() { - let node: CodeChain; - - beforeEach(async function() { - node = new CodeChain({ - argv: ["--force-sealing", "--no-reseal-timer"] - }); - await node.start(); - }); - - async function sendTxWithTimelock(timelock: Timelock): Promise { - const asset = await node.mintAsset({ supply: 1 }); - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs( - asset.createTransferInput({ - timelock - }) - ); - tx.addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - await node.signTransactionInput(tx, 0); - await node.sendAssetTransaction(tx); - return tx.tracker(); - } - - async function checkTx(tracker: H256, shouldBeConfirmed: boolean) { - const results = await node.sdk.rpc.chain.getTransactionResultsByTracker( - tracker - ); - if (shouldBeConfirmed) { - expect(results.length).to.equal(1); - expect(results[0]).to.be.true; - } else { - expect(results.length).to.equal(0); - } - } - - describe("Transaction should go into the current queue", async function() { - it(`Minted at block 1, send transfer with Timelock::Block(0)`, async function() { - const tracker = await sendTxWithTimelock({ - type: "block", - value: 0 - }); - await checkTx(tracker, true); - }); - - it(`Minted at block 1, send transfer with Timelock::BlockAge(0)`, async function() { - const tracker = await sendTxWithTimelock({ - type: "blockAge", - value: 0 - }); - await checkTx(tracker, true); - }); - - it("send transfer with Timelock::Time(0)", async function() { - const tracker = await sendTxWithTimelock({ - type: "time", - value: 0 - }); - await checkTx(tracker, true); - }); - - it("send transfer with Timelock::TimeAge(0)", async function() { - const tracker = await sendTxWithTimelock({ - type: "timeAge", - value: 0 - }); - await checkTx(tracker, true); - }); - }); - - it("A relative timelock for failed transaction's output", async function() { - const asset = await node.mintAsset({ supply: 1 }); - const failedTx = node.sdk.core.createTransferAssetTransaction(); - failedTx.addInputs(asset); - failedTx.addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - - await node.sendAssetTransactionExpectedToFail(failedTx); - - const output0 = failedTx.getTransferredAsset(0); - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs( - output0.createTransferInput({ - timelock: { - type: "blockAge", - value: 2 - } - }) - ); - tx.addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - await node.signTransactionInput(tx, 0); - try { - await node.sendAssetTransaction(tx); - expect.fail(); - } catch (e) { - expect(e.data).to.have.string("Timelocked"); - expect(e.data).to.have.string("BlockAge(2)"); - expect(e.data).to.have.string("18446744073709551615"); - } - await checkTx(tx.tracker(), false); - await node.sdk.rpc.devel.startSealing(); - }); - - describe("Transactions should go into the future queue and then move to current", async function() { - it("Minted at block 1, send transfer with Timelock::Block(3)", async function() { - const tracker = await sendTxWithTimelock({ - // available from block 3 - type: "block", - value: 3 - }); - - expect(await node.getBestBlockNumber()).to.equal(1); - await checkTx(tracker, false); - - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - await checkTx(tracker, false); - await node.sdk.rpc.devel.startSealing(); - - expect(await node.getBestBlockNumber()).to.equal(4); - await checkTx(tracker, true); - }); - - it("Minted at block 1, send transfer with Timelock::BlockAge(3)", async function() { - const tracker = await sendTxWithTimelock({ - // available from block 4, since mintTx is at block 1. - type: "blockAge", - value: 3 - }); - - for (let i = 1; i <= 4; i++) { - expect(await node.getBestBlockNumber()).to.equal(i); - await checkTx(tracker, false); - - await node.sdk.rpc.devel.startSealing(); - } - - expect(await node.getBestBlockNumber()).to.equal(5); - await checkTx(tracker, true); - }); - }); - - async function sendTransferTx( - asset: Asset, - timelock?: Timelock, - options: { - fee?: number; - } = {} - ): Promise { - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs( - timelock - ? asset.createTransferInput({ - timelock - }) - : asset.createTransferInput() - ); - tx.addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - await node.signTransactionInput(tx, 0); - const { fee } = options; - await node.sendAssetTransaction(tx, { fee }); - return tx.tracker(); - } - - describe("The future items should move to the current queue", async function() { - it("Minted at block 1, send transfer with Timelock::Block(10) and then replace it with no timelock", async function() { - const asset = await node.mintAsset({ supply: 1 }); - await node.sdk.rpc.devel.stopSealing(); - const tracker1 = await sendTransferTx(asset, { - type: "block", - value: 10 - }); - const tracker2 = await sendTransferTx(asset, undefined, { - fee: 20 - }); - await checkTx(tracker1, false); - await checkTx(tracker2, false); - - await node.sdk.rpc.devel.startSealing(); - expect(await node.getBestBlockNumber()).to.equal(2); - await checkTx(tracker1, false); - await checkTx(tracker2, true); - }).timeout(10_000); - }); - - describe("Multiple timelocks", async function() { - let recipient: AssetAddress; - - beforeEach(async function() { - recipient = await node.createP2PKHAddress(); - }); - - async function createUTXOs(count: number): Promise { - const asset = await node.mintAsset({ supply: count }); - const transferTx = node.sdk.core.createTransferAssetTransaction(); - transferTx.addInputs(asset); - transferTx.addOutputs( - Array.from(Array(count)).map(_ => ({ - assetType: asset.assetType, - shardId: asset.shardId, - quantity: 1, - recipient - })) - ); - await node.signTransactionInput(transferTx, 0); - await node.sendAssetTransaction(transferTx); - return transferTx.getTransferredAssets(); - } - - it("2 inputs [Block(4), Block(6)] => Block(6)", async function() { - const assets = await createUTXOs(2); - const { assetType, shardId } = assets[0]; - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs([ - assets[0].createTransferInput({ - timelock: { - type: "block", - value: 4 - } - }), - assets[1].createTransferInput({ - timelock: { - type: "block", - value: 6 - } - }) - ]); - tx.addOutputs({ quantity: 2, recipient, assetType, shardId }); - await node.signTransactionInput(tx, 0); - await node.signTransactionInput(tx, 1); - await node.sendAssetTransaction(tx); - - expect(await node.getBestBlockNumber()).to.equal(2); - await checkTx(tx.tracker(), false); - - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - expect(await node.getBestBlockNumber()).to.equal(5); - await checkTx(tx.tracker(), false); - - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - expect(await node.getBestBlockNumber()).to.equal(7); - await checkTx(tx.tracker(), true); - }).timeout(10_000); - - it("2 inputs [Block(6), Block(4)] => Block(4)", async function() { - const assets = await createUTXOs(2); - const { assetType, shardId } = assets[0]; - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs([ - assets[0].createTransferInput({ - timelock: { - type: "block", - value: 6 - } - }), - assets[1].createTransferInput({ - timelock: { - type: "block", - value: 4 - } - }) - ]); - tx.addOutputs({ quantity: 2, recipient, assetType, shardId }); - await node.signTransactionInput(tx, 0); - await node.signTransactionInput(tx, 1); - await node.sendAssetTransaction(tx); - - expect(await node.getBestBlockNumber()).to.equal(2); - await checkTx(tx.tracker(), false); - - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - expect(await node.getBestBlockNumber()).to.equal(5); - await checkTx(tx.tracker(), false); - - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - expect(await node.getBestBlockNumber()).to.equal(7); - await checkTx(tx.tracker(), true); - }).timeout(10_000); - - it("2 inputs [Time(0), Block(4)] => Block(4)", async function() { - const assets = await createUTXOs(2); - const { assetType, shardId } = assets[0]; - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs([ - assets[0].createTransferInput({ - timelock: { - type: "time", - value: 0 - } - }), - assets[1].createTransferInput({ - timelock: { - type: "block", - value: 4 - } - }) - ]); - tx.addOutputs({ quantity: 2, recipient, assetType, shardId }); - await node.signTransactionInput(tx, 0); - await node.signTransactionInput(tx, 1); - await node.sendAssetTransaction(tx); - - expect(await node.getBestBlockNumber()).to.equal(2); - await checkTx(tx.tracker(), false); - - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - expect(await node.getBestBlockNumber()).to.equal(5); - await checkTx(tx.tracker(), true); - }).timeout(10_000); - - it("2 inputs [Time(now + 3 seconds), Block(4)] => Time(..)", async function() { - const assets = await createUTXOs(2); - const { assetType, shardId } = assets[0]; - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs([ - assets[0].createTransferInput({ - timelock: { - type: "time", - value: Math.floor(Date.now() / 1000) + 3 - } - }), - assets[1].createTransferInput({ - timelock: { - type: "block", - value: 4 - } - }) - ]); - tx.addOutputs({ quantity: 2, recipient, assetType, shardId }); - await node.signTransactionInput(tx, 0); - await node.signTransactionInput(tx, 1); - await node.sendAssetTransaction(tx); - - expect(await node.getBestBlockNumber()).to.equal(2); - await checkTx(tx.tracker(), false); - - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - expect(await node.getBestBlockNumber()).to.equal(4); - await checkTx(tx.tracker(), false); - - await wait(3_000); - - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - expect(await node.getBestBlockNumber()).to.equal(6); - await checkTx(tx.tracker(), true); - }).timeout(10_000); - }); - - afterEach(async function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - await node.clean(); - }); -}); diff --git a/test/src/e2e/burn.test.ts b/test/src/e2e/burn.test.ts deleted file mode 100644 index 629f7233e5..0000000000 --- a/test/src/e2e/burn.test.ts +++ /dev/null @@ -1,158 +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 { expect } from "chai"; -import "mocha"; -import { ERROR } from "../helper/error"; -import CodeChain from "../helper/spawn"; - -describe("Burn", function() { - let node: CodeChain; - before(async function() { - node = new CodeChain(); - await node.start(); - }); - - it("burn", async function() { - const asset = await node.mintAsset({ supply: 1 }); - const tx1 = node.sdk.core.createTransferAssetTransaction(); - tx1.addInputs(asset); - tx1.addOutputs({ - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHBurnAddress(), - quantity: 1 - }); - await node.signTransactionInput(tx1, 0); - const hash1 = await node.sendAssetTransaction(tx1); - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be.true; - - const transferredAsset = tx1.getTransferredAsset(0); - const tx2 = node.sdk.core.createTransferAssetTransaction(); - tx2.addBurns(transferredAsset); - await node.signTransactionBurn(tx2, 0); - const hash2 = await node.sendAssetTransaction(tx2); - expect(await node.sdk.rpc.chain.getTransaction(hash2)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash2)).be.true; - - expect( - await node.sdk.rpc.chain.getAsset(tx2.tracker(), 0, asset.shardId) - ).to.be.null; - }); - - it("burn ZeroQuantity", async function() { - const asset = await node.mintAsset({ supply: 1 }); - const tx1 = node.sdk.core.createTransferAssetTransaction(); - tx1.addInputs(asset); - tx1.addOutputs({ - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHBurnAddress(), - quantity: 1 - }); - await node.signTransactionInput(tx1, 0); - const hash = await node.sendAssetTransaction(tx1); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - - const tx2 = node.sdk.core.createTransferAssetTransaction(); - const { - assetType, - shardId, - lockScriptHash, - parameters - } = tx1.getTransferredAsset(0); - tx2.addBurns( - node.sdk.core.createAssetTransferInput({ - assetOutPoint: { - assetType, - shardId, - tracker: tx1.tracker(), - index: 0, - lockScriptHash, - parameters, - quantity: 0 - } - }) - ); - await node.signTransactionBurn(tx2, 0); - try { - await node.sendAssetTransaction(tx2); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_TX_ZERO_QUANTITY); - } - }); - - it("Cannot transfer P2PKHBurn asset", async function() { - const asset = await node.mintAsset({ supply: 1 }); - const tx1 = node.sdk.core.createTransferAssetTransaction(); - tx1.addInputs(asset); - tx1.addOutputs({ - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHBurnAddress(), - quantity: 1 - }); - await node.signTransactionInput(tx1, 0); - const hash1 = await node.sendAssetTransaction(tx1); - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be.true; - - const transferredAsset = tx1.getTransferredAsset(0); - const tx2 = node.sdk.core.createTransferAssetTransaction(); - tx2.addInputs(transferredAsset); - tx2.addOutputs({ - assetType: transferredAsset.assetType, - shardId: transferredAsset.shardId, - recipient: await node.createP2PKHBurnAddress(), - quantity: 1 - }); - await node.signTransactionP2PKHBurn( - tx2.input(0)!, - tx2.hashWithoutScript() - ); - - await node.sendAssetTransactionExpectedToFail(tx2); - - expect( - await node.sdk.rpc.chain.getAsset(tx1.tracker(), 0, asset.shardId) - ).not.to.be.null; - expect( - await node.sdk.rpc.chain.getAsset(tx2.tracker(), 0, asset.shardId) - ).be.null; - }); - - it("Cannot burn P2PKH asset", async function() { - const asset = await node.mintAsset({ supply: 1 }); - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addBurns(asset); - await node.signTransactionP2PKH(tx.burn(0)!, tx.hashWithoutScript()); - - await node.sendAssetTransactionExpectedToFail(tx); - }); - - afterEach(function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - }); - - after(async function() { - await node.clean(); - }); -}); diff --git a/test/src/e2e/chain.test.ts b/test/src/e2e/chain.test.ts index ccf2aeaf33..f305aa99ac 100644 --- a/test/src/e2e/chain.test.ts +++ b/test/src/e2e/chain.test.ts @@ -19,11 +19,9 @@ import * as chaiAsPromised from "chai-as-promised"; chai.use(chaiAsPromised); const expect = chai.expect; import { - AssetScheme, H160, H256, H512, - MintAsset, U64 } from "codechain-sdk/lib/core/classes"; import "mocha"; @@ -35,7 +33,6 @@ import { import CodeChain from "../helper/spawn"; describe("chain", function() { - const invalidH160 = H160.zero(); const invalidH256 = H256.zero(); let node: CodeChain; @@ -257,268 +254,6 @@ describe("chain", function() { ).to.be.null; }); - describe("Mint an asset", function() { - let tx: MintAsset; - let txAssetScheme: AssetScheme; - - before(async function() { - const recipient = await node.createP2PKHAddress(); - tx = node.sdk.core.createMintAssetTransaction({ - scheme: { - shardId: 0, - metadata: "", - supply: "0xa" - }, - recipient - }); - txAssetScheme = tx.getAssetScheme(); - - const signed = tx.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - await node.sdk.rpc.chain.sendSignedTransaction(signed); - }); - - it("getTransactionsByTracker", async function() { - expect( - (await node.sdk.rpc.chain.getTransactionByTracker( - tx.tracker() - ))!.unsigned - ).to.deep.equal(tx); - expect( - await node.sdk.rpc.chain.getTransactionByTracker(invalidH256) - ).be.null; - }); - - it("getTransactionResultsByTracker", async function() { - expect( - await node.sdk.rpc.chain.getTransactionResultsByTracker( - tx.tracker() - ) - ).deep.equal([true]); - }); - - it("getAsset", async function() { - const invalidShardId = 1; - const validShardId = 0; - expect( - await node.sdk.rpc.chain.getAsset(invalidH256, 0, validShardId) - ).to.be.null; - expect( - await node.sdk.rpc.chain.getAsset(tx.tracker(), 1, validShardId) - ).to.be.null; - expect( - await node.sdk.rpc.chain.getAsset( - tx.tracker(), - 1, - invalidShardId - ) - ).to.be.null; - expect( - await node.sdk.rpc.chain.getAsset(tx.tracker(), 0, validShardId) - ).to.deep.equal(tx.getMintedAsset()); - - const bestBlockNumber = await node.sdk.rpc.chain.getBestBlockNumber(); - expect( - await node.sdk.rpc.chain.getAsset( - tx.tracker(), - 0, - validShardId, - bestBlockNumber - ) - ).to.deep.equal(tx.getMintedAsset()); - expect( - await node.sdk.rpc.chain.getAsset( - tx.tracker(), - 0, - validShardId, - 0 - ) - ).to.be.null; - expect( - await node.sdk.rpc.chain.getAsset( - tx.tracker(), - 0, - validShardId, - bestBlockNumber + 1 - ) - ).to.be.null; - }); - - it("getAssetSchemeByTracker", async function() { - const invalidShardId = 1; - const validShardId = 0; - expect( - await node.sdk.rpc.chain.getAssetSchemeByTracker( - invalidH256, - validShardId - ) - ).to.be.null; - expect( - await node.sdk.rpc.chain.getAssetSchemeByTracker( - tx.tracker(), - invalidShardId - ) - ).to.be.null; - - const assetScheme = await node.sdk.rpc.chain.getAssetSchemeByTracker( - tx.tracker(), - validShardId - ); - if (assetScheme == null) { - throw Error("Cannot get asset scheme"); - } - expect(assetScheme.supply).to.deep.equal(txAssetScheme.supply); - expect(assetScheme.metadata).to.equal(txAssetScheme.metadata); - expect(assetScheme.approver).to.deep.equal(txAssetScheme.approver); - }); - - it("getAssetSchemeByType", async function() { - const invalidShardId = 1; - const validShardId = 0; - expect( - await node.sdk.rpc.chain.getAssetSchemeByType( - invalidH160, - validShardId - ) - ).to.be.null; - expect( - await node.sdk.rpc.chain.getAssetSchemeByType( - tx.getAssetType(), - invalidShardId - ) - ).to.be.null; - - const assetScheme = await node.sdk.rpc.chain.getAssetSchemeByType( - tx.getAssetType(), - validShardId - ); - if (assetScheme == null) { - throw Error("Cannot get asset scheme"); - } - expect(assetScheme.supply).to.deep.equal(txAssetScheme.supply); - expect(assetScheme.metadata).to.equal(txAssetScheme.metadata); - expect(assetScheme.approver).to.deep.equal(txAssetScheme.approver); - }); - }); - - it("isAssetSpent", async function() { - const asset = await node.mintAsset({ supply: 10 }); - expect( - await node.sdk.rpc.chain.isAssetSpent( - asset.outPoint.tracker, - asset.outPoint.index, - asset.outPoint.shardId - ) - ).to.be.false; - - const recipient = await node.createP2PKHAddress(); - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs(asset); - tx.addOutputs({ - assetType: asset.assetType, - shardId: asset.shardId, - recipient, - quantity: "0xa" - }); - await node.signTransactionInput(tx, 0); - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect( - await node.sdk.rpc.chain.isAssetSpent( - asset.outPoint.tracker, - asset.outPoint.index, - asset.outPoint.shardId - ) - ).to.be.true; - - const bestBlockNumber = await node.sdk.rpc.chain.getBestBlockNumber(); - expect( - await node.sdk.rpc.chain.isAssetSpent( - asset.outPoint.tracker, - asset.outPoint.index, - asset.outPoint.shardId, - bestBlockNumber - ) - ).to.be.true; - expect( - await node.sdk.rpc.chain.isAssetSpent( - asset.outPoint.tracker, - asset.outPoint.index, - asset.outPoint.shardId, - bestBlockNumber - 1 - ) - ).to.be.false; - expect( - await node.sdk.rpc.chain.isAssetSpent( - asset.outPoint.tracker, - asset.outPoint.index, - asset.outPoint.shardId, - 0 - ) - ).to.be.null; - }); - - it("executeTransaction", async function() { - const scheme = node.sdk.core.createAssetScheme({ - shardId: 0, - metadata: "", - supply: 10000 - }); - const tx = node.sdk.core.createMintAssetTransaction({ - scheme, - recipient: await node.createP2PKHAddress() - }); - tx.setFee(0); - - const data = tx.toJSON(); - - await node.sdk.rpc - .sendRpcRequest("chain_executeTransaction", [ - data, - faucetAddress.value - ]) - .then(result => { - expect(result).to.be.null; - }); - }); - - it("getNumberOfShards", async function() { - expect( - await node.sdk.rpc.sendRpcRequest("chain_getNumberOfShards", [null]) - ).to.equal(1); - - expect( - await node.sdk.rpc.sendRpcRequest("chain_getNumberOfShards", [0]) - ).to.equal(1); - }); - - it("getShardRoot", async function() { - await node.sdk.rpc - .sendRpcRequest("chain_getShardRoot", [0, null]) - .then(result => { - expect(result).not.to.be.null; - H256.ensure(result); - }); - - await node.sdk.rpc - .sendRpcRequest("chain_getShardRoot", [0, 0]) - .then(result => { - expect(result).not.to.be.null; - H256.ensure(result); - }); - - await node.sdk.rpc - .sendRpcRequest("chain_getShardRoot", [10000, null]) - .then(result => { - expect(result).to.be.null; - }); - }); - it("getMiningReward", async function() { await node.sdk.rpc .sendRpcRequest("chain_getMiningReward", [0]) diff --git a/test/src/e2e/changeAssetScheme.test.ts b/test/src/e2e/changeAssetScheme.test.ts deleted file mode 100644 index dfdd44ac9c..0000000000 --- a/test/src/e2e/changeAssetScheme.test.ts +++ /dev/null @@ -1,156 +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 { expect } from "chai"; -import { MintAsset } from "codechain-sdk/lib/core/classes"; -import "mocha"; -import { faucetAddress, faucetSecret } from "../helper/constants"; -import CodeChain from "../helper/spawn"; - -describe("ChangeAssetScheme", function() { - let node: CodeChain; - before(async function() { - node = new CodeChain(); - await node.start(); - }); - - let mint: MintAsset; - beforeEach(async function() { - const recipient = await node.createP2PKHAddress(); - const scheme = node.sdk.core.createAssetScheme({ - registrar: faucetAddress, - shardId: 0, - metadata: "", - supply: 10 - }); - mint = node.sdk.core.createMintAssetTransaction({ - scheme, - recipient - }); - const hash = await node.sendAssetTransaction(mint); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("successful", async function() { - const seq = (await node.sdk.rpc.chain.getSeq(faucetAddress))!; - const changeAssetScheme = node.sdk.core.createChangeAssetSchemeTransaction( - { - shardId: 0, - assetType: mint.getAssetType(), - scheme: { - metadata: "A", - allowedScriptHashes: [] - }, - approvals: [] - } - ); - const signedChangeAssetScheme = changeAssetScheme.sign({ - secret: faucetSecret, - seq, - fee: 10 - }); - const hash = await node.sdk.rpc.chain.sendSignedTransaction( - signedChangeAssetScheme - ); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - - it("Changing to another scheme and set back to the original", async function() { - const seq = (await node.sdk.rpc.chain.getSeq(faucetAddress))!; - const changeAssetScheme0 = node.sdk.core.createChangeAssetSchemeTransaction( - { - shardId: 0, - assetType: mint.getAssetType(), - scheme: { - metadata: "A", - registrar: faucetAddress, - allowedScriptHashes: [] - }, - approvals: [] - } - ); - const signedChangeAssetScheme0 = changeAssetScheme0.sign({ - secret: faucetSecret, - seq, - fee: 10 - }); - const hash0 = await node.sdk.rpc.chain.sendSignedTransaction( - signedChangeAssetScheme0 - ); - expect(await node.sdk.rpc.chain.getTransaction(hash0)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash0)).be.true; - - const changeAssetScheme1 = node.sdk.core.createChangeAssetSchemeTransaction( - { - shardId: 0, - assetType: mint.getAssetType(), - scheme: { - metadata: "B", - registrar: faucetAddress, - allowedScriptHashes: [] - }, - seq: 1, - approvals: [] - } - ); - const signedChangeAssetScheme1 = changeAssetScheme1.sign({ - secret: faucetSecret, - seq: seq + 1, - fee: 10 - }); - const hash1 = await node.sdk.rpc.chain.sendSignedTransaction( - signedChangeAssetScheme1 - ); - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be.true; - - const changeAssetScheme2 = node.sdk.core.createChangeAssetSchemeTransaction( - { - shardId: 0, - assetType: mint.getAssetType(), - seq: 2, - scheme: { - metadata: "A", - registrar: faucetAddress, - allowedScriptHashes: [] - }, - approvals: [] - } - ); - const signedChangeAssetScheme2 = changeAssetScheme2.sign({ - secret: faucetSecret, - seq: seq + 2, - fee: 10 - }); - const hash2 = await node.sdk.rpc.chain.sendSignedTransaction( - signedChangeAssetScheme2 - ); - expect(await node.sdk.rpc.chain.getTransaction(hash2)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash2)).be.true; - }); - - afterEach(function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - }); - - after(async function() { - await node.clean(); - }); -}); diff --git a/test/src/e2e/increaseAssetSupply.test.ts b/test/src/e2e/increaseAssetSupply.test.ts deleted file mode 100644 index 273a057753..0000000000 --- a/test/src/e2e/increaseAssetSupply.test.ts +++ /dev/null @@ -1,336 +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 { expect } from "chai"; -import { PlatformAddress, U64 } from "codechain-sdk/lib/core/classes"; -import "mocha"; -import { faucetAddress, faucetSecret } from "../helper/constants"; -import CodeChain from "../helper/spawn"; - -describe("IncreaseAssetSupply", async function() { - let outsider: PlatformAddress; - let node: CodeChain; - - beforeEach(async function() { - node = new CodeChain(); - await node.start(); - - outsider = await node.createPlatformAddress(); - await node.pay(outsider, 10000); - }); - - it("can increase the total supply", async function() { - const amount = 100; - const increasedAmount = 300; - const asset = await node.mintAsset({ - supply: amount, - registrar: faucetAddress - }); - const tx = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient: await node.createP2PKHAddress(), - supply: increasedAmount - }); - - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - - const assetScheme = await node.sdk.rpc.chain.getAssetSchemeByType( - asset.assetType, - asset.shardId - ); - expect(assetScheme!.supply.toString(10)).equal( - new U64(amount + increasedAmount).toString(10) - ); - - const additionalAsset = await node.sdk.rpc.chain.getAsset( - tx.tracker(), - 0, - asset.shardId - ); - expect(additionalAsset!.quantity.toString(10)).equal( - new U64(increasedAmount).toString(10) - ); - }); - - it("cannot increase supply with the same transaction", async function() { - const amount = 100; - const increasedAmount = 300; - const asset = await node.mintAsset({ - supply: amount, - registrar: faucetAddress - }); - const recipient = await node.createP2PKHAddress(); - const tx1 = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient, - supply: increasedAmount - }); - const tx2 = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient, - supply: increasedAmount - }); - expect(tx1.tracker().value).equal(tx2.tracker().value); - - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - - const hash1 = await node.sendAssetTransaction(tx1, { seq }); - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - - await node.sendAssetTransactionExpectedToFail(tx2, { seq: seq + 1 }); - }); - - it("cannot increase supply with the same transaction even the asset is moved", async function() { - const amount = 100; - const increasedAmount = 300; - const asset = await node.mintAsset({ - supply: amount, - registrar: faucetAddress - }); - const recipient = await node.createP2PKHAddress(); - const tx1 = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient, - supply: increasedAmount - }); - const tx2 = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient, - supply: increasedAmount - }); - expect(tx1.tracker().value).equal(tx2.tracker().value); - - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - - const hash1 = await node.sendAssetTransaction(tx1, { seq }); - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - - const input = tx1.getMintedAsset().createTransferInput(); - const transfer = await node.sdk.core.createTransferAssetTransaction({ - inputs: [input], - outputs: [ - node.sdk.core.createAssetTransferOutput({ - assetType: input.prevOut.assetType, - shardId: input.prevOut.shardId, - quantity: input.prevOut.quantity, - recipient - }) - ] - }); - await node.signTransactionInput(transfer, 0); - const transferHash = await node.sdk.rpc.chain.sendSignedTransaction( - transfer.sign({ - secret: faucetSecret, - fee: 100, - seq: seq + 1 - }) - ); - expect(await node.sdk.rpc.chain.containsTransaction(transferHash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(transferHash)).be.not - .null; - - await node.sendAssetTransactionExpectedToFail(tx2, { seq: seq + 2 }); - }); - - it("can increase supply again", async function() { - const amount = 100; - const increasedAmount = 300; - const asset = await node.mintAsset({ - supply: amount, - registrar: faucetAddress - }); - const recipient = await node.createP2PKHAddress(); - const tx1 = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient, - supply: increasedAmount - }); - const tx2 = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient, - seq: 1, - supply: increasedAmount - }); - expect(tx1.tracker().value).not.equal(tx2.tracker().value); - - const hash1 = await node.sendAssetTransaction(tx1); - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - - const hash2 = await node.sendAssetTransaction(tx2); - expect(await node.sdk.rpc.chain.containsTransaction(hash2)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash2)).not.null; - }); - - it("can increase supply again after move", async function() { - const amount = 100; - const increasedAmount = 300; - const asset = await node.mintAsset({ - supply: amount, - registrar: faucetAddress - }); - const recipient = await node.createP2PKHAddress(); - const tx1 = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient, - supply: increasedAmount - }); - const tx2 = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient, - seq: 1, - supply: increasedAmount - }); - expect(tx1.tracker().value).not.equal(tx2.tracker().value); - - const hash1 = await node.sendAssetTransaction(tx1); - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - - const input = tx1.getMintedAsset().createTransferInput(); - const transfer = await node.sdk.core.createTransferAssetTransaction({ - inputs: [input], - outputs: [ - node.sdk.core.createAssetTransferOutput({ - assetType: input.prevOut.assetType, - shardId: input.prevOut.shardId, - quantity: input.prevOut.quantity, - recipient - }) - ] - }); - - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - - await node.signTransactionInput(transfer, 0); - const transferHash = await node.sdk.rpc.chain.sendSignedTransaction( - transfer.sign({ - secret: faucetSecret, - fee: 100, - seq - }) - ); - expect(await node.sdk.rpc.chain.containsTransaction(transferHash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(transferHash)).be.not - .null; - - const blockNumber = await node.getBestBlockNumber(); - const hash2 = await node.sendAssetTransaction(tx2); - await node.waitBlockNumber(blockNumber + 1); - - expect(await node.sdk.rpc.chain.containsTransaction(hash2)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash2)).be.not.null; - }); - - it("cannot increase without registrar", async function() { - const amount = 100; - const increasedAmount = 300; - const asset = await node.mintAsset({ - supply: amount - }); - const tx = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient: await node.createP2PKHAddress(), - supply: increasedAmount - }); - - await node.sendAssetTransactionExpectedToFail(tx); - - const additionalAsset = await node.sdk.rpc.chain.getAsset( - tx.tracker(), - 0, - asset.shardId - ); - expect(additionalAsset).to.be.null; - }); - - it("outsider cannot increase", async function() { - const amount = 100; - const increasedAmount = 300; - const asset = await node.mintAsset({ - supply: amount, - registrar: faucetAddress - }); - const tx = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient: await node.createP2PKHAddress(), - supply: increasedAmount - }); - - await node.sendTransactionExpectedToFail(tx, { account: outsider }); - - const results = await node.sdk.rpc.chain.getTransactionResultsByTracker( - tx.tracker(), - { - timeout: 300 * 1000 - } - ); - expect(results).deep.equal([false]); - - const additionalAsset = await node.sdk.rpc.chain.getAsset( - tx.tracker(), - 0, - asset.shardId - ); - expect(additionalAsset).to.be.null; - }); - - it("cannot be overflowed", async function() { - const asset = await node.mintAsset({ - supply: U64.MAX_VALUE, - registrar: faucetAddress - }); - const tx = node.sdk.core.createIncreaseAssetSupplyTransaction({ - shardId: asset.shardId, - assetType: asset.assetType, - recipient: await node.createP2PKHAddress(), - supply: 1 - }); - - await node.sendAssetTransactionExpectedToFail(tx); - - const additionalAsset = await node.sdk.rpc.chain.getAsset( - tx.tracker(), - 0, - asset.shardId - ); - expect(additionalAsset).to.be.null; - }); - - afterEach(async function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - await node.clean(); - }); -}); diff --git a/test/src/e2e/mempool.test.ts b/test/src/e2e/mempool.test.ts index 66666d2e45..bccc487567 100644 --- a/test/src/e2e/mempool.test.ts +++ b/test/src/e2e/mempool.test.ts @@ -16,7 +16,6 @@ import { expect } from "chai"; import { H256 } from "codechain-primitives/lib"; -import { Asset, Timelock } from "codechain-sdk/lib/core/classes"; import "mocha"; import { faucetAddress } from "../helper/constants"; import CodeChain from "../helper/spawn"; @@ -62,7 +61,7 @@ describe("Future queue", function() { expect(await node.sdk.rpc.chain.getSeq(faucetAddress)).to.equal(seq); await node.sendPayTx({ seq: seq + 1 }); expect(await node.sdk.rpc.chain.getSeq(faucetAddress)).to.equal(seq); - await node.sendPayTx({ seq: seq }); + await node.sendPayTx({ seq }); expect(await node.sdk.rpc.chain.getSeq(faucetAddress)).to.equal( seq + 4 ); @@ -75,86 +74,3 @@ describe("Future queue", function() { await node.clean(); }); }); - -describe("Timelock", function() { - let node: CodeChain; - - beforeEach(async function() { - node = new CodeChain({ - argv: ["--force-sealing", "--no-reseal-timer"] - }); - await node.start(); - }); - - async function checkTx(txhash: H256, shouldBeConfirmed: boolean) { - const results = await node.sdk.rpc.chain.getTransactionResultsByTracker( - txhash - ); - expect(results).deep.equal(shouldBeConfirmed ? [true] : []); - } - - async function sendTransferTx( - asset: Asset, - timelock?: Timelock, - options: { - fee?: number; - } = {} - ): Promise { - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs( - timelock - ? asset.createTransferInput({ - timelock - }) - : asset.createTransferInput() - ); - tx.addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - await node.signTransactionInput(tx, 0); - const { fee } = options; - await node.sendAssetTransaction(tx, { fee }); - return tx.tracker(); - } - - describe("The current items should move to the future queue", async function() { - it("Minted at block 1, send transfer without timelock and then replace it with Timelock::Block(3)", async function() { - const asset = await node.mintAsset({ supply: 1 }); - await node.sdk.rpc.devel.stopSealing(); - const txhash1 = await sendTransferTx(asset, undefined); - const txhash2 = await sendTransferTx( - asset, - { - type: "block", - value: 3 - }, - { - fee: 20 - } - ); - await checkTx(txhash1, false); - await checkTx(txhash2, false); - - await node.sdk.rpc.devel.startSealing(); - await node.sdk.rpc.devel.startSealing(); - expect(await node.getBestBlockNumber()).to.equal(3); - await checkTx(txhash1, false); - await checkTx(txhash2, false); - - await node.sdk.rpc.devel.startSealing(); - expect(await node.getBestBlockNumber()).to.equal(4); - await checkTx(txhash1, false); - await checkTx(txhash2, true); - }); - }); - - afterEach(async function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - await node.clean(); - }); -}); diff --git a/test/src/e2e/mintAsset.test.ts b/test/src/e2e/mintAsset.test.ts deleted file mode 100644 index 9df736d2c1..0000000000 --- a/test/src/e2e/mintAsset.test.ts +++ /dev/null @@ -1,103 +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 { expect } from "chai"; -import { U64 } from "codechain-sdk/lib/core/classes"; -import "mocha"; -import { faucetAddress, faucetSecret } from "../helper/constants"; -import { ERROR } from "../helper/error"; -import CodeChain from "../helper/spawn"; - -describe("MintAsset", async function() { - let node: CodeChain; - before(async function() { - node = new CodeChain(); - await node.start(); - }); - - [1, 100, U64.MAX_VALUE].forEach(function(supply) { - it(`Mint successful - supply ${supply}`, async function() { - const recipient = await node.createP2PKHAddress(); - const scheme = node.sdk.core.createAssetScheme({ - shardId: 0, - metadata: "", - supply - }); - const tx = node.sdk.core.createMintAssetTransaction({ - scheme, - recipient - }); - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - }); - - it("Mint unsuccessful - mint supply 0", async function() { - const scheme = node.sdk.core.createAssetScheme({ - shardId: 0, - metadata: "", - supply: 0 - }); - const tx = node.sdk.core.createMintAssetTransaction({ - scheme, - recipient: await node.createP2PKHAddress() - }); - - try { - await node.sendAssetTransaction(tx); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_TX_ZERO_QUANTITY); - } - }); - - it("Mint unsuccessful - mint supply U64.MAX_VALUE + 1", async function() { - const scheme = node.sdk.core.createAssetScheme({ - shardId: 0, - metadata: "", - supply: 0 - }); - (scheme.supply.value as any) = U64.MAX_VALUE.value.plus(1); - - const tx = node.sdk.core.createMintAssetTransaction({ - scheme, - recipient: await node.createP2PKHAddress() - }); - const signed = tx.sign({ - secret: faucetSecret, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress), - fee: 11 - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(signed); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - - afterEach(function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - }); - - after(async function() { - await node.clean(); - }); -}); diff --git a/test/src/e2e/multisig.test.ts b/test/src/e2e/multisig.test.ts deleted file mode 100644 index 1f1dd7efe8..0000000000 --- a/test/src/e2e/multisig.test.ts +++ /dev/null @@ -1,930 +0,0 @@ -// Copyright 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 { Buffer } from "buffer"; -import { expect } from "chai"; -import { - Asset, - AssetAddress, - H160, - Script, - TransferAsset, - Transaction -} from "codechain-sdk/lib/core/classes"; -import { - blake160, - encodeSignatureTag, - signEcdsa, - SignatureTag -} from "codechain-sdk/lib/utils"; -import "mocha"; -import { - alicePublic, - aliceSecret, - bobPublic, - bobSecret, - carolPublic, - carolSecret, - daveSecret, - faucetAddress -} from "../helper/constants"; -import { AssetTransaction } from "codechain-sdk/lib/core/Transaction"; -import CodeChain from "../helper/spawn"; - -const { PUSH, PUSHB, CHKMULTISIG } = Script.Opcode; - -// If one only sends certainly failing trasactions, the miner would not generate any block. -// So to clearly check the result failed, insert the failing transactions inbetween succeessful ones. -async function expectTransactionFail( - node: CodeChain, - targetTx: Transaction & AssetTransaction -) { - await node.sdk.rpc.devel.stopSealing(); - - const blockNumber = await node.getBestBlockNumber(); - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - const signedDummyTx = await node.sendPayTx({ seq, quantity: 1 }); - const targetTxHash = await node.sendAssetTransaction(targetTx, { - seq: seq + 1 - }); - - await node.sdk.rpc.devel.startSealing(); - await node.waitBlockNumber(blockNumber + 1); - - expect(await node.sdk.rpc.chain.containsTransaction(signedDummyTx.hash())) - .be.true; - expect(await node.sdk.rpc.chain.containsTransaction(targetTxHash)).be.false; - expect(await node.sdk.rpc.chain.getErrorHint(targetTxHash)).not.null; -} - -function createUnlockScript( - tag: SignatureTag, - ...signatures: Array -): Buffer { - const encodedTag = encodeSignatureTag(tag); - const inputArray = [PUSHB, encodedTag.byteLength, ...encodedTag]; - - signatures.forEach((sigInstance: string) => { - inputArray.push(PUSHB, 65, ...Buffer.from(sigInstance, "hex")); - }); - - return Buffer.from(inputArray); -} - -function createLockScript( - atLeast: number, - total: number, - ...publics: Array -): Buffer { - const inputArray = [PUSH, atLeast]; - publics.forEach((publicInstance: string) => { - inputArray.push(PUSHB, 64, ...Buffer.from(publicInstance, "hex")); - }); - inputArray.push(PUSH, total, CHKMULTISIG); - - return Buffer.from(inputArray); -} - -describe("Multisig", function() { - let node: CodeChain; - const defaultTag: SignatureTag = { input: "all", output: "all" }; - - beforeEach(async function() { - node = new CodeChain(); - await node.start(); - }); - - describe("1 of 2", async function() { - const lockScript = createLockScript(1, 2, alicePublic, bobPublic); - const lockScriptHash = new H160(blake160(lockScript)); - let recipient: AssetAddress; - let transfer: TransferAsset; - beforeEach(async function() { - recipient = AssetAddress.fromTypeAndPayload(0, lockScriptHash, { - networkId: node.sdk.networkId - }); - - const asset = await node.mintAsset({ supply: 1, recipient }); - - transfer = node.sdk.core - .createTransferAssetTransaction() - .addInputs(asset) - .addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - transfer.input(0)!.setLockScript(lockScript); - }); - - it("unlock with the first key", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature = signEcdsa(hashWithoutScript.value, aliceSecret); - - transfer - .input(0)! - .setUnlockScript(createUnlockScript(defaultTag, signature)); - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("unlock with the second key", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature = signEcdsa(hashWithoutScript.value, bobSecret); - transfer - .input(0)! - .setUnlockScript(createUnlockScript(defaultTag, signature)); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("fail to unlock with the unknown key", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature = signEcdsa(hashWithoutScript.value, carolSecret); - - transfer - .input(0)! - .setUnlockScript(createUnlockScript(defaultTag, signature)); - - await expectTransactionFail(node, transfer); - }); - - describe("Test partial signing", async function() { - let additionalAsset: Asset; - beforeEach(async function() { - additionalAsset = await node.mintAsset({ - supply: 10, - recipient - }); - }); - it("unlock with fixed inputs", async function() { - const tag: SignatureTag = { input: "all", output: [0] }; - transfer.addInputs(additionalAsset); - transfer.input(1)!.setLockScript(lockScript); - - const hashWithoutScript0 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 0 - }); - const signature0 = signEcdsa( - hashWithoutScript0.value, - aliceSecret - ); - const hashWithoutScript1 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 1 - }); - const signature1 = signEcdsa( - hashWithoutScript1.value, - bobSecret - ); - - transfer.addOutputs({ - quantity: 10, - assetType: additionalAsset.assetType, - shardId: additionalAsset.shardId, - recipient: await node.createP2PKHAddress() - }); - transfer - .input(0)! - .setUnlockScript(createUnlockScript(tag, signature0)); - - transfer - .input(1)! - .setUnlockScript(createUnlockScript(tag, signature1)); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("unlock with fixed outputs", async function() { - const tag: SignatureTag = { input: "single", output: [0, 1] }; - transfer.addOutputs({ - quantity: 10, - assetType: additionalAsset.assetType, - shardId: additionalAsset.shardId, - recipient: await node.createP2PKHBurnAddress() - }); - - const hashWithoutScript0 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 0 - }); - const signature0 = signEcdsa( - hashWithoutScript0.value, - aliceSecret - ); - transfer.addInputs(additionalAsset); - transfer.input(1)!.setLockScript(lockScript); - - const hashWithoutScript1 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 1 - }); - const signature1 = signEcdsa( - hashWithoutScript1.value, - bobSecret - ); - transfer - .input(0)! - .setUnlockScript(createUnlockScript(tag, signature0)); - - transfer - .input(1)! - .setUnlockScript(createUnlockScript(tag, signature1)); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("unlock with both outputs and inputs dynamic", async function() { - const tag0: SignatureTag = { input: "single", output: [0] }; - const tag1: SignatureTag = { input: "single", output: [1] }; - - const hashWithoutScript0 = transfer.hashWithoutScript({ - tag: tag0, - type: "input", - index: 0 - }); - const signature0 = signEcdsa( - hashWithoutScript0.value, - aliceSecret - ); - - transfer.addInputs(additionalAsset).addOutputs({ - quantity: 10, - assetType: additionalAsset.assetType, - shardId: additionalAsset.shardId, - recipient: await node.createP2PKHBurnAddress() - }); - transfer.input(1)!.setLockScript(lockScript); - - const hashWithoutScript1 = transfer.hashWithoutScript({ - tag: tag1, - type: "input", - index: 1 - }); - const signature1 = signEcdsa( - hashWithoutScript1.value, - bobSecret - ); - - transfer - .input(0)! - .setUnlockScript(createUnlockScript(tag0, signature0)); - - transfer - .input(1)! - .setUnlockScript(createUnlockScript(tag1, signature1)); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - }); - }); - - describe("1 of 3", async function() { - const lockScript = createLockScript( - 1, - 3, - alicePublic, - bobPublic, - carolPublic - ); - const lockScriptHash = new H160(blake160(lockScript)); - - let transfer: TransferAsset; - beforeEach(async function() { - const recipient = AssetAddress.fromTypeAndPayload( - 0, - lockScriptHash, - { - networkId: node.sdk.networkId - } - ); - - const asset = await node.mintAsset({ supply: 1, recipient }); - - transfer = node.sdk.core - .createTransferAssetTransaction() - .addInputs(asset) - .addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - }); - - it("unlock with the first key", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature = signEcdsa(hashWithoutScript.value, aliceSecret); - - transfer.input(0)!.setLockScript(lockScript); - transfer - .input(0)! - .setUnlockScript(createUnlockScript(defaultTag, signature)); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("unlock with the second key", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature = signEcdsa(hashWithoutScript.value, bobSecret); - - transfer.input(0)!.setLockScript(lockScript); - transfer - .input(0)! - .setUnlockScript(createUnlockScript(defaultTag, signature)); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("unlock with the third key", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature = signEcdsa(hashWithoutScript.value, carolSecret); - - transfer.input(0)!.setLockScript(lockScript); - transfer - .input(0)! - .setUnlockScript(createUnlockScript(defaultTag, signature)); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("fail to unlock with the unknown key", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature = signEcdsa(hashWithoutScript.value, daveSecret); - - transfer.input(0)!.setLockScript(lockScript); - transfer - .input(0)! - .setUnlockScript(createUnlockScript(defaultTag, signature)); - - await expectTransactionFail(node, transfer); - }); - }); - - describe("2 of 3", async function() { - const lockScript = createLockScript( - 2, - 3, - alicePublic, - bobPublic, - carolPublic - ); - const lockScriptHash = new H160(blake160(lockScript)); - let recipient: AssetAddress; - let transfer: TransferAsset; - beforeEach(async function() { - recipient = AssetAddress.fromTypeAndPayload(0, lockScriptHash, { - networkId: node.sdk.networkId - }); - - const asset = await node.mintAsset({ supply: 1, recipient }); - - transfer = node.sdk.core - .createTransferAssetTransaction() - .addInputs(asset) - .addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - transfer.input(0)!.setLockScript(lockScript); - }); - - it("unlock with the first and the second key", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature1 = signEcdsa(hashWithoutScript.value, aliceSecret); - const signature2 = signEcdsa(hashWithoutScript.value, bobSecret); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(defaultTag, signature1, signature2) - ); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("unlock with the first and the third key", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature1 = signEcdsa(hashWithoutScript.value, aliceSecret); - const signature2 = signEcdsa(hashWithoutScript.value, carolSecret); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(defaultTag, signature1, signature2) - ); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("unlock with the second and the third key", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature1 = signEcdsa(hashWithoutScript.value, bobSecret); - const signature2 = signEcdsa(hashWithoutScript.value, carolSecret); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(defaultTag, signature1, signature2) - ); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("fail to unlock with the second and the first key - signature unordered", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature1 = signEcdsa(hashWithoutScript.value, bobSecret); - const signature2 = signEcdsa(hashWithoutScript.value, aliceSecret); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(defaultTag, signature1, signature2) - ); - - await expectTransactionFail(node, transfer); - }); - - it("fail to unlock with the third and the first key - signature unordered", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature1 = signEcdsa(hashWithoutScript.value, carolSecret); - const signature2 = signEcdsa(hashWithoutScript.value, aliceSecret); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(defaultTag, signature1, signature2) - ); - - await expectTransactionFail(node, transfer); - }); - - it("fail to unlock with the third and the second key - signature unordered", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature1 = signEcdsa(hashWithoutScript.value, carolSecret); - const signature2 = signEcdsa(hashWithoutScript.value, bobSecret); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(defaultTag, signature1, signature2) - ); - - await expectTransactionFail(node, transfer); - }); - - it("fail to unlock if the first key is unknown", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature1 = signEcdsa(hashWithoutScript.value, aliceSecret); - const signature2 = signEcdsa(hashWithoutScript.value, daveSecret); - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(defaultTag, signature1, signature2) - ); - - await expectTransactionFail(node, transfer); - }); - - it("fail to unlock if the second key is unknown", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature1 = signEcdsa(hashWithoutScript.value, daveSecret); - const signature2 = signEcdsa(hashWithoutScript.value, bobSecret); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(defaultTag, signature1, signature2) - ); - - await expectTransactionFail(node, transfer); - }); - - it("fail to unlock if the same key signs twice", async function() { - const hashWithoutScript = transfer.hashWithoutScript({ - tag: defaultTag, - type: "input", - index: 0 - }); - const signature1 = signEcdsa(hashWithoutScript.value, aliceSecret); - const signature2 = signEcdsa(hashWithoutScript.value, aliceSecret); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(defaultTag, signature1, signature2) - ); - - await expectTransactionFail(node, transfer); - }); - - describe("Test partial signing", async function() { - let additionalAsset: Asset; - beforeEach(async function() { - additionalAsset = await node.mintAsset({ - supply: 10, - recipient - }); - }); - it("fail to add inputs after sign with all inputs tag", async function() { - const tag: SignatureTag = { input: "all", output: [0] }; - const hashWithoutScript0 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 0 - }); - const signature0_1 = signEcdsa( - hashWithoutScript0.value, - aliceSecret - ); - const signature0_2 = signEcdsa( - hashWithoutScript0.value, - bobSecret - ); - - transfer.addInputs(additionalAsset).addOutputs({ - quantity: 10, - assetType: additionalAsset.assetType, - shardId: additionalAsset.shardId, - recipient: await node.createP2PKHAddress() - }); - transfer.input(1)!.setLockScript(lockScript); - const hashWithoutScript1 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 1 - }); - const signature1_1 = signEcdsa( - hashWithoutScript1.value, - bobSecret - ); - const signature1_2 = signEcdsa( - hashWithoutScript1.value, - carolSecret - ); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript( - defaultTag, - signature0_1, - signature0_2 - ) - ); - - transfer - .input(1)! - .setUnlockScript( - createUnlockScript( - defaultTag, - signature1_1, - signature1_2 - ) - ); - - await expectTransactionFail(node, transfer); - }); - - it("unlock with fixed inputs", async function() { - const tag: SignatureTag = { input: "all", output: [0] }; - transfer.addInputs(additionalAsset); - transfer.input(1)!.setLockScript(lockScript); - - const hashWithoutScript0 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 0 - }); - const signature0_1 = signEcdsa( - hashWithoutScript0.value, - aliceSecret - ); - const signatrue0_2 = signEcdsa( - hashWithoutScript0.value, - bobSecret - ); - - const hashWithoutScript1 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 1 - }); - const signature1_1 = signEcdsa( - hashWithoutScript1.value, - bobSecret - ); - const signature1_2 = signEcdsa( - hashWithoutScript1.value, - carolSecret - ); - - transfer.addOutputs({ - quantity: 10, - assetType: additionalAsset.assetType, - shardId: additionalAsset.shardId, - recipient: await node.createP2PKHAddress() - }); - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(tag, signature0_1, signatrue0_2) - ); - - transfer - .input(1)! - .setUnlockScript( - createUnlockScript(tag, signature1_1, signature1_2) - ); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("fail to add inputs after sign with all outputs tag", async function() { - const tag: SignatureTag = { input: "single", output: "all" }; - transfer.addInputs(additionalAsset); - transfer.input(1)!.setLockScript(lockScript); - - const hashWithoutScript0 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 0 - }); - const signature0_1 = signEcdsa( - hashWithoutScript0.value, - aliceSecret - ); - const signature0_2 = signEcdsa( - hashWithoutScript0.value, - bobSecret - ); - - transfer.addOutputs({ - quantity: 10, - assetType: additionalAsset.assetType, - shardId: additionalAsset.shardId, - recipient: await node.createP2PKHBurnAddress() - }); - - const hashWithoutScript1 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 1 - }); - const signature1_1 = signEcdsa( - hashWithoutScript1.value, - bobSecret - ); - const signature1_2 = signEcdsa( - hashWithoutScript1.value, - carolSecret - ); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(tag, signature0_1, signature0_2) - ); - - transfer - .input(1)! - .setUnlockScript( - createUnlockScript(tag, signature1_1, signature1_2) - ); - - await expectTransactionFail(node, transfer); - }); - - it("unlock with fixed outputs", async function() { - const tag: SignatureTag = { input: "single", output: "all" }; - transfer.addOutputs({ - quantity: 10, - assetType: additionalAsset.assetType, - shardId: additionalAsset.shardId, - recipient: await node.createP2PKHBurnAddress() - }); - - const hashWithoutScript0 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 0 - }); - const signature0_1 = signEcdsa( - hashWithoutScript0.value, - aliceSecret - ); - const signature0_2 = signEcdsa( - hashWithoutScript0.value, - bobSecret - ); - - transfer.addInputs(additionalAsset); - transfer.input(1)!.setLockScript(lockScript); - - const hashWithoutScript1 = transfer.hashWithoutScript({ - tag, - type: "input", - index: 1 - }); - const signature1_1 = signEcdsa( - hashWithoutScript1.value, - bobSecret - ); - const signature1_2 = signEcdsa( - hashWithoutScript1.value, - carolSecret - ); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(tag, signature0_1, signature0_2) - ); - - transfer - .input(1)! - .setUnlockScript( - createUnlockScript(tag, signature1_1, signature1_2) - ); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - - it("unlock with both outputs and inputs dynamic", async function() { - const tag0: SignatureTag = { input: "single", output: [0] }; - const tag1: SignatureTag = { input: "single", output: [1] }; - - const hashWithoutScript0 = transfer.hashWithoutScript({ - tag: tag0, - type: "input", - index: 0 - }); - const signature0_1 = signEcdsa( - hashWithoutScript0.value, - aliceSecret - ); - const signatrue0_2 = signEcdsa( - hashWithoutScript0.value, - bobSecret - ); - - transfer.addInputs(additionalAsset).addOutputs({ - quantity: 10, - assetType: additionalAsset.assetType, - shardId: additionalAsset.shardId, - recipient: await node.createP2PKHBurnAddress() - }); - transfer.input(1)!.setLockScript(lockScript); - - const hashWithoutScript1 = transfer.hashWithoutScript({ - tag: tag1, - type: "input", - index: 1 - }); - const signature1_1 = signEcdsa( - hashWithoutScript1.value, - bobSecret - ); - const signature1_2 = signEcdsa( - hashWithoutScript1.value, - carolSecret - ); - - transfer - .input(0)! - .setUnlockScript( - createUnlockScript(tag0, signature0_1, signatrue0_2) - ); - - transfer - .input(1)! - .setUnlockScript( - createUnlockScript(tag1, signature1_1, signature1_2) - ); - - const hash = await node.sendAssetTransaction(transfer); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - }); - }); - - afterEach(async function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - await node.clean(); - }); -}); diff --git a/test/src/e2e/partialSignature.test.ts b/test/src/e2e/partialSignature.test.ts deleted file mode 100644 index 19c3490c6e..0000000000 --- a/test/src/e2e/partialSignature.test.ts +++ /dev/null @@ -1,470 +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 { expect } from "chai"; -import { Asset, AssetAddress, H256 } from "codechain-sdk/lib/core/classes"; -import * as _ from "lodash"; -import "mocha"; -import CodeChain from "../helper/spawn"; - -describe("Partial signature", function() { - let node: CodeChain; - - before(async function() { - node = new CodeChain(); - await node.start(); - }); - - let assets: Asset[]; - let assetType: H256; - let address1: AssetAddress; - let address2: AssetAddress; - let burnAddress1: AssetAddress; - let burnAddress2: AssetAddress; - beforeEach(async function() { - address1 = await node.sdk.key.createAssetAddress({ - type: "P2PKH" - }); - address2 = await node.sdk.key.createAssetAddress({ - type: "P2PKH" - }); - burnAddress1 = await node.sdk.key.createAssetAddress({ - type: "P2PKHBurn" - }); - burnAddress2 = await node.sdk.key.createAssetAddress({ - type: "P2PKHBurn" - }); - const mintTx = node.sdk.core.createMintAssetTransaction({ - scheme: { - shardId: 0, - metadata: "", - supply: 4000 - }, - recipient: address1 - }); - const asset = mintTx.getMintedAsset(); - ({ assetType } = asset); - const transferTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(asset) - .addOutputs( - { - assetType, - quantity: 1000, - recipient: address1, - shardId: 0 - }, - { - assetType, - quantity: 1000, - recipient: address2, - shardId: 0 - }, - { - assetType, - quantity: 1000, - recipient: burnAddress1, - shardId: 0 - }, - { - assetType, - quantity: 1000, - recipient: burnAddress2, - shardId: 0 - } - ); - await node.sdk.key.signTransactionInput(transferTx, 0); - assets = transferTx.getTransferredAssets(); - await node.sendAssetTransaction(mintTx); - await node.sendAssetTransaction(transferTx); - }); - - it("Can't add burns after signing with the signature tag of all inputs", async function() { - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(assets[0]) - .addOutputs({ - assetType, - shardId: 0, - quantity: 1000, - recipient: address1 - }); - await node.sdk.key.signTransactionInput(tx, 0); - tx.addBurns(assets[2]); - await node.sdk.key.signTransactionBurn(tx, 0); - - await node.sendAssetTransactionExpectedToFail(tx); - }); - - it("Can add burns after signing with the signature tag of single input", async function() { - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(assets[0]) - .addOutputs({ - assetType, - shardId: 0, - quantity: 1000, - recipient: address1 - }); - await node.sdk.key.signTransactionInput(tx, 0, { - signatureTag: { input: "single", output: "all" } - }); - tx.addBurns(assets[2]); - await node.sdk.key.signTransactionBurn(tx, 0); - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - - it("Can't add inputs after signing with the signature tag of all inputs when signing burn", async function() { - const tx = node.sdk.core - .createTransferAssetTransaction() - .addBurns(assets[2]) - .addOutputs({ - assetType, - shardId: 0, - quantity: 1000, - recipient: address1 - }); - await node.sdk.key.signTransactionBurn(tx, 0); - tx.addInputs(assets[0]); - await node.sdk.key.signTransactionInput(tx, 0); - - await node.sendAssetTransactionExpectedToFail(tx); - }); - - it("Can add inputs after signing with the signature tag of signle input when signing burn", async function() { - const tx = node.sdk.core - .createTransferAssetTransaction() - .addBurns(assets[2]) - .addOutputs({ - assetType, - shardId: 0, - quantity: 1000, - recipient: address1 - }); - await node.sdk.key.signTransactionBurn(tx, 0, { - signatureTag: { input: "single", output: "all" } - }); - tx.addInputs(assets[0]); - await node.sdk.key.signTransactionInput(tx, 0); - - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - - // FIXME: (WIP) It fails - it("Can't add inputs after signing with the signature tag of all inputs", async function() { - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(assets[0]) - .addOutputs({ - assetType, - shardId: 0, - quantity: 2000, - recipient: address1 - }); - await node.sdk.key.signTransactionInput(tx, 0); - tx.addInputs(assets[1]); - await node.sdk.key.signTransactionInput(tx, 1); - - await node.sendAssetTransactionExpectedToFail(tx); - }); - - it("Can add inputs after signing with the signature tag of single input", async function() { - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(assets[0]) - .addOutputs({ - assetType, - shardId: 0, - quantity: 2000, - recipient: address1 - }); - await node.sdk.key.signTransactionInput(tx, 0, { - signatureTag: { input: "single", output: "all" } - }); - tx.addInputs(assets[1]); - await node.sdk.key.signTransactionInput(tx, 1); - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - - it("Can't add outputs after signing the signature tag of all outputs", async function() { - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(assets[0]) - .addOutputs({ - assetType, - shardId: 0, - quantity: 500, - recipient: address1 - }); - await node.sdk.key.signTransactionInput(tx, 0); - tx.addOutputs({ - assetType, - shardId: 0, - quantity: 500, - recipient: address2 - }); - - await node.sendAssetTransactionExpectedToFail(tx); - }); - - it("Can add outputs after signing the signature tag of some outputs", async function() { - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(assets[0]) - .addOutputs({ - assetType, - shardId: 0, - quantity: 500, - recipient: address1 - }); - await node.sdk.key.signTransactionInput(tx, 0, { - signatureTag: { - input: "all", - output: [0] - } - }); - tx.addOutputs({ - assetType, - shardId: 0, - quantity: 500, - recipient: address2 - }); - - const blockNumber = await node.getBestBlockNumber(); - const hash = await node.sendAssetTransaction(tx); - await node.waitBlockNumber(blockNumber + 1); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - - it("Can only change the output protected by signature", async function() { - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(assets[0]) - .addOutputs( - { - assetType, - shardId: 0, - quantity: 500, - recipient: address1 - }, - { - assetType, - shardId: 0, - quantity: 500, - recipient: address2 - } - ); - await node.sdk.key.signTransactionInput(tx, 0, { - signatureTag: { - input: "all", - output: [0] - } - }); - const address1Param = (tx as any)._transaction.outputs[0].parameters; - const address2Param = (tx as any)._transaction.outputs[1].parameters; - ((tx as any)._transaction.outputs[0].parameters as any) = address2Param; - - await node.sendAssetTransactionExpectedToFail(tx); - - ((tx as any)._transaction.outputs[0].parameters as any) = address1Param; - // FIXME - (tx as any)._fee = null; - (tx as any)._seq = null; - await node.sdk.key.signTransactionInput(tx, 0, { - signatureTag: { - input: "all", - output: [0] - } - }); - - ((tx as any)._transaction.outputs[1].parameters as any) = address1Param; - const hash2 = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash2)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash2)).be.true; - }); - - describe("many outputs", function() { - [5, 10, 100, 504].forEach(function(length) { - it(`${length} + 1 outputs`, async function() { - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(assets[0]) - .addOutputs( - _.times(length, () => ({ - assetType, - shardId: 0, - quantity: 1, - recipient: address1 - })) - ); - - await node.sdk.key.signTransactionInput(tx, 0, { - signatureTag: { - input: "all", - output: _.range(length) - } - }); - tx.addOutputs({ - assetType, - shardId: 0, - quantity: 1000 - length, - recipient: address1 - }); - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - }).timeout(length * 10 + 5_000); - }); - }); - - describe("dynamic inputs and outputs", function() { - let splitedAssets: Asset[]; - const splitCount = 50; - - beforeEach(async function() { - const splitTx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(assets[0]) - .addOutputs( - _.times(splitCount, () => ({ - assetType, - shardId: 0, - quantity: 1000 / splitCount, - recipient: address1 - })) - ); - - await node.sdk.key.signTransactionInput(splitTx, 0); - splitedAssets = splitTx.getTransferredAssets(); - await node.sendAssetTransaction(splitTx); - }); - [5, 10, 20].forEach(function(length) { - it(`${length} inputs and outputs : one-to-one sign`, async function() { - const tx = node.sdk.core.createTransferAssetTransaction(); - for (let i = 0; i < length; i++) { - tx.addInputs(splitedAssets[i]).addOutputs({ - assetType, - shardId: 0, - quantity: 1000 / splitCount, - recipient: address2 - }); - await node.sdk.key.signTransactionInput(tx, i, { - signatureTag: { - input: "single", - output: [i] - } - }); - } - - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - }).timeout(length * 1000 + 5_000); - }); - - [5, 10, 20].forEach(function(length) { - it(`${length} inputs and outputs : one-to-many sign`, async function() { - const tx = node.sdk.core.createTransferAssetTransaction(); - for (let i = 0; i < length; i++) { - tx.addInputs(splitedAssets[i]).addOutputs({ - assetType, - shardId: 0, - quantity: 1000 / splitCount, - recipient: address2 - }); - await node.sdk.key.signTransactionInput(tx, i, { - signatureTag: { - input: "single", - output: _.range(i) - } - }); - } - - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - }).timeout(length * 1000 + 5_000); - }); - - [5, 10, 20].forEach(function(length) { - it(`${length} burns, inputs and outputs : one-to-many sign`, async function() { - const tx = node.sdk.core.createTransferAssetTransaction(); - for (let i = 0; i < Math.floor(length / 2); i++) { - tx.addInputs(splitedAssets[i]).addOutputs({ - assetType, - shardId: 0, - quantity: 1000 / splitCount, - recipient: address2 - }); - await node.sdk.key.signTransactionInput(tx, i, { - signatureTag: { - input: "single", - output: _.range(i) - } - }); - } - - tx.addBurns(assets[2]); - await node.sdk.key.signTransactionBurn(tx, 0, { - signatureTag: { - input: "single", - output: _.range(Math.floor(length / 2)) - } - }); - - for (let i = Math.floor(length / 2); i < length; i++) { - tx.addInputs(splitedAssets[i]).addOutputs({ - assetType, - shardId: 0, - quantity: 1000 / splitCount, - recipient: address2 - }); - await node.sdk.key.signTransactionInput(tx, i, { - signatureTag: { - input: "single", - output: _.range(i) - } - }); - } - - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - }).timeout(length * 1000 + 5_000); - }); - }); - - afterEach(function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - }); - - after(async function() { - await node.clean(); - }); -}); diff --git a/test/src/e2e/shard.test.ts b/test/src/e2e/shard.test.ts deleted file mode 100644 index fcd8e235ab..0000000000 --- a/test/src/e2e/shard.test.ts +++ /dev/null @@ -1,462 +0,0 @@ -// Copyright 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 * as chai from "chai"; -import * as chaiAsPromised from "chai-as-promised"; -chai.use(chaiAsPromised); -import "mocha"; -import { - aliceAddress, - aliceSecret, - bobAddress, - bobSecret, - faucetAddress, - faucetSecret -} from "../helper/constants"; -import CodeChain from "../helper/spawn"; - -const expect = chai.expect; - -describe.skip("CreateShard", function() { - let node: CodeChain; - before(async function() { - node = new CodeChain({ argv: ["--allow-create-shard"] }); - await node.start(); - }); - - it("Create 1 shard", async function() { - const seq: number = (await node.sdk.rpc.chain.getSeq(faucetAddress))!; - - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ recipient: aliceAddress, quantity: 1 }) - .sign({ secret: faucetSecret, seq, fee: 10 }) - ); - - const tx = node.sdk.core - .createCreateShardTransaction({ users: [aliceAddress] }) - .sign({ secret: faucetSecret, seq: seq + 1, fee: 10 }); - const beforeBlockNumber = await node.sdk.rpc.chain.getBestBlockNumber(); - expect( - await node.sdk.rpc.sendRpcRequest("chain_getShardIdByHash", [ - tx.hash(), - null - ]) - ).to.be.null; - await node.sdk.rpc.chain.sendSignedTransaction(tx); - expect(await node.sdk.rpc.chain.containsTransaction(tx.hash())).be.true; - expect(await node.sdk.rpc.chain.getTransaction(tx.hash())).not.null; - const afterShardId = await node.sdk.rpc.sendRpcRequest( - "chain_getShardIdByHash", - [tx.hash(), null] - ); - expect(afterShardId).not.to.be.null; - - const shardOwners = await node.sdk.rpc.sendRpcRequest( - "chain_getShardOwners", - [afterShardId, null] - ); - expect(shardOwners).to.deep.equal([faucetAddress.value]); // The creator becomes the owner. - const shardUsers = await node.sdk.rpc.sendRpcRequest( - "chain_getShardUsers", - [afterShardId, null] - ); - expect(shardUsers).to.deep.equal([aliceAddress.value]); - - expect( - await node.sdk.rpc.sendRpcRequest("chain_getShardOwners", [ - afterShardId, - beforeBlockNumber - ]) - ).to.be.null; - expect( - await node.sdk.rpc.sendRpcRequest("chain_getShardUsers", [ - afterShardId, - beforeBlockNumber - ]) - ).to.be.null; - }); - - it("setShardUsers", async function() { - const seq: number = (await node.sdk.rpc.chain.getSeq(faucetAddress))!; - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ recipient: aliceAddress, quantity: 1 }) - .sign({ secret: faucetSecret, seq, fee: 10 }) - ); - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ recipient: bobAddress, quantity: 1 }) - .sign({ secret: faucetSecret, seq: seq + 1, fee: 10 }) - ); - - const tx = node.sdk.core - .createCreateShardTransaction({ users: [aliceAddress] }) - .sign({ secret: faucetSecret, seq: seq + 2, fee: 10 }); - await node.sdk.rpc.chain.sendSignedTransaction(tx); - const shardId = await node.sdk.rpc.sendRpcRequest( - "chain_getShardIdByHash", - [tx.hash(), null] - ); - - const users = [aliceAddress, bobAddress]; - const setShardUsers = node.sdk.core - .createSetShardUsersTransaction({ shardId, users }) - .sign({ secret: faucetSecret, seq: seq + 3, fee: 10 }); - await node.sdk.rpc.chain.sendSignedTransaction(setShardUsers); - const shardUsers = await node.sdk.rpc.sendRpcRequest( - "chain_getShardUsers", - [shardId, null] - ); - expect(shardUsers).to.deep.equal(users.map(user => user.value)); - }); - - it("setShardOwners", async function() { - const seq: number = (await node.sdk.rpc.chain.getSeq(faucetAddress))!; - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ recipient: aliceAddress, quantity: 1 }) - .sign({ secret: faucetSecret, seq, fee: 10 }) - ); - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ recipient: bobAddress, quantity: 1 }) - .sign({ secret: faucetSecret, seq: seq + 1, fee: 10 }) - ); - const tx = node.sdk.core - .createCreateShardTransaction({ users: [aliceAddress, bobAddress] }) - .sign({ secret: faucetSecret, seq: seq + 2, fee: 10 }); - await node.sdk.rpc.chain.sendSignedTransaction(tx); - const shardId = await node.sdk.rpc.sendRpcRequest( - "chain_getShardIdByHash", - [tx.hash(), null] - ); - - const owners = [aliceAddress, faucetAddress, bobAddress]; - const setShardOwners = node.sdk.core - .createSetShardOwnersTransaction({ shardId, owners }) - .sign({ secret: faucetSecret, seq: seq + 3, fee: 10 }); - await node.sdk.rpc.chain.sendSignedTransaction(setShardOwners); - const shardOwners = await node.sdk.rpc.sendRpcRequest( - "chain_getShardOwners", - [shardId, null] - ); - expect(shardOwners).to.deep.equal(owners.map(owner => owner.value)); - }); - - it("Create 2 shards", async function() { - const seq: number = (await node.sdk.rpc.chain.getSeq(faucetAddress))!; - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ recipient: aliceAddress, quantity: 1 }) - .sign({ secret: faucetSecret, seq, fee: 10 }) - ); - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ recipient: bobAddress, quantity: 1 }) - .sign({ secret: faucetSecret, seq: seq + 1, fee: 10 }) - ); - const tx1 = node.sdk.core - .createCreateShardTransaction({ users: [aliceAddress, bobAddress] }) - .sign({ secret: faucetSecret, seq: seq + 2, fee: 10 }); - expect( - await node.sdk.rpc.sendRpcRequest("chain_getShardIdByHash", [ - tx1.hash(), - null - ]) - ).to.be.null; - await node.sdk.rpc.chain.sendSignedTransaction(tx1); - expect(await node.sdk.rpc.chain.containsTransaction(tx1.hash())).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(tx1.hash())).not.null; - expect( - await node.sdk.rpc.sendRpcRequest("chain_getShardIdByHash", [ - tx1.hash(), - null - ]) - ).not.to.be.null; - - const tx2 = node.sdk.core - .createCreateShardTransaction({ users: [aliceAddress, bobAddress] }) - .sign({ secret: faucetSecret, seq: seq + 3, fee: 10 }); - expect( - await node.sdk.rpc.sendRpcRequest("chain_getShardIdByHash", [ - tx2.hash(), - null - ]) - ).to.be.null; - await node.sdk.rpc.chain.sendSignedTransaction(tx2); - expect(await node.sdk.rpc.chain.containsTransaction(tx2.hash())).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(tx2.hash())).not.null; - expect( - await node.sdk.rpc.sendRpcRequest("chain_getShardIdByHash", [ - tx2.hash(), - null - ]) - ).not.to.be.null; - }); - - it("non-user cannot mint", async function() { - const faucetSeq: number = (await node.sdk.rpc.chain.getSeq( - faucetAddress - ))!; - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ recipient: aliceAddress, quantity: 1 }) - .sign({ secret: faucetSecret, seq: faucetSeq, fee: 10 }) - ); - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ recipient: bobAddress, quantity: 1 }) - .sign({ secret: faucetSecret, seq: faucetSeq + 1, fee: 10 }) - ); - const createShard = node.sdk.core - .createCreateShardTransaction({ users: [aliceAddress] }) - .sign({ secret: faucetSecret, seq: faucetSeq + 2, fee: 10 }); - await node.sdk.rpc.chain.sendSignedTransaction(createShard); - const shardId = await node.sdk.rpc.sendRpcRequest( - "chain_getShardIdByHash", - [createShard.hash(), null] - ); - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ - recipient: bobAddress, - quantity: 100 - }) - .sign({ secret: faucetSecret, seq: faucetSeq + 3, fee: 10 }) - ); - - const bobSeq: number = (await node.sdk.rpc.chain.getSeq(bobAddress))!; - const pay = node.sdk.core - .createPayTransaction({ - recipient: aliceAddress, - quantity: 1 - }) - .sign({ secret: bobSecret, seq: bobSeq, fee: 10 }); - const mint = node.sdk.core - .createMintAssetTransaction({ - scheme: { - shardId, - metadata: "", - supply: "0xa" - }, - recipient: await node.createP2PKHAddress() - }) - .sign({ secret: bobSecret, seq: bobSeq + 1, fee: 10 }); - - await node.sdk.rpc.devel.stopSealing(); - const blockNumber = await node.sdk.rpc.chain.getBestBlockNumber(); - await node.sdk.rpc.chain.sendSignedTransaction(pay); - await node.sdk.rpc.chain.sendSignedTransaction(mint); - await node.sdk.rpc.devel.startSealing(); - await node.waitBlockNumber(blockNumber + 1); - - const hint = await node.sdk.rpc.chain.getErrorHint(mint.hash()); - expect(hint).includes("permission"); - }); - - it("user can mint", async function() { - const faucetSeq: number = (await node.sdk.rpc.chain.getSeq( - faucetAddress - ))!; - const createShard = node.sdk.core - .createCreateShardTransaction({ users: [aliceAddress] }) - .sign({ secret: faucetSecret, seq: faucetSeq, fee: 10 }); - await node.sdk.rpc.chain.sendSignedTransaction(createShard); - const shardId = await node.sdk.rpc.sendRpcRequest( - "chain_getShardIdByHash", - [createShard.hash(), null] - ); - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ - recipient: aliceAddress, - quantity: 100 - }) - .sign({ secret: faucetSecret, seq: faucetSeq + 1, fee: 10 }) - ); - - const aliceSeq: number = (await node.sdk.rpc.chain.getSeq( - aliceAddress - ))!; - const mint = node.sdk.core - .createMintAssetTransaction({ - scheme: { - shardId, - metadata: "", - supply: "0xa" - }, - recipient: await node.createP2PKHAddress() - }) - .sign({ secret: aliceSecret, seq: aliceSeq, fee: 10 }); - await node.sdk.rpc.chain.sendSignedTransaction(mint); - - expect(await node.sdk.rpc.chain.containsTransaction(mint.hash())).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(mint.hash())).not.null; - const hint = await node.sdk.rpc.chain.getErrorHint(mint.hash()); - expect(hint).to.be.null; - }); - - it("non-user can mint after becoming a user", async function() { - const faucetSeq: number = (await node.sdk.rpc.chain.getSeq( - faucetAddress - ))!; - const createShard = node.sdk.core - .createCreateShardTransaction({ users: [aliceAddress] }) - .sign({ secret: faucetSecret, seq: faucetSeq, fee: 10 }); - await node.sdk.rpc.chain.sendSignedTransaction(createShard); - const shardId = await node.sdk.rpc.sendRpcRequest( - "chain_getShardIdByHash", - [createShard.hash(), null] - ); - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ - recipient: bobAddress, - quantity: 100 - }) - .sign({ secret: faucetSecret, seq: faucetSeq + 1, fee: 10 }) - ); - - const bobSeq: number = (await node.sdk.rpc.chain.getSeq(bobAddress))!; - const recipient = await node.createP2PKHAddress(); - const mint1 = node.sdk.core.createMintAssetTransaction({ - scheme: { - shardId, - metadata: "", - supply: "0xa" - }, - recipient - }); - const signedMint1 = mint1.sign({ - secret: bobSecret, - seq: bobSeq + 1, - fee: 30 - }); - - const blockNumber = await node.sdk.rpc.chain.getBestBlockNumber(); - await node.sdk.rpc.devel.stopSealing(); - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ - recipient: aliceAddress, - quantity: 1 - }) - .sign({ - secret: bobSecret, - seq: bobSeq, - fee: 10 - }) - ); - await node.sdk.rpc.chain.sendSignedTransaction(signedMint1); - await node.sdk.rpc.devel.startSealing(); - await node.waitBlockNumber(blockNumber + 1); - expect( - await node.sdk.rpc.chain.getTransactionResultsByTracker( - mint1.tracker() - ) - ).deep.equal([false]); - const hint = await node.sdk.rpc.chain.getErrorHint(signedMint1.hash()); - expect(hint).includes("permission"); - - const newUsers = [aliceAddress, bobAddress]; - const setShardUsers = node.sdk.core - .createSetShardUsersTransaction({ shardId, users: newUsers }) - .sign({ secret: faucetSecret, seq: faucetSeq + 2, fee: 10 }); - await node.sdk.rpc.chain.sendSignedTransaction(setShardUsers); - const shardUsers = await node.sdk.rpc.sendRpcRequest( - "chain_getShardUsers", - [shardId, null] - ); - expect(shardUsers).to.deep.equal(newUsers.map(user => user.value)); - - const mint2 = node.sdk.core.createMintAssetTransaction({ - scheme: { - shardId, - metadata: "", - supply: "0xa" - }, - recipient - }); - expect(mint1.tracker().value).equal(mint2.tracker().value); - const signedMint2 = mint2.sign({ - secret: bobSecret, - seq: bobSeq + 1, - fee: 20 - }); - await node.sdk.rpc.chain.sendSignedTransaction(signedMint2); - - expect(await node.sdk.rpc.chain.containsTransaction(signedMint2.hash())) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(signedMint2.hash())).not - .null; - expect( - await node.sdk.rpc.chain.getTransactionResultsByTracker( - mint2.tracker() - ) - ).deep.equal([false, true]); - expect(await node.sdk.rpc.chain.getErrorHint(signedMint2.hash())).to.be - .null; - }); - - after(async function() { - await node.clean(); - }); -}); - -describe.skip("Cannot create shard without allow-create-shard flag", function() { - let node: CodeChain; - before(async function() { - node = new CodeChain(); - await node.start(); - }); - - it("Create 1 shard", async function() { - const seq: number = (await node.sdk.rpc.chain.getSeq(faucetAddress))!; - - await node.sdk.rpc.chain.sendSignedTransaction( - node.sdk.core - .createPayTransaction({ recipient: aliceAddress, quantity: 1 }) - .sign({ secret: faucetSecret, seq, fee: 10 }) - ); - - const tx = node.sdk.core - .createCreateShardTransaction({ users: [aliceAddress] }) - .sign({ secret: faucetSecret, seq: seq + 1, fee: 10 }); - expect( - await node.sdk.rpc.sendRpcRequest("chain_getShardIdByHash", [ - tx.hash(), - null - ]) - ).be.null; - expect(node.sdk.rpc.chain.sendSignedTransaction(tx)).be.rejected; - expect(await node.sdk.rpc.chain.containsTransaction(tx.hash())).be - .false; - expect(await node.sdk.rpc.chain.getTransaction(tx.hash())).be.null; - const afterShardId = await node.sdk.rpc.sendRpcRequest( - "chain_getShardIdByHash", - [tx.hash(), null] - ); - expect(afterShardId).be.null; - }); - - after(async function() { - await node.clean(); - }); -}); diff --git a/test/src/e2e/transactionResult.test.ts b/test/src/e2e/transactionResult.test.ts deleted file mode 100644 index 62b0d9dd2b..0000000000 --- a/test/src/e2e/transactionResult.test.ts +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 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 { expect } from "chai"; -import "mocha"; -import { aliceAddress, faucetAddress, faucetSecret } from "../helper/constants"; -import CodeChain from "../helper/spawn"; - -describe("transaction result", function() { - let node: CodeChain; - before(async function() { - node = new CodeChain(); - await node.start(); - }); - - it("of Mint Asset", async function() { - const recipient = await node.createP2PKHAddress(); - const mint = node.sdk.core.createMintAssetTransaction({ - scheme: { - shardId: 0, - metadata: "", - supply: "0xa" - }, - recipient - }); - const signedMint = mint.sign({ - secret: faucetSecret, - fee: 10, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress) - }); - - await node.sdk.rpc.chain.sendSignedTransaction(signedMint); - - expect( - await node.sdk.rpc.chain.getTransactionResultsByTracker( - mint.tracker() - ) - ).deep.equal([true]); - expect(await node.sdk.rpc.chain.containsTransaction(signedMint.hash())) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(signedMint.hash())).not - .null; - - const bestBlockNumber = await node.sdk.rpc.chain.getBestBlockNumber(); - const bestBlock = (await node.sdk.rpc.chain.getBlock(bestBlockNumber))!; - expect(bestBlock).not.to.be.null; - }); - - it("of Transfer Asset", async function() { - const blockNumberBeforeTx = await node.sdk.rpc.chain.getBestBlockNumber(); - const mint = node.sdk.core.createMintAssetTransaction({ - scheme: { - shardId: 0, - metadata: "", - supply: "0xa" - }, - recipient: await node.createP2PKHAddress() - }); - - const asset = mint.getMintedAsset(); - const recipient = await node.createP2PKHAddress(); - const transfer1 = node.sdk.core.createTransferAssetTransaction(); - transfer1.addInputs(asset); - transfer1.addOutputs({ - assetType: asset.assetType, - shardId: asset.shardId, - recipient, - quantity: 10 - }); - await node.signTransactionInput(transfer1, 0); - const transfer2 = node.sdk.core.createTransferAssetTransaction(); - transfer2.addInputs(asset); - transfer2.addOutputs({ - assetType: asset.assetType, - shardId: asset.shardId, - recipient, - quantity: 10 - }); - await node.signTransactionInput(transfer2, 0); - - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - const signedPay = node.sdk.core - .createPayTransaction({ recipient: aliceAddress, quantity: 1 }) - .sign({ - secret: faucetSecret, - fee: 10, - seq - }); - const signedTransfer1 = transfer1.sign({ - secret: faucetSecret, - fee: 10, - seq: seq + 1 - }); - const signedMint = mint.sign({ - secret: faucetSecret, - fee: 10, - seq: seq + 1 - }); - const signedTransfer2 = transfer2.sign({ - secret: faucetSecret, - fee: 10, - seq: seq + 2 - }); - - await node.sdk.rpc.devel.stopSealing(); - // Send pay because the miner doesn't allow the empty block. - await node.sdk.rpc.chain.sendSignedTransaction(signedPay); - await node.sdk.rpc.chain.sendSignedTransaction(signedTransfer1); - await node.sdk.rpc.devel.startSealing(); - await node.waitBlockNumber(blockNumberBeforeTx + 1); - - await node.sdk.rpc.devel.stopSealing(); - await node.sdk.rpc.chain.sendSignedTransaction(signedMint); - await node.sdk.rpc.chain.sendSignedTransaction(signedTransfer2); - await node.sdk.rpc.devel.startSealing(); - await node.waitBlockNumber(blockNumberBeforeTx + 2); - - expect( - await node.sdk.rpc.chain.getTransactionResultsByTracker( - mint.tracker() - ) - ).deep.equal([true]); - - expect( - await node.sdk.rpc.chain.getTransactionResultsByTracker( - transfer2.tracker() - ) - ).deep.equal([false, true]); - - expect( - await node.sdk.rpc.chain.containsTransaction(signedTransfer1.hash()) - ).be.false; - expect(await node.sdk.rpc.chain.getErrorHint(signedTransfer1.hash())) - .not.null; - - expect(await node.sdk.rpc.chain.containsTransaction(signedMint.hash())) - .be.true; - expect(await node.sdk.rpc.chain.getTransaction(signedMint.hash())).not - .null; - - expect( - await node.sdk.rpc.chain.containsTransaction(signedTransfer2.hash()) - ).be.true; - expect(await node.sdk.rpc.chain.getTransaction(signedTransfer2.hash())) - .not.null; - - const block1 = (await node.sdk.rpc.chain.getBlock( - blockNumberBeforeTx + 1 - ))!; - expect(block1).not.to.be.null; - expect(block1.transactions.length).to.equal(1); - expect(block1.transactions[0].hash().value).to.equal( - signedPay.hash().value - ); - - const block2 = (await node.sdk.rpc.chain.getBlock( - blockNumberBeforeTx + 2 - ))!; - expect(block2).not.to.be.null; - expect(block2.transactions.length).to.equal(2); - expect(block2.transactions[0].hash().value).to.equal( - signedMint.hash().value - ); - expect(block2.transactions[1].hash().value).to.equal( - signedTransfer2.hash().value - ); - }); - - after(async function() { - await node.clean(); - }); -}); diff --git a/test/src/e2e/transferAsset.test.ts b/test/src/e2e/transferAsset.test.ts deleted file mode 100644 index 96f95adc10..0000000000 --- a/test/src/e2e/transferAsset.test.ts +++ /dev/null @@ -1,412 +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 { Buffer } from "buffer"; -import { expect } from "chai"; -import { - Asset, - AssetAddress, - H160, - PlatformAddress, - Script, - TransferAsset -} from "codechain-sdk/lib/core/classes"; -import { P2PKH } from "codechain-sdk/lib/key/P2PKH"; -import { blake160 } from "codechain-sdk/lib/utils"; -import * as _ from "lodash"; -import "mocha"; -import { ERROR } from "../helper/error"; -import CodeChain from "../helper/spawn"; - -describe("TransferAsset", function() { - let node: CodeChain; - before(async function() { - node = new CodeChain(); - await node.start(); - }); - - describe("1 input (100 quantity)", async function() { - let input: Asset; - const amount = 100; - - beforeEach(async function() { - const asset = await node.mintAsset({ supply: amount }); - input = asset; - }); - - [[100], [99, 1], [1, 99], Array(100).fill(1)].forEach(function( - amounts - ) { - it(`output amount list: ${amounts}`, async function() { - const recipient = await node.createP2PKHAddress(); - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs(input); - tx.addOutputs( - amounts.map(quantity => ({ - assetType: input.assetType, - shardId: input.shardId, - recipient, - quantity - })) - ); - await node.signTransactionInput(tx, 0); - - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - }); - }); - - [[0], [99], [101], [100, 100]].forEach(function(amounts) { - it(`InconsistentTransactionInOut - output amount list: ${amounts}`, async function() { - const recipient = await node.createP2PKHAddress(); - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs(input); - tx.addOutputs( - amounts.map(quantity => ({ - assetType: input.assetType, - shardId: input.shardId, - recipient, - quantity - })) - ); - await node.signTransactionInput(tx, 0); - try { - await node.sendAssetTransaction(tx); - expect.fail(); - } catch (e) { - expect(e).is.similarTo( - ERROR.INVALID_TX_INCONSISTENT_IN_OUT - ); - } - }); - }); - - it("unsuccessful(ZeroAmount) - output amount list: [100, 0]", async function() { - const amounts = [100, 0]; - const recipient = await node.createP2PKHAddress(); - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs(input); - tx.addOutputs( - amounts.map(quantity => ({ - assetType: input.assetType, - shardId: input.shardId, - recipient, - quantity - })) - ); - await node.signTransactionInput(tx, 0); - try { - await node.sendAssetTransaction(tx); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_TX_ZERO_QUANTITY); - } - }); - - it("unsuccessful - wrong asset type", async function() { - const recipient = await node.createP2PKHAddress(); - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs(input); - tx.addOutputs({ - assetType: H160.zero(), - shardId: input.shardId, - recipient, - quantity: amount - }); - await node.signTransactionInput(tx, 0); - try { - await node.sendAssetTransaction(tx); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_TX_INCONSISTENT_IN_OUT); - } - }); - - it("unsuccessful - previous output is duplicated", async function() { - const recipient = await node.createP2PKHAddress(); - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs(input, input); - tx.addOutputs({ - assetType: input.assetType, - shardId: input.shardId, - recipient, - quantity: amount * 2 - }); - await node.signTransactionInput(tx, 0); - try { - await node.sendAssetTransaction(tx); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_TX_DUPLICATED_PREV_OUT); - } - }); - }); - - describe("2 different types of input (10 amount, 20 amount)", async function() { - let input1: Asset; - let input2: Asset; - const amount1 = 10; - const amount2 = 20; - - beforeEach(async function() { - let asset = await node.mintAsset({ supply: amount1 }); - input1 = asset; - asset = await node.mintAsset({ supply: amount2 }); - input2 = asset; - }); - - [ - { input1Amounts: [10], input2Amounts: [20] }, - { input1Amounts: [5, 5], input2Amounts: [10, 10] }, - { - input1Amounts: [1, 1, 1, 1, 1, 5], - input2Amounts: [1, 1, 1, 1, 1, 5, 10] - } - ].forEach(function(params: { - input1Amounts: number[]; - input2Amounts: number[]; - }) { - const { input1Amounts, input2Amounts } = params; - - it(`asset1 ${input1Amounts}, asset2 ${input2Amounts}`, async function() { - const recipient = await node.createP2PKHAddress(); - const tx = node.sdk.core.createTransferAssetTransaction(); - tx.addInputs(_.shuffle([input1, input2])); - tx.addOutputs( - _.shuffle([ - ...input1Amounts.map(amount => ({ - assetType: input1.assetType, - shardId: input1.shardId, - recipient, - quantity: amount - })), - ...input2Amounts.map(amount => ({ - assetType: input2.assetType, - shardId: input2.shardId, - recipient, - quantity: amount - })) - ]) - ); - await node.signTransactionInput(tx, 0); - await node.signTransactionInput(tx, 1); - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be - .true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - }); - }); - }); - - it("Nonexistent assetType", async function() { - const asset = await node.mintAsset({ supply: 1 }); - const assetType = new H160("0000000000000000000000000000000000123456"); - const transferAsset = node.sdk.core.createTransferAssetTransaction(); - const input = node.sdk.core.createAssetTransferInput({ - assetOutPoint: { - tracker: asset.outPoint.tracker, - index: asset.outPoint.index, - assetType, - shardId: asset.shardId, - quantity: asset.quantity, - lockScriptHash: asset.outPoint.lockScriptHash, - parameters: asset.outPoint.parameters - } - }); - transferAsset.addInputs(input); - const recipient = await node.sdk.key.createAssetAddress(); - transferAsset.addOutputs({ - quantity: asset.quantity, - assetType, - shardId: 0, - recipient - }); - await node.signTransactionInput(transferAsset, 0); - await node.sendAssetTransactionExpectedToFail(transferAsset); - }); - - describe("ScriptError", function() { - it("Cannot transfer with invalid unlock script", async function() { - const Opcode = Script.Opcode; - const asset = await node.mintAsset({ supply: 1 }); - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(asset) - .addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - tx.input(0)!.setLockScript(P2PKH.getLockScript()); - tx.input(0)!.setUnlockScript(Buffer.from([Opcode.NOP])); // Invalid Opcode for unlock_script - - await node.sendAssetTransactionExpectedToFail(tx); - }); - - it("Cannot transfer trivially fail script", async function() { - const triviallyFail = Buffer.from([0x03]); // Opcode.FAIL - const asset = await node.mintAsset({ - supply: 1, - recipient: AssetAddress.fromTypeAndPayload( - 0, - blake160(triviallyFail), - { - networkId: "tc" - } - ) - }); - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(asset) - .addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - tx.input(0)!.setLockScript(triviallyFail); - tx.input(0)!.setUnlockScript(Buffer.from([])); - - await node.sendAssetTransactionExpectedToFail(tx); - }); - - it("Can transfer trivially success script", async function() { - const Opcode = Script.Opcode; - const triviallySuccess = Buffer.from([Opcode.PUSH, 1]); - const asset = await node.mintAsset({ - supply: 1, - recipient: AssetAddress.fromTypeAndPayload( - 0, - blake160(triviallySuccess), - { - networkId: "tc" - } - ) - }); - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(asset) - .addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - tx.input(0)!.setLockScript(triviallySuccess); - tx.input(0)!.setUnlockScript(Buffer.from([])); - - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - - it("Cannot transfer when lock script left multiple values in stack", async function() { - const Opcode = Script.Opcode; - const leaveMultipleValue = Buffer.from([ - Opcode.PUSH, - 1, - Opcode.DUP - ]); - const asset = await node.mintAsset({ - supply: 1, - recipient: AssetAddress.fromTypeAndPayload( - 0, - blake160(leaveMultipleValue), - { - networkId: "tc" - } - ) - }); - const tx = node.sdk.core - .createTransferAssetTransaction() - .addInputs(asset) - .addOutputs({ - quantity: 1, - assetType: asset.assetType, - shardId: asset.shardId, - recipient: await node.createP2PKHAddress() - }); - tx.input(0)!.setLockScript(leaveMultipleValue); - tx.input(0)!.setUnlockScript(Buffer.from([])); - - await node.sendAssetTransactionExpectedToFail(tx); - }); - }); - - describe("approver", function() { - let approver: PlatformAddress; - let nonApprover: PlatformAddress; - let transferTx: TransferAsset; - before(async function() { - approver = await node.createPlatformAddress(); - nonApprover = await node.createPlatformAddress(); - await node.pay(approver, 10000); - await node.pay(nonApprover, 10000); - }); - - beforeEach(async function() { - const recipient = await node.createP2PKHAddress(); - const tx = node.sdk.core.createMintAssetTransaction({ - scheme: { - shardId: 0, - metadata: "", - supply: 10000, - approver - }, - recipient - }); - await node.sendAssetTransaction(tx); - const asset = await node.sdk.rpc.chain.getAsset(tx.tracker(), 0, 0); - if (asset === null) { - throw Error(`Failed to mint an asset`); - } - transferTx = node.sdk.core.createTransferAssetTransaction(); - transferTx.addInputs(asset); - transferTx.addOutputs({ - assetType: asset.assetType, - shardId: asset.shardId, - quantity: 10000, - recipient: await node.createP2PKHAddress() - }); - await node.signTransactionInput(transferTx, 0); - }); - - it("approver sends a transaction", async function() { - const hash = await node.sendTransaction(transferTx, { - account: approver - }); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - - it("nonApprover cannot send a transaction", async function() { - await node.sendAssetTransactionExpectedToFail(transferTx); - }); - }); - - afterEach(function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - }); - - after(async function() { - await node.clean(); - }); -}); diff --git a/test/src/e2e/unwrap.test.ts b/test/src/e2e/unwrap.test.ts deleted file mode 100644 index e5a1db6127..0000000000 --- a/test/src/e2e/unwrap.test.ts +++ /dev/null @@ -1,228 +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 { expect } from "chai"; -import { - AssetAddress, - MintAsset, - PlatformAddress, - SignedTransaction, - U64 -} from "codechain-sdk/lib/core/classes"; -import "mocha"; -import { - aliceAddress, - faucetAccointId, - faucetAddress, - faucetSecret -} from "../helper/constants"; -import { ERROR } from "../helper/error"; -import CodeChain from "../helper/spawn"; - -describe("Unwrap CCC", function() { - let node: CodeChain; - before(async function() { - node = new CodeChain(); - await node.start(); - }); - - describe("Wrap CCC with P2PKHBurnAddress", function() { - let recipient: AssetAddress; - let wrapTransaction: SignedTransaction; - const quantity = 100; - beforeEach(async function() { - recipient = await node.createP2PKHBurnAddress(); - wrapTransaction = node.sdk.core - .createWrapCCCTransaction({ - shardId: 0, - recipient, - quantity, - payer: PlatformAddress.fromAccountId(faucetAccointId, { - networkId: "tc" - }) - }) - .sign({ - secret: faucetSecret, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress), - fee: 10 - }); - - const blockNumber = await node.getBestBlockNumber(); - const hash = await node.sdk.rpc.chain.sendSignedTransaction( - wrapTransaction - ); - await node.waitBlockNumber(blockNumber + 1); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - - it("Unwrap successful", async function() { - const beforeAliceBalance = await node.sdk.rpc.chain.getBalance( - aliceAddress - ); - const tx = node.sdk.core.createUnwrapCCCTransaction({ - burn: wrapTransaction.getAsset(), - receiver: aliceAddress - }); - await node.signTransactionBurn(tx, 0); - const hash = await node.sendAssetTransaction(tx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect( - ( - await node.sdk.rpc.chain.getBalance(aliceAddress) - ).toEncodeObject() - ).eq( - U64.plus( - beforeAliceBalance, - wrapTransaction.getAsset().quantity - ) - .plus(2 /* stake share */) - .toEncodeObject() - ); - }); - }); - - describe("with P2PKHAddress", function() { - let recipient: AssetAddress; - let wrapTransaction: SignedTransaction; - const quantity = 100; - beforeEach(async function() { - recipient = await node.createP2PKHAddress(); - wrapTransaction = node.sdk.core - .createWrapCCCTransaction({ - shardId: 0, - recipient, - quantity, - payer: PlatformAddress.fromAccountId(faucetAccointId, { - networkId: "tc" - }) - }) - .sign({ - secret: faucetSecret, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress), - fee: 10 - }); - - const blockNumber = await node.getBestBlockNumber(); - const hash = await node.sdk.rpc.chain.sendSignedTransaction( - wrapTransaction - ); - await node.waitBlockNumber(blockNumber + 1); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - - it("Transfer then Unwrap successful", async function() { - const recipientBurn = await node.createP2PKHBurnAddress(); - const asset1 = wrapTransaction.getAsset(); - - const transferTx = node.sdk.core.createTransferAssetTransaction(); - transferTx.addInputs(asset1); - transferTx.addOutputs({ - assetType: asset1.assetType, - shardId: asset1.shardId, - recipient: recipientBurn, - quantity - }); - await node.signTransactionInput(transferTx, 0); - const hash1 = await node.sendAssetTransaction(transferTx); - expect(await node.sdk.rpc.chain.getTransaction(hash1)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash1)).be.true; - - const asset2 = await node.sdk.rpc.chain.getAsset( - transferTx.tracker(), - 0, - asset1.shardId - ); - - const beforeAliceBalance = await node.sdk.rpc.chain.getBalance( - aliceAddress - ); - const unwrapTx = node.sdk.core.createUnwrapCCCTransaction({ - burn: asset2!, - receiver: aliceAddress - }); - await node.signTransactionBurn(unwrapTx, 0); - const hash2 = await node.sendAssetTransaction(unwrapTx); - expect(await node.sdk.rpc.chain.getTransaction(hash2)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash2)).be.true; - - expect( - ( - await node.sdk.rpc.chain.getBalance(aliceAddress) - ).toEncodeObject() - ).eq( - U64.plus(beforeAliceBalance, asset2!.quantity) - .plus(2 /* stake share */) - .toEncodeObject() - ); - }); - }); - - describe("With minted asset (not wrapped CCC)", function() { - let recipient: AssetAddress; - let mintTx: MintAsset; - const supply = 100; - beforeEach(async function() { - recipient = await node.createP2PKHBurnAddress(); - const scheme = node.sdk.core.createAssetScheme({ - shardId: 0, - metadata: "", - supply - }); - mintTx = node.sdk.core.createMintAssetTransaction({ - scheme, - recipient - }); - const hash = await node.sendAssetTransaction(mintTx); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - - it("Invalid asset type", async function() { - const tx = node.sdk.core.createUnwrapCCCTransaction({ - burn: mintTx.getMintedAsset(), - receiver: aliceAddress - }); - await node.signTransactionBurn(tx, 0); - const beforeAliceBalance = await node.sdk.rpc.chain.getBalance( - aliceAddress - ); - try { - await node.sendAssetTransaction(tx); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_TX_ASSET_TYPE); - } - expect( - ( - await node.sdk.rpc.chain.getBalance(aliceAddress) - ).toEncodeObject() - ).eq(beforeAliceBalance.toEncodeObject()); - }); - }); - - afterEach(function() { - if (this.currentTest!.state === "failed") { - node.keepLogs(); - } - }); - - after(async function() { - await node.clean(); - }); -}); diff --git a/test/src/e2e/verification.test.ts b/test/src/e2e/verification.test.ts index 8e78b9a00a..096e1f8fcd 100644 --- a/test/src/e2e/verification.test.ts +++ b/test/src/e2e/verification.test.ts @@ -15,12 +15,7 @@ // along with this program. If not, see . import { expect } from "chai"; -import { AssetAddress, PlatformAddress } from "codechain-primitives"; -import { - AssetScheme, - AssetTransferInput, - AssetTransferOutput -} from "codechain-sdk/lib/core/classes"; +import { PlatformAddress } from "codechain-primitives"; import "mocha"; import { aliceAddress, @@ -130,28 +125,10 @@ describe("solo - 1 node", function() { { actionType: 2, actionLength: 4 }, { actionType: 3, actionLength: 1 }, // SetRegularKey { actionType: 3, actionLength: 3 }, - { actionType: 4, actionLength: 1 }, // CreateShard - { actionType: 4, actionLength: 3 }, - { actionType: 5, actionLength: 2 }, // SetShardOwners - { actionType: 5, actionLength: 4 }, - { actionType: 6, actionLength: 2 }, // SetShardUsers - { actionType: 6, actionLength: 4 }, - { actionType: 7, actionLength: 5 }, // WrapCCC - { actionType: 7, actionLength: 7 }, { actionType: 8, actionLength: 3 }, // Store { actionType: 8, actionLength: 5 }, { actionType: 9, actionLength: 2 }, // Remove { actionType: 9, actionLength: 4 }, - { actionType: 0x11, actionLength: 3 }, // UnwrapCCC - { actionType: 0x11, actionLength: 5 }, - { actionType: 0x13, actionLength: 10 }, // MintAsset - { actionType: 0x13, actionLength: 12 }, - { actionType: 0x14, actionLength: 8 }, // TransferAsset - { actionType: 0x14, actionLength: 10 }, - { actionType: 0x15, actionLength: 9 }, // ChangeAssetScheme - { actionType: 0x15, actionLength: 11 }, - { actionType: 0x18, actionLength: 8 }, // IncreaseAssetSupply - { actionType: 0x18, actionLength: 10 } ].forEach(function(params: { actionType: number; actionLength: number; @@ -194,322 +171,6 @@ describe("solo - 1 node", function() { }); }); - describe("Sending invalid transactions over the limits (in action 1: AssetTransaction)", function() { - let scheme: AssetScheme; - let input: AssetTransferInput; - let output: AssetTransferOutput; - let recipient: AssetAddress; - - before(async function() { - recipient = await node.createP2PKHAddress(); - scheme = node.sdk.core.createAssetScheme({ - shardId: 0, - metadata: "Valid metadata", - supply: 10 - }); - input = node.sdk.core.createAssetTransferInput({ - assetOutPoint: { - tracker: "0x" + "0".repeat(64), - index: 0, - assetType: "0x" + "1".repeat(40), - shardId: 0, - quantity: 12345 - }, - timelock: { - type: "block", - value: 0 - } - }); - output = node.sdk.core.createAssetTransferOutput({ - assetType: "0x" + "0".repeat(40), - shardId: 0, - quantity: 12345, - recipient - }); - }); - - describe("In assetMintTransction", function() { - let encoded: any[]; - beforeEach(async function() { - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - const tx = node.sdk.core.createMintAssetTransaction({ - scheme, - recipient - }); - const signed = tx.sign({ - secret: faucetSecret, - fee: 10, - seq - }); - encoded = signed.toEncodeObject(); - }); - - [65536, 100000].forEach(function(shardId) { - it(`shardId: ${shardId}`, async function() { - encoded[3][2] = shardId; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - ["0x01" + "0".repeat(64), "0x" + "f".repeat(128)].forEach(function( - amount - ) { - it(`amount: ${amount}`, async function() { - encoded[3][6] = amount; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - ["0x1" + "0".repeat(40), "0x" + "f".repeat(41)].forEach(function( - lockScriptHash - ) { - it(`lockScriptHash: ${lockScriptHash}`, async function() { - encoded[3][4] = lockScriptHash; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - it("parameters"); - it("registrar"); - }); - - describe("In assetTransferTransaction", function() { - let encoded: any[]; - beforeEach(async function() { - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - const tx = node.sdk.core - .createTransferAssetTransaction() - .addBurns(input) - .addInputs(input) - .addOutputs(output); - - const signed = tx.sign({ - secret: faucetSecret, - fee: 10, - seq - }); - encoded = signed.toEncodeObject(); - }); - - ["0x01" + "0".repeat(64), "0x" + "f".repeat(128)].forEach(function( - amount - ) { - it(`amount: ${amount}`, async function() { - // Burn - encoded[3][2][0][0][3] = amount; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - // Input - encoded[3][3][0][0][3] = amount; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - - // Output - encoded[3][4][0][3] = amount; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - ["0x1" + "0".repeat(64), "0x" + "f".repeat(65)].forEach(function( - tracker - ) { - it(`tracker: ${tracker}`, async function() { - // Burn - encoded[3][2][0][0][0] = tracker; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - // Input - encoded[3][3][0][0][0] = tracker; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - ["0x1" + "0".repeat(64), "0x" + "f".repeat(65)].forEach(function( - assetType - ) { - it(`assetType: ${assetType}`, async function() { - // Burn - encoded[3][2][0][0][2] = assetType; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - // Input - encoded[3][3][0][0][2] = assetType; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - - // Output - encoded[3][4][0][2] = assetType; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - ["0x1" + "0".repeat(40), "0x" + "f".repeat(41)].forEach(function( - lockScriptHash - ) { - it(`lockScriptHash: ${lockScriptHash}`, async function() { - encoded[3][4][0][0] = lockScriptHash; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - it("parameters"); - it("index"); - it("timelock"); - it("lockscript/unlockscript"); - it("expiration"); - }); - - describe("In assetUnwrapCCCTransaction", function() { - let encoded: any[]; - beforeEach(async function() { - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - const tx = node.sdk.core.createUnwrapCCCTransaction({ - burn: input, - receiver: aliceAddress - }); - - const signed = tx.sign({ - secret: faucetSecret, - fee: 10, - seq - }); - encoded = signed.toEncodeObject(); - }); - - ["0x01" + "0".repeat(64), "0x" + "f".repeat(128)].forEach(function( - amount - ) { - it(`amount: ${amount}`, async function() { - encoded[3][2][0][3] = amount; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - ["0x1" + "0".repeat(64), "0x" + "f".repeat(65)].forEach(function( - tracker - ) { - it(`tracker: ${tracker}`, async function() { - encoded[3][2][0][0] = tracker; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - ["0x1" + "0".repeat(64), "0x" + "f".repeat(65)].forEach(function( - assetType - ) { - it(`assetType: ${assetType}`, async function() { - encoded[3][2][0][2] = assetType; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - it("parameters"); - it("index"); - it("timelock"); - it("lockscript/unlockscript"); - }); - }); - describe("Sending invalid transactions over the limits (in action 2: Pay)", function() { let encoded: any[]; beforeEach(async function() { @@ -599,148 +260,6 @@ describe("solo - 1 node", function() { }); }); - describe("Sending invalid transactions over the limits (in action 5: SetShardOwners)", function() { - let encoded: any[]; - beforeEach(async function() { - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - const account = await node.createPlatformAddress(); - const signed = node.sdk.core - .createSetShardOwnersTransaction({ - shardId: 0, - owners: [account] - }) - .sign({ - secret: faucetSecret, - fee: 10, - seq - }); - encoded = signed.toEncodeObject(); - }); - - [65536, 100000].forEach(function(shardId) { - it(`shardId: ${shardId}`, async function() { - encoded[3][1] = shardId; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - it("Owners"); - }); - - describe("Sending invalid transactions over the limits (in action 6: SetShardUsers)", function() { - let encoded: any[]; - beforeEach(async function() { - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - const account = await node.createPlatformAddress(); - const signed = node.sdk.core - .createSetShardUsersTransaction({ - shardId: 0, - users: [account] - }) - .sign({ - secret: faucetSecret, - fee: 10, - seq - }); - encoded = signed.toEncodeObject(); - }); - - [65536, 100000].forEach(function(shardId) { - it(`shardId: ${shardId}`, async function() { - encoded[3][1] = shardId; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - it("Users"); - }); - - describe("Sending invalid transactions over the limits (in action 7: WrapCCC)", function() { - let encoded: any[]; - beforeEach(async function() { - const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); - const account = await node.createPlatformAddress(); - const recipient = await node.createP2PKHAddress(); - const signed = node.sdk.core - .createWrapCCCTransaction({ - shardId: 0, - recipient, - quantity: 10, - payer: PlatformAddress.fromAccountId(faucetAccointId, { - networkId: "tc" - }) - }) - .sign({ - secret: faucetSecret, - fee: 10, - seq - }); - encoded = signed.toEncodeObject(); - }); - - [65536, 100000].forEach(function(shardId) { - it(`shardId: ${shardId}`, async function() { - encoded[3][1] = shardId; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - ["0x01" + "0".repeat(64), "0x" + "f".repeat(128)].forEach(function( - amount - ) { - it(`amount: ${amount}`, async function() { - encoded[3][4] = amount; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - ["0x1" + "0".repeat(40), "0x" + "f".repeat(41)].forEach(function( - lockScriptHash - ) { - it(`lockScriptHash: ${lockScriptHash}`, async function() { - encoded[3][2] = lockScriptHash; - try { - await node.sendSignedTransactionWithRlpBytes( - RLP.encode(encoded) - ); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_RLP_TOO_BIG); - } - }); - }); - - it("parameters"); - }); - [0, 9].forEach(function(fee) { it(`Sending invalid transactions (low fee): ${fee}`, async function() { const seq = await node.sdk.rpc.chain.getSeq(faucetAddress); diff --git a/test/src/e2e/wrap.test.ts b/test/src/e2e/wrap.test.ts deleted file mode 100644 index a8530c582e..0000000000 --- a/test/src/e2e/wrap.test.ts +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 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 * as chai from "chai"; -import * as chaiAsPromised from "chai-as-promised"; -chai.use(chaiAsPromised); -import { H160, PlatformAddress } from "codechain-primitives"; -import "mocha"; -import { - faucetAccointId, - faucetAddress, - faucetSecret -} from "../helper/constants"; -import { ERROR } from "../helper/error"; -import CodeChain from "../helper/spawn"; - -const expect = chai.expect; - -describe("WrapCCC", function() { - let node: CodeChain; - beforeEach(async function() { - node = new CodeChain(); - await node.start(); - }); - - [1, 100].forEach(function(amount) { - it(`Wrap {amount}`, async function() { - const recipient = await node.createP2PKHAddress(); - const transaction = node.sdk.core - .createWrapCCCTransaction({ - shardId: 0, - recipient, - quantity: amount, - payer: PlatformAddress.fromAccountId(faucetAccointId, { - networkId: "tc" - }) - }) - .sign({ - secret: faucetSecret, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress), - fee: 10 - }); - - const blockNumber = await node.getBestBlockNumber(); - const hash = await node.sdk.rpc.chain.sendSignedTransaction( - transaction - ); - await node.waitBlockNumber(blockNumber + 1); - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - }); - }); - - it("Wrap 0 CCC fails", async function() { - const recipient = await node.createP2PKHAddress(); - const transaction = node.sdk.core - .createWrapCCCTransaction({ - shardId: 0, - recipient, - quantity: 0, - payer: PlatformAddress.fromAccountId(faucetAccointId, { - networkId: "tc" - }) - }) - .sign({ - secret: faucetSecret, - seq: await node.sdk.rpc.chain.getSeq(faucetAddress), - fee: 10 - }); - - try { - await node.sdk.rpc.chain.sendSignedTransaction(transaction); - expect.fail(); - } catch (e) { - expect(e).is.similarTo(ERROR.INVALID_TX_ZERO_QUANTITY); - } - }); - - it("WCCC can be burnt", async function() { - const shardId = 0; - const wrapCCC = node.sdk.core.createWrapCCCTransaction({ - shardId, - recipient: await node.createP2PKHBurnAddress(), - quantity: 30, - payer: PlatformAddress.fromAccountId(faucetAccointId, { - networkId: "tc" - }) - }); - const seq = (await node.sdk.rpc.chain.getSeq(faucetAddress))!; - expect(seq).not.to.be.null; - const signedWrapCCC = wrapCCC.sign({ - secret: faucetSecret, - seq, - fee: 10 - }); - - await node.sdk.rpc.chain.sendSignedTransaction(signedWrapCCC); - expect( - await node.sdk.rpc.chain.containsTransaction(signedWrapCCC.hash()) - ).be.true; - expect(await node.sdk.rpc.chain.getTransaction(signedWrapCCC.hash())) - .not.null; - - const schemeAfterWrap = (await node.sdk.rpc.chain.getAssetSchemeByType( - H160.zero(), - shardId - ))!; - expect(schemeAfterWrap.supply.toString(10)).be.equal("30"); - - const blockNumberBeforeBurn = await node.sdk.rpc.chain.getBestBlockNumber(); - - const WCCC = wrapCCC.getAsset(); - - const burn = node.sdk.core - .createTransferAssetTransaction() - .addBurns(WCCC); - await node.signTransactionP2PKHBurn( - burn.burn(0)!, - burn.hashWithoutScript() - ); - const signedBurn = burn.sign({ - secret: faucetSecret, - seq: seq + 1, - fee: 10 - }); - const hash = await node.sdk.rpc.chain.sendSignedTransaction(signedBurn); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - - const schemeAfterBurn = (await node.sdk.rpc.chain.getAssetSchemeByType( - H160.zero(), - shardId - ))!; - expect(schemeAfterBurn.supply.isEqualTo(0)).to.be.true; - - const schemeBeforeBurn = (await node.sdk.rpc.chain.getAssetSchemeByType( - H160.zero(), - shardId, - blockNumberBeforeBurn - ))!; - expect(schemeBeforeBurn.supply.isEqualTo(30)).to.be.true; - }).timeout(30_000); - - it("Changing asset scheme of WCCC causes syntax error", async function() { - const wrapCCC = node.sdk.core.createWrapCCCTransaction({ - shardId: 0, - recipient: await node.createP2PKHBurnAddress(), - quantity: 30, - payer: PlatformAddress.fromAccountId(faucetAccointId, { - networkId: "tc" - }) - }); - const seq = (await node.sdk.rpc.chain.getSeq(faucetAddress))!; - expect(seq).not.to.be.null; - const signedWrapCCC = wrapCCC.sign({ - secret: faucetSecret, - seq, - fee: 10 - }); - - const hash = await node.sdk.rpc.chain.sendSignedTransaction( - signedWrapCCC - ); - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransaction(hash)).not.null; - - const changeAssetScheme = node.sdk.core.createChangeAssetSchemeTransaction( - { - shardId: 0, - assetType: H160.zero(), - scheme: { - metadata: "WCCC", - allowedScriptHashes: [] - }, - approvals: [] - } - ); - const signedChangeAssetScheme = changeAssetScheme.sign({ - secret: faucetSecret, - seq: seq + 1, - fee: 10 - }); - await expect( - node.sdk.rpc.chain.sendSignedTransaction(signedChangeAssetScheme) - ).to.be.rejected; - }).timeout(30_000); - - it("WCCC tracker should return the corresponding transaction", async function() { - const wrapCCC = node.sdk.core.createWrapCCCTransaction({ - shardId: 0, - recipient: await node.createP2PKHBurnAddress(), - quantity: 30, - payer: PlatformAddress.fromAccountId(faucetAccointId, { - networkId: "tc" - }) - }); - const seq = (await node.sdk.rpc.chain.getSeq(faucetAddress))!; - expect(seq).not.to.be.null; - const signedWrapCCC = wrapCCC.sign({ - secret: faucetSecret, - seq, - fee: 10 - }); - - const hash = await node.sdk.rpc.chain.sendSignedTransaction( - signedWrapCCC - ); - const tracker = wrapCCC.tracker(); - - expect(await node.sdk.rpc.chain.containsTransaction(hash)).be.true; - expect(await node.sdk.rpc.chain.getTransactionByTracker(tracker)).not - .null; - expect( - await node.sdk.rpc.chain.getTransactionResultsByTracker(tracker) - ).deep.equal([true]); - }); - - afterEach(async function() { - await node.clean(); - }); -}); diff --git a/test/src/helper/error.ts b/test/src/helper/error.ts index d75c62df45..3c3405fbd1 100644 --- a/test/src/helper/error.ts +++ b/test/src/helper/error.ts @@ -94,26 +94,6 @@ export const ERROR: any = { data: $containsWord("Syntax(ZeroQuantity"), message: $anything }, - INVALID_TX_INCONSISTENT_IN_OUT: { - code: -32099, - data: $containsWord("Syntax(InconsistentTransactionInOut"), - message: $anything - }, - INVALID_TX_ASSET_TYPE: { - code: -32099, - data: $containsWord("Syntax(InvalidAssetType"), - message: $anything - }, - INVALID_TX_DUPLICATED_PREV_OUT: { - code: -32099, - data: $containsWord("Syntax(DuplicatedPreviousOutput"), - message: $anything - }, - INVALID_ORIGIN_OUTPUTS: { - code: -32099, - message: $anything, - data: $containsWord("InvalidOriginOutputs") - }, DISABLED_TRANSACTION: { code: -32099, message: $anything, diff --git a/test/src/helper/spawn.ts b/test/src/helper/spawn.ts index 8c3816360a..b745cfb73d 100644 --- a/test/src/helper/spawn.ts +++ b/test/src/helper/spawn.ts @@ -18,18 +18,13 @@ import { expect } from "chai"; import { ChildProcess, spawn } from "child_process"; import { SDK } from "codechain-sdk"; import { - Asset, - AssetAddress, - AssetTransferInput, H256, PlatformAddress, SignedTransaction, Transaction, - TransferAsset, U64, UnwrapCCC } from "codechain-sdk/lib/core/classes"; -import { AssetTransaction } from "codechain-sdk/lib/core/Transaction"; import { P2PKH } from "codechain-sdk/lib/key/P2PKH"; import { P2PKHBurn } from "codechain-sdk/lib/key/P2PKHBurn"; import * as stake from "codechain-stakeholder-sdk"; @@ -461,65 +456,16 @@ export default class CodeChain { return p2pkh.createAddress(); } - public async signTransactionP2PKHBurn( - txInput: AssetTransferInput, - txhash: H256 - ) { - const keyStore = await this.sdk.key.createLocalKeyStore( - this.localKeyStorePath - ); - const p2pkhBurn = this.sdk.key.createP2PKHBurn({ keyStore }); - if (txInput.prevOut.parameters === undefined) { - throw Error(`prevOut.parameters is undefined`); - } - const publicKeyHash = Buffer.from( - txInput.prevOut.parameters[0] - ).toString("hex"); - txInput.setLockScript(P2PKHBurn.getLockScript()); - txInput.setUnlockScript( - await p2pkhBurn.createUnlockScript(publicKeyHash, txhash) - ); - } - - public async signTransactionP2PKH( - txInput: AssetTransferInput, - txhash: H256 - ) { - const keyStore = await this.sdk.key.createLocalKeyStore( - this.localKeyStorePath - ); - const p2pkh = this.sdk.key.createP2PKH({ keyStore }); - if (txInput.prevOut.parameters === undefined) { - throw Error(`prevOut.parameters is undefined`); - } - const publicKeyHash = Buffer.from( - txInput.prevOut.parameters[0] - ).toString("hex"); - txInput.setLockScript(P2PKH.getLockScript()); - txInput.setUnlockScript( - await p2pkh.createUnlockScript(publicKeyHash, txhash) - ); - } - - public async createP2PKHBurnAddress() { - const keyStore = await this.sdk.key.createLocalKeyStore( - this.localKeyStorePath - ); - const p2pkhBurn = this.sdk.key.createP2PKHBurn({ keyStore }); - return p2pkhBurn.createAddress(); - } - - public async createPlatformAddress() { - const keyStore = await this.sdk.key.createLocalKeyStore( - this.localKeyStorePath - ); - return this.sdk.key.createPlatformAddress({ keyStore }); - } - public async pay( recipient: string | PlatformAddress, - quantity: U64 | string | number + quantity: U64 | string | number, + options?: { + seq?: number + } ): Promise { + const { + seq = (await this.sdk.rpc.chain.getSeq(faucetAddress)) || 0, + } = options || {}; const tx = this.sdk.core .createPayTransaction({ recipient, @@ -527,7 +473,7 @@ export default class CodeChain { }) .sign({ secret: faucetSecret, - seq: await this.sdk.rpc.chain.getSeq(faucetAddress), + seq, fee: 10 }); return this.sdk.rpc.chain.sendSignedTransaction(tx); @@ -555,78 +501,6 @@ export default class CodeChain { return this.sdk.rpc.chain.sendSignedTransaction(signed); } - public async sendAssetTransaction( - tx: AssetTransaction & Transaction, - options?: { - seq?: number; - fee?: number; - secret?: string; - } - ): Promise { - const { - seq = (await this.sdk.rpc.chain.getSeq(faucetAddress)) || 0, - fee = 10, - secret = faucetSecret - } = options || {}; - const signed = tx.sign({ - secret, - fee: fee + this.id, - seq - }); - return this.sdk.rpc.chain.sendSignedTransaction(signed); - } - - public async mintAsset(params: { - supply: U64 | number; - recipient?: string | AssetAddress; - secret?: string; - seq?: number; - metadata?: string; - registrar?: PlatformAddress | string; - awaitMint?: boolean; - }): Promise { - const { - supply, - seq, - recipient = await this.createP2PKHAddress(), - secret, - metadata = "", - registrar, - awaitMint = true - } = params; - const tx = this.sdk.core.createMintAssetTransaction({ - scheme: { - shardId: 0, - metadata, - supply, - registrar - }, - recipient - }); - await this.sendAssetTransaction(tx, { - secret, - seq - }); - return tx.getMintedAsset(); - } - - public async signTransactionInput(tx: TransferAsset, index: number) { - const keyStore = await this.sdk.key.createLocalKeyStore( - this.localKeyStorePath - ); - await this.sdk.key.signTransactionInput(tx, index, { keyStore }); - } - - public async signTransactionBurn( - tx: TransferAsset | UnwrapCCC, - index: number - ) { - const keyStore = await this.sdk.key.createLocalKeyStore( - this.localKeyStorePath - ); - await this.sdk.key.signTransactionBurn(tx, index, { keyStore }); - } - public async setRegularKey( key: any, options?: { @@ -679,46 +553,6 @@ export default class CodeChain { return tx; } - // If one only sends certainly failing transactions, the miner would not generate any block. - // So to clearly check the result failed, insert the failing transactions after succeessful ones. - public async sendAssetTransactionExpectedToFail( - tx: Transaction & AssetTransaction, - options: { seq?: number } = {} - ): Promise { - await this.sdk.rpc.devel.stopSealing(); - - const seq = - options.seq == null - ? await this.sdk.rpc.chain.getSeq(faucetAddress) - : options.seq; - - const blockNumber = await this.getBestBlockNumber(); - const signedDummyTxHash = ( - await this.sendPayTx({ - seq, - quantity: 1 - }) - ).hash(); - const targetTxHash = await this.sendAssetTransaction(tx, { - seq: seq + 1 - }); - - await this.sdk.rpc.devel.startSealing(); - await this.waitBlockNumber(blockNumber + 1); - - expect(await this.sdk.rpc.chain.containsTransaction(targetTxHash)).be - .false; - expect(await this.sdk.rpc.chain.getErrorHint(targetTxHash)).not.null; - expect(await this.sdk.rpc.chain.getTransaction(targetTxHash)).be.null; - - expect(await this.sdk.rpc.chain.containsTransaction(signedDummyTxHash)) - .be.true; - expect(await this.sdk.rpc.chain.getErrorHint(signedDummyTxHash)).null; - expect(await this.sdk.rpc.chain.getTransaction(signedDummyTxHash)).not - .be.null; - return targetTxHash; - } - // If one only sends certainly failing transactions, the miner would not generate any block. // So to clearly check the result failed, insert the failing transactions after succeessful ones. public async sendTransactionExpectedToFail(