entrypoint.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use darkfi_sdk::{
  19. crypto::{poseidon_hash, ContractId, PublicKey},
  20. dark_tree::DarkLeaf,
  21. error::ContractResult,
  22. msg,
  23. pasta::pallas,
  24. wasm::{
  25. self,
  26. db::{db_contains_key, db_del, db_init, db_lookup, db_set, zkas_db_set},
  27. },
  28. ContractCall, ContractError,
  29. };
  30. use darkfi_serial::{deserialize, serialize, Encodable};
  31. use crate::{
  32. ContractFunction, HelloParams, HELLO_CONTRACT_MEMBER_TREE, HELLO_CONTRACT_ZKAS_SECRETCOMMIT_NS,
  33. };
  34. darkfi_sdk::define_contract!(
  35. init: init_contract,
  36. exec: process_instruction,
  37. apply: process_update,
  38. metadata: get_metadata
  39. );
  40. /// This entrypoint function runs when the contract is (re)deployed and initialized.
  41. /// We use this function to init all the necessary databases and prepare them with
  42. /// initial data if necessary.
  43. /// This is also the place where we bundle the zkas circuits that are to be used
  44. /// with functions provided by the contract.
  45. fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
  46. // zkas circuits can simply be embedded in the wasm and set up by using
  47. // respective db functions.
  48. // The special `zkas db` operations exist in order to be able to verify
  49. // the circuits being bundled and enforcing a specific tree inside sled,
  50. // and dlso creation of VerifyingKey.
  51. let circuit_bincode = include_bytes!("../proof/secret_commitment.zk.bin");
  52. // For that, we use `zkas_db_set` and pass in the bincode.
  53. zkas_db_set(&circuit_bincode[..])?;
  54. // Now we also want to create our own database to hold things.
  55. // This `lookup || init` method is a redeployment guard.
  56. if db_lookup(cid, HELLO_CONTRACT_MEMBER_TREE).is_err() {
  57. db_init(cid, HELLO_CONTRACT_MEMBER_TREE)?;
  58. }
  59. Ok(())
  60. }
  61. fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
  62. let call_idx = wasm::util::get_call_index()? as usize;
  63. let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
  64. let self_ = &calls[call_idx].data;
  65. let _func = ContractFunction::try_from(self_.data[0])?;
  66. // Deserialize the call parameters
  67. let params: HelloParams = deserialize(&self_.data[1..])?;
  68. // Public inputs for the ZK proofs we have to verify
  69. let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
  70. // Public keys for the transaction signatures we have to verify
  71. let signature_pubkeys: Vec<PublicKey> = vec![];
  72. zk_public_inputs
  73. .push((HELLO_CONTRACT_ZKAS_SECRETCOMMIT_NS.to_string(), vec![params.x, params.y]));
  74. // Serialize everything gathered and return it
  75. let mut metadata = vec![];
  76. zk_public_inputs.encode(&mut metadata)?;
  77. signature_pubkeys.encode(&mut metadata)?;
  78. wasm::util::set_return_data(&metadata)
  79. }
  80. fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
  81. let call_idx = wasm::util::get_call_index()? as usize;
  82. let calls: Vec<DarkLeaf<ContractCall>> = deserialize(ix)?;
  83. let self_ = &calls[call_idx].data;
  84. let func = ContractFunction::try_from(self_.data[0])?;
  85. // Deserialize the call parameters
  86. let params: HelloParams = deserialize(&self_.data[1..])?;
  87. // Open the db
  88. let db_members = db_lookup(cid, HELLO_CONTRACT_MEMBER_TREE)?;
  89. // Pubkey commitment
  90. let commitment = poseidon_hash([params.x, params.y]);
  91. match func {
  92. ContractFunction::Register => {
  93. if db_contains_key(db_members, &serialize(&commitment))? {
  94. msg!("Error: Member already in database");
  95. return Err(ContractError::Custom(1))
  96. }
  97. }
  98. ContractFunction::Deregister => {
  99. if !db_contains_key(db_members, &serialize(&commitment))? {
  100. msg!("Error: Member not in database");
  101. return Err(ContractError::Custom(2))
  102. }
  103. }
  104. }
  105. wasm::util::set_return_data(&serialize(&commitment))
  106. }
  107. fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
  108. let func = ContractFunction::try_from(update_data[0])?;
  109. let db_members = db_lookup(cid, HELLO_CONTRACT_MEMBER_TREE)?;
  110. let commitment = &update_data[1..];
  111. match func {
  112. ContractFunction::Register => db_set(db_members, commitment, &[])?,
  113. ContractFunction::Deregister => db_del(db_members, commitment)?,
  114. }
  115. Ok(())
  116. }