contract/consensus: Clean up and reorder UnstakeV1 state transition

This commit is contained in:
parazyd
2023-06-12 09:58:05 +02:00
parent 735ac84144
commit cbbbd18ff6

View File

@@ -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)
}