diff --git a/src/contract/consensus/src/entrypoint/unstake_v1.rs b/src/contract/consensus/src/entrypoint/unstake_v1.rs index 6f7c6ea3c..2d7135495 100644 --- a/src/contract/consensus/src/entrypoint/unstake_v1.rs +++ b/src/contract/consensus/src/entrypoint/unstake_v1.rs @@ -19,8 +19,8 @@ use darkfi_money_contract::{ error::MoneyError, model::{ConsensusUnstakeParamsV1, ConsensusUnstakeUpdateV1, MoneyUnstakeParamsV1}, - CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE, - CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, + MoneyFunction, CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE, + CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1, }; use darkfi_sdk::{ crypto::{pasta_prelude::*, ContractId, MONEY_CONTRACT_ID}, @@ -33,7 +33,7 @@ use darkfi_sdk::{ }; use darkfi_serial::{deserialize, serialize, Encodable, WriteExt}; -use crate::{error::ConsensusError, model::calculate_grace_period, ConsensusFunction}; +use crate::{error::ConsensusError, model::GRACE_PERIOD, ConsensusFunction}; /// `get_metadata` function for `Consensus::UnstakeV1` pub(crate) fn consensus_unstake_get_metadata_v1( @@ -50,11 +50,10 @@ pub(crate) fn consensus_unstake_get_metadata_v1( // Public keys for the transaction signatures we have to verify let signature_pubkeys = vec![input.signature_public]; - // Grab the pedersen commitments and signature pubkeys from the + // Grab the pedersen commitment and signature pubkey coordinates from the // anonymous input let value_coords = input.value_commit.to_affine().coordinates().unwrap(); let (sig_x, sig_y) = input.signature_public.xy(); - let epoch_palas = pallas::Base::from(input.epoch); // It is very important that these are in the same order as the // `constrain_instance` calls in the zkas code. @@ -63,7 +62,7 @@ pub(crate) fn consensus_unstake_get_metadata_v1( CONSENSUS_CONTRACT_ZKAS_BURN_NS_V1.to_string(), vec![ input.nullifier.inner(), - epoch_palas, + pallas::Base::from(input.epoch), sig_x, sig_y, input.merkle_root.inner(), @@ -76,7 +75,6 @@ pub(crate) fn consensus_unstake_get_metadata_v1( let mut metadata = vec![]; zk_public_inputs.encode(&mut metadata)?; signature_pubkeys.encode(&mut metadata)?; - Ok(metadata) } @@ -93,42 +91,12 @@ pub(crate) fn consensus_unstake_process_instruction_v1( // Access the necessary databases where there is information to // validate this state transition. let nullifiers_db = db_lookup(cid, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?; - let unstaked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE)?; let unstaked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE)?; // =================================== // Perform the actual state transition // =================================== - msg!("[ConsensusUnstakeV1] Validating anonymous input"); - - // The coin has passed through the grace period and is allowed to get unstaked. - if get_verifying_slot_epoch() - input.epoch <= calculate_grace_period() { - msg!("[ConsensusUnstakeV1] Error: Coin is not allowed to get unstaked yet"); - return Err(ConsensusError::CoinStillInGracePeriod.into()) - } - - /* - // Check that the coin exists in unstake set. - if !db_contains_key(unstaked_coins_db, &serialize(&input.coin))? { - msg!("[GenesisStakeV1] Error: Unstaked coin is not in unstake set"); - return Err(ConsensusError::CoinNotInUnstakeSet.into()) - } - */ - - // The Merkle root is used to know whether this is an unstaked coin that - // existed in a previous state. - if !db_contains_key(unstaked_coin_roots_db, &serialize(&input.merkle_root))? { - msg!("[ConsensusUnstakeV1] Error: Merkle root not found in previous state"); - return Err(MoneyError::TransferMerkleRootNotFound.into()) - } - - // The nullifiers should not already exist. It is the double-spend protection. - if db_contains_key(nullifiers_db, &serialize(&input.nullifier))? { - msg!("[ConsensusUnstakeV1] Error: Duplicate nullifier found"); - return Err(MoneyError::DuplicateNullifier.into()) - } - // Check next call is money contract let next_call_idx = call_idx + 1; if next_call_idx >= calls.len() as u32 { @@ -142,26 +110,44 @@ pub(crate) fn consensus_unstake_process_instruction_v1( return Err(MoneyError::UnstakeNextCallNotMoneyContract.into()) } - // Verify next call corresponds to Money::UnstakeV1 (0x07) - if next.data[0] != 0x07 { + // Verify next call corresponds to Money::UnstakeV1 + if next.data[0] != MoneyFunction::UnstakeV1 as u8 { msg!("[ConsensusUnstakeV1] Error: Next call function mismatch"); return Err(MoneyError::NextCallFunctionMismatch.into()) } - // Verify next call StakeInput is the same as this calls input + // Verify next call input is the same as this calls input let next_params: MoneyUnstakeParamsV1 = deserialize(&next.data[1..])?; if input != &next_params.input { msg!("[ConsensusUnstakeV1] Error: Next call input mismatch"); return Err(MoneyError::NextCallInputMismatch.into()) } + msg!("[ConsensusUnstakeV1] Validating anonymous input"); + // The coin has passed through the grace period and is allowed to get unstaked. + if get_verifying_slot_epoch() - input.epoch <= GRACE_PERIOD { + msg!("[ConsensusUnstakeV1] Error: Coin is not allowed to get unstaked yet"); + return Err(ConsensusError::CoinStillInGracePeriod.into()) + } + + // The Merkle root is used to know whether this is an unstaked coin that + // existed in a previous state. + if !db_contains_key(unstaked_coin_roots_db, &serialize(&input.merkle_root))? { + msg!("[ConsensusUnstakeV1] Error: Merkle root not found in previous state"); + return Err(MoneyError::TransferMerkleRootNotFound.into()) + } + + // The nullifiers should not already exist. It is the double-spend protection. + if db_contains_key(nullifiers_db, &serialize(&input.nullifier))? { + msg!("[ConsensusUnstakeV1] Error: Duplicate nullifier found"); + return Err(MoneyError::DuplicateNullifier.into()) + } + // At this point the state transition has passed, so we create a state update let update = ConsensusUnstakeUpdateV1 { nullifier: input.nullifier }; let mut update_data = vec![]; update_data.write_u8(ConsensusFunction::UnstakeV1 as u8)?; update.encode(&mut update_data)?; - - // and return it Ok(update_data) }