Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Call private contract methods from another private contract (read-only) #10086

Merged
merged 11 commits into from
Feb 7, 2019

Conversation

grbIzl
Copy link
Collaborator

@grbIzl grbIzl commented Dec 19, 2018

This PR adds possibility to make calls of private contract methods from another private contract (with condition, that caller has access to the keys for both private contracts).
In order to achieve this, ABI of permissioning contract of Secret Store was extended with availableKeys method, that returns all keys, available for the account.
The further solution is rather straightforward: after patching the state for the current private contract, we also patch states for all private contracts, available for the node, and execute the private transaction on this state.
Some details of the solution:

  • Only read-only calls are supported. Client can modify the state of other private contracts during execution of the private transaction, but these changes won't be saved
  • All code, responsible for work with Secret Store keys, moved to the separate module

Closes #9199

@grbIzl grbIzl added A0-pleasereview 🤓 Pull request needs code review. M4-core ⛓ Core client code / Rust. labels Dec 19, 2018
@grbIzl grbIzl added this to In progress in Permissioning via automation Dec 19, 2018
@5chdn 5chdn added this to the 2.3 milestone Jan 2, 2019
@@ -24,7 +24,7 @@ use ethcore::CreateContractAddress;
use transaction::{Transaction, Action};
use ethcore::executive::{contract_address};
use ethcore::test_helpers::{push_block_with_transactions};
use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor, Importer, SignedPrivateTransaction};
use ethcore_private_tx::{Provider, ProviderConfig, NoopEncryptor, Importer, SignedPrivateTransaction, StoringKeyProvider };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra tab

// Patch other available private contracts' states as well
if let Some(key_server_account) = self.keys_provider.key_server_account() {
if let Some(available_contracts) = self.keys_provider.available_keys(block, &key_server_account) {
for private_contract in available_contracts {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be a performance bottleneck. I don't think we need to fix it immediately, but what we can do is:

  • Add a hook in Externalities::call that checks the contract address.
  • From there, only patch an account in the state if it's actually called.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're right! TODO added into the code and the corresponding task #10133 created

@5chdn 5chdn modified the milestones: 2.3, 2.4 Jan 10, 2019
@5chdn 5chdn added A8-looksgood 🦄 Pull request is reviewed well. and removed A0-pleasereview 🤓 Pull request needs code review. labels Jan 28, 2019
@5chdn
Copy link
Contributor

5chdn commented Jan 28, 2019

Needs a 2nd review, could you have a look at this @dvdplm @tomusdrw ?

Copy link
Collaborator

@tomusdrw tomusdrw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, couple minor grumbles.

contract_address);

let keys_acl_contract = self.keys_acl_contract.write();
keys_acl_contract.and(contract_address);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a no-op, do we actually want to update the keys_acl_contract? Can we test this function?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. Sorry about that. Fixed, test added

impl StoringKeyProvider {
/// Store available keys
pub fn set_available_keys(&self, keys: &Vec<Address>) {
let mut current = self.available_keys.write();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just *self.available_keys.write() = Some(keys.clone())?

if let Ok(value) = self.client.call_contract(block, acl_contract_address, data) {
self.keys_to_addresses(decoder.decode(&value).ok())
} else {
None
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we log something here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's not an exceptional situation


fn keys_to_addresses(&self, keys: Option<Vec<H256>>) -> Option<Vec<Address>> {
keys.map(|key_values| {
let mut addresses: Vec<Address> = Vec::new();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key_values.iter().map(key_to_address).collect()?

@@ -511,25 +524,35 @@ impl Provider where {
let (new_address, _) = ethcore_contract_address(engine.create_address_scheme(env_info.number), &sender, &nonce, &transaction.data);
Some(new_address)
});
let contract_address = contract_address.expect("Private contract address should be non zero by this moment; qed");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be doesn't sound like a proof, where exactly is it supposed to be initialised? Can we reach this line if private transactions are not part of the registry?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-phrased with more explicit proof.

};
Ok(PrivateExecutionResult {
code: encrypted_code,
state: encrypted_storage,
contract_address,
contract_address: Some(contract_address),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's worth to change the type if it's always Some?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep

Copy link
Collaborator

@tomusdrw tomusdrw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, minor grumble regarding redudant .expect

@@ -512,25 +525,36 @@ impl Provider where {
let (new_address, _) = ethcore_contract_address(engine.create_address_scheme(env_info.number), &sender, &nonce, &transaction.data);
Some(new_address)
});
let contract_address = contract_address.expect("Private contract address is non zero by this point, \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe change the above line to unwrap_or_else(|| ?
The proof won't be necessary and also the contract address will be evaluated lazily.

@5chdn 5chdn merged commit 45d7c60 into master Feb 7, 2019
Permissioning automation moved this from In progress to Done Feb 7, 2019
@5chdn 5chdn deleted the PrivateCallPrivate branch February 7, 2019 11:39
ordian added a commit that referenced this pull request Apr 5, 2019
* master:
  fix: parity-clib/examples/cpp/CMakeLists.txt (#10313)
  CI optimizations (#10297)
  Increase number of requested block bodies in chain sync (#10247)
  Deprecate account management (#10213)
  Properly handle check_epoch_end_signal errors (#10015)
  fix(osx and windows builds): bump parity-daemonize (#10291)
  Add missing step for  Using `systemd` service file (#10175)
  Call private contract methods from another private contract (read-only)  (#10086)
  update ring to 0.14 (#10262)
  fix(secret-store): deprecation warning (#10301)
  Update to jsonrpc-derive 10.0.2, fixes aliases bug (#10300)
  Convert to jsonrpc-derive, use jsonrpc-* from crates.io (#10298)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A8-looksgood 🦄 Pull request is reviewed well. M4-core ⛓ Core client code / Rust.
Projects
Permissioning
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

4 participants