Skip to content

Commit

Permalink
Implement a test for transaction privacy
Browse files Browse the repository at this point in the history
The test will pass only when run against a Quorum network. The test is runnable
also on EthereumJS TestRPC, but will fail on purpose.
  • Loading branch information
vjrantal committed May 12, 2017
1 parent c17213f commit dbf0438
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 3 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
# Introduction

This repository contains a simple telemetry contract, but more importantly, it contains a test specific
for [Quorum](https://github.com/jpmorganchase/quorum). The test acts as a sample for a private deployment
of the contract and a private transaction through it and verifies the privacy of the data in this scenario.

# Testing with Quorum

## Dependencies

Install the Quorum 7nodes example network as instructed at https://github.com/jpmorganchase/quorum-examples.

Currently, the code in this repository assumes using the default configurations of the 7nodes network, but if
that is not the case, the node addresses and public keys need to be updated.

```
npm install -g truffle
```

## Running

```
truffle test --network quorum
```

# Testing with testrpc

## Dependencies
Expand Down
6 changes: 5 additions & 1 deletion contracts/Telemetry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ contract Telemetry {
}

function getLatestTelemetry(address addr) returns (string) {
return latestTelemetry[addr];
if (bytes(latestTelemetry[addr]).length == 0) {
return "{ \"error\": \"Not Found\" }";
} else {
return latestTelemetry[addr];
}
}
}
4 changes: 3 additions & 1 deletion migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
var Telemetry = artifacts.require('./Telemetry.sol');

module.exports = function(deployer) {
deployer.deploy(Telemetry);
deployer.deploy(Telemetry, {
privateFor: ['ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc=']
});
};
89 changes: 88 additions & 1 deletion test/telemetry.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,32 @@ const sampleTelemetry = {
]
};

const testrpc = web3.version.node.includes('EthereumJS TestRPC');

const nodes = {
node2: {
url: testrpc ? 'http://localhost:8545' : 'http://localhost:22001',
publicKey: 'QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc='
},
node3: {
url: testrpc ? 'http://localhost:8545' : 'http://localhost:22002',
publicKey: '1iTZde/ndBHvzhcl7V68x44Vx7pl8nwx9LqnM/AfJUg='
},
node7: {
url: testrpc ? 'http://localhost:8545' : 'http://localhost:22006',
publicKey: 'ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc='
},
};

const setProvider = function (instance, url) {
const newProvider = new web3.providers.HttpProvider(url);
web3.setProvider(newProvider);
instance.contract._eth._requestManager.provider = newProvider;
};

contract('Telemetry', function (accounts) {
const fromAccount = accounts[0];

it('should get an event when telemetry sent', function (done) {
Telemetry.deployed().then(function (instance) {
const telemetryReceived = instance.TelemetryReceived();
Expand All @@ -21,7 +46,69 @@ contract('Telemetry', function (accounts) {

done();
});
instance.sendTelemetry(JSON.stringify(sampleTelemetry));
instance.sendTelemetry(JSON.stringify(sampleTelemetry), {
from: fromAccount,
privateFor: [nodes.node7.publicKey]
});
});
});

it('should not be able to get private telemetry', function (done) {
Telemetry.deployed().then(function (instance) {
const resultChecker = function (result) {
// The result is checked with a retry loop, because the transaction is initially
// written via node2 and it takes a while until the data is synced and readable
// via node7 (which is used for checking the final result since node7 public key
// is used as the privateFor value in the transaction and when contract was deployed).
const latestTelemetry = JSON.parse(result);
if (latestTelemetry.error === 'Not Found') {
setTimeout(function () {
instance.getLatestTelemetry.call(fromAccount).then(resultChecker);
}, 1000);
return;
}
assert.equal(latestTelemetry.values[0].value, sampleTelemetry.values[0].value,
'node 7 should have access to the private telemetry');
done();
};

// Send the telemetry via node2.
setProvider(instance, nodes.node2.url);
instance.sendTelemetry.sendTransaction(JSON.stringify(sampleTelemetry), {
from: fromAccount,
privateFor: [nodes.node7.publicKey]
})
.then(function (tx) {
return instance.sendTelemetry.sendTransaction(JSON.stringify(sampleTelemetry), {
from: fromAccount,
privateFor: [nodes.node7.publicKey]
});
})
.then(function (tx) {
setProvider(instance, nodes.node3.url);
return instance.getLatestTelemetry.call(fromAccount);
})
.catch(function (error) {
// This catch is here, because Quorum release v1.1.0 has
// an issue which causes an error when making an unauthorized
// call to a private contract and when string is expected as
// return value.
assert(error.name, 'BigNumber Error', 'a specific error is expected');
// Return empty string to "simulate" what should be returned after
// the issue in Quorum is fixed.
return '';
})
.then(function (result) {
// The expectation is that we should end up here, because
// node3 does not have permissions to call the contract
// deployed privately for other nodes.
assert.equal(result, '',
'node 3 should not have access to the private telemetry');
setProvider(instance, nodes.node7.url);
return instance.getLatestTelemetry.call(fromAccount);
})
.then(resultChecker);
});
});

});

0 comments on commit dbf0438

Please sign in to comment.