Skip to content

Commit

Permalink
Merge pull request #79 from psofiterol/chore/update-0.7.0
Browse files Browse the repository at this point in the history
chore: update example and reqs for 0.7.0
  • Loading branch information
psofiterol authored Nov 21, 2024
2 parents 7d03184 + b0e77b2 commit f2b8eba
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 111 deletions.
182 changes: 74 additions & 108 deletions quickstart_complete/client_code/secret_addition_complete.py
Original file line number Diff line number Diff line change
@@ -1,141 +1,107 @@
"""
In this example, we:
1. connect to the local nillion-devnet
2. store the secret addition program
3. store a secret to be used in the computation
4. compute the secret addition program with the stored secret and another computation time secret
1. import packages we'll be using
2. connect to the local nillion-devnet
3. store the secret addition program
4. store a secret to be used in the computation
5. compute the secret addition program with the stored secret and another computation time secret
6. return the computation result
"""

import asyncio
import py_nillion_client as nillion
import os

from py_nillion_client import NodeKey, UserKey
from nillion_client import (
InputPartyBinding,
Network,
NilChainPayer,
NilChainPrivateKey,
OutputPartyBinding,
Permissions,
SecretInteger,
VmClient,
PrivateKey,
)
from dotenv import load_dotenv
from nillion_python_helpers import get_quote_and_pay, create_nillion_client, create_payments_config

from cosmpy.aerial.client import LedgerClient
from cosmpy.aerial.wallet import LocalWallet
from cosmpy.crypto.keypairs import PrivateKey

home = os.getenv("HOME")
load_dotenv(f"{home}/.config/nillion/nillion-devnet.env")

async def main():
# 1. Initial setup
# 1.1. Get cluster_id, grpc_endpoint, & chain_id from the .env file
cluster_id = os.getenv("NILLION_CLUSTER_ID")
grpc_endpoint = os.getenv("NILLION_NILCHAIN_GRPC")
chain_id = os.getenv("NILLION_NILCHAIN_CHAIN_ID")
# 1.2 pick a seed and generate user and node keys
seed = "my_seed"
userkey = UserKey.from_seed(seed)
nodekey = NodeKey.from_seed(seed)

# 2. Initialize NillionClient against nillion-devnet
# Create Nillion Client for user
client = create_nillion_client(userkey, nodekey)

party_id = client.party_id
user_id = client.user_id
# 2. Initial setup, Initialize NillionClient against nillion-devnet
# Use the devnet configuration generated by `nillion-devnet`
network = Network.from_config("devnet")

# Create payments config and set up Nillion wallet with a private key to pay for operations
nilchain_key: str = os.getenv("NILLION_NILCHAIN_PRIVATE_KEY_0") # type: ignore
payer = NilChainPayer(
network,
wallet_private_key=NilChainPrivateKey(bytes.fromhex(nilchain_key)),
gas_limit=10000000,
)

# 3. Pay for and store the program
# Set the program name and path to the compiled program
# Use a random key to identify ourselves
signing_key = PrivateKey()
client = await VmClient.create(signing_key, network, payer)
party_name = "Party1"
program_name = "secret_addition_complete"
program_mir_path = f"../nada_quickstart_programs/target/{program_name}.nada.bin"

# Create payments config, client and wallet
payments_config = create_payments_config(chain_id, grpc_endpoint)
payments_client = LedgerClient(payments_config)
payments_wallet = LocalWallet(
PrivateKey(bytes.fromhex(os.getenv("NILLION_NILCHAIN_PRIVATE_KEY_0"))),
prefix="nillion",
)

# Pay to store the program and obtain a receipt of the payment
receipt_store_program = await get_quote_and_pay(
client,
nillion.Operation.store_program(program_mir_path),
payments_wallet,
payments_client,
cluster_id,
)
# 3. Pay for and store the program
print("-----STORE PROGRAM")

# Store the program
action_id = await client.store_program(
cluster_id, program_name, program_mir_path, receipt_store_program
)
# Store program
program_mir = open(program_mir_path, "rb").read()
program_id = await client.store_program(program_name, program_mir).invoke()

