demo.rs 46 KB

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