validate.rs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. use std::any::{Any, TypeId};
  2. use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
  3. use log::error;
  4. use pasta_curves::{
  5. arithmetic::CurveAffine,
  6. group::{Curve, Group},
  7. pallas,
  8. };
  9. use darkfi::{
  10. crypto::{
  11. keypair::PublicKey, merkle_node::MerkleNode, nullifier::Nullifier, types::DrkCircuitField,
  12. },
  13. Error as DarkFiError,
  14. };
  15. use crate::{
  16. contract::{
  17. dao_contract, dao_contract::State as DaoState, money_contract,
  18. money_contract::state::State as MoneyState,
  19. },
  20. note::EncryptedNote2,
  21. util::{CallDataBase, StateRegistry, Transaction, UpdateBase},
  22. };
  23. #[derive(Debug, Clone, thiserror::Error)]
  24. pub enum Error {
  25. #[error("Invalid proposal")]
  26. InvalidProposal,
  27. #[error("Voting with already spent coinage")]
  28. SpentCoin,
  29. #[error("Double voting")]
  30. DoubleVote,
  31. #[error("Invalid input merkle root")]
  32. InvalidInputMerkleRoot,
  33. #[error("DarkFi error: {0}")]
  34. DarkFiError(String),
  35. }
  36. type Result<T> = std::result::Result<T, Error>;
  37. impl From<DarkFiError> for Error {
  38. fn from(err: DarkFiError) -> Self {
  39. Self::DarkFiError(err.to_string())
  40. }
  41. }
  42. #[derive(Clone, SerialEncodable, SerialDecodable)]
  43. pub struct CallData {
  44. pub header: Header,
  45. pub inputs: Vec<Input>,
  46. }
  47. impl CallDataBase for CallData {
  48. fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)> {
  49. let mut zk_publics = Vec::new();
  50. let mut all_votes_commit = pallas::Point::identity();
  51. assert!(!self.inputs.is_empty(), "inputs length cannot be zero");
  52. for input in &self.inputs {
  53. all_votes_commit += input.vote_commit;
  54. let value_coords = input.vote_commit.to_affine().coordinates().unwrap();
  55. let sigpub_coords = input.signature_public.0.to_affine().coordinates().unwrap();
  56. zk_publics.push((
  57. "dao-vote-burn".to_string(),
  58. vec![
  59. input.nullifier.inner(),
  60. *value_coords.x(),
  61. *value_coords.y(),
  62. self.header.token_commit,
  63. input.merkle_root.0,
  64. *sigpub_coords.x(),
  65. *sigpub_coords.y(),
  66. ],
  67. ));
  68. }
  69. let yes_vote_commit_coords = self.header.yes_vote_commit.to_affine().coordinates().unwrap();
  70. let vote_commit_coords = all_votes_commit.to_affine().coordinates().unwrap();
  71. zk_publics.push((
  72. "dao-vote-main".to_string(),
  73. vec![
  74. self.header.token_commit,
  75. self.header.proposal_bulla,
  76. *yes_vote_commit_coords.x(),
  77. *yes_vote_commit_coords.y(),
  78. *vote_commit_coords.x(),
  79. *vote_commit_coords.y(),
  80. ],
  81. ));
  82. zk_publics
  83. }
  84. fn as_any(&self) -> &dyn Any {
  85. self
  86. }
  87. fn signature_public_keys(&self) -> Vec<PublicKey> {
  88. let mut signature_public_keys = vec![];
  89. for input in self.inputs.clone() {
  90. signature_public_keys.push(input.signature_public);
  91. }
  92. signature_public_keys
  93. }
  94. fn encode_bytes(
  95. &self,
  96. mut writer: &mut dyn std::io::Write,
  97. ) -> core::result::Result<usize, std::io::Error> {
  98. self.encode(&mut writer)
  99. }
  100. }
  101. #[derive(Clone, SerialEncodable, SerialDecodable)]
  102. pub struct Header {
  103. pub token_commit: pallas::Base,
  104. pub proposal_bulla: pallas::Base,
  105. pub yes_vote_commit: pallas::Point,
  106. pub enc_note: EncryptedNote2,
  107. }
  108. #[derive(Clone, SerialEncodable, SerialDecodable)]
  109. pub struct Input {
  110. pub nullifier: Nullifier,
  111. pub vote_commit: pallas::Point,
  112. pub merkle_root: MerkleNode,
  113. pub signature_public: PublicKey,
  114. }
  115. pub fn state_transition(
  116. states: &StateRegistry,
  117. func_call_index: usize,
  118. parent_tx: &Transaction,
  119. ) -> Result<Box<dyn UpdateBase + Send>> {
  120. let func_call = &parent_tx.func_calls[func_call_index];
  121. let call_data = func_call.call_data.as_any();
  122. assert_eq!((*call_data).type_id(), TypeId::of::<CallData>());
  123. let call_data = call_data.downcast_ref::<CallData>();
  124. // This will be inside wasm so unwrap is fine.
  125. let call_data = call_data.unwrap();
  126. let dao_state = states.lookup::<DaoState>(*dao_contract::CONTRACT_ID).unwrap();
  127. // Check proposal_bulla exists
  128. let votes_info = dao_state.lookup_proposal_votes(call_data.header.proposal_bulla);
  129. if votes_info.is_none() {
  130. return Err(Error::InvalidProposal)
  131. }
  132. let votes_info = votes_info.unwrap();
  133. // Check the merkle roots for the input coins are valid
  134. let mut vote_nulls = Vec::new();
  135. let mut all_vote_commit = pallas::Point::identity();
  136. for input in &call_data.inputs {
  137. let money_state = states.lookup::<MoneyState>(*money_contract::CONTRACT_ID).unwrap();
  138. if !money_state.is_valid_merkle(&input.merkle_root) {
  139. return Err(Error::InvalidInputMerkleRoot)
  140. }
  141. if money_state.nullifier_exists(&input.nullifier) {
  142. return Err(Error::SpentCoin)
  143. }
  144. if votes_info.nullifier_exists(&input.nullifier) {
  145. return Err(Error::DoubleVote)
  146. }
  147. all_vote_commit += input.vote_commit;
  148. vote_nulls.push(input.nullifier);
  149. }
  150. Ok(Box::new(Update {
  151. proposal_bulla: call_data.header.proposal_bulla,
  152. vote_nulls,
  153. yes_vote_commit: call_data.header.yes_vote_commit,
  154. all_vote_commit,
  155. }))
  156. }
  157. #[derive(Clone)]
  158. pub struct Update {
  159. proposal_bulla: pallas::Base,
  160. vote_nulls: Vec<Nullifier>,
  161. pub yes_vote_commit: pallas::Point,
  162. pub all_vote_commit: pallas::Point,
  163. }
  164. impl UpdateBase for Update {
  165. fn apply(mut self: Box<Self>, states: &mut StateRegistry) {
  166. let state = states.lookup_mut::<DaoState>(*dao_contract::CONTRACT_ID).unwrap();
  167. let votes_info = state.lookup_proposal_votes_mut(self.proposal_bulla).unwrap();
  168. votes_info.yes_votes_commit += self.yes_vote_commit;
  169. votes_info.all_votes_commit += self.all_vote_commit;
  170. votes_info.vote_nulls.append(&mut self.vote_nulls);
  171. }
  172. }