9.2 KiB
title, author
| title | author |
|---|---|
| DAO demo architecture | jstark |
This document outlines a simple demo to showcase the smart contract schema underlying the initial DAO MVP. We have tried to mimic the basic DarkFi architecture while remaining as simple as possible.
We do not have a blockchain, p2p network, or encrypted wallet database in this highly simplified demo. It is just a local network of 4 nodes and a relayer. The values are all stored in memory.
Layers
bin Located in darkfi/bin/dao.
- daod/: receives rpc requests and operates a
client. - dao-cli/: command-line interface that receives input and sends rpc requests.
- relayerd/: receives transactions on TCP and relays them to all nodes.
src Located in darkfi/bin/dao/daod.
- contract/: source code for dao and money contracts.
- util/: demo-wide utilities.
- state/: stores dao and money states.
- tx: underlying types required by transactions, function calls and call data.
- node/: a dao full node.
node
A dao node containing client and wallet submodules.
- client/: operates a wallet and performs state transition and validate methods.
- wallet/: owns and operates secret values.
proof Located in darkfi/bin/dao/proof. Contains the zk proofs.
Command Flow
The following assumes that a user has already compiled the zk contracts
by running make.
This requires a Makescript as follows:
ZK_SRC_FILES := $(wildcard proof/*.zk)
ZK_BIN_FILES := $(patsubst proof/%.zk, proof/%.zk.bin, $(ZK_SRC_FILES))
daod: $(ZK_BIN_FILES)
cargo run --release
proof/%.zk.bin: proof/%.zk
zkas $<
We will also need to write a shell script that opens 9 terminals and runs the following:
Terminal 1: relayerd. Terminal 2-5: 4 instances of daod. Terminal 6-9: 4 instances of dao-cli.
Relayerd and daod should be sent to the background, so the demo will consist visually of 4 terminals running dao-cli.
Start relayer
relayerdstarts a listener for all TCP ports specified in config.
Initialize DAO
Note: this happens automatically on daod first run.
daod: starts a listener on the relayer TCP port.daod:creates a client and callsclient.init().client: creates a money wallet.money-wallet: generates cashier, faucet keys.client: gets public keys from wallet and callsstate.new().state: creates ZkContractTable, StateRegistry.state: loads all zk binaries and saves them in ZkContractTable.state: creates a new money/dao state and registers them in StateRegistry.
Stage 1: create DAO
dao-cli:sendscreate()rpc request to daod.daod: receives rpc request and callsclient.create().client: creates a dao wallet.dao-wallet: specifies the dao params.dao-wallet: creates a dao keypair, bulla blind, and signature secret.
build sequence.
Note: Builders differ according to the FuncCall, but the basic sequence is the same.
dao-wallet: build: creates dao_contract::mint::wallet::Builder.dao-wallet: generates a FuncCall from builder.build().dao-wallet: adds FuncCall to a vector.dao-wallet: sign the vector of FuncCalls.
send sequence.
dao-wallet: create a Transaction.dao-wallet: send the Transaction to the relayer.relayer: receives a Transaction on one of its connections.relayer: relays the Transaction to all connected nodes.
recv sequence.
daod: receives a Transaction on its relayerd listener.- 'daod`: sends the Transaction to Client.
validate sequence.
client: validate: creates an empty vector of updates.client: loops through all FuncCalls in the Transaction.client: runs a match statement on the FUNC_ID.client: finds mint FUNC_ID and runs a state transition function.client: pushes the result to Vecclient: outside the loop, atomically applies all updates.client: calls zk_verify() on the Transaction.client: verifies signatures.
client: sends Transaction to the relayer.relayer: receives Transaction and relays.
- TODO:
dao-wallet: waits until Transction is confirmed. (how?)
dao-wallet: look up the dao state and call witness().dao-wallet: get the dao bulla from the Transaction.dao-cli: print "Created DAO {}".
Stage 2: fund DAO
- TODO: for the demo it might be better to call mint() first and then fund(), passing the values into fund()
Here we are creating a treasury token and sending it to the DAO.
dao-cli:fund()rpc request to daoddaod: receives rpc request and callsclient.fund().client: creates treasury token, random token ID and supply
Note: dao-wallet must manually track coins to retrieve coins belonging to its private key.
-
dao-wallet: looks up the money state, and calls state.wallet_cache.track() -
money-wallet: sets spend hook to dao_contract::exec::FUNC_ID -
money-wallet: sets user_data to dao_bulla
- TODO: how does it get the dao_bulla? Must be stored somewhere.
money-wallet: specifies dao public key and treasury token BuilderOutputInfo.money-wallet: runs the build sequence for money::transfer.money-wallet: create Transaction and send.relayer: receives Transaction and relays.daod: receives a Transaction and sends to client.client: runs the validate sequence.
Note: here we get all coins associated with the private key.
13. dao-wallet: looks up the state and calls WalletCache.get_received()
14. dao-wallet: check the coin is valid by recreating Coin
15. daod: sendswith token ID and balance to dao-cli.
16. dao-cli: displays data using pretty table.
Stage 3: airdrop
dao-cli: calls keygen()daod: client.keygen()daod: money-wallet.keygen()money-wallet: creates new keypairmoney-wallet: looks up the money_contract State and calls WalletCache.track()money-wallet: return the public keydao-cli: prints the public key
Note: do this 3 times to generate 3 pubkey keys for different daod instances.
dao-cli: calls mint()daod: call client.mint()client:creates governance token with random token ID and supplydao-cli: prints "created token {} with supply {}"dao-cli: calls airdrop() and passes a value and a pubkey.dao-wallet:runs the build sequence for money::transfer.dao-wallet: create Transaction and send.relayer: receives Transaction and relays.daod: receives a Transaction and sends to client.client: runs the validate sequence.money-wallet: state.wallet_cache.get_received()money-wallet: check the coin is valid by recreating Coindaod: sends token ID and balance to clidao-cli: prints "received coin {} with value {}".
- TODO: money-wallet must keep track of Coins and have a flag for whether or not they are spent.
- Hashmap of <Coin, bool> ?
Stage 4: create proposal
- TODO: maybe for the demo we should just hardcode a user/ proposal recipient.
dao-cli: calls propose() and enter a user pubkey and an amountdao-wallet: runs the build sequence for dao_contract::proposedao-wallet: specifies user pubkey, amount and token ID in Proposaldao-cli: prints "Created proposal to send {} xDRK to {}"dao-wallet: create Transaction and send.relayer: receives Transaction and relays.daod: receives a Transaction and sends to client.client: runs the validate sequence.
- TODO: how does everyone have access to DAO private key?
dao-wallet: reads received proposal and tries to decrypt Notedao-wallet: sends decrypted values to daoddao-cli: prints "Proposal is now active"
Stage 5 vote
dao-cli: calls vote() and enters a vote option (yes or no) and an amountdaod: calls client.vote()money-wallet: get money_leaf_position and money_merkle_pathmoney-wallet: create builder sequence for dao_contract::votemoney-wallet: specify dao_keypair in vote_keypair field
- TODO: this implies that money-wallet is able to access private values in dao-wallet
money-wallet: signs and sendsrelayer: receives Transaction and relays.daod: receives a Transaction and sends to client.client: runs the validate sequence.dao-wallet: tries to decrypt the Vote.dao-cli: prints "Received vote {} value {}"
Note: repeat 3 times with different values and vote options.
- TODO: ignore section re: vote commitments?
- TODO: determine outcome: yes_votes_value/ all_votes_value e.g. when the quorum is reached, print "Quorum reached! Outcome {}" or just hardcode it for X n. of voters
Stage 6: Executing the proposal
dao-cli: calls exec()
- TODO: how does dao have access to user data?
dao-wallet: get money_leaf_position and money_merkle_pathdao-wallet: specifies user_kaypair and proposal amount in 1st outputdao-wallet: specifies change in 2nd outputdao-wallet: run build sequence for money_contract::transferdao-wallet: run build sequence for dao_contract::execdao-wallet: signs transaction and sendsrelayer: receives Transaction and relays.daod: receives a Transaction and sends to client.client: runs the validate sequence.