-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Implement caching for service transactions checker #10088
Conversation
# Conflicts: # ethcore/res/contracts/tx_acl.json # ethcore/src/tx_filter.rs
It looks like @VladLupashevskyi signed our Contributor License Agreement. 👍 Many thanks, Parity Technologies CLA Bot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea looks reasonable I'm only concerned with circular call to state - we should make sure that all the calls are not vulnerable to deadlocks or some data races now.
(and obv the implementation needs some improvements)
ethcore/src/client/client.rs
Outdated
let transaction = Transaction { | ||
nonce: self.latest_nonce(&authoring_params.author), | ||
action: Action::Call(address), | ||
gas: self.importer.miner.sensible_gas_limit(), | ||
gas: gas_price, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you meant to change gas_price
not gas
.
ethcore/src/client/client.rs
Outdated
@@ -2112,10 +2113,15 @@ impl BlockChainClient for Client { | |||
|
|||
fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error> { | |||
let authoring_params = self.importer.miner.authoring_params(); | |||
let service_transaction_checker = ServiceTransactionChecker::default(); | |||
let gas_price = match service_transaction_checker.check_address(self, address) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
address
is contract address you try to call, not the sender (which should be checked here).
ethcore/src/miner/mod.rs
Outdated
@@ -20,7 +20,7 @@ | |||
//! Keeps track of transactions and currently sealed pending block. | |||
|
|||
mod miner; | |||
mod service_transaction_checker; | |||
pub mod service_transaction_checker; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please group with other pub mod
@tomusdrw I pushed the fixes and sorry for these typos. I am not sure what kind of deadlocks or data races could occur because free tx permission is checked for the latest mined block and not for the pending one. What I can think of is that issues could occur if we would call Maybe I am missing something, so I would be happy to get more feedback and dig into solving it :) |
# Conflicts: # ethcore/src/client/client.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
|
||
/// Checks if given address is whitelisted to send service transactions. | ||
pub fn check_address<C: CallContract + RegistryInfo>(&self, client: &C, sender: Address) -> Result<bool, String> { | ||
let contract_address = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would the performance be a concern here? registry_address
would need to query the state if registrar
is set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that an issue, some cache would be nice (best would be if previously queried registry entries would be refreshed after a block is imported), but the code is not super hot (only in \.transact
which is called by the engine, or by the miner, called only for zero-gas-price transactions attempting to enter the pool).
I added a cache for certified addresses and provided logic as @tomusdrw described. This is first time I'm working with caching so there is definitely something to improve and I'm always happy to get a feedback :) |
@tomusdrw I think idea with moving ServiceTxChecker to one place sounds reasonable! I would create a public method to get the checker instance from miner, so it's done more generic than just exposing a |
@tomusdrw I updated the code according to the comments, now it looks much cleaner! I'm thinking it would be nice to introduce some cache limiting, I would propose to use the solution I introduced in another PR for NodeFilter: where basically I used What do you think about it? |
Could you revisit this, @tomusdrw |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, few nitpicks.
|
||
use_contract!(service_transaction, "res/contracts/service_transaction.json"); | ||
|
||
const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transaction_checker"; | ||
|
||
/// Service transactions checker. | ||
#[derive(Default, Clone)] | ||
pub struct ServiceTransactionChecker; | ||
#[derive(Clone)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need Clone
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need Clone
in order to share ServiceTransactionChecker
with Client
and PoolClient
.
@@ -44,9 +55,42 @@ impl ServiceTransactionChecker { | |||
|
|||
/// Checks if given address is whitelisted to send service transactions. | |||
pub fn check_address<C: CallContract + RegistryInfo>(&self, client: &C, sender: Address) -> Result<bool, String> { | |||
trace!(target: "txqueue", "Checking service transaction checker contract from {}", sender); | |||
if let Some(allowed) = self.certified_addresses_cache.try_read().as_ref().and_then(|c| c.get(&sender)){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.as_ref()
seems redundant, also missing space before {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot do this without .as_ref()
since the c
doesn't live long enough in this case. I tried to do it with .map
, but in this case Option<Option<&bool>>
is returned, so one more check is needed. Not sure what would be better solution here.
# Conflicts: # Cargo.lock # ethcore/private-tx/src/lib.rs # ethcore/src/miner/miner.rs # ethcore/src/miner/pool_client.rs
# Conflicts: # Cargo.lock # ethcore/private-tx/src/lib.rs # ethcore/src/miner/miner.rs # ethcore/src/miner/pool_client.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌
Needs a 2nd review 👍 |
* master: fix(light cull): poll light cull instead of timer (#10559) Update Issue Template to direct security issue to email (#10562) RPC: Implements eth_subscribe("syncing") (#10311) Explicitly enable or disable Stratum in config file (Issue 9785) (#10521) version: bump master to 2.6 (#10560) tx-pool: check transaction readiness before replacing (#10526) fix(light account response): update `tx_queue` (#10545) Update light client harcoded headers (#10547) fix(light eth_gasPrice): ask network if not in cache (#10535) Implement caching for service transactions checker (#10088) build android with cache, win fixes (#10546) clique: make state backfill time measurement more accurate (#10551) updated lru-cache to 0.1.2 (#10542)
In cases when certain address is allowed for executing free transactions it makes sense in my opinion to submit transactions which are automatically submitted by the client (such as validators reporting etc) with the gas price set to zero.
Here I propose my code improvement to achieve this by adding check for free tx certification in transact_contract fn which is called while doing validators reporting and other actions.
Looking forward for the feedback :)