dao.rs 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. use std::{any::TypeId, time::Instant};
  2. use incrementalmerkletree::Tree;
  3. use log::debug;
  4. use pasta_curves::{
  5. arithmetic::CurveAffine,
  6. group::{ff::Field, Curve, Group},
  7. pallas,
  8. };
  9. use rand::rngs::OsRng;
  10. use darkfi::{
  11. crypto::{
  12. keypair::{Keypair, PublicKey, SecretKey},
  13. proof::{ProvingKey, VerifyingKey},
  14. types::{DrkSpendHook, DrkUserData, DrkValue},
  15. util::{pedersen_commitment_u64, poseidon_hash},
  16. },
  17. zk::circuit::{BurnContract, MintContract},
  18. zkas::decoder::ZkBinary,
  19. };
  20. mod contract;
  21. mod error;
  22. mod note;
  23. mod util;
  24. use crate::{
  25. contract::{dao, example, money},
  26. util::{sign, StateRegistry, Transaction, ZkContractTable},
  27. };
  28. // TODO: Anonymity leaks in this proof of concept:
  29. //
  30. // * Vote updates are linked to the proposal_bulla
  31. // * Nullifier of vote will link vote with the coin when it's spent
  32. // TODO: strategize and cleanup Result/Error usage
  33. // TODO: fix up code doc
  34. type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
  35. ///////////////////////////////////////////////////
  36. ///// Example contract
  37. ///////////////////////////////////////////////////
  38. pub async fn example() -> Result<()> {
  39. debug!(target: "demo", "Stage 0. Example contract");
  40. // Lookup table for smart contract states
  41. let mut states = StateRegistry::new();
  42. // Initialize ZK binary table
  43. let mut zk_bins = ZkContractTable::new();
  44. let zk_example_foo_bincode = include_bytes!("../proof/foo.zk.bin");
  45. let zk_example_foo_bin = ZkBinary::decode(zk_example_foo_bincode)?;
  46. zk_bins.add_contract("example-foo".to_string(), zk_example_foo_bin, 13);
  47. let example_state = example::state::State::new();
  48. states.register(*example::CONTRACT_ID, example_state);
  49. //// Wallet
  50. let foo_w = example::foo::wallet::Foo { a: 5, b: 10 };
  51. let signature_secret = SecretKey::random(&mut OsRng);
  52. let builder = example::foo::wallet::Builder { foo: foo_w, signature_secret };
  53. let func_call = builder.build(&zk_bins);
  54. let func_calls = vec![func_call];
  55. let signatures = sign([signature_secret].to_vec(), &func_calls);
  56. let tx = Transaction { func_calls, signatures };
  57. //// Validator
  58. let mut updates = vec![];
  59. // Validate all function calls in the tx
  60. for (idx, func_call) in tx.func_calls.iter().enumerate() {
  61. if func_call.func_id == *example::foo::FUNC_ID {
  62. debug!("example::foo::state_transition()");
  63. let update = example::foo::validate::state_transition(&states, idx, &tx)
  64. .expect("example::foo::validate::state_transition() failed!");
  65. updates.push(update);
  66. }
  67. }
  68. // Atomically apply all changes
  69. for update in updates {
  70. update.apply(&mut states);
  71. }
  72. tx.zk_verify(&zk_bins).unwrap();
  73. tx.verify_sigs();
  74. Ok(())
  75. }
  76. #[async_std::main]
  77. async fn main() -> Result<()> {
  78. env_logger::init();
  79. // Example smart contract
  80. //// TODO: this will be moved to a different file
  81. example().await?;
  82. // Money parameters
  83. let xdrk_supply = 1_000_000;
  84. let xdrk_token_id = pallas::Base::random(&mut OsRng);
  85. // Governance token parameters
  86. let gdrk_supply = 1_000_000;
  87. let gdrk_token_id = pallas::Base::random(&mut OsRng);
  88. // DAO parameters
  89. let dao_proposer_limit = 110;
  90. let dao_quorum = 110;
  91. let dao_approval_ratio_quot = 1;
  92. let dao_approval_ratio_base = 2;
  93. // Lookup table for smart contract states
  94. let mut states = StateRegistry::new();
  95. // Initialize ZK binary table
  96. let mut zk_bins = ZkContractTable::new();
  97. debug!(target: "demo", "Loading dao-mint.zk");
  98. let zk_dao_mint_bincode = include_bytes!("../proof/dao-mint.zk.bin");
  99. let zk_dao_mint_bin = ZkBinary::decode(zk_dao_mint_bincode)?;
  100. zk_bins.add_contract("dao-mint".to_string(), zk_dao_mint_bin, 13);
  101. debug!(target: "demo", "Loading money-transfer contracts");
  102. {
  103. let start = Instant::now();
  104. let mint_pk = ProvingKey::build(11, &MintContract::default());
  105. debug!("Mint PK: [{:?}]", start.elapsed());
  106. let start = Instant::now();
  107. let burn_pk = ProvingKey::build(11, &BurnContract::default());
  108. debug!("Burn PK: [{:?}]", start.elapsed());
  109. let start = Instant::now();
  110. let mint_vk = VerifyingKey::build(11, &MintContract::default());
  111. debug!("Mint VK: [{:?}]", start.elapsed());
  112. let start = Instant::now();
  113. let burn_vk = VerifyingKey::build(11, &BurnContract::default());
  114. debug!("Burn VK: [{:?}]", start.elapsed());
  115. zk_bins.add_native("money-transfer-mint".to_string(), mint_pk, mint_vk);
  116. zk_bins.add_native("money-transfer-burn".to_string(), burn_pk, burn_vk);
  117. }
  118. debug!(target: "demo", "Loading dao-propose-main.zk");
  119. let zk_dao_propose_main_bincode = include_bytes!("../proof/dao-propose-main.zk.bin");
  120. let zk_dao_propose_main_bin = ZkBinary::decode(zk_dao_propose_main_bincode)?;
  121. zk_bins.add_contract("dao-propose-main".to_string(), zk_dao_propose_main_bin, 13);
  122. debug!(target: "demo", "Loading dao-propose-burn.zk");
  123. let zk_dao_propose_burn_bincode = include_bytes!("../proof/dao-propose-burn.zk.bin");
  124. let zk_dao_propose_burn_bin = ZkBinary::decode(zk_dao_propose_burn_bincode)?;
  125. zk_bins.add_contract("dao-propose-burn".to_string(), zk_dao_propose_burn_bin, 13);
  126. debug!(target: "demo", "Loading dao-vote-main.zk");
  127. let zk_dao_vote_main_bincode = include_bytes!("../proof/dao-vote-main.zk.bin");
  128. let zk_dao_vote_main_bin = ZkBinary::decode(zk_dao_vote_main_bincode)?;
  129. zk_bins.add_contract("dao-vote-main".to_string(), zk_dao_vote_main_bin, 13);
  130. debug!(target: "demo", "Loading dao-vote-burn.zk");
  131. let zk_dao_vote_burn_bincode = include_bytes!("../proof/dao-vote-burn.zk.bin");
  132. let zk_dao_vote_burn_bin = ZkBinary::decode(zk_dao_vote_burn_bincode)?;
  133. zk_bins.add_contract("dao-vote-burn".to_string(), zk_dao_vote_burn_bin, 13);
  134. let zk_dao_exec_bincode = include_bytes!("../proof/dao-exec.zk.bin");
  135. let zk_dao_exec_bin = ZkBinary::decode(zk_dao_exec_bincode)?;
  136. zk_bins.add_contract("dao-exec".to_string(), zk_dao_exec_bin, 13);
  137. // State for money contracts
  138. let cashier_signature_secret = SecretKey::random(&mut OsRng);
  139. let cashier_signature_public = PublicKey::from_secret(cashier_signature_secret);
  140. let faucet_signature_secret = SecretKey::random(&mut OsRng);
  141. let faucet_signature_public = PublicKey::from_secret(faucet_signature_secret);
  142. ///////////////////////////////////////////////////
  143. let money_state = money::state::State::new(cashier_signature_public, faucet_signature_public);
  144. states.register(*money::CONTRACT_ID, money_state);
  145. /////////////////////////////////////////////////////
  146. let dao_state = dao::State::new();
  147. states.register(*dao::CONTRACT_ID, dao_state);
  148. /////////////////////////////////////////////////////
  149. ////// Create the DAO bulla
  150. /////////////////////////////////////////////////////
  151. debug!(target: "demo", "Stage 1. Creating DAO bulla");
  152. //// Wallet
  153. //// Setup the DAO
  154. let dao_keypair = Keypair::random(&mut OsRng);
  155. let dao_bulla_blind = pallas::Base::random(&mut OsRng);
  156. let signature_secret = SecretKey::random(&mut OsRng);
  157. // Create DAO mint tx
  158. let builder = dao::mint::wallet::Builder {
  159. dao_proposer_limit,
  160. dao_quorum,
  161. dao_approval_ratio_quot,
  162. dao_approval_ratio_base,
  163. gov_token_id: gdrk_token_id,
  164. dao_pubkey: dao_keypair.public,
  165. dao_bulla_blind,
  166. _signature_secret: signature_secret,
  167. };
  168. let func_call = builder.build(&zk_bins);
  169. let func_calls = vec![func_call];
  170. let signatures = sign([signature_secret].to_vec(), &func_calls);
  171. let tx = Transaction { func_calls, signatures };
  172. //// Validator
  173. let mut updates = vec![];
  174. // Validate all function calls in the tx
  175. for (idx, func_call) in tx.func_calls.iter().enumerate() {
  176. // So then the verifier will lookup the corresponding state_transition and apply
  177. // functions based off the func_id
  178. if func_call.func_id == *dao::mint::FUNC_ID {
  179. debug!("dao::mint::state_transition()");
  180. let update = dao::mint::validate::state_transition(&states, idx, &tx)
  181. .expect("dao::mint::validate::state_transition() failed!");
  182. updates.push(update);
  183. }
  184. }
  185. // Atomically apply all changes
  186. for update in updates {
  187. update.apply(&mut states);
  188. }
  189. tx.zk_verify(&zk_bins).unwrap();
  190. tx.verify_sigs();
  191. // Wallet stuff
  192. // In your wallet, wait until you see the tx confirmed before doing anything below
  193. // So for example keep track of tx hash
  194. //assert_eq!(tx.hash(), tx_hash);
  195. // We need to witness() the value in our local merkle tree
  196. // Must be called as soon as this DAO bulla is added to the state
  197. let dao_leaf_position = {
  198. let state = states.lookup_mut::<dao::State>(*dao::CONTRACT_ID).unwrap();
  199. state.dao_tree.witness().unwrap()
  200. };
  201. // It might just be easier to hash it ourselves from keypair and blind...
  202. let dao_bulla = {
  203. assert_eq!(tx.func_calls.len(), 1);
  204. let func_call = &tx.func_calls[0];
  205. let call_data = func_call.call_data.as_any();
  206. assert_eq!((*call_data).type_id(), TypeId::of::<dao::mint::validate::CallData>());
  207. let call_data = call_data.downcast_ref::<dao::mint::validate::CallData>().unwrap();
  208. call_data.dao_bulla.clone()
  209. };
  210. debug!(target: "demo", "Create DAO bulla: {:?}", dao_bulla.0);
  211. ///////////////////////////////////////////////////
  212. //// Mint the initial supply of treasury token
  213. //// and send it all to the DAO directly
  214. ///////////////////////////////////////////////////
  215. debug!(target: "demo", "Stage 2. Minting treasury token");
  216. let state = states.lookup_mut::<money::State>(*money::CONTRACT_ID).unwrap();
  217. state.wallet_cache.track(dao_keypair.secret);
  218. //// Wallet
  219. // Address of deployed contract in our example is dao::exec::FUNC_ID
  220. // This field is public, you can see it's being sent to a DAO
  221. // but nothing else is visible.
  222. //
  223. // In the python code we wrote:
  224. //
  225. // spend_hook = b"0xdao_ruleset"
  226. //
  227. let spend_hook = *dao::exec::FUNC_ID;
  228. // The user_data can be a simple hash of the items passed into the ZK proof
  229. // up to corresponding linked ZK proof to interpret however they need.
  230. // In out case, it's the bulla for the DAO
  231. let user_data = dao_bulla.0;
  232. let builder = money::transfer::wallet::Builder {
  233. clear_inputs: vec![money::transfer::wallet::BuilderClearInputInfo {
  234. value: xdrk_supply,
  235. token_id: xdrk_token_id,
  236. signature_secret: cashier_signature_secret,
  237. }],
  238. inputs: vec![],
  239. outputs: vec![money::transfer::wallet::BuilderOutputInfo {
  240. value: xdrk_supply,
  241. token_id: xdrk_token_id,
  242. public: dao_keypair.public,
  243. serial: pallas::Base::random(&mut OsRng),
  244. coin_blind: pallas::Base::random(&mut OsRng),
  245. spend_hook,
  246. user_data,
  247. }],
  248. };
  249. let func_call = builder.build(&zk_bins)?;
  250. let func_calls = vec![func_call];
  251. let signatures = sign([cashier_signature_secret].to_vec(), &func_calls);
  252. let tx = Transaction { func_calls, signatures };
  253. //// Validator
  254. let mut updates = vec![];
  255. // Validate all function calls in the tx
  256. for (idx, func_call) in tx.func_calls.iter().enumerate() {
  257. // So then the verifier will lookup the corresponding state_transition and apply
  258. // functions based off the func_id
  259. if func_call.func_id == *money::transfer::FUNC_ID {
  260. debug!("money::transfer::state_transition()");
  261. let update = money::transfer::validate::state_transition(&states, idx, &tx)
  262. .expect("money::transfer::validate::state_transition() failed!");
  263. updates.push(update);
  264. }
  265. }
  266. // Atomically apply all changes
  267. for update in updates {
  268. update.apply(&mut states);
  269. }
  270. tx.zk_verify(&zk_bins).unwrap();
  271. tx.verify_sigs();
  272. //// Wallet
  273. // DAO reads the money received from the encrypted note
  274. let state = states.lookup_mut::<money::State>(*money::CONTRACT_ID).unwrap();
  275. let mut recv_coins = state.wallet_cache.get_received(&dao_keypair.secret);
  276. assert_eq!(recv_coins.len(), 1);
  277. let dao_recv_coin = recv_coins.pop().unwrap();
  278. let treasury_note = dao_recv_coin.note;
  279. // Check the actual coin received is valid before accepting it
  280. let coords = dao_keypair.public.0.to_affine().coordinates().unwrap();
  281. let coin = poseidon_hash::<8>([
  282. *coords.x(),
  283. *coords.y(),
  284. DrkValue::from(treasury_note.value),
  285. treasury_note.token_id,
  286. treasury_note.serial,
  287. treasury_note.spend_hook,
  288. treasury_note.user_data,
  289. treasury_note.coin_blind,
  290. ]);
  291. assert_eq!(coin, dao_recv_coin.coin.0);
  292. assert_eq!(treasury_note.spend_hook, *dao::exec::FUNC_ID);
  293. assert_eq!(treasury_note.user_data, dao_bulla.0);
  294. debug!("DAO received a coin worth {} xDRK", treasury_note.value);
  295. ///////////////////////////////////////////////////
  296. //// Mint the governance token
  297. //// Send it to three hodlers
  298. ///////////////////////////////////////////////////
  299. debug!(target: "demo", "Stage 3. Minting governance token");
  300. //// Wallet
  301. // Hodler 1
  302. let gov_keypair_1 = Keypair::random(&mut OsRng);
  303. // Hodler 2
  304. let gov_keypair_2 = Keypair::random(&mut OsRng);
  305. // Hodler 3: the tiebreaker
  306. let gov_keypair_3 = Keypair::random(&mut OsRng);
  307. let state = states.lookup_mut::<money::State>(*money::CONTRACT_ID).unwrap();
  308. state.wallet_cache.track(gov_keypair_1.secret);
  309. state.wallet_cache.track(gov_keypair_2.secret);
  310. state.wallet_cache.track(gov_keypair_3.secret);
  311. let gov_keypairs = vec![gov_keypair_1, gov_keypair_2, gov_keypair_3];
  312. // Spend hook and user data disabled
  313. let spend_hook = DrkSpendHook::from(0);
  314. let user_data = DrkUserData::from(0);
  315. let output1 = money::transfer::wallet::BuilderOutputInfo {
  316. value: 400000,
  317. token_id: gdrk_token_id,
  318. public: gov_keypair_1.public,
  319. serial: pallas::Base::random(&mut OsRng),
  320. coin_blind: pallas::Base::random(&mut OsRng),
  321. spend_hook,
  322. user_data,
  323. };
  324. let output2 = money::transfer::wallet::BuilderOutputInfo {
  325. value: 400000,
  326. token_id: gdrk_token_id,
  327. public: gov_keypair_2.public,
  328. serial: pallas::Base::random(&mut OsRng),
  329. coin_blind: pallas::Base::random(&mut OsRng),
  330. spend_hook,
  331. user_data,
  332. };
  333. let output3 = money::transfer::wallet::BuilderOutputInfo {
  334. value: 200000,
  335. token_id: gdrk_token_id,
  336. public: gov_keypair_3.public,
  337. serial: pallas::Base::random(&mut OsRng),
  338. coin_blind: pallas::Base::random(&mut OsRng),
  339. spend_hook,
  340. user_data,
  341. };
  342. assert!(2 * 400000 + 200000 == gdrk_supply);
  343. let builder = money::transfer::wallet::Builder {
  344. clear_inputs: vec![money::transfer::wallet::BuilderClearInputInfo {
  345. value: gdrk_supply,
  346. token_id: gdrk_token_id,
  347. signature_secret: cashier_signature_secret,
  348. }],
  349. inputs: vec![],
  350. outputs: vec![output1, output2, output3],
  351. };
  352. let func_call = builder.build(&zk_bins)?;
  353. let func_calls = vec![func_call];
  354. let signatures = sign([cashier_signature_secret].to_vec(), &func_calls);
  355. let tx = Transaction { func_calls, signatures };
  356. //// Validator
  357. let mut updates = vec![];
  358. // Validate all function calls in the tx
  359. for (idx, func_call) in tx.func_calls.iter().enumerate() {
  360. // So then the verifier will lookup the corresponding state_transition and apply
  361. // functions based off the func_id
  362. if func_call.func_id == *money::transfer::FUNC_ID {
  363. debug!("money::transfer::state_transition()");
  364. let update = money::transfer::validate::state_transition(&states, idx, &tx)
  365. .expect("money::transfer::validate::state_transition() failed!");
  366. updates.push(update);
  367. }
  368. }
  369. // Atomically apply all changes
  370. for update in updates {
  371. update.apply(&mut states);
  372. }
  373. tx.zk_verify(&zk_bins).unwrap();
  374. tx.verify_sigs();
  375. //// Wallet
  376. let mut gov_recv = vec![None, None, None];
  377. // Check that each person received one coin
  378. for (i, key) in gov_keypairs.iter().enumerate() {
  379. let gov_recv_coin = {
  380. let state = states.lookup_mut::<money::State>(*money::CONTRACT_ID).unwrap();
  381. let mut recv_coins = state.wallet_cache.get_received(&key.secret);
  382. assert_eq!(recv_coins.len(), 1);
  383. let recv_coin = recv_coins.pop().unwrap();
  384. let note = &recv_coin.note;
  385. assert_eq!(note.token_id, gdrk_token_id);
  386. // Normal payment
  387. assert_eq!(note.spend_hook, pallas::Base::from(0));
  388. assert_eq!(note.user_data, pallas::Base::from(0));
  389. let coords = key.public.0.to_affine().coordinates().unwrap();
  390. let coin = poseidon_hash::<8>([
  391. *coords.x(),
  392. *coords.y(),
  393. DrkValue::from(note.value),
  394. note.token_id,
  395. note.serial,
  396. note.spend_hook,
  397. note.user_data,
  398. note.coin_blind,
  399. ]);
  400. assert_eq!(coin, recv_coin.coin.0);
  401. debug!("Holder{} received a coin worth {} gDRK", i, note.value);
  402. recv_coin
  403. };
  404. gov_recv[i] = Some(gov_recv_coin);
  405. }
  406. // unwrap them for this demo
  407. let gov_recv: Vec<_> = gov_recv.into_iter().map(|r| r.unwrap()).collect();
  408. ///////////////////////////////////////////////////
  409. // DAO rules:
  410. // 1. gov token IDs must match on all inputs
  411. // 2. proposals must be submitted by minimum amount
  412. // 3. all votes >= quorum
  413. // 4. outcome > approval_ratio
  414. // 5. structure of outputs
  415. // output 0: value and address
  416. // output 1: change address
  417. ///////////////////////////////////////////////////
  418. ///////////////////////////////////////////////////
  419. // Propose the vote
  420. // In order to make a valid vote, first the proposer must
  421. // meet a criteria for a minimum number of gov tokens
  422. ///////////////////////////////////////////////////
  423. debug!(target: "demo", "Stage 4. Propose the vote");
  424. //// Wallet
  425. // TODO: look into proposal expiry once time for voting has finished
  426. let user_keypair = Keypair::random(&mut OsRng);
  427. let (money_leaf_position, money_merkle_path) = {
  428. let state = states.lookup::<money::State>(*money::CONTRACT_ID).unwrap();
  429. let tree = &state.tree;
  430. let leaf_position = gov_recv[0].leaf_position;
  431. let root = tree.root(0).unwrap();
  432. let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
  433. (leaf_position, merkle_path)
  434. };
  435. // TODO: is it possible for an invalid transfer() to be constructed on exec()?
  436. // need to look into this
  437. let signature_secret = SecretKey::random(&mut OsRng);
  438. let input = dao::propose::wallet::BuilderInput {
  439. secret: gov_keypair_1.secret,
  440. note: gov_recv[0].note.clone(),
  441. leaf_position: money_leaf_position,
  442. merkle_path: money_merkle_path,
  443. signature_secret,
  444. };
  445. let (dao_merkle_path, dao_merkle_root) = {
  446. let state = states.lookup::<dao::State>(*dao::CONTRACT_ID).unwrap();
  447. let tree = &state.dao_tree;
  448. let root = tree.root(0).unwrap();
  449. let merkle_path = tree.authentication_path(dao_leaf_position, &root).unwrap();
  450. (merkle_path, root)
  451. };
  452. let dao_params = dao::mint::wallet::DaoParams {
  453. proposer_limit: dao_proposer_limit,
  454. quorum: dao_quorum,
  455. approval_ratio_base: dao_approval_ratio_base,
  456. approval_ratio_quot: dao_approval_ratio_quot,
  457. gov_token_id: gdrk_token_id,
  458. public_key: dao_keypair.public,
  459. bulla_blind: dao_bulla_blind,
  460. };
  461. let proposal = dao::propose::wallet::Proposal {
  462. dest: user_keypair.public,
  463. amount: 1000,
  464. serial: pallas::Base::random(&mut OsRng),
  465. token_id: xdrk_token_id,
  466. blind: pallas::Base::random(&mut OsRng),
  467. };
  468. let builder = dao::propose::wallet::Builder {
  469. inputs: vec![input],
  470. proposal,
  471. dao: dao_params.clone(),
  472. dao_leaf_position,
  473. dao_merkle_path,
  474. dao_merkle_root,
  475. };
  476. let func_call = builder.build(&zk_bins);
  477. let func_calls = vec![func_call];
  478. let signatures = sign([signature_secret].to_vec(), &func_calls);
  479. let tx = Transaction { func_calls, signatures };
  480. //// Validator
  481. let mut updates = vec![];
  482. // Validate all function calls in the tx
  483. for (idx, func_call) in tx.func_calls.iter().enumerate() {
  484. if func_call.func_id == *dao::propose::FUNC_ID {
  485. debug!(target: "demo", "dao::propose::state_transition()");
  486. let update = dao::propose::validate::state_transition(&states, idx, &tx)
  487. .expect("dao::propose::validate::state_transition() failed!");
  488. updates.push(update);
  489. }
  490. }
  491. // Atomically apply all changes
  492. for update in updates {
  493. update.apply(&mut states);
  494. }
  495. tx.zk_verify(&zk_bins).unwrap();
  496. tx.verify_sigs();
  497. //// Wallet
  498. // Read received proposal
  499. let (proposal, proposal_bulla) = {
  500. assert_eq!(tx.func_calls.len(), 1);
  501. let func_call = &tx.func_calls[0];
  502. let call_data = func_call.call_data.as_any();
  503. assert_eq!((*call_data).type_id(), TypeId::of::<dao::propose::validate::CallData>());
  504. let call_data = call_data.downcast_ref::<dao::propose::validate::CallData>().unwrap();
  505. let header = &call_data.header;
  506. let note: dao::propose::wallet::Note =
  507. header.enc_note.decrypt(&dao_keypair.secret).unwrap();
  508. // TODO: check it belongs to DAO bulla
  509. // Return the proposal info
  510. (note.proposal, call_data.header.proposal_bulla)
  511. };
  512. debug!(target: "demo", "Proposal now active!");
  513. debug!(target: "demo", " destination: {:?}", proposal.dest);
  514. debug!(target: "demo", " amount: {}", proposal.amount);
  515. debug!(target: "demo", " token_id: {:?}", proposal.token_id);
  516. debug!(target: "demo", " dao_bulla: {:?}", dao_bulla.0);
  517. debug!(target: "demo", "Proposal bulla: {:?}", proposal_bulla);
  518. ///////////////////////////////////////////////////
  519. // Proposal is accepted!
  520. // Start the voting
  521. ///////////////////////////////////////////////////
  522. // Copying these schizo comments from python code:
  523. // Lets the voting begin
  524. // Voters have access to the proposal and dao data
  525. // vote_state = VoteState()
  526. // We don't need to copy nullifier set because it is checked from gov_state
  527. // in vote_state_transition() anyway
  528. //
  529. // TODO: what happens if voters don't unblind their vote
  530. // Answer:
  531. // 1. there is a time limit
  532. // 2. both the MPC or users can unblind
  533. //
  534. // TODO: bug if I vote then send money, then we can double vote
  535. // TODO: all timestamps missing
  536. // - timelock (future voting starts in 2 days)
  537. // Fix: use nullifiers from money gov state only from
  538. // beginning of gov period
  539. // Cannot use nullifiers from before voting period
  540. debug!(target: "demo", "Stage 5. Start voting");
  541. // We were previously saving updates here for testing
  542. // let mut updates = vec![];
  543. // User 1: YES
  544. let (money_leaf_position, money_merkle_path) = {
  545. let state = states.lookup::<money::State>(*money::CONTRACT_ID).unwrap();
  546. let tree = &state.tree;
  547. let leaf_position = gov_recv[0].leaf_position;
  548. let root = tree.root(0).unwrap();
  549. let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
  550. (leaf_position, merkle_path)
  551. };
  552. let signature_secret = SecretKey::random(&mut OsRng);
  553. let input = dao::vote::wallet::BuilderInput {
  554. secret: gov_keypair_1.secret,
  555. note: gov_recv[0].note.clone(),
  556. leaf_position: money_leaf_position,
  557. merkle_path: money_merkle_path,
  558. signature_secret,
  559. };
  560. let vote_option: bool = true;
  561. // assert!(vote_option || !vote_option); // wtf
  562. // We create a new keypair to encrypt the vote.
  563. // For the demo MVP, you can just use the dao_keypair secret
  564. let vote_keypair_1 = Keypair::random(&mut OsRng);
  565. let builder = dao::vote::wallet::Builder {
  566. inputs: vec![input],
  567. vote: dao::vote::wallet::Vote {
  568. vote_option,
  569. vote_option_blind: pallas::Scalar::random(&mut OsRng),
  570. },
  571. vote_keypair: vote_keypair_1,
  572. proposal: proposal.clone(),
  573. dao: dao_params.clone(),
  574. };
  575. debug!(target: "demo", "build()...");
  576. let func_call = builder.build(&zk_bins);
  577. let func_calls = vec![func_call];
  578. let signatures = sign([signature_secret].to_vec(), &func_calls);
  579. let tx = Transaction { func_calls, signatures };
  580. //// Validator
  581. let mut updates = vec![];
  582. // Validate all function calls in the tx
  583. for (idx, func_call) in tx.func_calls.iter().enumerate() {
  584. if func_call.func_id == *dao::vote::FUNC_ID {
  585. debug!(target: "demo", "dao::vote::state_transition()");
  586. let update = dao::vote::validate::state_transition(&states, idx, &tx)
  587. .expect("dao::vote::validate::state_transition() failed!");
  588. updates.push(update);
  589. }
  590. }
  591. // Atomically apply all changes
  592. for update in updates {
  593. update.apply(&mut states);
  594. }
  595. tx.zk_verify(&zk_bins).unwrap();
  596. tx.verify_sigs();
  597. //// Wallet
  598. // Secret vote info. Needs to be revealed at some point.
  599. // TODO: look into verifiable encryption for notes
  600. // TODO: look into timelock puzzle as a possibility
  601. let vote_note_1 = {
  602. assert_eq!(tx.func_calls.len(), 1);
  603. let func_call = &tx.func_calls[0];
  604. let call_data = func_call.call_data.as_any();
  605. assert_eq!((*call_data).type_id(), TypeId::of::<dao::vote::validate::CallData>());
  606. let call_data = call_data.downcast_ref::<dao::vote::validate::CallData>().unwrap();
  607. let header = &call_data.header;
  608. let note: dao::vote::wallet::Note =
  609. header.enc_note.decrypt(&vote_keypair_1.secret).unwrap();
  610. note
  611. };
  612. debug!(target: "demo", "User 1 voted!");
  613. debug!(target: "demo", " vote_option: {}", vote_note_1.vote.vote_option);
  614. debug!(target: "demo", " value: {}", vote_note_1.vote_value);
  615. // User 2: NO
  616. let (money_leaf_position, money_merkle_path) = {
  617. let state = states.lookup::<money::State>(*money::CONTRACT_ID).unwrap();
  618. let tree = &state.tree;
  619. let leaf_position = gov_recv[1].leaf_position;
  620. let root = tree.root(0).unwrap();
  621. let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
  622. (leaf_position, merkle_path)
  623. };
  624. let signature_secret = SecretKey::random(&mut OsRng);
  625. let input = dao::vote::wallet::BuilderInput {
  626. secret: gov_keypair_2.secret,
  627. note: gov_recv[1].note.clone(),
  628. leaf_position: money_leaf_position,
  629. merkle_path: money_merkle_path,
  630. signature_secret,
  631. };
  632. let vote_option: bool = false;
  633. // assert!(vote_option || !vote_option); // wtf
  634. // We create a new keypair to encrypt the vote.
  635. let vote_keypair_2 = Keypair::random(&mut OsRng);
  636. let builder = dao::vote::wallet::Builder {
  637. inputs: vec![input],
  638. vote: dao::vote::wallet::Vote {
  639. vote_option,
  640. vote_option_blind: pallas::Scalar::random(&mut OsRng),
  641. },
  642. vote_keypair: vote_keypair_2,
  643. proposal: proposal.clone(),
  644. dao: dao_params.clone(),
  645. };
  646. debug!(target: "demo", "build()...");
  647. let func_call = builder.build(&zk_bins);
  648. let func_calls = vec![func_call];
  649. let signatures = sign([signature_secret].to_vec(), &func_calls);
  650. let tx = Transaction { func_calls, signatures };
  651. //// Validator
  652. let mut updates = vec![];
  653. // Validate all function calls in the tx
  654. for (idx, func_call) in tx.func_calls.iter().enumerate() {
  655. if func_call.func_id == *dao::vote::FUNC_ID {
  656. debug!(target: "demo", "dao::vote::state_transition()");
  657. let update = dao::vote::validate::state_transition(&states, idx, &tx)
  658. .expect("dao::vote::validate::state_transition() failed!");
  659. updates.push(update);
  660. }
  661. }
  662. // Atomically apply all changes
  663. for update in updates {
  664. update.apply(&mut states);
  665. }
  666. tx.zk_verify(&zk_bins).unwrap();
  667. tx.verify_sigs();
  668. //// Wallet
  669. // Secret vote info. Needs to be revealed at some point.
  670. // TODO: look into verifiable encryption for notes
  671. // TODO: look into timelock puzzle as a possibility
  672. let vote_note_2 = {
  673. assert_eq!(tx.func_calls.len(), 1);
  674. let func_call = &tx.func_calls[0];
  675. let call_data = func_call.call_data.as_any();
  676. assert_eq!((*call_data).type_id(), TypeId::of::<dao::vote::validate::CallData>());
  677. let call_data = call_data.downcast_ref::<dao::vote::validate::CallData>().unwrap();
  678. let header = &call_data.header;
  679. let note: dao::vote::wallet::Note =
  680. header.enc_note.decrypt(&vote_keypair_2.secret).unwrap();
  681. note
  682. };
  683. debug!(target: "demo", "User 2 voted!");
  684. debug!(target: "demo", " vote_option: {}", vote_note_2.vote.vote_option);
  685. debug!(target: "demo", " value: {}", vote_note_2.vote_value);
  686. // User 3: YES
  687. let (money_leaf_position, money_merkle_path) = {
  688. let state = states.lookup::<money::State>(*money::CONTRACT_ID).unwrap();
  689. let tree = &state.tree;
  690. let leaf_position = gov_recv[2].leaf_position;
  691. let root = tree.root(0).unwrap();
  692. let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
  693. (leaf_position, merkle_path)
  694. };
  695. let signature_secret = SecretKey::random(&mut OsRng);
  696. let input = dao::vote::wallet::BuilderInput {
  697. secret: gov_keypair_3.secret,
  698. note: gov_recv[2].note.clone(),
  699. leaf_position: money_leaf_position,
  700. merkle_path: money_merkle_path,
  701. signature_secret,
  702. };
  703. let vote_option: bool = true;
  704. // assert!(vote_option || !vote_option); // wtf
  705. // We create a new keypair to encrypt the vote.
  706. let vote_keypair_3 = Keypair::random(&mut OsRng);
  707. let builder = dao::vote::wallet::Builder {
  708. inputs: vec![input],
  709. vote: dao::vote::wallet::Vote {
  710. vote_option,
  711. vote_option_blind: pallas::Scalar::random(&mut OsRng),
  712. },
  713. vote_keypair: vote_keypair_3,
  714. proposal: proposal.clone(),
  715. dao: dao_params.clone(),
  716. };
  717. debug!(target: "demo", "build()...");
  718. let func_call = builder.build(&zk_bins);
  719. let func_calls = vec![func_call];
  720. let signatures = sign([signature_secret].to_vec(), &func_calls);
  721. let tx = Transaction { func_calls, signatures };
  722. //// Validator
  723. let mut updates = vec![];
  724. // Validate all function calls in the tx
  725. for (idx, func_call) in tx.func_calls.iter().enumerate() {
  726. if func_call.func_id == *dao::vote::FUNC_ID {
  727. debug!(target: "demo", "dao::vote::state_transition()");
  728. let update = dao::vote::validate::state_transition(&states, idx, &tx)
  729. .expect("dao::vote::validate::state_transition() failed!");
  730. updates.push(update);
  731. }
  732. }
  733. // Atomically apply all changes
  734. for update in updates {
  735. update.apply(&mut states);
  736. }
  737. tx.zk_verify(&zk_bins).unwrap();
  738. tx.verify_sigs();
  739. //// Wallet
  740. // Secret vote info. Needs to be revealed at some point.
  741. // TODO: look into verifiable encryption for notes
  742. // TODO: look into timelock puzzle as a possibility
  743. let vote_note_3 = {
  744. assert_eq!(tx.func_calls.len(), 1);
  745. let func_call = &tx.func_calls[0];
  746. let call_data = func_call.call_data.as_any();
  747. assert_eq!((*call_data).type_id(), TypeId::of::<dao::vote::validate::CallData>());
  748. let call_data = call_data.downcast_ref::<dao::vote::validate::CallData>().unwrap();
  749. let header = &call_data.header;
  750. let note: dao::vote::wallet::Note =
  751. header.enc_note.decrypt(&vote_keypair_3.secret).unwrap();
  752. note
  753. };
  754. debug!(target: "demo", "User 3 voted!");
  755. debug!(target: "demo", " vote_option: {}", vote_note_3.vote.vote_option);
  756. debug!(target: "demo", " value: {}", vote_note_3.vote_value);
  757. // Every votes produces a semi-homomorphic encryption of their vote.
  758. // Which is either yes or no
  759. // We copy the state tree for the governance token so coins can be used
  760. // to vote on other proposals at the same time.
  761. // With their vote, they produce a ZK proof + nullifier
  762. // The votes are unblinded by MPC to a selected party at the end of the
  763. // voting period.
  764. // (that's if we want votes to be hidden during voting)
  765. let mut yes_votes_value = 0;
  766. let mut yes_votes_blind = pallas::Scalar::from(0);
  767. let mut yes_votes_commit = pallas::Point::identity();
  768. let mut all_votes_value = 0;
  769. let mut all_votes_blind = pallas::Scalar::from(0);
  770. let mut all_votes_commit = pallas::Point::identity();
  771. // We were previously saving votes to a Vec<Update> for testing.
  772. // However since Update is now UpdateBase it gets moved into update.apply().
  773. // So we need to think of another way to run these tests.
  774. //assert!(updates.len() == 3);
  775. for (i, note /* update*/) in [vote_note_1, vote_note_2, vote_note_3]
  776. .iter() /*.zip(updates)*/
  777. .enumerate()
  778. {
  779. let vote_commit = pedersen_commitment_u64(note.vote_value, note.vote_value_blind);
  780. //assert!(update.value_commit == all_vote_value_commit);
  781. all_votes_commit += vote_commit;
  782. all_votes_blind += note.vote_value_blind;
  783. let yes_vote_commit = pedersen_commitment_u64(
  784. note.vote.vote_option as u64 * note.vote_value,
  785. note.vote.vote_option_blind,
  786. );
  787. //assert!(update.yes_vote_commit == yes_vote_commit);
  788. yes_votes_commit += yes_vote_commit;
  789. yes_votes_blind += note.vote.vote_option_blind;
  790. let vote_option = note.vote.vote_option;
  791. if vote_option {
  792. yes_votes_value += note.vote_value;
  793. }
  794. all_votes_value += note.vote_value;
  795. let vote_result: String = if vote_option { "yes".to_string() } else { "no".to_string() };
  796. debug!("Voter {} voted {}", i, vote_result);
  797. }
  798. debug!("Outcome = {} / {}", yes_votes_value, all_votes_value);
  799. assert!(all_votes_commit == pedersen_commitment_u64(all_votes_value, all_votes_blind));
  800. assert!(yes_votes_commit == pedersen_commitment_u64(yes_votes_value, yes_votes_blind));
  801. ///////////////////////////////////////////////////
  802. // Execute the vote
  803. ///////////////////////////////////////////////////
  804. //// Wallet
  805. // Used to export user_data from this coin so it can be accessed by DAO::exec()
  806. let user_data_blind = pallas::Base::random(&mut OsRng);
  807. let user_serial = pallas::Base::random(&mut OsRng);
  808. let user_coin_blind = pallas::Base::random(&mut OsRng);
  809. let dao_serial = pallas::Base::random(&mut OsRng);
  810. let dao_coin_blind = pallas::Base::random(&mut OsRng);
  811. let input_value = treasury_note.value;
  812. let input_value_blind = pallas::Scalar::random(&mut OsRng);
  813. let tx_signature_secret = SecretKey::random(&mut OsRng);
  814. let exec_signature_secret = SecretKey::random(&mut OsRng);
  815. let (treasury_leaf_position, treasury_merkle_path) = {
  816. let state = states.lookup::<money::State>(*money::CONTRACT_ID).unwrap();
  817. let tree = &state.tree;
  818. let leaf_position = dao_recv_coin.leaf_position;
  819. let root = tree.root(0).unwrap();
  820. let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
  821. (leaf_position, merkle_path)
  822. };
  823. let input = money::transfer::wallet::BuilderInputInfo {
  824. leaf_position: treasury_leaf_position,
  825. merkle_path: treasury_merkle_path,
  826. secret: dao_keypair.secret,
  827. note: treasury_note,
  828. user_data_blind,
  829. value_blind: input_value_blind,
  830. signature_secret: tx_signature_secret,
  831. };
  832. let builder = money::transfer::wallet::Builder {
  833. clear_inputs: vec![],
  834. inputs: vec![input],
  835. outputs: vec![
  836. // Sending money
  837. money::transfer::wallet::BuilderOutputInfo {
  838. value: 1000,
  839. token_id: xdrk_token_id,
  840. public: user_keypair.public,
  841. serial: proposal.serial,
  842. coin_blind: proposal.blind,
  843. spend_hook: pallas::Base::from(0),
  844. user_data: pallas::Base::from(0),
  845. },
  846. // Change back to DAO
  847. money::transfer::wallet::BuilderOutputInfo {
  848. value: xdrk_supply - 1000,
  849. token_id: xdrk_token_id,
  850. public: dao_keypair.public,
  851. serial: dao_serial,
  852. coin_blind: dao_coin_blind,
  853. spend_hook: *dao::exec::FUNC_ID,
  854. // TODO: should be DAO bulla
  855. user_data: proposal_bulla,
  856. },
  857. ],
  858. };
  859. let transfer_func_call = builder.build(&zk_bins)?;
  860. let builder = dao::exec::wallet::Builder {
  861. proposal,
  862. dao: dao_params,
  863. yes_votes_value,
  864. all_votes_value,
  865. yes_votes_blind,
  866. all_votes_blind,
  867. user_serial,
  868. user_coin_blind,
  869. dao_serial,
  870. dao_coin_blind,
  871. input_value,
  872. input_value_blind,
  873. hook_dao_exec: *dao::exec::FUNC_ID,
  874. signature_secret: exec_signature_secret,
  875. };
  876. let exec_func_call = builder.build(&zk_bins);
  877. let func_calls = vec![transfer_func_call, exec_func_call];
  878. let signatures = sign([tx_signature_secret, exec_signature_secret].to_vec(), &func_calls);
  879. let tx = Transaction { func_calls, signatures };
  880. {
  881. // Now the spend_hook field specifies the function DAO::exec()
  882. // so Money::transfer() must also be combined with DAO::exec()
  883. assert_eq!(tx.func_calls.len(), 2);
  884. let transfer_func_call = &tx.func_calls[0];
  885. let transfer_call_data = transfer_func_call.call_data.as_any();
  886. assert_eq!(
  887. (*transfer_call_data).type_id(),
  888. TypeId::of::<money::transfer::validate::CallData>()
  889. );
  890. let transfer_call_data =
  891. transfer_call_data.downcast_ref::<money::transfer::validate::CallData>();
  892. let transfer_call_data = transfer_call_data.unwrap();
  893. // At least one input has this field value which means DAO::exec() is invoked.
  894. assert_eq!(transfer_call_data.inputs.len(), 1);
  895. let input = &transfer_call_data.inputs[0];
  896. assert_eq!(input.revealed.spend_hook, *dao::exec::FUNC_ID);
  897. let user_data_enc = poseidon_hash::<2>([dao_bulla.0, user_data_blind]);
  898. assert_eq!(input.revealed.user_data_enc, user_data_enc);
  899. }
  900. //// Validator
  901. let mut updates = vec![];
  902. // Validate all function calls in the tx
  903. for (idx, func_call) in tx.func_calls.iter().enumerate() {
  904. if func_call.func_id == *dao::exec::FUNC_ID {
  905. debug!("dao::exec::state_transition()");
  906. let update = dao::exec::validate::state_transition(&states, idx, &tx)
  907. .expect("dao::exec::validate::state_transition() failed!");
  908. updates.push(update);
  909. } else if func_call.func_id == *money::transfer::FUNC_ID {
  910. debug!("money::transfer::state_transition()");
  911. let update = money::transfer::validate::state_transition(&states, idx, &tx)
  912. .expect("money::transfer::validate::state_transition() failed!");
  913. updates.push(update);
  914. }
  915. }
  916. // Atomically apply all changes
  917. for update in updates {
  918. update.apply(&mut states);
  919. }
  920. // Other stuff
  921. tx.zk_verify(&zk_bins).unwrap();
  922. tx.verify_sigs();
  923. //// Wallet
  924. Ok(())
  925. }