validate.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. use std::any::{Any, TypeId};
  2. use darkfi_sdk::crypto::MerkleNode;
  3. use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
  4. use log::error;
  5. use pasta_curves::{
  6. arithmetic::CurveAffine,
  7. group::{Curve, Group},
  8. pallas,
  9. };
  10. use darkfi::{
  11. crypto::{keypair::PublicKey, types::DrkCircuitField},
  12. Error as DarkFiError,
  13. };
  14. use crate::{
  15. contract::{
  16. dao_contract, dao_contract::State as DaoState, money_contract,
  17. money_contract::state::State as MoneyState,
  18. },
  19. note::EncryptedNote2,
  20. util::{CallDataBase, StateRegistry, Transaction, UpdateBase},
  21. };
  22. // used for debugging
  23. // const TARGET: &str = "dao_contract::propose::validate::state_transition()";
  24. #[derive(Debug, Clone, thiserror::Error)]
  25. pub enum Error {
  26. #[error("Invalid input merkle root")]
  27. InvalidInputMerkleRoot,
  28. #[error("Invalid DAO merkle root")]
  29. InvalidDaoMerkleRoot,
  30. #[error("DarkFi error: {0}")]
  31. DarkFiError(String),
  32. }
  33. type Result<T> = std::result::Result<T, Error>;
  34. impl From<DarkFiError> for Error {
  35. fn from(err: DarkFiError) -> Self {
  36. Self::DarkFiError(err.to_string())
  37. }
  38. }
  39. #[derive(Clone, SerialEncodable, SerialDecodable)]
  40. pub struct CallData {
  41. pub header: Header,
  42. pub inputs: Vec<Input>,
  43. }
  44. impl CallDataBase for CallData {
  45. fn zk_public_values(&self) -> Vec<(String, Vec<DrkCircuitField>)> {
  46. let mut zk_publics = Vec::new();
  47. let mut total_funds_commit = pallas::Point::identity();
  48. assert!(!self.inputs.is_empty(), "inputs length cannot be zero");
  49. for input in &self.inputs {
  50. total_funds_commit += input.value_commit;
  51. let value_coords = input.value_commit.to_affine().coordinates().unwrap();
  52. let sigpub_coords = input.signature_public.0.to_affine().coordinates().unwrap();
  53. zk_publics.push((
  54. "dao-propose-burn".to_string(),
  55. vec![
  56. *value_coords.x(),
  57. *value_coords.y(),
  58. self.header.token_commit,
  59. input.merkle_root.inner(),
  60. *sigpub_coords.x(),
  61. *sigpub_coords.y(),
  62. ],
  63. ));
  64. }
  65. let total_funds_coords = total_funds_commit.to_affine().coordinates().unwrap();
  66. zk_publics.push((
  67. "dao-propose-main".to_string(),
  68. vec![
  69. self.header.token_commit,
  70. self.header.dao_merkle_root.inner(),
  71. self.header.proposal_bulla,
  72. *total_funds_coords.x(),
  73. *total_funds_coords.y(),
  74. ],
  75. ));
  76. zk_publics
  77. }
  78. fn as_any(&self) -> &dyn Any {
  79. self
  80. }
  81. fn signature_public_keys(&self) -> Vec<PublicKey> {
  82. let mut signature_public_keys = vec![];
  83. for input in self.inputs.clone() {
  84. signature_public_keys.push(input.signature_public);
  85. }
  86. signature_public_keys
  87. }
  88. fn encode_bytes(
  89. &self,
  90. mut writer: &mut dyn std::io::Write,
  91. ) -> core::result::Result<usize, std::io::Error> {
  92. self.encode(&mut writer)
  93. }
  94. }
  95. #[derive(Clone, SerialEncodable, SerialDecodable)]
  96. pub struct Header {
  97. pub dao_merkle_root: MerkleNode,
  98. pub token_commit: pallas::Base,
  99. pub proposal_bulla: pallas::Base,
  100. pub enc_note: EncryptedNote2,
  101. }
  102. #[derive(Clone, SerialEncodable, SerialDecodable)]
  103. pub struct Input {
  104. pub value_commit: pallas::Point,
  105. pub merkle_root: MerkleNode,
  106. pub signature_public: PublicKey,
  107. }
  108. pub fn state_transition(
  109. states: &StateRegistry,
  110. func_call_index: usize,
  111. parent_tx: &Transaction,
  112. ) -> Result<Box<dyn UpdateBase + Send>> {
  113. let func_call = &parent_tx.func_calls[func_call_index];
  114. let call_data = func_call.call_data.as_any();
  115. assert_eq!((*call_data).type_id(), TypeId::of::<CallData>());
  116. let call_data = call_data.downcast_ref::<CallData>();
  117. // This will be inside wasm so unwrap is fine.
  118. let call_data = call_data.unwrap();
  119. // Check the merkle roots for the input coins are valid
  120. for input in &call_data.inputs {
  121. let money_state = states.lookup::<MoneyState>(*money_contract::CONTRACT_ID).unwrap();
  122. if !money_state.is_valid_merkle(&input.merkle_root) {
  123. return Err(Error::InvalidInputMerkleRoot)
  124. }
  125. }
  126. let state = states.lookup::<DaoState>(*dao_contract::CONTRACT_ID).unwrap();
  127. // Is the DAO bulla generated in the ZK proof valid
  128. if !state.is_valid_dao_merkle(&call_data.header.dao_merkle_root) {
  129. return Err(Error::InvalidDaoMerkleRoot)
  130. }
  131. // TODO: look at gov tokens avoid using already spent ones
  132. // Need to spend original coin and generate 2 nullifiers?
  133. Ok(Box::new(Update { proposal_bulla: call_data.header.proposal_bulla }))
  134. }
  135. #[derive(Clone)]
  136. pub struct Update {
  137. pub proposal_bulla: pallas::Base,
  138. }
  139. impl UpdateBase for Update {
  140. fn apply(self: Box<Self>, states: &mut StateRegistry) {
  141. let state = states.lookup_mut::<DaoState>(*dao_contract::CONTRACT_ID).unwrap();
  142. state.add_proposal_bulla(self.proposal_bulla);
  143. }
  144. }