| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
- use log::debug;
- use crate::{
- blockchain::{rocks::columns, RocksColumn},
- crypto::{
- coin::Coin,
- keypair::{PublicKey, SecretKey},
- merkle_node::MerkleNode,
- note::{EncryptedNote, Note},
- nullifier::Nullifier,
- proof::VerifyingKey,
- OwnCoin,
- },
- tx::Transaction,
- wallet::walletdb::WalletPtr,
- Result,
- };
- pub trait ProgramState {
- fn is_valid_cashier_public_key(&self, public: &PublicKey) -> bool;
- fn is_valid_merkle(&self, merkle: &MerkleNode) -> bool;
- fn nullifier_exists(&self, nullifier: &Nullifier) -> bool;
- fn mint_vk(&self) -> &VerifyingKey;
- fn spend_vk(&self) -> &VerifyingKey;
- }
- pub struct StateUpdate {
- pub nullifiers: Vec<Nullifier>,
- pub coins: Vec<Coin>,
- pub enc_notes: Vec<EncryptedNote>,
- }
- pub type VerifyResult<T> = std::result::Result<T, VerifyFailed>;
- #[derive(Debug, Clone, thiserror::Error)]
- pub enum VerifyFailed {
- #[error("Invalid cashier public key for clear input {0}")]
- InvalidCashierKey(usize),
- #[error("Invalid merkle root for input {0}")]
- InvalidMerkle(usize),
- #[error("Duplicate nullifier for input {0}")]
- DuplicateNullifier(usize),
- #[error("Spend proof for input {0}")]
- SpendProof(usize),
- #[error("Mint proof for input {0}")]
- MintProof(usize),
- #[error("Invalid signature for clear input {0}")]
- ClearInputSignature(usize),
- #[error("Invalid signature for input {0}")]
- InputSignature(usize),
- #[error("Money in does not match money out (value commits)")]
- MissingFunds,
- #[error("Assets don't match some inputs or outputs (token commits)")]
- AssetMismatch,
- }
- pub fn state_transition<S: ProgramState>(state: &S, tx: Transaction) -> VerifyResult<StateUpdate> {
- // Check deposits are legit
- debug!(target: "STATE TRANSITION", "iterate clear_inputs");
- for (i, input) in tx.clear_inputs.iter().enumerate() {
- // Check the public key in the clear inputs
- // It should be a valid public key for the cashier
- if !state.is_valid_cashier_public_key(&input.signature_public) {
- log::error!(target: "STATE TRANSITION", "Invalid cashier public key");
- return Err(VerifyFailed::InvalidCashierKey(i))
- }
- }
- debug!(target: "STATE TRANSITION", "iterate inputs");
- for (i, input) in tx.inputs.iter().enumerate() {
- let merkle = &input.revealed.merkle_root;
- // Merkle is used to know whether this is a coin that existed
- // in a previous state.
- if !state.is_valid_merkle(merkle) {
- return Err(VerifyFailed::InvalidMerkle(i))
- }
- // The nullifiers should not already exist
- // It is double spend protection.
- let nullifier = &input.revealed.nullifier;
- if state.nullifier_exists(nullifier) {
- return Err(VerifyFailed::DuplicateNullifier(i))
- }
- }
- debug!(target: "STATE TRANSITION", "Check the tx verifies correctly");
- tx.verify(state.mint_vk(), state.spend_vk())?;
- debug!(target: "STATE TRANSITION", "Verified successfully");
- let mut nullifiers = vec![];
- for input in tx.inputs {
- nullifiers.push(input.revealed.nullifier);
- }
- // Newly created coins for this tx
- let mut coins = vec![];
- let mut enc_notes = vec![];
- for output in tx.outputs {
- // Gather all the coins
- coins.push(output.revealed.coin);
- enc_notes.push(output.enc_note);
- }
- Ok(StateUpdate { nullifiers, coins, enc_notes })
- }
- pub struct State {
- /// The entire Merkle tree state
- pub tree: BridgeTree<MerkleNode, 32>,
- /// List of all previous and the current merkle roots.
- /// This is the hashed value of all the children.
- pub merkle_roots: RocksColumn<columns::MerkleRoots>,
- /// Nullifiers prevent double-spending
- pub nullifiers: RocksColumn<columns::Nullifiers>,
- /// List of Cashier public keys
- pub public_keys: Vec<PublicKey>,
- /// Verifying key for the Mint contract
- pub mint_vk: VerifyingKey,
- /// Verifying key for the Spend contract
- pub spend_vk: VerifyingKey,
- }
- impl State {
- pub async fn apply(
- &mut self,
- update: StateUpdate,
- secret_keys: Vec<SecretKey>,
- notify: Option<async_channel::Sender<(PublicKey, u64)>>,
- wallet: WalletPtr,
- ) -> Result<()> {
- // Extend our list of nullifiers with the ones from the update.
- debug!("Extend nullifiers");
- for nullifier in update.nullifiers {
- self.nullifiers.put(nullifier, vec![] as Vec<u8>)?;
- }
- debug!("Update Merkle tree and witness");
- for (coin, enc_note) in update.coins.into_iter().zip(update.enc_notes.iter()) {
- // Add the new coins to the Merkle tree
- let node = MerkleNode(coin.0);
- self.tree.append(&node);
- // Keep track of all Merkle roots that have existed
- self.merkle_roots.put(self.tree.root(), vec![] as Vec<u8>)?;
- for secret in secret_keys.iter() {
- if let Some(note) = State::try_decrypt_note(enc_note, *secret) {
- // TODO: What to do with witnesses?
- self.tree.witness();
- let nullifier = Nullifier::new(*secret, note.serial);
- let own_coin = OwnCoin {
- coin,
- note,
- secret: *secret,
- // witness: witness.clone(),
- nullifier,
- };
- wallet.put_own_coins(own_coin).await?;
- let pubkey = PublicKey::from_secret(*secret);
- debug!("Received a coin: amount {}", note.value);
- debug!("Send a notification");
- if let Some(ch) = notify.clone() {
- ch.send((pubkey, note.value)).await?;
- }
- }
- }
- }
- debug!("apply() exiting successfully");
- Ok(())
- }
- fn try_decrypt_note(ciphertext: &EncryptedNote, secret: SecretKey) -> Option<Note> {
- match ciphertext.decrypt(&secret) {
- Ok(note) => Some(note),
- Err(_) => None,
- }
- }
- }
- impl ProgramState for State {
- fn is_valid_cashier_public_key(&self, public: &PublicKey) -> bool {
- debug!("Check if it is a valid cashier public key");
- self.public_keys.contains(public)
- }
- fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
- debug!("Check if it is valid merkle");
- if let Ok(mr) = self.merkle_roots.key_exist(merkle_root.clone()) {
- return mr
- }
- false
- }
- fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
- debug!("Check if nullifier exists");
- if let Ok(nl) = self.nullifiers.key_exist(nullifier.to_bytes()) {
- return nl
- }
- false
- }
- fn mint_vk(&self) -> &VerifyingKey {
- &self.mint_vk
- }
- fn spend_vk(&self) -> &VerifyingKey {
- &self.spend_vk
- }
- }
|