Skip to content

Commit

Permalink
add nillion tool
Browse files Browse the repository at this point in the history
  • Loading branch information
oceans404 committed Mar 27, 2024
1 parent 6bc735a commit d7f790e
Show file tree
Hide file tree
Showing 22 changed files with 266 additions and 64 deletions.
43 changes: 2 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,51 +67,12 @@ yarn deploy

This command deploys a test smart contract to the local network. The contract is located in `packages/hardhat/contracts` and can be modified to suit your needs. The `yarn deploy` command uses the deploy script located in `packages/hardhat/deploy` to deploy the contract to the network. You can also customize the deploy script.

5. On a third terminal, run a Nillion local network cluster

Install [Nillion SDK Binaries](https://docs.nillion.com/quickstart#download-binaries) following the [Install binaries guide](https://docs.nillion.com/quickstart#install-the-nillion-sdk) if you don't have Nillion SDK tools installed locally

Then use the nillion [run-local-cluster tool](https://docs.nillion.com/program-simulator) to spin up a local cluster of Nillion nodes. You will run your app against this local cluster.
5. On a third terminal, run a Nillion local network cluster. This bootstraps a Nillion local network of nodes and adds cluster info to your NextJS app .env file

```
./run-local-cluster
yarn run-local-cluster
```

After a moment, the tool will log custom cluster information into your command line, for example:

```bash
# Example run-local-cluster output
ℹ️ cluster id is 798d89ce-37f4-4d7d-aab9-ba511ae67ccc
ℹ️ using 256 bit prime
ℹ️ storing state in /var/folders/1_/2yw8krkx5q5dn2jbhx69s4_r0000gn/T/.tmpfyozMh
⛓️ starting blockchain node...
✔️ blockchain node running on endpoint http://localhost:55501
🏃 starting node 12D3KooWSqDTmdKdJ6AWaVMgUKdLBBVeF6mRo2sLuqbgjjCFEtDK
⏳ waiting until bootnode is up...
🏃 starting node 12D3KooWQecC226DfT1q1CiYPxRGiJhrXpeLxV8AtcPZeKYB3wog
🏃 starting node 12D3KooWQc45ubzkGN6P3qipdUdFEgDTTjYtU3UuBbK7hBzJe5Ng
🏃 starting node 12D3KooWBXSwSu77B4vp5QQGL5nt959w2HjQDGcgiZKhaQRkd95J
🏃 starting node 12D3KooWBPfggEeDSSsfHya55oRH9gWgWeeC3yHF2GiQSXeSp91P
🎁 wallet keys written to /var/folders/1_/2yw8krkx5q5dn2jbhx69s4_r0000gn/T/.tmpfyozMh/private-keys.txt
📝 payments configuration written to /var/folders/1_/2yw8krkx5q5dn2jbhx69s4_r0000gn/T/.tmpfyozMh/payments-config.yaml
🥾 bootnode config written to /var/folders/1_/2yw8krkx5q5dn2jbhx69s4_r0000gn/T/.tmpfyozMh/bootnode.yaml
📝 configuration written to /Users/steph/Library/Application Support/nillion.nil-cli/config.yaml
✔️ cluster is running, bootnode is at /ip4/127.0.0.1/tcp/55692/p2p/12D3KooWSqDTmdKdJ6AWaVMgUKdLBBVeF6mRo2sLuqbgjjCFEtDK
🔗 websocket: /ip4/127.0.0.1/tcp/55693/ws/p2p/12D3KooWSqDTmdKdJ6AWaVMgUKdLBBVeF6mRo2sLuqbgjjCFEtDK
```
Use the output values to update all values within your [packages/nextjs/utils/nillion/nillionConfig.ts](https://github.com/NillionNetwork/scaffold-eth-with-nillion/blob/main/packages/nextjs/utils/nillion/nillionConfig.ts) file. Make the following updates:
- update websockets to be an array containing the output 🔗 websocket
- update cluster_id to the output ℹ️ cluster id
- update rpc_endpoint to the blockchain_rpc_endpoint value written into the 📝 payments configuration file
- update blinding_factors_manager to the blinding_factors_manager_sc_address value written into the 📝 payments configuration file
- update payments to the payments_sc_address value written into the 📝 payments configuration file
- update chain_id to the chain_id value written into the 📝 payments configuration file
- update private_key to one of the rotating values written into the 🎁 wallet keys file
Keep the cluster running in this terminal.
6. On a fourth terminal, start your NextJS app:

```
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"workspaces": {
"packages": [
"packages/hardhat",
"packages/nextjs"
"packages/nextjs",
"packages/nillion"
]
},
"scripts": {
Expand All @@ -28,7 +29,9 @@
"postinstall": "husky install",
"precommit": "lint-staged",
"vercel": "yarn workspace @se-2/nextjs vercel",
"vercel:yolo": "yarn workspace @se-2/nextjs vercel:yolo"
"vercel:yolo": "yarn workspace @se-2/nextjs vercel:yolo",
"nillion": "yarn workspace @se-2/nillion nillion",
"run-local-cluster": "yarn workspace @se-2/nillion run-local-cluster"
},
"packageManager": "[email protected]",
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ yarn-error.log*
.pnpm-debug.log*

# local env files
.env
.env.local
.env.development.local
.env.test.local
Expand Down
12 changes: 12 additions & 0 deletions packages/nextjs/app/nillion-compute/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import SecretForm from "~~/components/nillion/SecretForm";
import { Address } from "~~/components/scaffold-eth";
import { compute } from "~~/utils/nillion/compute";
import { getUserKeyFromSnap } from "~~/utils/nillion/getUserKeyFromSnap";
import { retrieveSecretCommand } from "~~/utils/nillion/retrieveSecretCommand";
import { storeProgram } from "~~/utils/nillion/storeProgram";
import { storeSecretsInteger } from "~~/utils/nillion/storeSecretsInteger";

Expand Down Expand Up @@ -202,6 +203,17 @@ const Home: NextPage = () => {
<p>
✅ Stored SecretInteger {key} <br />{" "}
<CopyString str={storedSecretsNameToStoreId[key] || ""} textBefore={`store_id: `} full />
<br />
<p>
👀 Optional: Copy and run the following command to retrieve-secret from the command line
to see the value of {key} using the nillion SDK tool
</p>
<CopyString
str={retrieveSecretCommand(userKey, storedSecretsNameToStoreId[key], key)}
start={30}
end={30}
code
/>
</p>
) : (
<SecretForm
Expand Down
31 changes: 20 additions & 11 deletions packages/nextjs/components/nillion/CopyString.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,26 @@ export const CopyString: React.FC<{
end?: number;
textBefore?: string;
full?: boolean;
}> = ({ str, textBefore = "", start = 5, end = 5, full }) => {
code?: boolean;
}> = ({ str, textBefore = "", start = 5, end = 5, full, code }) => {
return (
<span className="flex">
{textBefore}
{full ? str : shortenKeyHelper(str, start, end)}
<CopyToClipboard text={str}>
<DocumentDuplicateIcon
className="ml-1.5 text-xl font-normal text-sky-600 h-5 w-5 cursor-pointer"
aria-hidden="true"
/>
</CopyToClipboard>
</span>
<p className="flex text-center items-center justify-around">
<span className="flex ">
{textBefore}
{code ? (
<code>{full ? str : shortenKeyHelper(str, start, end)}</code>
) : full ? (
str
) : (
shortenKeyHelper(str, start, end)
)}
<CopyToClipboard text={str}>
<DocumentDuplicateIcon
className="ml-1.5 text-xl font-normal text-sky-600 h-5 w-5 cursor-pointer"
aria-hidden="true"
/>
</CopyToClipboard>
</span>
</p>
);
};
7 changes: 4 additions & 3 deletions packages/nextjs/utils/nillion/nillionClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ export const initializeNillionClient = (
export const getNillionClient = async (userKey: string) => {
await nillion.default();
const nillionUserKey = nillion.UserKey.from_base58(userKey);
const nodeKey = nillion.NodeKey.from_seed("scaffold-eth");
// temporary fix for an issue where nodekey cannot be reused between calls
const nodeKey = nillion.NodeKey.from_seed(`scaffold-eth-${Math.floor(Math.random() * 10000)}`);
const client = initializeNillionClient(
nillionUserKey,
nodeKey,
nillionConfig.websockets,
nillionConfig.payments_config,
nillionConfig.websockets as string[],
nillionConfig.payments_config as PaymentsConfig,
);
return {
nillion,
Expand Down
17 changes: 10 additions & 7 deletions packages/nextjs/utils/nillion/nillionConfig.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
export const nillionConfig = {
websockets: ["/ip4/127.0.0.1/tcp/55693/ws/p2p/12D3KooWSqDTmdKdJ6AWaVMgUKdLBBVeF6mRo2sLuqbgjjCFEtDK"],
cluster_id: "798d89ce-37f4-4d7d-aab9-ba511ae67ccc",
websockets: [process.env.NEXT_PUBLIC_NILLION_WEBSOCKETS],
cluster_id: process.env.NEXT_PUBLIC_NILLION_CLUSTER_ID,
payments_config: {
rpc_endpoint: "http://localhost:55501",
rpc_endpoint: process.env.NEXT_PUBLIC_NILLION_BLOCKCHAIN_RPC_ENDPOINT,
smart_contract_addresses: {
blinding_factors_manager: "a513e6e4b8f2a923d98304ec87f64353c4d5c853",
payments: "5fc8d32690cc91d4c39d9d3abcbd16989f875707",
blinding_factors_manager: process.env.NEXT_PUBLIC_NILLION_BLINDING_FACTORS_MANAGER_SC_ADDRESS,
payments: process.env.NEXT_PUBLIC_NILLION_PAYMENTS_SC_ADDRESS,
},
signer: {
wallet: {
chain_id: 31337,
private_key: "df57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e",
// @ts-ignore
chain_id: parseInt(process.env.NEXT_PUBLIC_NILLION_CHAIN_ID || 0),
private_key: process.env.NEXT_PUBLIC_NILLION_WALLET_PRIVATE_KEY,
},
},
},
};

console.log;
16 changes: 16 additions & 0 deletions packages/nextjs/utils/nillion/retrieveSecretCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const retrieveSecretCommand = (
user_key: any,
store_id: any,
secret_name: any,
) => `yarn nillion --user-key ${user_key} \
--node-key ${process.env.NEXT_PUBLIC_NILLION_NODEKEY_TEXT_PARTY_1} \
-b ${process.env.NEXT_PUBLIC_NILLION_BOOTNODE_MULTIADDRESS} \
--payments-private-key ${process.env.NEXT_PUBLIC_NILLION_WALLET_PRIVATE_KEY} \
--payments-chain-id ${process.env.NEXT_PUBLIC_NILLION_CHAIN_ID} \
--payments-rpc-endpoint ${process.env.NEXT_PUBLIC_NILLION_BLOCKCHAIN_RPC_ENDPOINT} \
--payments-sc-address ${process.env.NEXT_PUBLIC_NILLION_PAYMENTS_SC_ADDRESS} \
--blinding-factors-manager-sc-address ${process.env.NEXT_PUBLIC_NILLION_BLINDING_FACTORS_MANAGER_SC_ADDRESS} \
retrieve-secret \
--cluster-id ${process.env.NEXT_PUBLIC_NILLION_CLUSTER_ID} \
--store-id ${store_id} \
--secret-id ${secret_name}`;
1 change: 1 addition & 0 deletions packages/nillion/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
160 changes: 160 additions & 0 deletions packages/nillion/bootstrap-local-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#!/usr/bin/env bash

RUN_LOCAL_CLUSTER="./run-local-cluster"
USER_KEYGEN="./user-keygen"
NODE_KEYGEN="./node-keygen"

echo $RUN_LOCAL_CLUSTER
# kill any other run-local-cluster processes
pkill -9 -f $RUN_LOCAL_CLUSTER

for var in RUN_LOCAL_CLUSTER USER_KEYGEN NODE_KEYGEN; do
printf "ℹ️ found bin %-18s -> [${!var:?Failed to discover $var}]\n" "$var"
done

OUTFILE=$(mktemp);
PIDFILE=$(mktemp);

echo $OUTFILE

# Create node keys
NODEKEY_FILE_PARTY_1=$(mktemp);
NODEKEY_FILE_PARTY_2=$(mktemp);
NODEKEY_FILE_PARTY_3=$(mktemp);
NODEKEY_FILE_PARTY_4=$(mktemp);
NODEKEY_FILE_PARTY_5=$(mktemp);

# Crete user keys
USERKEY_FILE_PARTY_1=$(mktemp);
USERKEY_FILE_PARTY_2=$(mktemp);
USERKEY_FILE_PARTY_3=$(mktemp);
USERKEY_FILE_PARTY_4=$(mktemp);
USERKEY_FILE_PARTY_5=$(mktemp);

"$RUN_LOCAL_CLUSTER" >"$OUTFILE" & echo $! >"$PIDFILE";
ENV_TO_UPDATE=".env ../nextjs/.env"
echo "--------------------"
echo "Updating your ${ENV_TO_UPDATE} files with run-local-cluster environment info... This may take a minute."
echo "--------------------"
time_limit=160
while true; do
# Use 'wait' to check if the log file contains the string
if grep "cluster is running, bootnode is at" "$OUTFILE"; then
break
fi

# If the time limit has been reached, print an error message and exit
if [[ $SECONDS -ge $time_limit ]]; then
echo "Timeout reached while waiting for cluster to be ready in '$OUTFILE'" >&2
exit 1
fi
sleep 5
done

echo "ℹ️ Cluster has been STARTED (see $OUTFILE)"
cat "$OUTFILE"

CLUSTER_ID=$(grep "cluster id is" "$OUTFILE" | awk '{print $4}');
WEBSOCKET=$(grep "websocket:" "$OUTFILE" | awk '{print $2}');
BOOT_MULTIADDR=$(grep "cluster is running, bootnode is at" "$OUTFILE" | awk '{print $7}');
PAYMENTS_CONFIG_FILE=$(grep "payments configuration written to" "$OUTFILE" | awk '{print $5}');
WALLET_KEYS_FILE=$(grep "wallet keys written to" "$OUTFILE" | awk '{print $5}');
PAYMENTS_RPC=$(grep "blockchain_rpc_endpoint:" "$PAYMENTS_CONFIG_FILE" | awk '{print $2}');
PAYMENTS_CHAIN=$(grep "chain_id:" "$PAYMENTS_CONFIG_FILE" | awk '{print $2}');
PAYMENTS_SC_ADDR=$(grep "payments_sc_address:" "$PAYMENTS_CONFIG_FILE" | awk '{print $2}');
PAYMENTS_BF_ADDR=$(grep "blinding_factors_manager_sc_address:" "$PAYMENTS_CONFIG_FILE" | awk '{print $2}');
WALLET_PRIVATE_KEY=$(tail -n1 "$WALLET_KEYS_FILE")

# Generate multiple node keys
"$NODE_KEYGEN" "$NODEKEY_FILE_PARTY_1"
"$NODE_KEYGEN" "$NODEKEY_FILE_PARTY_2"
"$NODE_KEYGEN" "$NODEKEY_FILE_PARTY_3"
"$NODE_KEYGEN" "$NODEKEY_FILE_PARTY_4"
"$NODE_KEYGEN" "$NODEKEY_FILE_PARTY_5"

# Generate multiple user keys
"$USER_KEYGEN" "$USERKEY_FILE_PARTY_1"
"$USER_KEYGEN" "$USERKEY_FILE_PARTY_2"
"$USER_KEYGEN" "$USERKEY_FILE_PARTY_3"
"$USER_KEYGEN" "$USERKEY_FILE_PARTY_4"
"$USER_KEYGEN" "$USERKEY_FILE_PARTY_5"

echo "🔑 Node key and user keys have been generated"

# Function to update or add an environment variable
update_env() {
local key=$1
local value=$2
# Skip the first two arguments to get the file paths
local files=("${@:3}")

for file in "${files[@]}"; do
if [ -f "$file" ]; then # Check if file exists
# Check if the key exists in the file and remove it
if grep -q "^$key=" "$file"; then
# Key exists, remove it
grep -v "^$key=" "$file" > temp.txt && mv temp.txt "$file"
fi

# Append the new key-value pair to the file
echo "$key=$value" >> "$file"
else
echo "File $file not found. Creating $file"
touch $file
echo "$key=$value" >> "$file"
fi
done
}

log_file_contents() {
local file_path=$1 # Direct path to the target file

# Check if the file exists at the path
if [[ ! -f "$file_path" ]]; then
echo "File $file_path does not exist."
return 1 # Exit the function with an error status if the file does not exist
fi

# If the file exists, cat its contents
cat "$file_path"
}

# Add environment variables to .env
update_env "NEXT_PUBLIC_NILLION_WEBSOCKETS" "$WEBSOCKET" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_CLUSTER_ID" "$CLUSTER_ID" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_BLOCKCHAIN_RPC_ENDPOINT" "$PAYMENTS_RPC" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_BLINDING_FACTORS_MANAGER_SC_ADDRESS" "$PAYMENTS_BF_ADDR" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_PAYMENTS_SC_ADDRESS" "$PAYMENTS_SC_ADDR" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_CHAIN_ID" "$PAYMENTS_CHAIN" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_WALLET_PRIVATE_KEY" "$WALLET_PRIVATE_KEY" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_BOOTNODE_MULTIADDRESS" "$BOOT_MULTIADDR" $ENV_TO_UPDATE

# Add user key paths and user keys to .env
update_env "NEXT_PUBLIC_NILLION_USERKEY_PATH_PARTY_1" "$USERKEY_FILE_PARTY_1" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_USERKEY_TEXT_PARTY_1" $(log_file_contents $USERKEY_FILE_PARTY_1) $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_USERKEY_PATH_PARTY_2" "$USERKEY_FILE_PARTY_2" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_USERKEY_TEXT_PARTY_2" $(log_file_contents $USERKEY_FILE_PARTY_2) $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_USERKEY_PATH_PARTY_3" "$USERKEY_FILE_PARTY_3" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_USERKEY_TEXT_PARTY_3" $(log_file_contents $USERKEY_FILE_PARTY_3) $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_USERKEY_PATH_PARTY_4" "$USERKEY_FILE_PARTY_4" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_USERKEY_TEXT_PARTY_4" $(log_file_contents $USERKEY_FILE_PARTY_4) $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_USERKEY_PATH_PARTY_5" "$USERKEY_FILE_PARTY_5" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_USERKEY_TEXT_PARTY_5" $(log_file_contents $USERKEY_FILE_PARTY_5) $ENV_TO_UPDATE

# Add node key paths and node keys to .env
update_env "NEXT_PUBLIC_NILLION_NODEKEY_PATH_PARTY_1" "$NODEKEY_FILE_PARTY_1" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_NODEKEY_TEXT_PARTY_1" $(log_file_contents $NODEKEY_FILE_PARTY_1) $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_NODEKEY_PATH_PARTY_2" "$NODEKEY_FILE_PARTY_2" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_NODEKEY_TEXT_PARTY_2" $(log_file_contents $NODEKEY_FILE_PARTY_2) $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_NODEKEY_PATH_PARTY_3" "$NODEKEY_FILE_PARTY_3" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_NODEKEY_TEXT_PARTY_3" $(log_file_contents $NODEKEY_FILE_PARTY_3) $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_NODEKEY_PATH_PARTY_4" "$NODEKEY_FILE_PARTY_4" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_NODEKEY_TEXT_PARTY_4" $(log_file_contents $NODEKEY_FILE_PARTY_4) $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_NODEKEY_PATH_PARTY_5" "$NODEKEY_FILE_PARTY_5" $ENV_TO_UPDATE
update_env "NEXT_PUBLIC_NILLION_NODEKEY_TEXT_PARTY_5" $(log_file_contents $NODEKEY_FILE_PARTY_5) $ENV_TO_UPDATE

echo "--------------------"
echo "ℹ️ Updated your $ENV_TO_UPDATE file configurations with variables: websocket, cluster id, keys, blockchain info"
echo "💻 Your Nillion local cluster is still running - process pid: $(pgrep -f $RUN_LOCAL_CLUSTER)"

exit 0
13 changes: 13 additions & 0 deletions packages/nillion/foundry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash

set -ex

curl -L https://foundry.paradigm.xyz | bash

FOUNDRY_PATH="$HOME/.foundry/bin"
echo "Add $FOUNDRY_PATH to your PATH to have the foundryup available in your shell."

# The foundryup command uses its "latest" tag when no args are specified. We
# previously tried to pin the tag to a specific nightly release, but it turns
# out the foundry project deletes those tags periodically.
$FOUNDRY_PATH/foundryup
Binary file added packages/nillion/nada
Binary file not shown.
Binary file added packages/nillion/nillion
Binary file not shown.
Binary file added packages/nillion/nilup
Binary file not shown.
Binary file added packages/nillion/node-key2peerid
Binary file not shown.
Binary file added packages/nillion/node-keygen
Binary file not shown.
Loading

0 comments on commit d7f790e

Please sign in to comment.