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