From 18582d7b654382473a831eda59dc3d5139b39efe Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 30 Jun 2017 11:26:09 +0300 Subject: [PATCH] do not cache ACL storage contract --- secret_store/src/acl_storage.rs | 54 ++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs index 816d100dc..8ddc9a6e3 100644 --- a/secret_store/src/acl_storage.rs +++ b/secret_store/src/acl_storage.rs @@ -20,6 +20,7 @@ use parking_lot::Mutex; use ethkey::public_to_address; use ethcore::client::{Client, BlockChainClient, BlockId}; use native_contracts::SecretStoreAclStorage; +use util::{H256, Address}; use types::all::{Error, ServerKeyId, Public}; const ACL_CHECKER_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_acl_checker"; @@ -32,33 +33,64 @@ pub trait AclStorage: Send + Sync { /// On-chain ACL storage implementation. pub struct OnChainAclStorage { + /// Cached on-chain contract. + contract: Mutex, +} + +/// Cached on-chain ACL storage contract. +struct CachedContract { /// Blockchain client. client: Arc, - /// On-chain contract. - contract: Mutex>, + /// Hash of best block, when contract address has been read. + best_block_hash: Option, + /// Contract address. + contract_addr: Option
, + /// Contract at given address. + contract: Option, } impl OnChainAclStorage { pub fn new(client: Arc) -> Self { OnChainAclStorage { - client: client, - contract: Mutex::new(None), + contract: Mutex::new(CachedContract::new(client)), } } } impl AclStorage for OnChainAclStorage { fn check(&self, public: &Public, document: &ServerKeyId) -> Result { - let mut contract = self.contract.lock(); - if !contract.is_some() { - *contract = self.client.registry_address(ACL_CHECKER_CONTRACT_REGISTRY_NAME.to_owned()) - .and_then(|contract_addr| { + self.contract.lock().check(public, document) + } +} + +impl CachedContract { + pub fn new(client: Arc) -> Self { + CachedContract { + client: client, + best_block_hash: None, + contract_addr: None, + contract: None, + } + } + + pub fn check(&mut self, public: &Public, document: &ServerKeyId) -> Result { + let new_best_block_hash = self.client.best_block_header().hash(); + if self.best_block_hash.as_ref() != Some(&new_best_block_hash) { + let new_contract_addr = self.client.registry_address(ACL_CHECKER_CONTRACT_REGISTRY_NAME.to_owned()); + if self.contract_addr.as_ref() != new_contract_addr.as_ref() { + self.contract = new_contract_addr.map(|contract_addr| { trace!(target: "secretstore", "Configuring for ACL checker contract from {}", contract_addr); - Some(SecretStoreAclStorage::new(contract_addr)) - }) + SecretStoreAclStorage::new(contract_addr) + }); + + self.contract_addr = new_contract_addr; + } + + self.best_block_hash = Some(new_best_block_hash); } - if let Some(ref contract) = *contract { + + if let Some(contract) = self.contract.as_ref() { let address = public_to_address(&public); let do_call = |a, d| future::done(self.client.call_contract(BlockId::Latest, a, d)); contract.check_permissions(do_call, address, document.clone())