From ea1f185ac34c6143cb7e7a4d3eedc92e8d01868e Mon Sep 17 00:00:00 2001 From: yihuang Date: Mon, 13 Apr 2020 15:03:26 +0800 Subject: [PATCH] Problem (Fix #1308): unnecessary item wrappers for merkle trie storage Solution: - Do the switch to jellyfish merkle library. --- CHANGELOG.md | 1 + Cargo.lock | 1 - chain-abci/src/app/app_init.rs | 61 +-- chain-abci/src/app/commit.rs | 23 +- chain-abci/src/app/end_block.rs | 2 +- chain-abci/src/app/macros.rs | 24 +- chain-abci/src/app/mod.rs | 14 +- chain-abci/src/app/query.rs | 12 +- chain-abci/src/app/rewards.rs | 20 +- chain-abci/src/app/validate_tx.rs | 7 +- chain-abci/src/main.rs | 6 - chain-abci/src/staking/table.rs | 4 +- chain-abci/src/storage/mod.rs | 18 +- chain-abci/tests/abci_app.rs | 49 +- chain-abci/tests/punishment.rs | 20 +- chain-abci/tests/tx_validation.rs | 636 +++++--------------------- chain-abci/tests/validator_changes.rs | 12 +- chain-storage/Cargo.toml | 1 - chain-storage/src/buffer.rs | 118 +---- chain-storage/src/lib.rs | 17 +- test-common/src/block_generator.rs | 24 +- test-common/src/chain_env.rs | 36 +- 22 files changed, 253 insertions(+), 853 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 259e9880f..5a9f5dc07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * *chain-abci* [1100](https://github.com/crypto-com/chain/pull/1100): account nonce increased after reward distribution * *chain-abci* [1292](https://github.com/crypto-com/chain/pull/1292): implements new punishment and staking state transition specification and new nonce logic * *chain-storage* [1424](https://github.com/crypto-com/chain/pull/1424): add two columnes to the database +* *chain-storage* [1424](https://github.com/crypto-com/chain/pull/1424): change merkle tree of staking states to jellyfish-merkle * *chain-core* [1162](https://github.com/crypto-com/chain/pull/1162): transaction witness contains BIP-340-compatible Schnorr signatures (instead of the previous WIP scheme) * *chain-core* [1325](https://github.com/crypto-com/chain/pull/1325): blake3 for message digest (txid) + tree hashing * *chain-core* [1222](https://github.com/crypto-com/chain/pull/1258): Add common outer type for public(non-enclave) tx, tx serialization is changed. diff --git a/Cargo.lock b/Cargo.lock index 6611218ed..64f1cd441 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -547,7 +547,6 @@ dependencies = [ "kvdb-rocksdb", "parity-scale-codec", "quickcheck", - "starling", ] [[package]] diff --git a/chain-abci/src/app/app_init.rs b/chain-abci/src/app/app_init.rs index ea847df44..ea411a992 100644 --- a/chain-abci/src/app/app_init.rs +++ b/chain-abci/src/app/app_init.rs @@ -21,17 +21,15 @@ use chain_core::init::coin::Coin; use chain_core::init::config::InitConfig; use chain_core::init::config::NetworkParameters; use chain_core::state::account::StakedStateDestination; -use chain_core::state::account::{CouncilNode, StakedState, StakedStateAddress}; +use chain_core::state::account::{CouncilNode, StakedStateAddress}; use chain_core::state::tendermint::{BlockHeight, TendermintVotePower}; use chain_core::state::{ChainState, RewardsPoolState}; use chain_core::tx::TxAux; use chain_core::ChainInfo; -use chain_storage::account::AccountWrapper; -use chain_storage::account::StarlingFixedKey; -use chain_storage::account::{pure_account_storage, AccountStorage}; use chain_storage::buffer::{ - flush_storage, GetStaking, KVBuffer, StakingBuffer, StakingGetter, StoreKV, StoreStaking, + flush_storage, GetStaking, KVBuffer, StakingBuffer, StoreKV, StoreStaking, }; +use chain_storage::jellyfish::{compute_staking_root, StakingGetter, Version}; use chain_storage::{Storage, StoredChainState}; /// ABCI app state snapshot @@ -50,6 +48,8 @@ pub struct ChainNodeState { pub staking_table: StakingTable, /// genesis time pub genesis_time: Timespec, + /// Version number of staking merkle tree + pub staking_version: Version, /// The parts of states which involved in computing app_hash pub top_level: ChainState, @@ -73,7 +73,7 @@ impl ChainNodeState { pub fn genesis( genesis_apphash: H256, genesis_time: Timespec, - account_root: StarlingFixedKey, + account_root: H256, rewards_pool: RewardsPoolState, network_params: NetworkParameters, staking_table: StakingTable, @@ -85,6 +85,7 @@ impl ChainNodeState { block_height: BlockHeight::genesis(), staking_table, genesis_time, + staking_version: 0, top_level: ChainState { account_root, rewards_pool, @@ -104,8 +105,6 @@ pub enum BufferType { pub struct ChainNodeApp { /// the underlying key-value storage (+ possibly some info in the future) pub storage: Storage, - /// account trie storage - pub accounts: AccountStorage, /// valid transactions after DeliverTx before EndBlock/Commit pub delivered_txs: Vec, /// a reference to genesis (used when there is no committed state) @@ -207,17 +206,6 @@ fn get_voting_power( } } -pub fn compute_accounts_root( - account_storage: &mut AccountStorage, - accounts: &[StakedState], -) -> H256 { - let mut keys: Vec<_> = accounts.iter().map(StakedState::key).collect(); - let wrapped: Vec<_> = accounts.iter().cloned().map(AccountWrapper).collect(); - account_storage - .insert(None, &mut keys, &wrapped) - .expect("insert failed") -} - pub fn init_app_hash(conf: &InitConfig, genesis_time: Timespec) -> H256 { let (accounts, rp, _nodes) = conf .validate_config_get_genesis(genesis_time) @@ -225,7 +213,7 @@ pub fn init_app_hash(conf: &InitConfig, genesis_time: Timespec) -> H256 { compute_app_hash( &MerkleTree::empty(), - &compute_accounts_root(&mut pure_account_storage(20).unwrap(), &accounts), + &compute_staking_root(&accounts), &rp, &NetworkParameters::Genesis(conf.network_params.clone()), ) @@ -238,7 +226,6 @@ impl ChainNodeApp { genesis_app_hash: [u8; HASH_SIZE_256], chain_id: &str, storage: Storage, - accounts: AccountStorage, tx_query_address: Option, ) -> Self { let stored_genesis = storage.get_genesis_app_hash(); @@ -261,7 +248,6 @@ impl ChainNodeApp { .expect("failed to decode two last hex digits in chain ID")[0]; ChainNodeApp { storage, - accounts, delivered_txs: Vec::new(), chain_hex_id, genesis_app_hash, @@ -287,7 +273,6 @@ impl ChainNodeApp { /// * `gah` - hex-encoded genesis app hash /// * `chain_id` - the chain ID set in Tendermint genesis.json (our name convention is that the last two characters should be hex digits) /// * `storage` - underlying storage to be used (in-mem or persistent) - /// * `accounts` - underlying storage for account tries to be used (in-mem or persistent) /// * `tx_query_address` - address of tx query enclave to supply to clients (if any) /// * `enclave_server` - connection string which ZeroMQ server wrapper around the transaction validation enclave will listen on pub fn new_with_storage( @@ -295,7 +280,6 @@ impl ChainNodeApp { gah: &str, chain_id: &str, mut storage: Storage, - accounts: AccountStorage, tx_query_address: Option, enclave_server: Option, ) -> Self { @@ -344,7 +328,7 @@ impl ChainNodeApp { // populate the indexing structures in staking table. last_state.staking_table.initialize( - &StakingGetter::new(&accounts, Some(last_state.top_level.account_root)), + &StakingGetter::new(&storage, last_state.staking_version), last_state .top_level .network_params @@ -356,7 +340,6 @@ impl ChainNodeApp { genesis_app_hash, chain_id, storage, - accounts, tx_query_address, ) } else { @@ -374,7 +357,6 @@ impl ChainNodeApp { storage.write_genesis_chain_id(&genesis_app_hash, chain_id); ChainNodeApp { storage, - accounts, delivered_txs: Vec::new(), chain_hex_id, genesis_app_hash, @@ -420,7 +402,7 @@ impl ChainNodeApp { } let network_params = NetworkParameters::Genesis(conf.network_params); - let new_account_root = compute_accounts_root(&mut self.accounts, &accounts); + let new_account_root = self.storage.put_stakings(0, &accounts); let genesis_app_hash = compute_app_hash( &MerkleTree::empty(), &new_account_root, @@ -448,7 +430,7 @@ impl ChainNodeApp { let val_addresses = nodes.iter().map(|(addr, _)| *addr).collect::>(); let staking_table = StakingTable::from_genesis( - &StakingGetter::new(&self.accounts, Some(new_account_root)), + &staking_getter!(self, 0), network_params.get_required_council_node_stake(), network_params.get_max_validators(), &val_addresses, @@ -475,27 +457,30 @@ impl ChainNodeApp { } pub fn staking_store(&mut self, buffer_type: BufferType) -> impl StoreStaking + '_ { - let root = self + let version = self .last_state .as_ref() - .map(|state| state.top_level.account_root); - staking_store!(self, root, buffer_type) + .map(|state| state.staking_version) + .unwrap_or(0); + staking_store!(self, version, buffer_type) } pub fn staking_getter(&self, buffer_type: BufferType) -> impl GetStaking + '_ { - let root = self + let version = self .last_state .as_ref() - .map(|state| state.top_level.account_root); - staking_getter!(self, root, buffer_type) + .map(|state| state.staking_version) + .unwrap_or(0); + staking_getter!(self, version, buffer_type) } - pub fn staking_getter_committed(&self) -> StakingGetter<'_> { + pub fn staking_getter_committed(&self) -> StakingGetter<'_, Storage> { StakingGetter::new( - &self.accounts, + &self.storage, self.last_state .as_ref() - .map(|state| state.top_level.account_root), + .map(|state| state.staking_version) + .unwrap_or(0), ) } diff --git a/chain-abci/src/app/commit.rs b/chain-abci/src/app/commit.rs index c4a2d2929..fdb9297d3 100644 --- a/chain-abci/src/app/commit.rs +++ b/chain-abci/src/app/commit.rs @@ -8,7 +8,8 @@ use chain_core::compute_app_hash; use chain_core::tx::data::input::{TxoPointer, TxoSize}; use chain_core::tx::data::TxId; use chain_core::tx::{TxAux, TxEnclaveAux, TxPublicAux}; -use chain_storage::buffer::{flush_staking_storage, flush_storage, StoreKV}; +use chain_storage::buffer::{flush_storage, StoreKV}; +use chain_storage::jellyfish::flush_stakings; use parity_scale_codec::Encode; /// Given a db and a DB transaction, it will go through TX inputs and mark them as spent @@ -91,14 +92,20 @@ impl ChainNodeApp { top_level.rewards_pool.last_block_height = new_state.last_block_height; self.rewards_pool_updated = false; } + // flush staking storage - top_level.account_root = flush_staking_storage( - &mut self.accounts, - Some(top_level.account_root), - mem::take(&mut self.staking_buffer), - ) - .expect("merkle trie io error") - .expect("merkle trie update should return Some(root)"); + if !self.staking_buffer.is_empty() { + new_state.staking_version = new_state + .staking_version + .checked_add(1) + .expect("staking version overflow, no way to recover"); + top_level.account_root = flush_stakings( + &mut kv_store!(self), + new_state.staking_version, + mem::take(&mut self.staking_buffer), + ) + .expect("merkle trie io error"); + } let app_hash = compute_app_hash( &tree, diff --git a/chain-abci/src/app/end_block.rs b/chain-abci/src/app/end_block.rs index da6b28400..409710e4e 100644 --- a/chain-abci/src/app/end_block.rs +++ b/chain-abci/src/app/end_block.rs @@ -35,7 +35,7 @@ impl ChainNodeApp { // TODO: skipchain-based validator changes? let state = self.last_state.as_mut().expect("executing end block, but no app state stored (i.e. no initchain or recovery was executed)"); let val_updates = state.staking_table.end_block( - &staking_getter!(self, Some(state.top_level.account_root)), + &staking_getter!(self, state.staking_version), state.top_level.network_params.get_max_validators(), ); diff --git a/chain-abci/src/app/macros.rs b/chain-abci/src/app/macros.rs index e8649c746..ef0bee1f3 100644 --- a/chain-abci/src/app/macros.rs +++ b/chain-abci/src/app/macros.rs @@ -2,15 +2,15 @@ //! Ideally these should be methods of `ChainNodeApp`, but that borrow check don't allow that, //! because methods will need to retain the whole reference of `self` rather than individual fields. macro_rules! staking_store { - ($app:expr, $root:expr) => { - chain_storage::buffer::StakingBufferStore::new( - chain_storage::buffer::StakingGetter::new(&$app.accounts, $root), + ($app:expr, $version:expr) => { + chain_storage::jellyfish::StakingBufferStore::new( + chain_storage::jellyfish::StakingGetter::new(&$app.storage, $version), &mut $app.staking_buffer, ) }; - ($app:expr, $root:expr, $buffer_type:expr) => { - chain_storage::buffer::StakingBufferStore::new( - chain_storage::buffer::StakingGetter::new(&$app.accounts, $root), + ($app:expr, $version:expr, $buffer_type:expr) => { + chain_storage::jellyfish::StakingBufferStore::new( + chain_storage::jellyfish::StakingGetter::new(&$app.storage, $version), match $buffer_type { crate::app::app_init::BufferType::Consensus => &mut $app.staking_buffer, crate::app::app_init::BufferType::Mempool => &mut $app.mempool_staking_buffer, @@ -20,15 +20,15 @@ macro_rules! staking_store { } macro_rules! staking_getter { - ($app:expr, $root:expr) => { - chain_storage::buffer::StakingBufferGetter::new( - chain_storage::buffer::StakingGetter::new(&$app.accounts, $root), + ($app:expr, $version:expr) => { + chain_storage::jellyfish::StakingBufferGetter::new( + chain_storage::jellyfish::StakingGetter::new(&$app.storage, $version), &$app.staking_buffer, ) }; - ($app:expr, $root:expr, $buffer_type:expr) => { - chain_storage::buffer::StakingBufferGetter::new( - chain_storage::buffer::StakingGetter::new(&$app.accounts, $root), + ($app:expr, $version:expr, $buffer_type:expr) => { + chain_storage::jellyfish::StakingBufferGetter::new( + chain_storage::jellyfish::StakingGetter::new(&$app.storage, $version), match $buffer_type { crate::app::app_init::BufferType::Consensus => &$app.staking_buffer, crate::app::app_init::BufferType::Mempool => &$app.mempool_staking_buffer, diff --git a/chain-abci/src/app/mod.rs b/chain-abci/src/app/mod.rs index d3f654ee3..9aa4b1027 100644 --- a/chain-abci/src/app/mod.rs +++ b/chain-abci/src/app/mod.rs @@ -14,8 +14,7 @@ use log::info; #[cfg(fuzzing)] pub use self::app_init::check_validators; pub use self::app_init::{ - compute_accounts_root, get_validator_key, init_app_hash, BufferType, ChainNodeApp, - ChainNodeState, + get_validator_key, init_app_hash, BufferType, ChainNodeApp, ChainNodeState, }; use crate::app::validate_tx::ResponseWithCodeAndLog; use crate::enclave_bridge::EnclaveProxy; @@ -141,13 +140,11 @@ impl abci::Application for ChainNodeApp { .last_state .as_mut() .expect("executing begin block, but no app state stored (i.e. no initchain or recovery was executed)"); - let account_root = Some(last_state.top_level.account_root); - last_state.block_time = block_time; last_state.block_height = block_height; let slashes = last_state.staking_table.begin_block( - &mut staking_store!(self, account_root), + &mut staking_store!(self, last_state.staking_version), &last_state.top_level.network_params, block_time, block_height, @@ -193,9 +190,10 @@ impl abci::Application for ChainNodeApp { // FIXME: record based on votes if let Ok(proposer_address) = &proposer_address { - last_state - .staking_table - .reward_record(&staking_getter!(self, account_root), proposer_address); + last_state.staking_table.reward_record( + &staking_getter!(self, last_state.staking_version), + proposer_address, + ); } else { log::error!("invalid proposer address"); } diff --git a/chain-abci/src/app/query.rs b/chain-abci/src/app/query.rs index 407a95adc..223d7aed5 100644 --- a/chain-abci/src/app/query.rs +++ b/chain-abci/src/app/query.rs @@ -2,13 +2,13 @@ use std::convert::{TryFrom, TryInto}; use super::ChainNodeApp; use crate::enclave_bridge::{mock::handle_enc_dec, EnclaveProxy}; -use crate::storage::get_account; use abci::*; use chain_core::common::{MerkleTree, Proof as MerkleProof, H256, HASH_SIZE_256}; use chain_core::state::account::StakedStateAddress; use chain_core::state::tendermint::BlockHeight; use chain_core::state::ChainState; use chain_core::tx::data::{txid_hash, TXID_HASH_ID}; +use chain_storage::jellyfish::get_with_proof; use chain_storage::LookupItem; use parity_scale_codec::{Decode, Encode}; @@ -181,15 +181,15 @@ impl ChainNodeApp { "account" => { let account_address = StakedStateAddress::try_from(_req.data.as_slice()); if let (Some(state), Ok(address)) = (&self.last_state, account_address) { - let account = - get_account(&address, &state.top_level.account_root, &self.accounts); + let (account, _proof) = + get_with_proof(&self.storage, state.staking_version, &address); match account { - Ok(a) => { + Some(a) => { resp.value = a.encode(); // TODO: inclusion proof } - Err(e) => { - resp.log += format!("account lookup failed: {}", e).as_ref(); + None => { + resp.log += "account lookup failed: account not exists"; resp.code = 1; } } diff --git a/chain-abci/src/app/rewards.rs b/chain-abci/src/app/rewards.rs index d46d7e932..8cde9de54 100644 --- a/chain-abci/src/app/rewards.rs +++ b/chain-abci/src/app/rewards.rs @@ -5,7 +5,7 @@ use crate::enclave_bridge::EnclaveProxy; use chain_core::common::fixed::monetary_expansion; use chain_core::init::coin::Coin; use chain_core::state::account::StakedStateAddress; -use chain_storage::buffer::StakingGetter; +use chain_storage::jellyfish::StakingGetter; // rate < 1_000_000, no overflow. fn mul_micro(n: u64, rate: u64) -> u64 { @@ -21,7 +21,6 @@ impl ChainNodeApp { /// Distribute rewards pool pub fn rewards_try_distribute(&mut self) -> Option<(RewardsDistribution, Coin)> { let state = self.last_state.as_mut().unwrap(); - let account_root = Some(state.top_level.account_root); let top_level = &mut state.top_level; let params = &top_level.network_params; @@ -42,7 +41,7 @@ impl ChainNodeApp { let total_staking = state .staking_table - .reward_total_staking(&StakingGetter::new(&self.accounts, account_root)); + .reward_total_staking(&StakingGetter::new(&self.storage, state.staking_version)); let minted = if let Ok(can_mint) = params.get_rewards_monetary_expansion_cap() - top_level.rewards_pool.minted @@ -70,9 +69,10 @@ impl ChainNodeApp { let total_rewards = (top_level.rewards_pool.period_bonus + minted).unwrap(); top_level.rewards_pool.minted = (top_level.rewards_pool.minted + minted).unwrap(); - let (remainer, reward_distribution) = state - .staking_table - .reward_distribute(&mut staking_store!(self, account_root), total_rewards); + let (remainer, reward_distribution) = state.staking_table.reward_distribute( + &mut staking_store!(self, state.staking_version), + total_rewards, + ); top_level.rewards_pool.period_bonus = remainer; Some((reward_distribution, minted)) @@ -97,8 +97,8 @@ mod tests { fn check_rewards_distribution() { let expansion_cap = Coin::new(10_0000_0000_0000_0000).unwrap(); let dist = Coin::new(10_0000_0000_0000_0000).unwrap(); - let (env, storage, account_storage) = ChainEnv::new(dist, expansion_cap, 2); - let mut app = env.chain_node(storage, account_storage); + let (env, storage) = ChainEnv::new(dist, expansion_cap, 2); + let mut app = env.chain_node(storage); let _rsp = app.init_chain(&env.req_init_chain()); let total_staking = dist; @@ -163,8 +163,8 @@ mod tests { #[test] fn empty_block_should_not_change_app_hash() { - let (env, storage, account_storage) = ChainEnv::new(Coin::max(), Coin::zero(), 1); - let mut app = env.chain_node(storage, account_storage); + let (env, storage) = ChainEnv::new(Coin::max(), Coin::zero(), 1); + let mut app = env.chain_node(storage); let _rsp_init_chain = app.init_chain(&env.req_init_chain()); let mut req = env.req_begin_block(1, 0); diff --git a/chain-abci/src/app/validate_tx.rs b/chain-abci/src/app/validate_tx.rs index f404a8bd8..7e33ee916 100644 --- a/chain-abci/src/app/validate_tx.rs +++ b/chain-abci/src/app/validate_tx.rs @@ -71,7 +71,6 @@ impl ChainNodeApp { BufferType::Consensus => self.last_state.as_mut().expect("expect last_state"), BufferType::Mempool => self.mempool_state.as_mut().expect("expect last_state"), }; - let account_root = Some(state.top_level.account_root); let txaux = TxAux::decode(&mut req.tx())?; let txid = txaux.tx_id(); let (fee, maccount) = match &txaux { @@ -80,12 +79,12 @@ impl ChainNodeApp { &mut self.tx_validator, &tx, &extra_info, - &staking_getter!(self, account_root, buffer_type), + &staking_getter!(self, state.staking_version, buffer_type), &kv_store!(self, buffer_type), )?; // execute the action let maccount = execute_enclave_tx( - &mut staking_store!(self, account_root, buffer_type), + &mut staking_store!(self, state.staking_version, buffer_type), &mut kv_store!(self, buffer_type), state, &txid, @@ -94,7 +93,7 @@ impl ChainNodeApp { (action.fee(), maccount) } TxAux::PublicTx(tx) => process_public_tx( - &mut staking_store!(self, account_root, buffer_type), + &mut staking_store!(self, state.staking_version, buffer_type), &mut state.staking_table, &extra_info, &tx, diff --git a/chain-abci/src/main.rs b/chain-abci/src/main.rs index 8588028af..e3f944f67 100644 --- a/chain-abci/src/main.rs +++ b/chain-abci/src/main.rs @@ -9,7 +9,6 @@ use chain_abci::enclave_bridge::mock::MockClient; #[cfg(all(not(feature = "mock-validation"), target_os = "linux"))] use chain_abci::enclave_bridge::real::TxValidationApp; use chain_core::init::network::{get_network, get_network_id, init_chain_id}; -use chain_storage::account::AccountStorage; use chain_storage::{Storage, StorageConfig, StorageType}; #[cfg(any(feature = "mock-validation", not(target_os = "linux")))] use log::warn; @@ -186,11 +185,6 @@ fn main() { &config.genesis_app_hash.unwrap(), &config.chain_id.unwrap(), storage, - AccountStorage::new( - Storage::new(&StorageConfig::new(&opt.data, StorageType::AccountTrie)), - 20, - ) - .expect("account db"), config.tx_query, config.enclave_server, ), diff --git a/chain-abci/src/staking/table.rs b/chain-abci/src/staking/table.rs index 9d36427f6..b5cca4dd9 100644 --- a/chain-abci/src/staking/table.rs +++ b/chain-abci/src/staking/table.rs @@ -19,7 +19,7 @@ use chain_core::state::account::{ use chain_core::state::tendermint::{ BlockHeight, TendermintValidatorAddress, TendermintValidatorPubKey, TendermintVotePower, }; -use chain_storage::buffer::{Get, GetStaking, StakingGetter, StoreStaking}; +use chain_storage::buffer::{GetStaking, StoreStaking}; use crate::liveness::LivenessTracker; @@ -214,7 +214,7 @@ impl StakingTable { } /// The heap should not use the uncommited buffer. - pub fn reward_total_staking(&self, heap: &StakingGetter) -> Coin { + pub fn reward_total_staking(&self, heap: &impl GetStaking) -> Coin { // Sum of all the coins should not overflow max supply, TODO proof. sum_coins( self.chosen_validators diff --git a/chain-abci/src/storage/mod.rs b/chain-abci/src/storage/mod.rs index 9fee03b04..5d1b71862 100644 --- a/chain-abci/src/storage/mod.rs +++ b/chain-abci/src/storage/mod.rs @@ -3,13 +3,10 @@ use crate::staking::StakingTable; use crate::tx_error::PublicTxError; use chain_core::common::Timespec; use chain_core::init::coin::Coin; -use chain_core::state::account::{StakedState, StakedStateAddress, StakedStateOpAttributes}; +use chain_core::state::account::{StakedStateAddress, StakedStateOpAttributes}; use chain_core::tx::data::input::{TxoPointer, TxoSize}; use chain_core::tx::fee::Fee; use chain_core::tx::{TransactionId, TxEnclaveAux, TxObfuscated, TxPublicAux}; -use chain_storage::account::{ - get_staked_state, AccountStorage, StakedStateError, StarlingFixedKey, -}; use chain_storage::buffer::{GetKV, GetStaking, StoreStaking}; use chain_tx_validation::{verify_unjailed, witness::verify_tx_recover_address, ChainInfo, Error}; use enclave_protocol::{IntraEnclaveRequest, IntraEnclaveResponseOk, SealedLog}; @@ -84,19 +81,6 @@ impl TxEnclaveAction { } } -/// checks that the account can be retrieved from the trie storage -pub fn get_account( - account_address: &StakedStateAddress, - last_root: &StarlingFixedKey, - accounts: &AccountStorage, -) -> Result { - match get_staked_state(account_address, last_root, accounts) { - Ok(a) => Ok(a), - Err(StakedStateError::NotFound) => Err(Error::AccountNotFound), - Err(StakedStateError::IoError(_e)) => Err(Error::IoError), - } -} - fn check_spent_input_lookup( kvdb: &impl GetKV, inputs: &[TxoPointer], diff --git a/chain-abci/tests/abci_app.rs b/chain-abci/tests/abci_app.rs index 3c7f7c88e..6a4ce37d2 100644 --- a/chain-abci/tests/abci_app.rs +++ b/chain-abci/tests/abci_app.rs @@ -14,7 +14,7 @@ use chain_core::init::config::{ JailingParameters, RewardsParameters, SlashRatio, SlashingParameters, }; use chain_core::state::account::{ - to_stake_key, ConfidentialInit, CouncilNode, DepositBondTx, StakedState, StakedStateAddress, + ConfidentialInit, CouncilNode, DepositBondTx, StakedState, StakedStateAddress, StakedStateDestination, StakedStateOpAttributes, StakedStateOpWitness, UnbondTx, WithdrawUnbondedTx, }; @@ -41,9 +41,6 @@ use chain_core::tx::{ witness::{TxInWitness, TxWitness}, TxAux, TxEnclaveAux, TxPublicAux, }; -use chain_storage::account::AccountStorage; -use chain_storage::account::AccountWrapper; -use chain_storage::account::StarlingFixedKey; use chain_storage::buffer::Get; use chain_storage::{ LookupItem, Storage, COL_NODE_INFO, GENESIS_APP_HASH_KEY, LAST_STATE_KEY, NUM_COLUMNS, @@ -79,10 +76,6 @@ fn create_db() -> Arc { Arc::new(create(NUM_COLUMNS)) } -fn create_account_db() -> AccountStorage { - AccountStorage::new(Storage::new_db(Arc::new(create(1))), 20).expect("account db") -} - const TEST_CHAIN_ID: &str = "test-00"; #[test] @@ -94,7 +87,6 @@ fn proper_hash_and_chainid_should_be_stored() { example_hash, TEST_CHAIN_ID, Storage::new_db(db.clone()), - create_account_db(), None, None, ); @@ -115,7 +107,6 @@ fn too_long_hash_should_panic() { example_hash, TEST_CHAIN_ID, Storage::new_db(db.clone()), - create_account_db(), None, None, ); @@ -131,7 +122,6 @@ fn chain_id_without_hex_digits_should_panic() { example_hash, "test", Storage::new_db(db.clone()), - create_account_db(), None, None, ); @@ -147,7 +137,6 @@ fn nonhex_hash_should_panic() { example_hash, TEST_CHAIN_ID, Storage::new_db(db.clone()), - create_account_db(), None, None, ); @@ -186,6 +175,7 @@ fn get_dummy_app_state(app_hash: H256) -> ChainNodeState { block_height: BlockHeight::genesis(), genesis_time: 0, staking_table: StakingTable::default(), + staking_version: 0, top_level: ChainState { account_root: [0u8; 32], rewards_pool: RewardsPoolState::new(0, params.get_rewards_monetary_expansion_tau()), @@ -216,7 +206,6 @@ fn previously_stored_hash_should_match() { example_hash2, TEST_CHAIN_ID, Storage::new_db(db.clone()), - create_account_db(), None, None, ); @@ -271,17 +260,8 @@ fn init_chain_for(address: RedeemAddress) -> ChainNodeApp { let result = c.validate_config_get_genesis(t.get_seconds().try_into().unwrap()); if let Ok((accounts, rp, _nodes)) = result { let tx_tree = MerkleTree::empty(); - let mut account_tree = - AccountStorage::new(Storage::new_db(Arc::new(create(1))), 20).expect("account db"); - - let mut keys: Vec = accounts.iter().map(|x| x.key()).collect(); - // TODO: get rid of the extra allocations - let wrapped: Vec = - accounts.iter().map(|x| AccountWrapper(x.clone())).collect(); - let new_account_root = account_tree - .insert(None, &mut keys, &wrapped) - .expect("initial insert"); - + let mut storage = Storage::new_db(db.clone()); + let new_account_root = storage.put_stakings(0, &accounts); let genesis_app_hash = compute_app_hash( &tx_tree, &new_account_root, @@ -294,8 +274,7 @@ fn init_chain_for(address: RedeemAddress) -> ChainNodeApp { get_enclave_bridge_mock(), &example_hash, TEST_CHAIN_ID, - Storage::new_db(db.clone()), - create_account_db(), + storage, None, None, ); @@ -322,15 +301,9 @@ fn init_chain_should_create_db_items() { ChainNodeState::decode(&mut app.storage.get_last_app_state().unwrap().as_slice()).unwrap(); assert_eq!(genesis_app_hash, state.last_apphash); - let key = to_stake_key(&address.into()); - assert_eq!( - 1, - app.accounts - .get(&state.top_level.account_root, &mut [key]) - .expect("account") - .iter() - .count() - ); + app.staking_getter_committed() + .get(&address.into()) + .expect("account not exists"); } #[test] @@ -376,7 +349,6 @@ fn init_chain_panics_with_different_app_hash() { &example_hash, TEST_CHAIN_ID, Storage::new_db(db.clone()), - create_account_db(), None, None, ); @@ -397,7 +369,6 @@ fn init_chain_panics_with_empty_app_bytes() { &example_hash, TEST_CHAIN_ID, Storage::new_db(db.clone()), - create_account_db(), None, None, ); @@ -1035,11 +1006,11 @@ fn all_valid_tx_types_should_commit() { #[test] fn query_should_return_proof_for_committed_tx() { - let (env, storage, account_storage) = + let (env, storage) = ChainEnv::new_with_customizer(Coin::max(), Coin::zero(), 2, |parameters| { parameters.required_council_node_stake = (Coin::max() / 10).unwrap(); }); - let mut app = env.chain_node(storage, account_storage); + let mut app = env.chain_node(storage); let _rsp = app.init_chain(&env.req_init_chain()); app.begin_block(&env.req_begin_block(1, 0)); diff --git a/chain-abci/tests/punishment.rs b/chain-abci/tests/punishment.rs index e0cf4036b..c76a552e8 100644 --- a/chain-abci/tests/punishment.rs +++ b/chain-abci/tests/punishment.rs @@ -7,11 +7,11 @@ use test_common::chain_env::{get_account, ChainEnv}; #[test] fn end_block_should_update_liveness_tracker() { // Init Chain - let (env, storage, account_storage) = + let (env, storage) = ChainEnv::new_with_customizer(Coin::max(), Coin::zero(), 1, |parameters| { parameters.required_council_node_stake = Coin::max(); }); - let mut app = env.chain_node(storage, account_storage); + let mut app = env.chain_node(storage); let _rsp = app.init_chain(&env.req_init_chain()); // Begin Block @@ -49,8 +49,8 @@ fn end_block_should_update_liveness_tracker() { #[test] fn begin_block_should_jail_byzantine_validators() { // Init Chain - let (env, storage, account_storage) = ChainEnv::new(Coin::max(), Coin::zero(), 1); - let mut app = env.chain_node(storage, account_storage); + let (env, storage) = ChainEnv::new(Coin::max(), Coin::zero(), 1); + let mut app = env.chain_node(storage); let _rsp_init_chain = app.init_chain(&env.req_init_chain()); // Begin Block @@ -73,8 +73,8 @@ fn begin_block_should_jail_byzantine_validators() { #[test] fn begin_block_should_punish_non_live_validators() { // Init Chain - let (env, storage, account_storage) = ChainEnv::new(Coin::max(), Coin::zero(), 1); - let mut app = env.chain_node(storage, account_storage); + let (env, storage) = ChainEnv::new(Coin::max(), Coin::zero(), 1); + let mut app = env.chain_node(storage); let _rsp_init_chain = app.init_chain(&env.req_init_chain()); // Begin Block @@ -100,8 +100,8 @@ fn begin_block_should_punish_non_live_validators() { #[test] fn begin_block_should_slash_byzantine_validators() { // Init Chain - let (env, storage, account_storage) = ChainEnv::new(Coin::max(), Coin::zero(), 1); - let mut app = env.chain_node(storage, account_storage); + let (env, storage) = ChainEnv::new(Coin::max(), Coin::zero(), 1); + let mut app = env.chain_node(storage); let _rsp_init_chain = app.init_chain(&env.req_init_chain()); // Begin Block @@ -133,8 +133,8 @@ fn begin_block_should_slash_byzantine_validators() { #[test] fn begin_block_should_slash_non_live_validators() { // Init Chain - let (env, storage, account_storage) = ChainEnv::new(Coin::max(), Coin::zero(), 1); - let mut app = env.chain_node(storage, account_storage); + let (env, storage) = ChainEnv::new(Coin::max(), Coin::zero(), 1); + let mut app = env.chain_node(storage); let _rsp_init_chain = app.init_chain(&env.req_init_chain()); // Begin Block diff --git a/chain-abci/tests/tx_validation.rs b/chain-abci/tests/tx_validation.rs index 4cce61952..8778d639d 100644 --- a/chain-abci/tests/tx_validation.rs +++ b/chain-abci/tests/tx_validation.rs @@ -38,10 +38,8 @@ use chain_core::tx::PlainTxAux; use chain_core::tx::TransactionId; use chain_core::tx::TxObfuscated; use chain_core::tx::{TxAux, TxEnclaveAux, TxPublicAux}; -use chain_storage::account::AccountStorage; -use chain_storage::account::AccountWrapper; -use chain_storage::account::StarlingFixedKey; -use chain_storage::buffer::{Get, StakingBufferStore, StakingGetter}; +use chain_storage::buffer::Get; +use chain_storage::jellyfish::{StakingBufferStore, StakingGetter, Version}; use chain_storage::{Storage, COL_ENCLAVE_TX, COL_TX_META, NUM_COLUMNS}; use chain_tx_validation::{ verify_bonded_deposit_core, verify_transfer, verify_unbonded_withdraw_core, ChainInfo, Error, @@ -60,15 +58,14 @@ fn verify_enclave_tx( tx_validator: &mut T, txaux: &TxEnclaveAux, extra_info: &ChainInfo, - root: &StarlingFixedKey, + version: Version, storage: &Storage, - accounts: &AccountStorage, ) -> Result { verify_enclave_tx_inner( tx_validator, txaux, &extra_info, - &StakingGetter::new(&accounts, Some(*root)), + &StakingGetter::new(storage, version), storage, ) } @@ -77,18 +74,14 @@ fn verify_public_tx( txaux: &TxPublicAux, extra_info: &ChainInfo, info: NodeInfoWrap, - root: &StarlingFixedKey, - accounts: &AccountStorage, + version: Version, + storage: &Storage, ) -> Result<(Fee, Option), TxError> { - let mut tbl = StakingTable::from_genesis( - &StakingGetter::new(&accounts, Some(*root)), - info.0, - 50, - &info.1, - ); + let mut tbl = + StakingTable::from_genesis(&StakingGetter::new(storage, version), info.0, 50, &info.1); let mut buffer = HashMap::new(); - let mut store = StakingBufferStore::new(StakingGetter::new(accounts, Some(*root)), &mut buffer); + let mut store = StakingBufferStore::new(StakingGetter::new(storage, version), &mut buffer); let (fee, maddress) = process_public_tx(&mut store, &mut tbl, extra_info, txaux)?; Ok((fee, maddress.map(|addr| store.get(&addr).unwrap()))) } @@ -235,7 +228,7 @@ fn prepare_app_valid_transfer_tx( TxWitness, MerkleTree, SecretKey, - AccountStorage, + Storage, ) { let (db, txp, addr, merkle_tree, secret_key) = prepate_init_tx(timelocked); let secp = Secp256k1::new(); @@ -260,33 +253,25 @@ fn prepare_app_valid_transfer_tx( }, }; ( - db, + db.clone(), txaux, tx, witness.into(), merkle_tree, secret_key, - AccountStorage::new(Storage::new_db(create_db()), 20).expect("account db"), + Storage::new_db(db), ) } -fn prepare_app_valid_unbond_tx() -> ( - TxPublicAux, - UnbondTx, - SecretKey, - AccountStorage, - StarlingFixedKey, -) { - let mut tree = AccountStorage::new(Storage::new_db(create_db()), 20).expect("account db"); +fn prepare_app_valid_unbond_tx() -> (TxPublicAux, UnbondTx, SecretKey, Storage) { + let mut storage = Storage::new_db(create_db()); let secp = Secp256k1::new(); let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); let public_key = PublicKey::from_secret_key(&secp, &secret_key); let addr = RedeemAddress::from(&public_key); let account = StakedState::new(1, Coin::one(), Coin::zero(), 0, addr.into(), None); - let key = account.key(); - let wrapped = AccountWrapper(account); - let new_root = tree.insert(None, &mut [key], &[wrapped]).expect("insert"); + storage.put_stakings(0, &[account]); let tx = UnbondTx::new( addr.into(), 1, @@ -295,38 +280,26 @@ fn prepare_app_valid_unbond_tx() -> ( ); let witness = get_account_op_witness(secp, &tx.id(), &secret_key); let txaux = TxPublicAux::UnbondStakeTx(tx.clone(), witness); - (txaux, tx, secret_key, tree, new_root) + (txaux, tx, secret_key, storage) } #[test] fn existing_account_unbond_tx_should_verify() { - let (txaux, _, _, accounts, last_account_root_hash) = prepare_app_valid_unbond_tx(); + let (txaux, _, _, storage) = prepare_app_valid_unbond_tx(); let extra_info = get_chain_info_pub(&txaux); - let result = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &last_account_root_hash, - &accounts, - ); + let result = verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage); assert!(result.is_ok()); } #[test] fn test_account_unbond_verify_fail() { - let (txaux, tx, secret_key, accounts, last_account_root_hash) = prepare_app_valid_unbond_tx(); + let (txaux, tx, secret_key, storage) = prepare_app_valid_unbond_tx(); let extra_info = get_chain_info_pub(&txaux); // WrongChainHexId { let mut extra_info = extra_info; extra_info.chain_hex_id = DEFAULT_CHAIN_ID + 1; - let result = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &last_account_root_hash, - &accounts, - ); + let result = verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage); expect_error_public(&result, PublicTxError::WrongChainHexId); } // UnsupportedVersion @@ -337,13 +310,7 @@ fn test_account_unbond_verify_fail() { tx.clone(), get_account_op_witness(Secp256k1::new(), &tx.id(), &secret_key), ); - let result = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &last_account_root_hash, - &accounts, - ); + let result = verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage); expect_error_public(&result, PublicTxError::UnsupportedVersion); } // AccountNotFound, non exist account treated as a default account, so incorrect nonce. @@ -352,8 +319,8 @@ fn test_account_unbond_verify_fail() { &txaux, &extra_info, NodeInfoWrap::default(), - &[0; 32], - &accounts, + 0, + &create_storage(), ); expect_error_public(&result, PublicTxError::IncorrectNonce); } @@ -365,13 +332,7 @@ fn test_account_unbond_verify_fail() { tx.clone(), get_account_op_witness(Secp256k1::new(), &tx.id(), &secret_key), ); - let result = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &last_account_root_hash, - &accounts, - ); + let result = verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage); expect_error_public(&result, PublicTxError::IncorrectNonce); } // ZeroCoin @@ -382,13 +343,7 @@ fn test_account_unbond_verify_fail() { tx.clone(), get_account_op_witness(Secp256k1::new(), &tx.id(), &secret_key), ); - let result = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &last_account_root_hash, - &accounts, - ); + let result = verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage); expect_error_unbond(&result, UnbondError::ZeroValue); } // InputOutputDoNotMatch @@ -399,13 +354,7 @@ fn test_account_unbond_verify_fail() { tx.clone(), get_account_op_witness(Secp256k1::new(), &tx.id(), &secret_key), ); - let result = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &last_account_root_hash, - &accounts, - ); + let result = verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage); expect_error_unbond(&result, UnbondError::CoinError(CoinError::Negative)); } } @@ -418,10 +367,9 @@ fn prepare_app_valid_withdraw_tx( StakedStateOpWitness, StakedState, SecretKey, - AccountStorage, - StarlingFixedKey, + Storage, ) { - let mut tree = AccountStorage::new(Storage::new_db(create_db()), 20).expect("account db"); + let mut storage = create_storage(); let secp = Secp256k1::new(); let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); let public_key = PublicKey::from_secret_key(&secp, &secret_key); @@ -435,9 +383,7 @@ fn prepare_app_valid_withdraw_tx( addr.into(), None, ); - let key = account.key(); - let wrapped = AccountWrapper(account.clone()); - let new_root = tree.insert(None, &mut [key], &[wrapped]).expect("insert"); + storage.put_stakings(0, &[account.clone()]); let sk2 = SecretKey::from_slice(&[0x11; 32]).expect("32 bytes, within curve order"); @@ -462,43 +408,33 @@ fn prepare_app_valid_withdraw_tx( txpayload: PlainTxAux::WithdrawUnbondedStakeTx(tx.clone()).encode(), }, }; - (txaux, tx, witness, account, secret_key, tree, new_root) + (txaux, tx, witness, account, secret_key, storage) } #[test] fn existing_account_withdraw_tx_should_verify() { - let (txaux, _, _, _, _, accounts, last_account_root_hash) = prepare_app_valid_withdraw_tx(0); + let (txaux, _, _, _, _, storage) = prepare_app_valid_withdraw_tx(0); let extra_info = get_chain_info_enc(&txaux); let result = verify_enclave_tx( &mut get_enclave_bridge_mock(), &txaux, &extra_info, - &last_account_root_hash, - &create_storage(), - &accounts, + 0, + &storage, ); assert!(result.is_ok()); } #[test] fn test_account_withdraw_verify_fail() { - let storage = create_storage(); - let (txaux, tx, _, account, secret_key, accounts, last_account_root_hash) = - prepare_app_valid_withdraw_tx(0); + let (txaux, tx, _, account, secret_key, storage) = prepare_app_valid_withdraw_tx(0); let extra_info = get_chain_info_enc(&txaux); let mut mock_bridge = get_enclave_bridge_mock(); // WrongChainHexId { let mut extra_info = extra_info; extra_info.chain_hex_id = DEFAULT_CHAIN_ID + 1; - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_unbonded_withdraw_core(&tx, &extra_info, &account); expect_error(&result, Error::WrongChainHexId); @@ -514,14 +450,7 @@ fn test_account_withdraw_verify_fail() { Some(witness), None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_unbonded_withdraw_core(&tx, &extra_info, &account); expect_error(&result, Error::UnsupportedVersion); @@ -537,14 +466,7 @@ fn test_account_withdraw_verify_fail() { Some(witness), None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_unbonded_withdraw_core(&tx, &extra_info, &account); expect_error(&result, Error::NoOutputs); @@ -560,14 +482,7 @@ fn test_account_withdraw_verify_fail() { Some(witness), None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_unbonded_withdraw_core(&tx, &extra_info, &account); expect_error(&result, Error::ZeroCoin); @@ -585,14 +500,7 @@ fn test_account_withdraw_verify_fail() { Some(witness), None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_unbonded_withdraw_core(&tx, &extra_info, &account); expect_error( @@ -611,28 +519,14 @@ fn test_account_withdraw_verify_fail() { Some(witness), None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_unbonded_withdraw_core(&tx, &extra_info, &account); expect_error(&result, Error::InputOutputDoNotMatch); } // AccountNotFound { - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &[0; 32], - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &create_storage()); expect_error(&result, Error::AccountNotFound); } // AccountIncorrectNonce @@ -646,14 +540,7 @@ fn test_account_withdraw_verify_fail() { Some(witness), None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_unbonded_withdraw_core(&tx, &extra_info, &account); expect_error(&result, Error::AccountIncorrectNonce); @@ -669,30 +556,15 @@ fn test_account_withdraw_verify_fail() { Some(witness), None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_unbonded_withdraw_core(&tx, &extra_info, &account); expect_error(&result, Error::AccountWithdrawOutputNotLocked); } // AccountNotUnbonded { - let (txaux, _, _, account, _, accounts, last_account_root_hash) = - prepare_app_valid_withdraw_tx(20); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let (txaux, _, _, account, _, storage) = prepare_app_valid_withdraw_tx(20); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_unbonded_withdraw_core(&tx, &extra_info, &account); expect_error(&result, Error::AccountNotUnbonded); @@ -707,7 +579,7 @@ fn prepare_app_valid_deposit_tx( DepositBondTx, TxWitness, SecretKey, - AccountStorage, + Storage, ) { let (db, txp, _, merkle_tree, secret_key) = prepate_init_tx(timelocked); let secp = Secp256k1::new(); @@ -731,12 +603,12 @@ fn prepare_app_valid_deposit_tx( }, }; ( - db, + db.clone(), txaux, tx, witness.into(), secret_key, - AccountStorage::new(create_storage(), 20).expect("account db"), + Storage::new_db(db), ) } @@ -745,30 +617,11 @@ const DEFAULT_CHAIN_ID: u8 = 0; #[test] fn existing_utxo_input_tx_should_verify() { let mut mock_bridge = get_enclave_bridge_mock(); - let (db, txaux, _, _, _, _, accounts) = prepare_app_valid_transfer_tx(false); - let storage = Storage::new_db(db); + let (_, txaux, _, _, _, _, storage) = prepare_app_valid_transfer_tx(false); let extra_info = get_chain_info_enc(&txaux); - let last_account_root_hash = [0u8; 32]; - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); - assert!(result.is_ok()); - let (db, txaux, _, _, _, accounts) = prepare_app_valid_deposit_tx(false); - let storage = Storage::new_db(db); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); - assert!(result.is_ok()); + verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage).unwrap(); + let (_, txaux, _, _, _, storage) = prepare_app_valid_deposit_tx(false); + verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage).unwrap(); } fn expect_error(res: &Result, expected: Error) @@ -820,22 +673,13 @@ fn expect_error_unjail(res: &Result, expected: UnjailError) { #[test] fn test_deposit_verify_fail() { let mut mock_bridge = get_enclave_bridge_mock(); - let (db, txaux, tx, witness, secret_key, accounts) = prepare_app_valid_deposit_tx(false); - let storage = Storage::new_db(db.clone()); + let (db, txaux, tx, witness, secret_key, storage) = prepare_app_valid_deposit_tx(false); let extra_info = get_chain_info_enc(&txaux); - let last_account_root_hash = [0u8; 32]; // WrongChainHexId { let mut extra_info = extra_info; extra_info.chain_hex_id = DEFAULT_CHAIN_ID + 1; - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_bonded_deposit_core(&tx, &witness, &extra_info, vec![]); expect_error(&result, Error::WrongChainHexId); @@ -850,14 +694,7 @@ fn test_deposit_verify_fail() { None, Some(tx.clone()), ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_bonded_deposit_core(&tx, &witness, &extra_info, vec![]); expect_error(&result, Error::UnsupportedVersion); @@ -872,14 +709,7 @@ fn test_deposit_verify_fail() { None, Some(tx.clone()), ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_bonded_deposit_core(&tx, &witness, &extra_info, vec![]); expect_error(&result, Error::NoInputs); @@ -895,14 +725,7 @@ fn test_deposit_verify_fail() { None, Some(tx.clone()), ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_bonded_deposit_core(&tx, &witness, &extra_info, vec![]); expect_error(&result, Error::DuplicateInputs); @@ -918,14 +741,7 @@ fn test_deposit_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_bonded_deposit_core(&tx, &witness, &extra_info, vec![]); expect_error(&result, Error::UnexpectedWitnesses); @@ -938,14 +754,7 @@ fn test_deposit_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_bonded_deposit_core(&tx, &vec![].into(), &extra_info, vec![]); expect_error(&result, Error::MissingWitnesses); @@ -960,14 +769,7 @@ fn test_deposit_verify_fail() { ); db.write(inittx).unwrap(); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); expect_error(&result, Error::InputSpent); let mut reset = db.transaction(); @@ -1013,40 +815,19 @@ fn test_deposit_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); } // InvalidInput { - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &create_storage(), - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &create_storage()); expect_error(&result, Error::InvalidInput); } // InputOutputDoNotMatch { let mut extra_info = extra_info; extra_info.min_fee_computed = Fee::new(Coin::one()); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_bonded_deposit_core(&tx, &witness, &extra_info, vec![]); expect_error(&result, Error::InputOutputDoNotMatch); @@ -1130,23 +911,14 @@ fn replace_tx_payload( #[test] fn test_transfer_verify_fail() { let mut mock_bridge = get_enclave_bridge_mock(); - let (db, txaux, tx, witness, merkle_tree, secret_key, accounts) = + let (db, txaux, tx, witness, merkle_tree, secret_key, storage) = prepare_app_valid_transfer_tx(false); - let storage = Storage::new_db(db.clone()); let extra_info = get_chain_info_enc(&txaux); - let last_account_root_hash = [0u8; 32]; // WrongChainHexId { let mut extra_info = extra_info; extra_info.chain_hex_id = DEFAULT_CHAIN_ID + 1; - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_transfer(&tx, &witness, &extra_info, vec![]); expect_error(&result, Error::WrongChainHexId); @@ -1161,23 +933,9 @@ fn test_transfer_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); expect_error(&result, Error::UnsupportedVersion); } // NoInputs @@ -1190,14 +948,7 @@ fn test_transfer_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); expect_error(&result, Error::NoInputs); } // NoOutputs @@ -1212,14 +963,7 @@ fn test_transfer_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); } // DuplicateInputs @@ -1235,14 +979,7 @@ fn test_transfer_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); } // ZeroCoin @@ -1257,14 +994,7 @@ fn test_transfer_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); } // UnexpectedWitnesses @@ -1280,14 +1010,7 @@ fn test_transfer_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); } // MissingWitnesses @@ -1298,14 +1021,7 @@ fn test_transfer_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); let result = verify_transfer(&tx.clone(), &vec![].into(), &extra_info, vec![]); expect_error(&result, Error::MissingWitnesses); @@ -1329,14 +1045,7 @@ fn test_transfer_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); } // InputSpent @@ -1349,14 +1058,7 @@ fn test_transfer_verify_fail() { ); db.write(inittx).unwrap(); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); expect_error(&result, Error::InputSpent); let mut reset = db.transaction(); @@ -1402,26 +1104,12 @@ fn test_transfer_verify_fail() { None, None, ); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); } // InvalidInput { - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &create_storage(), - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &create_storage()); expect_error(&result, Error::InvalidInput); } // InputOutputDoNotMatch @@ -1434,20 +1122,12 @@ fn test_transfer_verify_fail() { let result = verify_transfer(&tx, &witness, &extra_info, vec![]); expect_error(&result, Error::InputOutputDoNotMatch); let txaux = replace_tx_payload(txaux, PlainTxAux::TransferTx(tx, witness), None, None); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); } // OutputInTimelock { - let (db, txaux, tx, witness, _, _, accounts) = prepare_app_valid_transfer_tx(true); - let storage = Storage::new_db(db); + let (_, txaux, tx, witness, _, _, storage) = prepare_app_valid_transfer_tx(true); let addr = get_address(&Secp256k1::new(), &secret_key).0; let input_tx = get_old_tx(addr, true); let result = verify_transfer( @@ -1457,28 +1137,18 @@ fn test_transfer_verify_fail() { vec![TxWithOutputs::Transfer(input_tx)], ); expect_error(&result, Error::OutputInTimelock); - let result = verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &last_account_root_hash, - &storage, - &accounts, - ); + let result = verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage); assert!(result.is_err()); } } fn prepare_jailed_accounts() -> ( - Arc, - AccountStorage, + Storage, SecretKey, RedeemAddress, MerkleTree, - StarlingFixedKey, ) { - let db = create_db(); - let mut accounts = AccountStorage::new(Storage::new_db(db.clone()), 20).expect("account db"); + let mut storage = create_storage(); let secp = Secp256k1::new(); let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); @@ -1507,13 +1177,9 @@ fn prepare_jailed_accounts() -> ( }), ); - let key = account.key(); - let wrapped = AccountWrapper(account); - let root = accounts - .insert(None, &mut [key], &[wrapped]) - .expect("insert"); + storage.put_stakings(0, &[account]); - (db, accounts, secret_key, addr, merkle_tree, root) + (storage, secret_key, addr, merkle_tree) } fn prepare_withdraw_transaction(secret_key: &SecretKey) -> TxEnclaveAux { @@ -1594,22 +1260,14 @@ fn prepare_unjail_transaction( #[test] fn check_verify_fail_for_jailed_account() { let mut mock_bridge = get_enclave_bridge_mock(); - let (db, accounts, secret_key, address, merkle_tree, root) = prepare_jailed_accounts(); - let storage = Storage::new_db(db); + let (storage, secret_key, address, merkle_tree) = prepare_jailed_accounts(); // Withdraw transaction let txaux = prepare_withdraw_transaction(&secret_key); let extra_info = get_chain_info_enc(&txaux); expect_error( - &verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &root, - &storage, - &accounts, - ), + &verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage), Error::AccountJailed, ); @@ -1619,14 +1277,7 @@ fn check_verify_fail_for_jailed_account() { let extra_info = get_chain_info_enc(&txaux); expect_error( - &verify_enclave_tx( - &mut mock_bridge, - &txaux, - &extra_info, - &root, - &storage, - &accounts, - ), + &verify_enclave_tx(&mut mock_bridge, &txaux, &extra_info, 0, &storage), Error::AccountJailed, ); @@ -1636,13 +1287,7 @@ fn check_verify_fail_for_jailed_account() { let extra_info = get_chain_info_pub(&txaux); expect_error_unbond( - &verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &root, - &accounts, - ), + &verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage), UnbondError::IsJailed, ); @@ -1653,20 +1298,14 @@ fn check_verify_fail_for_jailed_account() { let extra_info = get_chain_info_pub(&txaux); expect_error_joinnode( - &verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &root, - &accounts, - ), + &verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage), NodeJoinError::IsJailed, ); } #[test] fn check_unjail_transaction() { - let (_db, accounts, secret_key, address, _merkle_tree, root) = prepare_jailed_accounts(); + let (storage, secret_key, address, _merkle_tree) = prepare_jailed_accounts(); // Incorrect nonce @@ -1675,13 +1314,7 @@ fn check_unjail_transaction() { let extra_info = get_chain_info_pub(&txaux); expect_error_public( - &verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &root, - &accounts, - ), + &verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage), PublicTxError::IncorrectNonce, ); @@ -1692,13 +1325,7 @@ fn check_unjail_transaction() { let extra_info = get_chain_info_pub(&txaux); expect_error_unjail( - &verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &root, - &accounts, - ), + &verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage), UnjailError::JailTimeNotExpired, ); @@ -1716,14 +1343,9 @@ fn check_unjail_transaction() { unbonding_period: 1, }; - let (fee, new_account) = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &root, - &accounts, - ) - .expect("Verification of unjail transaction failed"); + let (fee, new_account) = + verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage) + .expect("Verification of unjail transaction failed"); assert_eq!(Fee::new(Coin::zero()), fee); assert!(!new_account.unwrap().is_jailed()); @@ -1760,10 +1382,9 @@ fn prepare_valid_nodejoin_tx( NodeJoinRequestTx, StakedStateAddress, SecretKey, - AccountStorage, - StarlingFixedKey, + Storage, ) { - let mut tree = AccountStorage::new(Storage::new_db(create_db()), 20).expect("account db"); + let mut storage = Storage::new_db(create_db()); let secp = Secp256k1::new(); let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order"); let public_key = PublicKey::from_secret_key(&secp, &secret_key); @@ -1786,26 +1407,19 @@ fn prepare_valid_nodejoin_tx( None }, ); - let key = account.key(); - let wrapped = AccountWrapper(account); - let new_root = tree.insert(None, &mut [key], &[wrapped]).expect("insert"); + storage.put_stakings(0, &[account]); let (txaux, tx) = prepare_nodejoin_transaction(&secret_key, addr.into()); - (txaux, tx, addr.into(), secret_key, tree, new_root) + (txaux, tx, addr.into(), secret_key, storage) } #[test] fn test_nodejoin_success() { - let (txaux, _, _, _, accounts, root) = prepare_valid_nodejoin_tx(false); + let (txaux, _, _, _, storage) = prepare_valid_nodejoin_tx(false); let extra_info = get_chain_info_pub(&txaux); - let (fee, new_account) = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &root, - &accounts, - ) - .expect("Verification of node join transaction failed"); + let (fee, new_account) = + verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage) + .expect("Verification of node join transaction failed"); assert_eq!(Fee::new(Coin::zero()), fee); assert!(new_account.unwrap().validator.is_some()); @@ -1813,19 +1427,13 @@ fn test_nodejoin_success() { #[test] fn test_nodejoin_fail() { - let (txaux, tx, _addr, secret_key, accounts, root) = prepare_valid_nodejoin_tx(false); + let (txaux, tx, _addr, secret_key, storage) = prepare_valid_nodejoin_tx(false); let extra_info = get_chain_info_pub(&txaux); // WrongChainHexId { let mut extra_info = extra_info; extra_info.chain_hex_id = DEFAULT_CHAIN_ID + 1; - let result = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &root, - &accounts, - ); + let result = verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage); expect_error_public(&result, PublicTxError::WrongChainHexId); } // UnsupportedVersion @@ -1836,13 +1444,7 @@ fn test_nodejoin_fail() { tx.clone(), get_account_op_witness(Secp256k1::new(), &tx.id(), &secret_key), ); - let result = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &root, - &accounts, - ); + let result = verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage); expect_error_public(&result, PublicTxError::UnsupportedVersion); } // AccountNotFound, not exist account treated as empty account, so incorrect nonce @@ -1851,8 +1453,8 @@ fn test_nodejoin_fail() { &txaux, &extra_info, NodeInfoWrap::default(), - &[0; 32], - &accounts, + 0, + &create_storage(), ); expect_error_public(&result, PublicTxError::IncorrectNonce); } @@ -1864,13 +1466,7 @@ fn test_nodejoin_fail() { tx.clone(), get_account_op_witness(Secp256k1::new(), &tx.id(), &secret_key), ); - let result = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &root, - &accounts, - ); + let result = verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage); expect_error_public(&result, PublicTxError::IncorrectNonce); } // MismatchAccountAddress @@ -1881,26 +1477,20 @@ fn test_nodejoin_fail() { tx.clone(), get_account_op_witness(Secp256k1::new(), &tx.id(), &secret_key), ); - let result = verify_public_tx( - &txaux, - &extra_info, - NodeInfoWrap::default(), - &root, - &accounts, - ); + let result = verify_public_tx(&txaux, &extra_info, NodeInfoWrap::default(), 0, &storage); expect_error_public(&result, PublicTxError::StakingWitnessNotMatch); } // BondedNotEnough { let wrap = NodeInfoWrap::custom((Coin::one() + Coin::one()).unwrap(), Vec::new()); - let result = verify_public_tx(&txaux, &extra_info, wrap, &root, &accounts); + let result = verify_public_tx(&txaux, &extra_info, wrap, 0, &storage); expect_error_joinnode(&result, NodeJoinError::BondedNotEnough); } - let (txaux, _tx, addr, _secret_key, accounts, root) = prepare_valid_nodejoin_tx(true); + let (txaux, _tx, addr, _secret_key, storage) = prepare_valid_nodejoin_tx(true); // AlreadyJoined { let wrap = NodeInfoWrap::custom(Coin::one(), vec![addr]); - let result = verify_public_tx(&txaux, &extra_info, wrap, &root, &accounts); + let result = verify_public_tx(&txaux, &extra_info, wrap, 0, &storage); expect_error_joinnode(&result, NodeJoinError::AlreadyJoined); } } diff --git a/chain-abci/tests/validator_changes.rs b/chain-abci/tests/validator_changes.rs index 10e6d0b23..0cd8a9e03 100644 --- a/chain-abci/tests/validator_changes.rs +++ b/chain-abci/tests/validator_changes.rs @@ -12,11 +12,11 @@ use test_common::chain_env::{get_account, get_validator, ChainEnv}; #[test] fn check_unbonding_without_removing_validator() { // Init Chain - let (env, storage, account_storage) = + let (env, storage) = ChainEnv::new_with_customizer(Coin::max(), Coin::zero(), 2, |parameters| { parameters.required_council_node_stake = (Coin::max() / 10).unwrap(); }); - let mut app = env.chain_node(storage, account_storage); + let mut app = env.chain_node(storage); let _rsp = app.init_chain(&env.req_init_chain()); // Note: At this point, there are two validators with `Coin::max() / 2` staked amount each. @@ -58,11 +58,11 @@ fn check_unbonding_without_removing_validator() { #[test] fn check_unbonding_with_removing_validator() { // Init Chain - let (env, storage, account_storage) = + let (env, storage) = ChainEnv::new_with_customizer(Coin::max(), Coin::zero(), 2, |parameters| { parameters.required_council_node_stake = (Coin::max() / 10).unwrap(); }); - let mut app = env.chain_node(storage, account_storage); + let mut app = env.chain_node(storage); let _rsp = app.init_chain(&env.req_init_chain()); let state = app.last_state.as_ref().unwrap(); let tm_address = &env.validator_address(0); @@ -145,7 +145,7 @@ fn check_unbonding_with_removing_validator() { #[test] fn check_rejoin() { // Init Chain - let (env, storage, account_storage) = ChainEnv::new_with_customizer( + let (env, storage) = ChainEnv::new_with_customizer( (Coin::max() / 2).unwrap(), (Coin::max() / 2).unwrap(), 2, @@ -159,7 +159,7 @@ fn check_rejoin() { parameters.rewards_config.monetary_expansion_decay = 0; }, ); - let mut app = env.chain_node(storage, account_storage); + let mut app = env.chain_node(storage); let _rsp = app.init_chain(&env.req_init_chain()); let state = app.last_state.as_ref().unwrap(); let tm_address = &env.validator_address(0); diff --git a/chain-storage/Cargo.toml b/chain-storage/Cargo.toml index e72e70aab..e29991368 100644 --- a/chain-storage/Cargo.toml +++ b/chain-storage/Cargo.toml @@ -13,7 +13,6 @@ kvdb-rocksdb = "0.7" kvdb-memorydb = "0.5" chain-core = { path = "../chain-core" } bit-vec = { version = "0.6.1", features = ["serde_no_std"] } -starling = "3.1.4" parity-scale-codec = { features = ["derive"], version = "1.3" } integer-encoding = "1.1.5" anyhow = "1.0" diff --git a/chain-storage/src/buffer.rs b/chain-storage/src/buffer.rs index 219d80270..16c8b4045 100644 --- a/chain-storage/src/buffer.rs +++ b/chain-storage/src/buffer.rs @@ -37,11 +37,9 @@ use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; use kvdb::KeyValueDB; -use starling::traits::Exception; -use chain_core::state::account::{to_stake_key, StakedState, StakedStateAddress}; +use chain_core::state::account::{StakedState, StakedStateAddress}; -use crate::account::{AccountStorage as StakingStorage, AccountWrapper, StarlingFixedKey}; use crate::Storage; pub trait Get { @@ -88,29 +86,6 @@ pub trait StoreStaking: SimpleStore StoreStaking for S where S: SimpleStore {} -/// Implement `Get` for readonly merkle trie. -pub struct StakingGetter<'a> { - storage: &'a StakingStorage, - root: Option, -} -impl<'a> StakingGetter<'a> { - pub fn new(storage: &'a StakingStorage, root: Option) -> Self { - Self { storage, root } - } -} -impl<'a> Get for StakingGetter<'a> { - type Key = StakedStateAddress; - type Value = StakedState; - fn get(&self, key: &Self::Key) -> Option { - self.root.as_ref().and_then(|root| { - self.storage - .get_one(root, &to_stake_key(key)) - .unwrap() - .map(|AccountWrapper(o)| o) - }) - } -} - /// Generic readonly buffered storage implementation pub struct BufferGetter<'a, S: Get, H> { storage: S, @@ -235,11 +210,6 @@ where } } -/// Specialized for staking -pub type StakingBufferStore<'a, H> = BufferSimpleStore<'a, StakingGetter<'a>, H>; -/// Specialized for staking -pub type StakingBufferGetter<'a, H> = BufferGetter<'a, StakingGetter<'a>, H>; - /// Dummy storage implemented with a HashMap in memory. #[derive(Debug, Clone)] pub struct MemStore(HashMap); @@ -290,22 +260,6 @@ where /// Buffer used for staking storage pub type StakingBuffer = HashMap; -/// Flush buffer to merkle trie, and return the new root -pub fn flush_staking_storage( - storage: &mut StakingStorage, - root: Option, - buffer: StakingBuffer, -) -> Result, Exception> { - let (mut keys, values): (Vec<_>, Vec<_>) = buffer - .into_iter() - .map(|(addr, v)| (to_stake_key(&addr), AccountWrapper(v))) - .unzip(); - if keys.is_empty() { - return Ok(root); - } - Ok(Some(storage.insert(root.as_ref(), &mut keys, &values)?)) -} - /// Buffer used for key-value storage pub type KVBuffer = HashMap<(u32, Vec), Option>>; @@ -353,65 +307,33 @@ mod tests { use kvdb::KeyValueDB; use kvdb_memorydb::{create as create_memorydb, InMemory}; - use chain_core::state::account::{StakedState, StakedStateAddress}; - use super::*; - use crate::account::{pure_account_storage, AccountStorage as StakingStorage}; // demonstrate how to use buffered store in the chain abci app. struct App { kvdb: D, - trie: StakingStorage, - root: Option, - tmp_kv_buffer: KVBuffer, - tmp_trie_buffer: StakingBuffer, - kv_buffer: KVBuffer, - trie_buffer: StakingBuffer, } impl App { - fn new(kvdb: D, trie: StakingStorage) -> Self { + fn new(kvdb: D) -> Self { Self { kvdb, - trie, - root: None, tmp_kv_buffer: HashMap::new(), - tmp_trie_buffer: HashMap::new(), kv_buffer: HashMap::new(), - trie_buffer: HashMap::new(), } } fn commit(&mut self) { flush_kvdb(&self.kvdb, mem::take(&mut self.kv_buffer)).unwrap(); - self.root = - flush_staking_storage(&mut self.trie, self.root, mem::take(&mut self.trie_buffer)) - .unwrap(); - self.tmp_kv_buffer.clear(); - self.tmp_trie_buffer.clear(); - } - - fn staking_store(&mut self) -> impl StoreStaking + '_ { - StakingBufferStore::new( - StakingGetter::new(&self.trie, self.root), - &mut self.trie_buffer, - ) } fn kv_store(&mut self) -> impl StoreKV + '_ { BufferStore::new(&self.kvdb, &mut self.kv_buffer) } - fn tmp_staking_store(&mut self) -> impl StoreStaking + '_ { - StakingBufferStore::new( - StakingGetter::new(&self.trie, self.root), - &mut self.tmp_trie_buffer, - ) - } - fn tmp_kv_store(&mut self) -> impl StoreKV + '_ { BufferStore::new(&self.kvdb, &mut self.tmp_kv_buffer) } @@ -419,44 +341,10 @@ mod tests { impl App { fn new_memory() -> Self { - Self::new(create_memorydb(1), pure_account_storage(20).unwrap()) + Self::new(create_memorydb(1)) } } - #[test] - fn check_staking_store() { - let mut app = App::new_memory(); - let staking1 = StakedState::default(StakedStateAddress::BasicRedeem([0xcc; 20].into())); - let staking2 = StakedState::default(StakedStateAddress::BasicRedeem([0xcd; 20].into())); - app.staking_store().set_staking(staking1.clone()); - app.tmp_staking_store().set_staking(staking2.clone()); - assert_eq!( - app.staking_store().get(&staking1.address).unwrap(), - staking1 - ); - assert_eq!( - app.tmp_staking_store().get(&staking2.address).unwrap(), - staking2 - ); - // no conflict between two buffers. - assert!(app.staking_store().get(&staking2.address).is_none()); - assert!(app.tmp_staking_store().get(&staking1.address).is_none()); - - app.commit(); - - // after commit, staking1 is committed, staking2 is dropped - assert_eq!( - app.staking_store().get(&staking1.address).unwrap(), - staking1 - ); - assert_eq!( - app.tmp_staking_store().get(&staking1.address).unwrap(), - staking1 - ); - assert!(app.staking_store().get(&staking2.address).is_none(),); - assert!(app.tmp_staking_store().get(&staking2.address).is_none(),); - } - #[test] fn check_kvdb() { let mut app = App::new_memory(); diff --git a/chain-storage/src/lib.rs b/chain-storage/src/lib.rs index e11ae9da0..2c521e96a 100644 --- a/chain-storage/src/lib.rs +++ b/chain-storage/src/lib.rs @@ -1,10 +1,11 @@ -pub mod account; mod api; pub mod buffer; pub mod jellyfish; -use crate::buffer::Get; +use crate::buffer::{flush_storage, BufferStore, Get, KVBuffer}; +use crate::jellyfish::{put_stakings, Version}; use chain_core::common::H256; +use chain_core::state::account::StakedState; use chain_core::state::tendermint::BlockHeight; use chain_core::tx::data::TxId; use kvdb::{DBTransaction, KeyValueDB}; @@ -233,4 +234,16 @@ impl Storage { Ok(()) } } + + pub fn put_stakings(&mut self, version: Version, stakings: &[StakedState]) -> H256 { + let mut kv_buffer = KVBuffer::new(); + let root_hash = put_stakings( + &mut BufferStore::new(self, &mut kv_buffer), + version, + stakings.iter(), + ) + .unwrap(); + flush_storage(self, kv_buffer).unwrap(); + root_hash + } } diff --git a/test-common/src/block_generator.rs b/test-common/src/block_generator.rs index 2a2f12fce..3df76a72f 100644 --- a/test-common/src/block_generator.rs +++ b/test-common/src/block_generator.rs @@ -17,7 +17,7 @@ use tendermint::{ Signature, Time, }; -use chain_abci::app::{compute_accounts_root, ChainNodeState}; +use chain_abci::app::ChainNodeState; use chain_abci::staking::StakingTable; use chain_core::common::MerkleTree; use chain_core::compute_app_hash; @@ -34,8 +34,8 @@ use chain_core::state::tendermint::{ use chain_core::state::ChainState; use chain_core::tx::fee::{LinearFee, Milli}; use chain_core::tx::TxAux; -use chain_storage::account::{pure_account_storage, AccountStorage}; -use chain_storage::buffer::StakingGetter; +use chain_storage::buffer::MemStore; +use chain_storage::jellyfish::{put_stakings, StakingGetter}; use client_common::tendermint::types::{ AbciQuery, BlockResults, BroadcastTxResponse, Genesis, Results, }; @@ -274,8 +274,8 @@ impl TestnetSpec { } } - pub fn gen_genesis(&self) -> (Genesis, ChainNodeState, Arc) { - let mut account_storage = Arc::new(pure_account_storage(20).unwrap()); + pub fn gen_genesis(&self) -> (Genesis, ChainNodeState) { + let mut store = MemStore::new(); let config = self.init_config(); let genesis_seconds = self @@ -286,8 +286,7 @@ impl TestnetSpec { let (accounts, rewards_pool, nodes) = config .validate_config_get_genesis(genesis_seconds) .expect("distribution validation error"); - let account_root = - compute_accounts_root(Arc::get_mut(&mut account_storage).unwrap(), &accounts); + let account_root = put_stakings(&mut store, 0, accounts.iter()).unwrap(); let network_params = NetworkParameters::Genesis(config.network_params.clone()); let app_hash = compute_app_hash( &MerkleTree::empty(), @@ -328,10 +327,7 @@ impl TestnetSpec { }; let staking_table = StakingTable::from_genesis( - &StakingGetter::new( - Arc::get_mut(&mut account_storage).unwrap(), - Some(account_root), - ), + &StakingGetter::new(&store, 0), network_params.get_required_council_node_stake(), network_params.get_max_validators(), &nodes.iter().map(|(addr, _)| *addr).collect::>(), @@ -346,7 +342,7 @@ impl TestnetSpec { staking_table, ); - (genesis, state, account_storage) + (genesis, state) } pub fn validator_set(&self) -> validator::Set { @@ -379,7 +375,6 @@ pub struct BlockGenerator { pub spec: TestnetSpec, pub genesis: Genesis, pub genesis_state: ChainNodeState, - pub account_storage: Arc, pub validators: validator::Set, pub blocks: Vec, pub current_height: Option, @@ -388,13 +383,12 @@ pub struct BlockGenerator { impl BlockGenerator { pub fn new(spec: TestnetSpec) -> BlockGenerator { - let (genesis, genesis_state, account_storage) = spec.gen_genesis(); + let (genesis, genesis_state) = spec.gen_genesis(); let validators = spec.validator_set(); BlockGenerator { spec, genesis, genesis_state, - account_storage, validators, blocks: vec![], current_height: None, diff --git a/test-common/src/chain_env.rs b/test-common/src/chain_env.rs index 3e1d1257c..900f6998f 100644 --- a/test-common/src/chain_env.rs +++ b/test-common/src/chain_env.rs @@ -33,7 +33,6 @@ use chain_core::state::validator::NodeJoinRequestTx; use chain_core::tx::fee::{LinearFee, Milli}; use chain_core::tx::witness::EcdsaSignature; use chain_core::tx::{data::TxId, TransactionId, TxAux, TxPublicAux}; -use chain_storage::account::{AccountStorage, AccountWrapper, StarlingFixedKey}; use chain_storage::buffer::Get; use chain_storage::{Storage, NUM_COLUMNS}; @@ -80,12 +79,8 @@ pub fn get_enclave_bridge_mock() -> MockClient { MockClient::new(0) } -pub fn create_storage() -> (Storage, AccountStorage) { - ( - Storage::new_db(Arc::new(create(NUM_COLUMNS))), - AccountStorage::new(Storage::new_db(Arc::new(create(1))), 20) - .expect("Unable to create account storage"), - ) +pub fn create_storage() -> Storage { + Storage::new_db(Arc::new(create(NUM_COLUMNS))) } pub fn get_init_network_params(expansion_cap: Coin) -> InitNetworkParameters { @@ -184,11 +179,7 @@ pub struct ChainEnv { } impl ChainEnv { - pub fn new( - dist_coin: Coin, - expansion_cap: Coin, - count: usize, - ) -> (ChainEnv, Storage, AccountStorage) { + pub fn new(dist_coin: Coin, expansion_cap: Coin, count: usize) -> (ChainEnv, Storage) { ChainEnv::new_with_customizer(dist_coin, expansion_cap, count, |_| {}) } @@ -197,8 +188,8 @@ impl ChainEnv { expansion_cap: Coin, count: usize, customize_network_params: F, - ) -> (ChainEnv, Storage, AccountStorage) { - let (storage, mut account_storage) = create_storage(); + ) -> (ChainEnv, Storage) { + let mut storage = create_storage(); let locked = (Coin::max() - dist_coin - expansion_cap).unwrap(); let accounts: Vec = (0..count) .map(|i| { @@ -238,14 +229,7 @@ impl ChainEnv { .validate_config_get_genesis(timestamp.get_seconds().try_into().unwrap()) .expect("Error while validating distribution"); - let mut keys: Vec = states.iter().map(|account| account.key()).collect(); - let wrapped: Vec = - states.iter().map(|st| AccountWrapper(st.clone())).collect(); - - let new_account_root = account_storage - .insert(None, &mut keys, &wrapped) - .expect("initial insert"); - + let new_account_root = storage.put_stakings(0, &states); let genesis_app_hash = compute_app_hash( &MerkleTree::empty(), &new_account_root, @@ -263,7 +247,6 @@ impl ChainEnv { accounts, }, storage, - account_storage, ) } @@ -271,17 +254,12 @@ impl ChainEnv { (self.dist_coin / (self.accounts.len() as u64)).unwrap() } - pub fn chain_node( - &self, - storage: Storage, - account_storage: AccountStorage, - ) -> ChainNodeApp { + pub fn chain_node(&self, storage: Storage) -> ChainNodeApp { ChainNodeApp::new_with_storage( get_enclave_bridge_mock(), &hex::encode_upper(self.genesis_app_hash), TEST_CHAIN_ID, storage, - account_storage, None, None, )