# Create a variable for the program_id, which is the {user_id}/{program_name}. We will need this later
program_id = f"{user_id}/{program_name}"
print("Stored program. action_id:", action_id)
print("Stored program_id:", program_id)
# Print details about stored program
print(f"Stored program_id: {program_id}")

# 4. Create the 1st secret, add permissions, pay for and store it in the network
# Create a secret named "my_int1" with any value, ex: 500
new_secret = nillion.NadaValues(
{
"my_int1": nillion.SecretInteger(500),
}
)
print("-----STORE SECRETS")

# Set the input party for the secret
# The party name needs to match the party name that is storing "my_int1" in the program
party_name = "Party1"
# Create a secret
values = {
"my_int1": SecretInteger(500),
}

# Set permissions for the client to compute on the program
permissions = nillion.Permissions.default_for_user(client.user_id)
permissions.add_compute_permissions({client.user_id: {program_id}})

# Pay for and store the secret in the network and print the returned store_id
receipt_store = await get_quote_and_pay(
client,
nillion.Operation.store_values(new_secret, ttl_days=5),
payments_wallet,
payments_client,
cluster_id,
)
# Store a secret
store_id = await client.store_values(
cluster_id, new_secret, permissions, receipt_store
# Create a permissions object to attach to the stored secret
permissions = Permissions.defaults_for_user(client.user_id).allow_compute(
client.user_id, program_id
)
print(f"Computing using program {program_id}")
print(f"Use secret store_id: {store_id}")

# Store a secret, passing in the receipt that shows proof of payment
values_id = await client.store_values(
values, ttl_days=5, permissions=permissions
).invoke()

# 5. Create compute bindings to set input and output parties, add a computation time secret and pay for & run the computation
compute_bindings = nillion.ProgramBindings(program_id)
compute_bindings.add_input_party(party_name, party_id)
compute_bindings.add_output_party(party_name, party_id)

# Add my_int2, the 2nd secret at computation time
computation_time_secrets = nillion.NadaValues({"my_int2": nillion.SecretInteger(10)})

# Pay for the compute
receipt_compute = await get_quote_and_pay(
client,
nillion.Operation.compute(program_id, computation_time_secrets),
payments_wallet,
payments_client,
cluster_id,
)
print("-----COMPUTE")

# Compute on the secret
compute_id = await client.compute(
cluster_id,
compute_bindings,
[store_id],
computation_time_secrets,
receipt_compute,
)
# Bind the parties in the computation to the client to set input and output parties
input_bindings = [InputPartyBinding(party_name, client.user_id)]
output_bindings = [OutputPartyBinding(party_name, [client.user_id])]

# 8. Return the computation result
# Create a computation time secret to use
compute_time_values = {"my_int2": SecretInteger(10)}

# Compute, passing in the compute time values as well as the previously uploaded value.
print(f"Invoking computation using program {program_id} and values id {values_id}")
compute_id = await client.compute(
program_id,
input_bindings,
output_bindings,
values=compute_time_values,
value_ids=[values_id],
).invoke()

# 6. Return the computation result
print(f"The computation was sent to the network. compute_id: {compute_id}")
while True:
compute_event = await client.next_compute_event()
if isinstance(compute_event, nillion.ComputeFinishedEvent):
print(f"✅ Compute complete for compute_id {compute_event.uuid}")
print(f"🖥️ The result is {compute_event.result.value}")
return compute_event.result.value
result = await client.retrieve_compute_results(compute_id).invoke()
print(f"✅ Compute complete for compute_id {compute_id}")
print(f"🖥️ The result is {result}")
return result


if __name__ == "__main__":
Expand Down
4 changes: 1 addition & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
py-nillion-client
nillion-client
nada-dsl
nillion-python-helpers
python-dotenv==1.0.0
cosmpy>=0.9.2

0 comments on commit f2b8eba

Please sign in to comment.