Consensys / quorum

A permissioned implementation of Ethereum supporting data privacy
https://www.goquorum.com/
GNU Lesser General Public License v3.0
4.68k stars 1.29k forks source link

Using contracts.methods.methodOne('0xabcd').call doesn't respect privacy #484

Closed Eithcowich closed 6 years ago

Eithcowich commented 6 years ago

I'm testing Quorum's privacy feature, but it seems like my data is getting published to all the nodes, or else the call method I'm using doesn't work with privateFrom. Here's my code.

The contract is compiled and deployed using truffle:

module.exports = function(deployer) {
  deployer.deploy(SomeData, {privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc=", 
"UfNSeSGySeKg11DVNEnqrUtxYRVor4+CvluI8tVv62Y="]});
};

To my understanding the contract should only be on the nodes specified above, and not on any of the other 5 nodes in the 7nodes example.

Now I'm adding some data using:

csContract.methods.addData("0xabcd", [s1hex,s2hex,s3hex]).send({from: 'ed9d02e382b34818e88b88a309c7fe71e65f419d', gas: 150000000,  
privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] }
  ) .then(receipt => {
         console.log("addData receipt " + receipt);
        },
          (error) => {
           console.log("Error in addData = " + error);
    }).catch((err) => {
       console.log("Catch Error in addData = " + error);
    });

And now I'm calling to see if the data was saved on the appropriate nodes:

  csContract.methods.getData('0xabcd').call({from: 'ed9d02e382b34818e88b88a309c7fe71e65f419d', gas: 150000000, 
privateFrom: ["oNspPPgszVUFw0qmGFfWwh1uxVUXgvBxleXORHj07g8="]})
      .then(receipt => {
          console.log("getValue receipt at 0 " + receipt);
        }
        ,  (error) =>{
           console.log("Error in getData = " + error);
        }).catch((err) => {
           console.log("Catch Error in getData = " + error);
        });

and even though the node in the privateFrom should not have the contract deployed, I'm getting the data that was pushed in addData. Which should not happen.

What am I missing?

fixanoid commented 6 years ago

@Eithcowich whenever you are using privateFor the caveat to consider is that there is also privateFrom which is also party to the same contract and its the originating node. So, if you submit this contract from Node 1 with private for "ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc" which is Node 7 -- the private contract is going to be accessible and visible from 2 nodes: Node 1 and Node 7.

fixanoid commented 6 years ago

Additionally, privateFrom is currently implied and cannot be set -- you control this by running the txn from the node the key belongs to to validate visibility.

Eithcowich commented 6 years ago

Thanks @fixanoid .

So, if I want the contract to be available on all nodes I use something like this, with all seven nodes?

module.exports = {
   networks: {
 development: {
   host: "127.0.0.1",
   port: 22000, // was 8545
   network_id: "*", // Match any network id
   gasPrice: 0,
   gas: 4500000
 },
 nodefour:  {
   host: "127.0.0.1",
   port: 22003,
   network_id: "*", // Match any network id
   gasPrice: 0,
   gas: 4500000
 },
 nodeseven:  {
   host: "127.0.0.1",
   port: 22006,
   network_id: "*", // Match any network id
   gasPrice: 0,
   gas: 4500000
  }
  }
 }; 

And then I can add data with privateFor one or two of the nodes, and it would be available only from them, and not from the others? Is this the pattern?

fixanoid commented 6 years ago

@Eithcowich if you want contract to be available on all nodes, then you use a regular public contract without any privateFor usage.

If you want a private contract between Node 1, Node 4, and Node 7, what you do if call contract creation from origination node (1, 4, or 7) and supply privateFor for the non-origination nodes: If contract is executed on the --network development with truffle, then you'd need keys for Node 4 and Node 7 in the privateFor. If the contract is executed on Node 4, then you need keys for Node 1 and Node 7 in your privateFor. In all of the above cases, Node 2, 3, 5, or 6 will not have this contract on their nodes and will not be able to read or write to it.

Eithcowich commented 6 years ago

What I have in mind - the project's requirement - is to have the contract on all nodes, but to write different data to different subsets.

For example nodes 1, 2, 3 would have the string "hello1" while nodes 4,5,6 would have "hello2" and node 7 "hello3".

Is this possible? If so, how do I then get the data from the various subsets?

fixanoid commented 6 years ago

Yes, this is a caveat to watch out for and is exactly how private state works in Quorum. You may look into 5nodeRTGS example for an illustration: https://github.com/bacen/quorum-examples/tree/master/examples/5nodesRTGS

Eithcowich commented 6 years ago

So, it looks like I cannot deploy a contract to more than 1 privateFor node? If I try this:

module.exports = function(deployer) {
  deployer.deploy(DataContract,
    { privateFor:
      ["oNspPPgszVUFw0qmGFfWwh1uxVUXgvBxleXORHj07g8="] 
    }
  );
};

It works. But when trying with more than one account,

module.exports = function(deployer) {
      deployer.deploy(DataContract,
        { privateFor:["QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc=","1iTZde/ndBHvzhcl7V68x44Vx7pl8nwx9LqnM/AfJUg=","oNspPPgszVUFw0qmGFfWwh1uxVUXgvBxleXORHj07g8="] 
        }
      );
    };

the deployment fails with RPC is not running error. But vagrant is actually up and running.

So again, the question is can I deploy the contract to more than one private node? Or is this not how it works, and I have to deploy the contract to each node, and then use separate add data transactions to each of the nodes.

fixanoid commented 6 years ago

@Eithcowich the above should run just fine -- the only caveat is to make sure NOT to include the key of the node you are executing from. Are you executing from node 2, 3, or 4? If so, this will throw an error.

Another note is that if possible, please update to master quorum since there are a number of fixes in it from the last official release.