Skip to content

Commit

Permalink
[refactor] hyperledger-iroha#2817: Remove interior mutability from `W…
Browse files Browse the repository at this point in the history
…orldStateView`

Signed-off-by: Shanin Roman <shanin1000@yandex.ru>
  • Loading branch information
Erigara committed May 26, 2023
1 parent 8ac6f42 commit d694927
Show file tree
Hide file tree
Showing 30 changed files with 663 additions and 812 deletions.
4 changes: 2 additions & 2 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,10 @@ impl Iroha {
// Validate every transaction in genesis block
if let Some(ref genesis) = genesis {
let span = span!(tracing::Level::TRACE, "genesis").entered();
let wsv_clone = wsv.clone();
let mut wsv_clone = wsv.clone();

transaction_validator
.validate_every(genesis.iter().cloned(), &wsv_clone)
.validate_every(genesis.iter().cloned(), &mut wsv_clone)
.wrap_err("Transaction validation failed in genesis block")?;
span.exit();
}
Expand Down
9 changes: 5 additions & 4 deletions cli/src/torii/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl VerifiedQuery {
/// - Account has incorrect permissions
pub fn validate(
self,
wsv: &WorldStateView,
wsv: &mut WorldStateView,
) -> Result<(ValidQueryRequest, PredicateBox), QueryExecutionFailure> {
let account_has_public_key = wsv.map_account(&self.payload.account_id, |account| {
account.signatories.contains(self.signature.public_key())
Expand All @@ -76,6 +76,7 @@ impl VerifiedQuery {
)));
}
wsv.validator_view()
.clone() // Cloning validator is cheep operation
.validate(wsv, &self.payload.account_id, self.payload.query.clone())
.map_err(|err| QueryExecutionFailure::Permission(err.to_string()))?;
Ok((
Expand Down Expand Up @@ -107,7 +108,7 @@ pub(crate) async fn handle_instructions(
transaction: VersionedSignedTransaction,
) -> Result<Empty> {
let transaction: SignedTransaction = transaction.into_v1();
let transaction_limits = sumeragi.wsv(|wsv| wsv.config.borrow().transaction_limits);
let transaction_limits = sumeragi.wsv(|wsv| wsv.config.transaction_limits);
let transaction = <AcceptedTransaction as InBlock>::accept(transaction, &transaction_limits)
.map_err(Error::AcceptTransaction)?
.into();
Expand Down Expand Up @@ -136,8 +137,8 @@ pub(crate) async fn handle_queries(
let request: VerifiedQuery = request.try_into()?;

let (result, filter) = {
let wsv = sumeragi.wsv(Clone::clone);
let (valid_request, filter) = request.validate(&wsv)?;
let mut wsv = sumeragi.wsv(Clone::clone);
let (valid_request, filter) = request.validate(&mut wsv)?;
let original_result = valid_request.execute(&wsv)?;
(filter.filter(original_result), filter)
};
Expand Down
67 changes: 67 additions & 0 deletions client/tests/integration/triggers/by_call_trigger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,73 @@ fn trigger_in_genesis_using_base64() -> Result<()> {
Ok(())
}

#[test]
fn trigger_should_be_able_to_modify_other_trigger() -> Result<()> {
let (_rt, _peer, mut test_client) = <PeerBuilder>::new().with_port(10_085).start_with_runtime();
wait_for_genesis_committed(&vec![test_client.clone()], 0);

let asset_definition_id = "rose#wonderland".parse()?;
let account_id = AccountId::from_str("alice@wonderland")?;
let asset_id = AssetId::new(asset_definition_id, account_id.clone());
let trigger_id_unregister =
<Trigger<FilterBox, Executable> as Identifiable>::Id::from_str("unregister_other_trigger")?;
let trigger_id_should_be_unregistered =
<Trigger<FilterBox, Executable> as Identifiable>::Id::from_str(
"should_be_unregistered_trigger",
)?;

let trigger_unregister_instructions =
vec![UnregisterBox::new(trigger_id_should_be_unregistered.clone()).into()];
let register_trigger = RegisterBox::new(Trigger::new(
trigger_id_unregister.clone(),
Action::new(
trigger_unregister_instructions,
Repeats::from(1_u32),
account_id.clone(),
FilterBox::ExecuteTrigger(ExecuteTriggerEventFilter::new(
trigger_id_unregister.clone(),
account_id.clone(),
)),
),
));
test_client.submit_blocking(register_trigger)?;

let trigger_should_be_unregistered_instructions =
vec![MintBox::new(1_u32, asset_id.clone()).into()];
let register_trigger = RegisterBox::new(Trigger::new(
trigger_id_should_be_unregistered.clone(),
Action::new(
trigger_should_be_unregistered_instructions,
Repeats::from(1_u32),
account_id.clone(),
FilterBox::ExecuteTrigger(ExecuteTriggerEventFilter::new(
trigger_id_should_be_unregistered.clone(),
account_id,
)),
),
));
test_client.submit_blocking(register_trigger)?;

// Saving current asset value
let prev_asset_value = get_asset_value(&mut test_client, asset_id.clone())?;

// Executing triggers
let execute_trigger_unregister = ExecuteTriggerBox::new(trigger_id_unregister);
let execute_trigger_should_be_unregistered =
ExecuteTriggerBox::new(trigger_id_should_be_unregistered);
test_client.submit_all_blocking([
execute_trigger_unregister.into(),
execute_trigger_should_be_unregistered.into(),
])?;

// Checking results
// First trigger should cancel second one, so value should stay the same
let new_asset_value = get_asset_value(&mut test_client, asset_id)?;
assert_eq!(new_asset_value, prev_asset_value);

Ok(())
}

fn get_asset_value(client: &mut Client, asset_id: AssetId) -> Result<u32> {
let asset = client.request(client::asset::by_id(asset_id))?;
Ok(*TryAsRef::<u32>::try_as_ref(asset.value())?)
Expand Down
Binary file modified configs/peer/validator.wasm
Binary file not shown.
4 changes: 2 additions & 2 deletions core/benches/apply_blocks/apply_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ fn build_wsv(
key_pair: KeyPair,
) -> Result<WorldStateView> {
let kura = iroha_core::kura::Kura::blank_kura_for_testing();
let wsv = WorldStateView::new(World::with([], BTreeSet::new()), kura);
let mut wsv = WorldStateView::new(World::with([], BTreeSet::new()), kura);

let mut instructions: Vec<InstructionBox> = Vec::new();
for i in 0..domains {
Expand Down Expand Up @@ -220,7 +220,7 @@ impl WsvApplyBlocks {
/// If wsv doesn't one block ahead of finalized wsv.
pub fn measure(Self { wsv, blocks }: &Self) -> Result<()> {
let mut finalized_wsv = wsv.clone();
let wsv = finalized_wsv.clone();
let mut wsv = finalized_wsv.clone();

for block in blocks {
finalized_wsv = wsv.clone();
Expand Down
8 changes: 4 additions & 4 deletions core/benches/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fn build_test_and_transient_wsv(keys: KeyPair) -> WorldStateView {
let kura = iroha_core::kura::Kura::blank_kura_for_testing();
let (public_key, _) = keys.into();

let wsv = WorldStateView::new(
let mut wsv = WorldStateView::new(
{
let domain_id = DomainId::from_str(START_DOMAIN).expect("Valid");
let account_id = AccountId::new(
Expand All @@ -87,7 +87,7 @@ fn build_test_and_transient_wsv(keys: KeyPair) -> WorldStateView {
let validator = Validator::new(WasmSmartContract::from_compiled(wasm));
let authority = "genesis@genesis".parse().expect("Valid");
UpgradeBox::new(validator)
.execute(&authority, &wsv)
.execute(&authority, &mut wsv)
.expect("Failed to load validator");
}

Expand Down Expand Up @@ -139,8 +139,8 @@ fn validate_transaction(criterion: &mut Criterion) {
let _ = criterion.bench_function("validate", move |b| {
let transaction_validator = TransactionValidator::new(TRANSACTION_LIMITS);
b.iter(|| {
let wsv = wsv.clone();
match transaction_validator.validate(transaction.clone(), false, &wsv) {
let mut wsv = wsv.clone();
match transaction_validator.validate(transaction.clone(), false, &mut wsv) {
Ok(_) => success_count += 1,
Err(_) => failure_count += 1,
}
Expand Down
24 changes: 15 additions & 9 deletions core/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub struct BlockBuilder {

impl BlockBuilder {
/// Create a new [`PendingBlock`] from transactions.
pub fn build(self) -> PendingBlock {
pub fn build(mut self) -> PendingBlock {
let timestamp = crate::current_time().as_millis();
let height = self.wsv.height() + 1;
let previous_block_hash = self.wsv.latest_block_hash();
Expand All @@ -81,7 +81,7 @@ impl BlockBuilder {
let mut rejected = Vec::new();

for tx in self.transactions {
match transaction_validator.validate(tx.into_v1(), header.is_genesis(), &self.wsv) {
match transaction_validator.validate(tx.into_v1(), header.is_genesis(), &mut self.wsv) {
Ok(tx) => txs.push(tx),
Err(tx) => {
iroha_logger::warn!(
Expand Down Expand Up @@ -289,7 +289,10 @@ impl Revalidate for PendingBlock {
/// - Block header transaction hashes don't match with computed transaction hashes
/// - Error during revalidation of individual transactions
#[allow(clippy::too_many_lines)]
fn revalidate<const IS_GENESIS: bool>(&self, wsv: WorldStateView) -> Result<(), eyre::Report> {
fn revalidate<const IS_GENESIS: bool>(
&self,
mut wsv: WorldStateView,
) -> Result<(), eyre::Report> {
let latest_block_hash = wsv.latest_block_hash();
let block_height = wsv.height();
let transaction_validator = wsv.transaction_validator();
Expand Down Expand Up @@ -359,7 +362,7 @@ impl Revalidate for PendingBlock {
.map(|accepted_tx| {
accepted_tx.and_then(|tx| {
transaction_validator
.validate(tx, self.header.is_genesis(), &wsv)
.validate(tx, self.header.is_genesis(), &mut wsv)
.map_err(|rejected_tx| rejected_tx.into_v1().rejection_reason)
.wrap_err("Failed to validate transaction")
})
Expand Down Expand Up @@ -391,7 +394,7 @@ impl Revalidate for PendingBlock {
})
.map(|accepted_tx| {
accepted_tx.and_then(|tx| {
match transaction_validator.validate(tx, self.header.is_genesis(), &wsv) {
match transaction_validator.validate(tx, self.header.is_genesis(), &mut wsv) {
Err(rejected_transaction) => Ok(rejected_transaction),
Ok(_) => Err(eyre!("Transactions which supposed to be rejected is valid")),
}
Expand Down Expand Up @@ -435,7 +438,10 @@ impl Revalidate for VersionedCommittedBlock {
/// - Block header transaction hashes don't match with computed transaction hashes
/// - Error during revalidation of individual transactions
#[allow(clippy::too_many_lines)]
fn revalidate<const IS_GENESIS: bool>(&self, wsv: WorldStateView) -> Result<(), eyre::Report> {
fn revalidate<const IS_GENESIS: bool>(
&self,
mut wsv: WorldStateView,
) -> Result<(), eyre::Report> {
let latest_block_hash = wsv.latest_block_hash();
let block_height = wsv.height();
let transaction_validator = wsv.transaction_validator();
Expand Down Expand Up @@ -477,7 +483,7 @@ impl Revalidate for VersionedCommittedBlock {
let last_committed_block = wsv
.latest_block_ref()
.expect("Not in genesis round so must have at least genesis block");
let new_peers = wsv.peers_ids().iter().map(|id| id.clone()).collect();
let new_peers = wsv.peers_ids().iter().cloned().collect();
let view_change_index = block
.header
.view_change_index
Expand Down Expand Up @@ -544,7 +550,7 @@ impl Revalidate for VersionedCommittedBlock {
.map(|accepted_tx| {
accepted_tx.and_then(|tx| {
transaction_validator
.validate(tx, block.header.is_genesis(), &wsv)
.validate(tx, block.header.is_genesis(), &mut wsv)
.map_err(|rejected_tx| rejected_tx.into_v1().rejection_reason)
.wrap_err("Failed to validate transaction")
})
Expand Down Expand Up @@ -579,7 +585,7 @@ impl Revalidate for VersionedCommittedBlock {
match transaction_validator.validate(
tx,
block.header.is_genesis(),
&wsv,
&mut wsv,
) {
Err(rejected_transaction) => Ok(rejected_transaction),
Ok(_) => Err(eyre!(
Expand Down
4 changes: 1 addition & 3 deletions core/src/gossiper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,7 @@ impl TransactionGossiper {
fn handle_transaction_gossip(&self, TransactionGossip { txs }: TransactionGossip) {
iroha_logger::trace!(size = txs.len(), "Received new transaction gossip");

let transaction_limits = self
.sumeragi
.wsv(|wsv| wsv.config.borrow().transaction_limits);
let transaction_limits = self.sumeragi.wsv(|wsv| wsv.config.transaction_limits);

for tx in txs {
match <AcceptedTransaction as InBlock>::accept(tx.into_v1(), &transaction_limits) {
Expand Down
14 changes: 7 additions & 7 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ pub mod validator;
pub mod wsv;

use core::time::Duration;
use std::collections::{HashMap, HashSet};

use dashmap::{DashMap, DashSet};
use gossiper::TransactionGossip;
use iroha_data_model::{permission::Permissions, prelude::*};
use parity_scale_codec::{Decode, Encode};
Expand All @@ -32,23 +32,23 @@ pub const TX_RETRIEVAL_INTERVAL: Duration = Duration::from_millis(100);
pub type IrohaNetwork = iroha_p2p::NetworkHandle<NetworkMessage>;

/// Ids of peers.
pub type PeersIds = DashSet<<Peer as Identifiable>::Id>;
pub type PeersIds = HashSet<<Peer as Identifiable>::Id>;

/// Parameters set.
pub type Parameters = DashSet<Parameter>;
pub type Parameters = HashSet<Parameter>;

/// API to work with collections of [`DomainId`] : [`Domain`] mappings.
pub type DomainsMap = DashMap<<Domain as Identifiable>::Id, Domain>;
pub type DomainsMap = HashMap<<Domain as Identifiable>::Id, Domain>;

/// API to work with a collections of [`RoleId`]: [`Role`] mappings.
pub type RolesMap = DashMap<<Role as Identifiable>::Id, Role>;
pub type RolesMap = HashMap<<Role as Identifiable>::Id, Role>;

/// API to work with a collections of [`AccountId`] [`Permissions`] mappings.
pub type PermissionTokensMap = DashMap<<Account as Identifiable>::Id, Permissions>;
pub type PermissionTokensMap = HashMap<<Account as Identifiable>::Id, Permissions>;

/// API to work with a collections of [`PermissionTokenDefinitionId`] : [`PermissionTokenDefinition`] mappings.
pub type PermissionTokenDefinitionsMap =
DashMap<<PermissionTokenDefinition as Identifiable>::Id, PermissionTokenDefinition>;
HashMap<<PermissionTokenDefinition as Identifiable>::Id, PermissionTokenDefinition>;

/// Type of `Sender<Event>` which should be used for channels of `Event` messages.
pub type EventsSender = broadcast::Sender<Event>;
Expand Down
10 changes: 5 additions & 5 deletions core/src/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,10 +814,10 @@ mod tests {
fn push_tx_already_in_blockchain() {
let alice_key = KeyPair::generate().expect("Failed to generate keypair.");
let kura = Kura::blank_kura_for_testing();
let wsv = Arc::new(WorldStateView::new(
let mut wsv = WorldStateView::new(
world_with_test_domains([alice_key.public_key().clone()]),
kura.clone(),
));
);
let tx = accepted_tx("alice@wonderland", 100_000, alice_key);
wsv.transactions.insert(tx.hash());
let queue = Queue::from_configuration(&Configuration {
Expand All @@ -842,10 +842,10 @@ mod tests {
let max_txs_in_block = 2;
let alice_key = KeyPair::generate().expect("Failed to generate keypair.");
let kura = Kura::blank_kura_for_testing();
let wsv = Arc::new(WorldStateView::new(
let mut wsv = WorldStateView::new(
world_with_test_domains([alice_key.public_key().clone()]),
kura.clone(),
));
);
let tx = accepted_tx("alice@wonderland", 100_000, alice_key);
let queue = Queue::from_configuration(&Configuration {
transaction_time_to_live_ms: 100_000,
Expand Down Expand Up @@ -996,7 +996,7 @@ mod tests {
// Spawn a thread where we get_transactions_for_block and add them to WSV
let get_txs_handle = {
let queue_arc_clone = Arc::clone(&queue);
let wsv_clone = wsv.clone();
let mut wsv_clone = wsv.clone();

thread::spawn(move || {
while start_time.elapsed() < run_for {
Expand Down
Loading

0 comments on commit d694927

Please sign in to comment.