main.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. use darkfi::{
  2. blockchain::Blockchain,
  3. consensus::{TESTNET_GENESIS_HASH_BYTES, TESTNET_GENESIS_TIMESTAMP},
  4. crypto::{
  5. coin::Coin,
  6. proof::{ProvingKey, VerifyingKey},
  7. types::{DrkSpendHook, DrkUserData, DrkValue},
  8. },
  9. runtime::vm_runtime::Runtime,
  10. zk::circuit::{BurnContract, MintContract},
  11. zkas::decoder::ZkBinary,
  12. Result,
  13. };
  14. use darkfi_sdk::{
  15. crypto::{
  16. constants::MERKLE_DEPTH, pedersen::pedersen_commitment_u64, poseidon_hash, ContractId,
  17. Keypair, MerkleNode, MerkleTree, PublicKey, SecretKey, TokenId,
  18. schnorr::SchnorrSecret,
  19. },
  20. tx::ContractCall,
  21. };
  22. use darkfi_serial::{deserialize, serialize, Decodable, Encodable, WriteExt};
  23. use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
  24. use log::{debug, error};
  25. use pasta_curves::{
  26. arithmetic::CurveAffine,
  27. group::{ff::Field, Curve},
  28. pallas,
  29. };
  30. use rand::rngs::OsRng;
  31. use std::{
  32. any::{Any, TypeId},
  33. io::Cursor,
  34. time::Instant,
  35. };
  36. use dao_contract::{DaoFunction, DaoMintParams};
  37. use money_contract::{MoneyFunction, MoneyTransferParams};
  38. use crate::{
  39. contract::{dao, example, money},
  40. note::EncryptedNote2,
  41. schema::WalletCache,
  42. tx::Transaction,
  43. util::{StateRegistry, ZkContractTable},
  44. };
  45. mod contract;
  46. mod error;
  47. mod note;
  48. mod schema;
  49. mod tx;
  50. mod util;
  51. fn show_dao_state(chain: &Blockchain, contract_id: &ContractId) -> Result<()> {
  52. let db_info = chain.contracts.lookup(&chain.sled_db, contract_id, "info")?;
  53. let value = db_info.get(&serialize(&"dao_tree".to_string())).expect("dao_tree").unwrap();
  54. let mut decoder = Cursor::new(&value);
  55. let set_size: u32 = Decodable::decode(&mut decoder)?;
  56. let tree: MerkleTree = Decodable::decode(decoder)?;
  57. debug!(target: "demo", "DAO state:");
  58. debug!(target: "demo", " tree: {} bytes", value.len());
  59. debug!(target: "demo", " set size: {}", set_size);
  60. let db_roots = chain.contracts.lookup(&chain.sled_db, contract_id, "dao_roots")?;
  61. for i in 0..set_size {
  62. let root = db_roots.get(&serialize(&i)).expect("dao_roots").unwrap();
  63. let root: MerkleNode = deserialize(&root)?;
  64. debug!(target: "demo", " root {}: {:?}", i, root);
  65. }
  66. Ok(())
  67. }
  68. fn show_money_state(chain: &Blockchain, contract_id: &ContractId) -> Result<()> {
  69. let db = chain.contracts.lookup(&chain.sled_db, contract_id, "wagies")?;
  70. debug!(target: "demo", "Money state:");
  71. for obj in db.iter() {
  72. let (key, value) = obj.unwrap();
  73. let name: String = deserialize(&key)?;
  74. let age: u32 = deserialize(&value)?;
  75. debug!(target: "demo", " {}: {}", name, age);
  76. }
  77. Ok(())
  78. }
  79. type BoxResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
  80. fn validate(
  81. tx: &Transaction,
  82. dao_wasm_bytes: &[u8],
  83. dao_contract_id: ContractId,
  84. money_wasm_bytes: &[u8],
  85. money_contract_id: ContractId,
  86. blockchain: &Blockchain,
  87. zk_bins: &ZkContractTable,
  88. ) -> Result<()> {
  89. // ContractId is not Hashable so put them in a Vec and do linear scan
  90. let wasm_bytes_lookup = vec![
  91. (dao_contract_id, "DAO", dao_wasm_bytes),
  92. (money_contract_id, "Money", money_wasm_bytes),
  93. ];
  94. // We can do all exec(), zk proof checks and signature verifies in parallel.
  95. let mut updates = vec![];
  96. let mut zkpublic_table = vec![];
  97. let mut sigpub_table = vec![];
  98. // Validate all function calls in the tx
  99. for (idx, call) in tx.calls.iter().enumerate() {
  100. // So then the verifier will lookup the corresponding state_transition and apply
  101. // functions based off the func_id
  102. // Write the actual payload data
  103. let mut payload = Vec::new();
  104. // Call index
  105. payload.write_u32(idx as u32)?;
  106. // Actuall calldata
  107. tx.calls.encode(&mut payload)?;
  108. // Lookup the wasm bytes
  109. let (_, contract_name, wasm_bytes) =
  110. wasm_bytes_lookup.iter().find(|(id, _name, _bytes)| *id == call.contract_id).unwrap();
  111. debug!(target: "demo", "{}::exec() contract called", contract_name);
  112. let mut runtime = Runtime::new(wasm_bytes, blockchain.clone(), call.contract_id)?;
  113. let update = runtime.exec(&payload)?;
  114. updates.push(update);
  115. let metadata = runtime.metadata(&payload)?;
  116. let mut decoder = Cursor::new(&metadata);
  117. let zk_public_values: Vec<(String, Vec<pallas::Base>)> = Decodable::decode(&mut decoder)?;
  118. let signature_public_keys: Vec<pallas::Point> = Decodable::decode(&mut decoder)?;
  119. zkpublic_table.push(zk_public_values);
  120. sigpub_table.push(signature_public_keys);
  121. }
  122. tx.zk_verify(&zk_bins, &zkpublic_table)?;
  123. //tx.verify_sigs();
  124. // Now we finished verification stage, just apply all changes
  125. assert_eq!(tx.calls.len(), updates.len());
  126. for (call, update) in tx.calls.iter().zip(updates.iter()) {
  127. // Lookup the wasm bytes
  128. let (_, contract_name, wasm_bytes) =
  129. wasm_bytes_lookup.iter().find(|(id, _name, _bytes)| *id == call.contract_id).unwrap();
  130. debug!(target: "demo", "{}::apply() contract called", contract_name);
  131. let mut runtime = Runtime::new(wasm_bytes, blockchain.clone(), call.contract_id)?;
  132. runtime.apply(&update)?;
  133. }
  134. Ok(())
  135. }
  136. #[async_std::main]
  137. async fn main() -> BoxResult<()> {
  138. // Debug log configuration
  139. let mut cfg = simplelog::ConfigBuilder::new();
  140. cfg.add_filter_ignore("sled".to_string());
  141. simplelog::TermLogger::init(
  142. simplelog::LevelFilter::Debug,
  143. cfg.build(),
  144. simplelog::TerminalMode::Mixed,
  145. simplelog::ColorChoice::Auto,
  146. )?;
  147. println!("wakie wakie young wagie");
  148. //return Ok(());
  149. //schema::schema().await?;
  150. //return Ok(());
  151. // =============================
  152. // Setup initial program parameters
  153. // =============================
  154. // Money parameters
  155. let xdrk_supply = 1_000_000;
  156. let xdrk_token_id = TokenId::from(pallas::Base::random(&mut OsRng));
  157. // Governance token parameters
  158. let gdrk_supply = 1_000_000;
  159. let gdrk_token_id = TokenId::from(pallas::Base::random(&mut OsRng));
  160. // DAO parameters
  161. let dao_proposer_limit = 110;
  162. let dao_quorum = 110;
  163. let dao_approval_ratio_quot = 1;
  164. let dao_approval_ratio_base = 2;
  165. // Initialize ZK binary table
  166. let mut zk_bins = ZkContractTable::new();
  167. debug!(target: "demo", "Loading dao-mint.zk");
  168. let zk_dao_mint_bincode = include_bytes!("../proof/dao-mint.zk.bin");
  169. let zk_dao_mint_bin = ZkBinary::decode(zk_dao_mint_bincode)?;
  170. zk_bins.add_contract("dao-mint".to_string(), zk_dao_mint_bin, 13);
  171. debug!(target: "demo", "Loading money-transfer contracts");
  172. {
  173. let start = Instant::now();
  174. let mint_pk = ProvingKey::build(11, &MintContract::default());
  175. debug!("Mint PK: [{:?}]", start.elapsed());
  176. let start = Instant::now();
  177. let burn_pk = ProvingKey::build(11, &BurnContract::default());
  178. debug!("Burn PK: [{:?}]", start.elapsed());
  179. let start = Instant::now();
  180. let mint_vk = VerifyingKey::build(11, &MintContract::default());
  181. debug!("Mint VK: [{:?}]", start.elapsed());
  182. let start = Instant::now();
  183. let burn_vk = VerifyingKey::build(11, &BurnContract::default());
  184. debug!("Burn VK: [{:?}]", start.elapsed());
  185. zk_bins.add_native("money-transfer-mint".to_string(), mint_pk, mint_vk);
  186. zk_bins.add_native("money-transfer-burn".to_string(), burn_pk, burn_vk);
  187. }
  188. /*
  189. debug!(target: "demo", "Loading dao-propose-main.zk");
  190. let zk_dao_propose_main_bincode = include_bytes!("../proof/dao-propose-main.zk.bin");
  191. let zk_dao_propose_main_bin = ZkBinary::decode(zk_dao_propose_main_bincode)?;
  192. zk_bins.add_contract("dao-propose-main".to_string(), zk_dao_propose_main_bin, 13);
  193. debug!(target: "demo", "Loading dao-propose-burn.zk");
  194. let zk_dao_propose_burn_bincode = include_bytes!("../proof/dao-propose-burn.zk.bin");
  195. let zk_dao_propose_burn_bin = ZkBinary::decode(zk_dao_propose_burn_bincode)?;
  196. zk_bins.add_contract("dao-propose-burn".to_string(), zk_dao_propose_burn_bin, 13);
  197. debug!(target: "demo", "Loading dao-vote-main.zk");
  198. let zk_dao_vote_main_bincode = include_bytes!("../proof/dao-vote-main.zk.bin");
  199. let zk_dao_vote_main_bin = ZkBinary::decode(zk_dao_vote_main_bincode)?;
  200. zk_bins.add_contract("dao-vote-main".to_string(), zk_dao_vote_main_bin, 13);
  201. debug!(target: "demo", "Loading dao-vote-burn.zk");
  202. let zk_dao_vote_burn_bincode = include_bytes!("../proof/dao-vote-burn.zk.bin");
  203. let zk_dao_vote_burn_bin = ZkBinary::decode(zk_dao_vote_burn_bincode)?;
  204. zk_bins.add_contract("dao-vote-burn".to_string(), zk_dao_vote_burn_bin, 13);
  205. let zk_dao_exec_bincode = include_bytes!("../proof/dao-exec.zk.bin");
  206. let zk_dao_exec_bin = ZkBinary::decode(zk_dao_exec_bincode)?;
  207. zk_bins.add_contract("dao-exec".to_string(), zk_dao_exec_bin, 13);
  208. */
  209. // State for money contracts
  210. let cashier_signature_secret = SecretKey::random(&mut OsRng);
  211. let cashier_signature_public = PublicKey::from_secret(cashier_signature_secret);
  212. let faucet_signature_secret = SecretKey::random(&mut OsRng);
  213. let faucet_signature_public = PublicKey::from_secret(faucet_signature_secret);
  214. // We use this to receive coins
  215. let mut cache = WalletCache::new();
  216. // Initialize a dummy blockchain
  217. // TODO: This blockchain interface should perhaps be ValidatorState and Mutex/RwLock.
  218. let db = sled::Config::new().temporary(true).open()?;
  219. let blockchain = Blockchain::new(&db, *TESTNET_GENESIS_TIMESTAMP, *TESTNET_GENESIS_HASH_BYTES)?;
  220. // ================================================================
  221. // Deploy the wasm contracts
  222. // ================================================================
  223. let dao_wasm_bytes = std::fs::read("dao_contract.wasm")?;
  224. let dao_contract_id = ContractId::from(pallas::Base::from(1));
  225. let money_wasm_bytes = std::fs::read("money_contract.wasm")?;
  226. let money_contract_id = ContractId::from(pallas::Base::from(2));
  227. // Block 1
  228. // This has 2 transaction deploying the DAO and Money wasm contracts
  229. // together with their ZK proofs.
  230. {
  231. let mut dao_runtime = Runtime::new(&dao_wasm_bytes, blockchain.clone(), dao_contract_id)?;
  232. let mut money_runtime =
  233. Runtime::new(&money_wasm_bytes, blockchain.clone(), money_contract_id)?;
  234. // 1. exec() - zk and sig verify also
  235. // ... none in this block
  236. // 2. commit() - all apply() and deploy()
  237. // Deploy function to initialize the smart contract state.
  238. // Here we pass an empty payload, but it's possible to feed in arbitrary data.
  239. dao_runtime.deploy(&[])?;
  240. money_runtime.deploy(&[])?;
  241. debug!(target: "demo", "Deployed DAO and money contracts");
  242. }
  243. // ================================================================
  244. // DAO::mint()
  245. // ================================================================
  246. // Wallet
  247. let dao_keypair = Keypair::random(&mut OsRng);
  248. let dao_bulla_blind = pallas::Base::random(&mut OsRng);
  249. let tx = {
  250. let signature_secret = SecretKey::random(&mut OsRng);
  251. // Create DAO mint tx
  252. let builder = dao::mint::wallet::Builder {
  253. dao_proposer_limit,
  254. dao_quorum,
  255. dao_approval_ratio_quot,
  256. dao_approval_ratio_base,
  257. gov_token_id: gdrk_token_id,
  258. dao_pubkey: dao_keypair.public,
  259. dao_bulla_blind,
  260. signature_secret,
  261. };
  262. let (params, dao_mint_proofs) = builder.build(&zk_bins);
  263. // Write the actual call data
  264. let mut calldata = Vec::new();
  265. // Selects which path executes in the contract.
  266. calldata.write_u8(DaoFunction::Mint as u8)?;
  267. params.encode(&mut calldata)?;
  268. let calls = vec![ContractCall { contract_id: dao_contract_id, data: calldata }];
  269. let signatures = vec![];
  270. //for func_call in &func_calls {
  271. // let sign = sign([signature_secret].to_vec(), func_call);
  272. // signatures.push(sign);
  273. //}
  274. let proofs = vec![dao_mint_proofs];
  275. Transaction { calls, proofs, signatures }
  276. };
  277. //// Validator
  278. validate(
  279. &tx,
  280. &dao_wasm_bytes,
  281. dao_contract_id,
  282. &money_wasm_bytes,
  283. money_contract_id,
  284. &blockchain,
  285. &zk_bins,
  286. )
  287. .expect("validate failed");
  288. // Wallet stuff
  289. // In your wallet, wait until you see the tx confirmed before doing anything below
  290. // So for example keep track of tx hash
  291. //
  292. // We also need to loop through all newly added items to the validator node
  293. // and repeat the same for our local merkle tree. The order of added items
  294. // to local merkle trees must be the same.
  295. //
  296. // One way to do this would be that .apply() keeps an in-memory per block
  297. // list of the order txs were applied. So then we can repeat the same order
  298. // for our local wallet trees.
  299. //
  300. // [ tx1, tx2, ... ]
  301. //
  302. // So the wallets know these are the new txs and this was the order they
  303. // were applied to the state in.
  304. // State updates are atomic so this will always be linear.
  305. //
  306. // When we see our DAO bulla, we call .witness()
  307. // We need to witness() the value in our local merkle tree
  308. let dao_bulla = {
  309. assert_eq!(tx.calls.len(), 1);
  310. let calldata = &tx.calls[0].data;
  311. let params_data = &calldata[1..];
  312. let params: DaoMintParams = Decodable::decode(params_data)?;
  313. params.dao_bulla.clone()
  314. };
  315. let mut dao_tree = MerkleTree::new(100);
  316. let dao_leaf_position = {
  317. let node = MerkleNode::from(dao_bulla.0);
  318. dao_tree.append(&node);
  319. dao_tree.witness().unwrap()
  320. };
  321. debug!(target: "demo", "Create DAO bulla: {:?}", dao_bulla.0);
  322. ///////////////////////////////////////////////////
  323. //// Mint the initial supply of treasury token
  324. //// and send it all to the DAO directly
  325. ///////////////////////////////////////////////////
  326. debug!(target: "demo", "Stage 2. Minting treasury token");
  327. cache.track(dao_keypair.secret);
  328. //// Wallet
  329. // Address of deployed contract in our example is dao::exec::FUNC_ID
  330. // This field is public, you can see it's being sent to a DAO
  331. // but nothing else is visible.
  332. //
  333. // In the python code we wrote:
  334. //
  335. // spend_hook = b"0xdao_ruleset"
  336. //
  337. let spend_hook = *dao::exec::FUNC_ID;
  338. let tx = {
  339. // The user_data can be a simple hash of the items passed into the ZK proof
  340. // up to corresponding linked ZK proof to interpret however they need.
  341. // In out case, it's the bulla for the DAO
  342. let user_data = dao_bulla.0;
  343. let builder = money::transfer::wallet::Builder {
  344. clear_inputs: vec![money::transfer::wallet::BuilderClearInputInfo {
  345. value: xdrk_supply,
  346. token_id: xdrk_token_id,
  347. signature_secret: cashier_signature_secret,
  348. }],
  349. inputs: vec![],
  350. outputs: vec![money::transfer::wallet::BuilderOutputInfo {
  351. value: xdrk_supply,
  352. token_id: xdrk_token_id,
  353. public: dao_keypair.public,
  354. serial: pallas::Base::random(&mut OsRng),
  355. coin_blind: pallas::Base::random(&mut OsRng),
  356. spend_hook,
  357. user_data,
  358. }],
  359. };
  360. let (params, proofs) = builder.build(&zk_bins)?;
  361. // Write the actual call data
  362. let mut calldata = Vec::new();
  363. // Selects which path executes in the contract.
  364. calldata.write_u8(MoneyFunction::Transfer as u8)?;
  365. params.encode(&mut calldata)?;
  366. let calls = vec![ContractCall { contract_id: money_contract_id, data: calldata }];
  367. let proofs = vec![proofs];
  368. // We sign everything
  369. let mut unsigned_tx_data = vec![];
  370. calls.encode(&mut unsigned_tx_data)?;
  371. proofs.encode(&mut unsigned_tx_data)?;
  372. let signature = cashier_signature_secret.sign(&mut OsRng, &unsigned_tx_data[..]);
  373. // Our tx has a single contract call which itself has a single input
  374. let signatures = vec![vec![signature]];
  375. Transaction { calls, proofs, signatures }
  376. };
  377. //let func_call = builder.build(&zk_bins)?;
  378. //let func_calls = vec![func_call];
  379. //let mut signatures = vec![];
  380. //for func_call in &func_calls {
  381. // let sign = sign([cashier_signature_secret].to_vec(), func_call);
  382. // signatures.push(sign);
  383. //}
  384. //let tx = Transaction { func_calls, signatures };
  385. ///////////////////////////////////////////////////
  386. show_dao_state(&blockchain, &dao_contract_id)?;
  387. show_money_state(&blockchain, &money_contract_id)?;
  388. Ok(())
  389. }