-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: dwertent <[email protected]>
- Loading branch information
Showing
17 changed files
with
871 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
# Private Storage Contract | ||
|
||
In this tutorial, you'll learn how to deploy and interact with a **private storage contract** using Paladin's privacy groups. Unlike the public storage example, here only authorized members of a privacy group can interact with the contract, ensuring secure and private data handling. | ||
|
||
--- | ||
|
||
## Prerequisites | ||
|
||
Before starting, make sure you have: | ||
|
||
1. Completed the [Public Storage Tutorial](./public-storage.md) and are familiar with: | ||
- Deploying and interacting with contracts. | ||
- Using Paladin SDK for blockchain transactions. | ||
2. A running Paladin network with multiple nodes (at least 3 for this tutorial). | ||
|
||
--- | ||
|
||
## Overview | ||
|
||
The `PrivateStorage` tutorial demonstrates how to: | ||
|
||
1. Create a **privacy group** with selected members. | ||
2. Deploy a **private Storage contract** within the group. | ||
3. Interact with the contract securely within the group. | ||
4. Test privacy by attempting access from a non-member node. | ||
|
||
The example code can be found in the [Paladin example repository](https://github.com/LF-Decentralized-Trust-labs/paladin/blob/main/example/private-storage). | ||
|
||
The Solidity contract remains the same as in the [Public Storage Tutorial](https://github.com/LF-Decentralized-Trust-labs/paladin/blob/main/solidity/contracts/tutorial/Storage.sol). However, the interaction is scoped to the privacy group. | ||
|
||
--- | ||
|
||
## Step 1: Create a Privacy Group | ||
|
||
To enable private interactions, start by creating a privacy group with selected members. | ||
|
||
```typescript | ||
// Create a privacy group with Node1 and Node2 | ||
logger.log("Creating a privacy group for Node1 and Node2..."); | ||
const penteFactory = new PenteFactory(paladinNode1, "pente"); | ||
const memberPrivacyGroup = await penteFactory.newPrivacyGroup(verifierNode1, { | ||
group: { | ||
salt: newGroupSalt(), // Generate a unique salt for the group | ||
members: [verifierNode1, verifierNode2], // Include Node1 and Node2 as members | ||
}, | ||
evmVersion: "shanghai", | ||
endorsementType: "group_scoped_identities", | ||
externalCallsEnabled: true, | ||
}); | ||
|
||
if (!checkDeploy(memberPrivacyGroup)) { | ||
logger.error("Failed to create the privacy group."); | ||
return false; | ||
} | ||
logger.log("Privacy group created successfully!"); | ||
``` | ||
|
||
--- | ||
|
||
## Step 2: Deploy the Contract in the Privacy Group | ||
|
||
Deploy the `Storage` contract within the created privacy group. | ||
|
||
```typescript | ||
logger.log("Deploying a private Storage contract..."); | ||
const contractAddress = await memberPrivacyGroup.deploy( | ||
storageJson.abi, // ABI of the Storage contract | ||
storageJson.bytecode, // Bytecode of the Storage contract | ||
verifierNode1 // Deploying as Node1 | ||
); | ||
|
||
if (!contractAddress) { | ||
logger.error("Failed to deploy the private Storage contract."); | ||
return false; | ||
} | ||
logger.log(`Private Storage contract deployed! Address: ${contractAddress}`); | ||
``` | ||
|
||
--- | ||
|
||
## Step 3: Store and Retrieve Values as Group Members | ||
|
||
### Store a Value | ||
|
||
Group members can store values securely in the private contract. | ||
|
||
```typescript | ||
const privateStorage = new PrivateStorage(memberPrivacyGroup, contractAddress); | ||
|
||
logger.log("Storing value (125) in the private Storage contract..."); | ||
const storeTx = await privateStorage.invoke(verifierNode1, "store", { num: 125 }); | ||
logger.log("Value stored successfully! Transaction hash:", storeTx?.transactionHash); | ||
``` | ||
|
||
--- | ||
|
||
### Retrieve the Value as a Member | ||
|
||
Authorized group members can retrieve the stored value. | ||
|
||
```typescript | ||
logger.log("Node1 retrieving the stored value..."); | ||
const retrievedValueNode1 = await privateStorage.call(verifierNode1, "retrieve", []); | ||
logger.log("Node1 retrieved the value successfully:", retrievedValueNode1["0"]); | ||
|
||
logger.log("Node2 retrieving the stored value..."); | ||
const retrievedValueNode2 = await privateStorage | ||
.using(paladinNode2) | ||
.call(verifierNode2, "retrieve", []); | ||
logger.log("Node2 retrieved the value successfully:", retrievedValueNode2["0"]); | ||
``` | ||
|
||
--- | ||
|
||
## Step 4: Verify Privacy by Testing Unauthorized Access | ||
|
||
When an outsider (Node3) tries to access the private contract, the attempt should fail. | ||
|
||
```typescript | ||
try { | ||
logger.log("Node3 (outsider) attempting to retrieve the value..."); | ||
await privateStorage.using(paladinNode3).call(verifierNode3, "retrieve", []); | ||
logger.error("Node3 (outsider) should not have access to the private Storage contract!"); | ||
return false; | ||
} catch (error) { | ||
logger.info("Node3 (outsider) cannot retrieve data. Access denied."); | ||
} | ||
``` | ||
|
||
--- | ||
|
||
## Conclusion | ||
|
||
Congratulations! You’ve successfully: | ||
|
||
1. Created a privacy group with selected members. | ||
2. Deployed a `Storage` contract in the privacy group. | ||
3. Ensured secure interactions with the contract for group members. | ||
4. Verified that unauthorized access is blocked. | ||
|
||
--- | ||
|
||
## Next Steps |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"version": "0.2.0", | ||
"configurations": [ | ||
{ | ||
"name": "Run", | ||
"runtimeExecutable": "npm", | ||
"args": ["run", "start"], | ||
"request": "launch", | ||
"type": "node", | ||
"outputCapture": "std" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Example: Hello World | ||
|
||
|
||
See the [tutorial](https://lf-decentralized-trust-labs.github.io/paladin/head/tutorials/private-storage/) for a detailed explanation. | ||
|
||
## Pre-requisites | ||
|
||
Requires a local Paladin instance running on `localhost:31548`. | ||
Requires a local Paladin instance running on `localhost:31648`. | ||
Requires a local Paladin instance running on `localhost:31748`. | ||
|
||
## Run standalone | ||
|
||
Compile [Solidity contracts](../../solidity): | ||
|
||
```shell | ||
cd ../../solidity | ||
npm install | ||
npm run compile | ||
``` | ||
|
||
Build [TypeScript SDK](../../sdk/typescript): | ||
|
||
```shell | ||
cd ../../sdk/typescript | ||
npm install | ||
npm run abi | ||
npm run build | ||
``` | ||
|
||
Run example: | ||
|
||
```shell | ||
npm install | ||
npm run abi | ||
npm run start | ||
``` | ||
|
||
## Run with Gradle | ||
|
||
The following will perform all pre-requisites and then run the example: | ||
|
||
```shell | ||
../../gradlew build | ||
npm run start | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* Copyright © 2024 Kaleido, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on | ||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations under the License. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
configurations { | ||
// Resolvable configurations | ||
contractCompile { | ||
canBeConsumed = false | ||
canBeResolved = true | ||
} | ||
buildSDK { | ||
canBeConsumed = false | ||
canBeResolved = true | ||
} | ||
} | ||
|
||
dependencies { | ||
contractCompile project(path: ':solidity', configuration: 'compiledContracts') | ||
buildSDK project(path: ':sdk:typescript', configuration: 'buildSDK') | ||
} | ||
|
||
task install(type: Exec) { | ||
executable 'npm' | ||
args 'install' | ||
|
||
inputs.files(configurations.buildSDK) | ||
inputs.files('package.json') | ||
outputs.files('package-lock.json') | ||
outputs.dir('node_modules') | ||
} | ||
|
||
task copyABI(type: Exec, dependsOn: install) { | ||
executable 'npm' | ||
args 'run' | ||
args 'abi' | ||
|
||
inputs.files(configurations.contractCompile) | ||
inputs.dir('scripts') | ||
outputs.dir('src/abis') | ||
} | ||
|
||
task build(type: Exec, dependsOn: [install, copyABI]) { | ||
executable 'npm' | ||
args 'run' | ||
args 'build' | ||
|
||
inputs.dir('src') | ||
outputs.dir('build') | ||
} | ||
|
||
task e2e(type: Exec, dependsOn: [build]) { | ||
dependsOn ':operator:deploy' | ||
|
||
executable 'npm' | ||
args 'run' | ||
args 'start' | ||
} | ||
|
||
task clean(type: Delete) { | ||
delete 'node_modules' | ||
delete 'build' | ||
} |
Oops, something went wrong.