mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
contract/consensus: Introduce separate Merkle tree for unstaked coins
This commit is contained in:
@@ -36,7 +36,7 @@ use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
|
||||
|
||||
use crate::{
|
||||
error::ConsensusError,
|
||||
model::{calculate_grace_period, ConsensusProposalUpdateV1},
|
||||
model::{ConsensusProposalUpdateV1, GRACE_PERIOD},
|
||||
ConsensusFunction,
|
||||
};
|
||||
|
||||
@@ -120,7 +120,7 @@ pub(crate) fn consensus_unstake_request_process_instruction_v1(
|
||||
msg!("[ConsensusUnstakeRequestV1] Validating anonymous input");
|
||||
|
||||
// The coin has passed through the grace period and is allowed to request unstake.
|
||||
if input.epoch != 0 && get_verifying_slot_epoch() - input.epoch <= calculate_grace_period() {
|
||||
if input.epoch != 0 && get_verifying_slot_epoch() - input.epoch <= GRACE_PERIOD {
|
||||
msg!("[ConsensusUnstakeRequestV1] Error: Coin is not allowed to request unstake yet");
|
||||
return Err(ConsensusError::CoinStillInGracePeriod.into())
|
||||
}
|
||||
@@ -138,14 +138,6 @@ pub(crate) fn consensus_unstake_request_process_instruction_v1(
|
||||
return Err(MoneyError::DuplicateNullifier.into())
|
||||
}
|
||||
|
||||
/*
|
||||
// Check that the coin hasn't existed before in unstake set.
|
||||
if db_contains_key(unstaked_coins_db, &serialize(&input.coin))? {
|
||||
msg!("[ConsensusUnstakeRequestV1] Error: Unstaked coin found in input");
|
||||
return Err(MoneyError::DuplicateCoin.into())
|
||||
}
|
||||
*/
|
||||
|
||||
msg!("[ConsensusUnstakeRequestV1] Validating anonymous output");
|
||||
|
||||
// Verify value commits match
|
||||
@@ -166,8 +158,6 @@ pub(crate) fn consensus_unstake_request_process_instruction_v1(
|
||||
let mut update_data = vec![];
|
||||
update_data.write_u8(ConsensusFunction::UnstakeRequestV1 as u8)?;
|
||||
update.encode(&mut update_data)?;
|
||||
|
||||
// and return it
|
||||
Ok(update_data)
|
||||
}
|
||||
|
||||
@@ -185,10 +175,10 @@ pub(crate) fn consensus_unstake_request_process_update_v1(
|
||||
msg!("[ConsensusUnstakeRequestV1] Adding new nullifier to the set");
|
||||
db_set(nullifiers_db, &serialize(&update.nullifier), &[])?;
|
||||
|
||||
msg!("[ConsensusUnstakeRequestV1] Adding new coin to the set");
|
||||
msg!("[ConsensusUnstakeRequestV1] Adding new coin to the unstaked coins set");
|
||||
db_set(unstaked_coins_db, &serialize(&update.coin), &[])?;
|
||||
|
||||
msg!("[ConsensusUnstakeRequestV1] Adding new coin to the Merkle tree");
|
||||
msg!("[ConsensusUnstakeRequestV1] Adding new coin to the unstaked coins Merkle tree");
|
||||
let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
|
||||
merkle_add(
|
||||
info_db,
|
||||
|
||||
@@ -72,12 +72,14 @@ pub struct ConsensusProposalUpdateV1 {
|
||||
|
||||
/// Parameters for `Consensus::UnstakeRequest`
|
||||
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
|
||||
// ANCHOR: ConsensusUnstakeRequestParams
|
||||
pub struct ConsensusUnstakeRequestParamsV1 {
|
||||
/// Burnt token revealed info
|
||||
pub input: ConsensusInput,
|
||||
/// Anonymous output
|
||||
pub output: Output,
|
||||
}
|
||||
// ANCHOR_END: ConsensusUnstakeRequestParams
|
||||
|
||||
// ======================================================================
|
||||
// Consensus parameters configuration
|
||||
|
||||
@@ -106,7 +106,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
|
||||
|
||||
// Gather new staked owncoin
|
||||
let alice_staked_oc =
|
||||
th.gather_consensus_owncoin(Holder::Alice, genesis_stake_params.output, None)?;
|
||||
th.gather_consensus_staked_owncoin(Holder::Alice, genesis_stake_params.output, None)?;
|
||||
|
||||
// Verify values match
|
||||
assert!(ALICE_INITIAL == alice_staked_oc.note.value);
|
||||
@@ -139,7 +139,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
|
||||
th.assert_trees();
|
||||
|
||||
// Gather new staked owncoin which includes the reward
|
||||
let alice_rewarded_staked_oc = th.gather_consensus_owncoin(
|
||||
let alice_rewarded_staked_oc = th.gather_consensus_staked_owncoin(
|
||||
Holder::Alice,
|
||||
proposal_params.output,
|
||||
Some(proposal_output_secret_key),
|
||||
@@ -184,7 +184,7 @@ async fn consensus_contract_genesis_stake_unstake() -> Result<()> {
|
||||
th.assert_trees();
|
||||
|
||||
// Gather new unstake request owncoin
|
||||
let alice_unstake_request_oc = th.gather_consensus_owncoin(
|
||||
let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
|
||||
Holder::Alice,
|
||||
unstake_request_params.output,
|
||||
Some(unstake_request_secret_key),
|
||||
|
||||
@@ -154,7 +154,8 @@ pub struct Wallet {
|
||||
pub keypair: Keypair,
|
||||
pub state: ValidatorStatePtr,
|
||||
pub money_merkle_tree: MerkleTree,
|
||||
pub consensus_merkle_tree: MerkleTree,
|
||||
pub consensus_staked_merkle_tree: MerkleTree,
|
||||
pub consensus_unstaked_merkle_tree: MerkleTree,
|
||||
pub wallet: WalletPtr,
|
||||
pub coins: Vec<OwnCoin>,
|
||||
pub spent_coins: Vec<OwnCoin>,
|
||||
@@ -179,7 +180,8 @@ impl Wallet {
|
||||
.await?;
|
||||
|
||||
let money_merkle_tree = MerkleTree::new(100);
|
||||
let consensus_merkle_tree = MerkleTree::new(100);
|
||||
let consensus_staked_merkle_tree = MerkleTree::new(100);
|
||||
let consensus_unstaked_merkle_tree = MerkleTree::new(100);
|
||||
|
||||
let coins = vec![];
|
||||
let spent_coins = vec![];
|
||||
@@ -188,7 +190,8 @@ impl Wallet {
|
||||
keypair,
|
||||
state,
|
||||
money_merkle_tree,
|
||||
consensus_merkle_tree,
|
||||
consensus_staked_merkle_tree,
|
||||
consensus_unstaked_merkle_tree,
|
||||
wallet,
|
||||
coins,
|
||||
spent_coins,
|
||||
@@ -395,7 +398,7 @@ impl ConsensusTestHarness {
|
||||
let erroneous_txs =
|
||||
wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
|
||||
assert!(erroneous_txs.is_empty());
|
||||
wallet.consensus_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
|
||||
wallet.consensus_staked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
|
||||
tx_action_benchmark.verify_times.push(timer.elapsed());
|
||||
|
||||
Ok(())
|
||||
@@ -515,7 +518,7 @@ impl ConsensusTestHarness {
|
||||
let erroneous_txs =
|
||||
wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
|
||||
assert!(erroneous_txs.is_empty());
|
||||
wallet.consensus_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
|
||||
wallet.consensus_staked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
|
||||
tx_action_benchmark.verify_times.push(timer.elapsed());
|
||||
|
||||
Ok(())
|
||||
@@ -542,7 +545,7 @@ impl ConsensusTestHarness {
|
||||
slot_checkpoint,
|
||||
fork_hash,
|
||||
fork_previous_hash: fork_hash,
|
||||
merkle_tree: wallet.consensus_merkle_tree.clone(),
|
||||
merkle_tree: wallet.consensus_staked_merkle_tree.clone(),
|
||||
proposal_zkbin: proposal_zkbin.clone(),
|
||||
proposal_pk: proposal_pk.clone(),
|
||||
}
|
||||
@@ -591,7 +594,7 @@ impl ConsensusTestHarness {
|
||||
let erroneous_txs =
|
||||
wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
|
||||
assert!(erroneous_txs.is_empty());
|
||||
wallet.consensus_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
|
||||
wallet.consensus_staked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
|
||||
tx_action_benchmark.verify_times.push(timer.elapsed());
|
||||
|
||||
Ok(())
|
||||
@@ -636,7 +639,7 @@ impl ConsensusTestHarness {
|
||||
let unstake_request_call_debris = ConsensusUnstakeRequestCallBuilder {
|
||||
coin: staked_oc.clone(),
|
||||
epoch,
|
||||
tree: wallet.consensus_merkle_tree.clone(),
|
||||
tree: wallet.consensus_staked_merkle_tree.clone(),
|
||||
burn_zkbin: burn_zkbin.clone(),
|
||||
burn_pk: burn_pk.clone(),
|
||||
mint_zkbin: mint_zkbin.clone(),
|
||||
@@ -686,7 +689,7 @@ impl ConsensusTestHarness {
|
||||
let erroneous_txs =
|
||||
wallet.state.read().await.verify_transactions(&[tx], slot, true).await?;
|
||||
assert!(erroneous_txs.is_empty());
|
||||
wallet.consensus_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
|
||||
wallet.consensus_unstaked_merkle_tree.append(&MerkleNode::from(params.output.coin.inner()));
|
||||
tx_action_benchmark.verify_times.push(timer.elapsed());
|
||||
|
||||
Ok(())
|
||||
@@ -727,7 +730,7 @@ impl ConsensusTestHarness {
|
||||
// Building Consensus::Unstake params
|
||||
let consensus_unstake_call_debris = ConsensusUnstakeCallBuilder {
|
||||
coin: staked_oc.clone(),
|
||||
tree: wallet.consensus_merkle_tree.clone(),
|
||||
tree: wallet.consensus_unstaked_merkle_tree.clone(),
|
||||
burn_zkbin: burn_zkbin.clone(),
|
||||
burn_pk: burn_pk.clone(),
|
||||
}
|
||||
@@ -830,14 +833,38 @@ impl ConsensusTestHarness {
|
||||
Ok(oc)
|
||||
}
|
||||
|
||||
pub fn gather_consensus_owncoin(
|
||||
pub fn gather_consensus_staked_owncoin(
|
||||
&mut self,
|
||||
holder: Holder,
|
||||
output: ConsensusOutput,
|
||||
secret_key: Option<SecretKey>,
|
||||
) -> Result<ConsensusOwnCoin> {
|
||||
let wallet = self.holders.get_mut(&holder).unwrap();
|
||||
let leaf_position = wallet.consensus_merkle_tree.witness().unwrap();
|
||||
let leaf_position = wallet.consensus_staked_merkle_tree.witness().unwrap();
|
||||
let secret_key = match secret_key {
|
||||
Some(key) => key,
|
||||
None => wallet.keypair.secret,
|
||||
};
|
||||
let note: ConsensusNote = output.note.decrypt(&secret_key)?;
|
||||
let oc = ConsensusOwnCoin {
|
||||
coin: Coin::from(output.coin),
|
||||
note: note.clone(),
|
||||
secret: secret_key,
|
||||
nullifier: Nullifier::from(poseidon_hash([wallet.keypair.secret.inner(), note.serial])),
|
||||
leaf_position,
|
||||
};
|
||||
|
||||
Ok(oc)
|
||||
}
|
||||
|
||||
pub fn gather_consensus_unstaked_owncoin(
|
||||
&mut self,
|
||||
holder: Holder,
|
||||
output: ConsensusOutput,
|
||||
secret_key: Option<SecretKey>,
|
||||
) -> Result<ConsensusOwnCoin> {
|
||||
let wallet = self.holders.get_mut(&holder).unwrap();
|
||||
let leaf_position = wallet.consensus_unstaked_merkle_tree.witness().unwrap();
|
||||
let secret_key = match secret_key {
|
||||
Some(key) => key,
|
||||
None => wallet.keypair.secret,
|
||||
|
||||
@@ -87,8 +87,11 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
|
||||
th.assert_trees();
|
||||
|
||||
// Gather new staked owncoin
|
||||
let alice_staked_oc =
|
||||
th.gather_consensus_owncoin(Holder::Alice, stake_params.output, Some(stake_secret_key))?;
|
||||
let alice_staked_oc = th.gather_consensus_staked_owncoin(
|
||||
Holder::Alice,
|
||||
stake_params.output,
|
||||
Some(stake_secret_key),
|
||||
)?;
|
||||
|
||||
// Verify values match
|
||||
assert!(alice_oc.note.value == alice_staked_oc.note.value);
|
||||
@@ -136,7 +139,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
|
||||
th.assert_trees();
|
||||
|
||||
// Gather new staked owncoin which includes the reward
|
||||
let alice_rewarded_staked_oc = th.gather_consensus_owncoin(
|
||||
let alice_rewarded_staked_oc = th.gather_consensus_staked_owncoin(
|
||||
Holder::Alice,
|
||||
proposal_params.output,
|
||||
Some(proposal_decryption_secret_key),
|
||||
@@ -181,7 +184,7 @@ async fn consensus_contract_stake_unstake() -> Result<()> {
|
||||
th.assert_trees();
|
||||
|
||||
// Gather new unstake request owncoin
|
||||
let alice_unstake_request_oc = th.gather_consensus_owncoin(
|
||||
let alice_unstake_request_oc = th.gather_consensus_unstaked_owncoin(
|
||||
Holder::Alice,
|
||||
unstake_request_params.output,
|
||||
Some(unstake_request_secret_key),
|
||||
|
||||
@@ -32,7 +32,7 @@ use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
|
||||
use crate::{
|
||||
error::MoneyError,
|
||||
model::{ConsensusUnstakeParamsV1, MoneyUnstakeParamsV1, MoneyUnstakeUpdateV1},
|
||||
MoneyFunction, CONSENSUS_CONTRACT_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_NULLIFIERS_TREE,
|
||||
MoneyFunction, CONSENSUS_CONTRACT_NULLIFIERS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE,
|
||||
MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
|
||||
MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
|
||||
};
|
||||
@@ -89,8 +89,8 @@ pub(crate) fn money_unstake_process_instruction_v1(
|
||||
let money_coins_db = db_lookup(cid, MONEY_CONTRACT_COINS_TREE)?;
|
||||
let consensus_nullifiers_db =
|
||||
db_lookup(*CONSENSUS_CONTRACT_ID, CONSENSUS_CONTRACT_NULLIFIERS_TREE)?;
|
||||
let consensus_coin_roots_db =
|
||||
db_lookup(*CONSENSUS_CONTRACT_ID, CONSENSUS_CONTRACT_COIN_ROOTS_TREE)?;
|
||||
let consensus_unstaked_coin_roots_db =
|
||||
db_lookup(*CONSENSUS_CONTRACT_ID, CONSENSUS_CONTRACT_UNSTAKED_COIN_ROOTS_TREE)?;
|
||||
|
||||
// ===================================
|
||||
// Perform the actual state transition
|
||||
@@ -118,7 +118,7 @@ pub(crate) fn money_unstake_process_instruction_v1(
|
||||
|
||||
// The Merkle root is used to know whether this is a coin that
|
||||
// existed in a previous state.
|
||||
if !db_contains_key(consensus_coin_roots_db, &serialize(&input.merkle_root))? {
|
||||
if !db_contains_key(consensus_unstaked_coin_roots_db, &serialize(&input.merkle_root))? {
|
||||
msg!("[MoneyUnstakeV1] Error: Merkle root not found in previous state");
|
||||
return Err(MoneyError::TransferMerkleRootNotFound.into())
|
||||
}
|
||||
|
||||
@@ -253,10 +253,12 @@ pub struct ConsensusStakeUpdateV1 {
|
||||
|
||||
/// Parameters for `Consensus::UnstakeRequest`
|
||||
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
|
||||
// ANCHOR: ConsensusUnstakeReqParams
|
||||
pub struct ConsensusUnstakeReqParamsV1 {
|
||||
pub input: ConsensusInput,
|
||||
pub output: ConsensusOutput,
|
||||
}
|
||||
// ANCHOR_END: ConsensusUnstakeReqParams
|
||||
|
||||
/// Parameters for `Consensus::Unstake`
|
||||
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
|
||||
|
||||
Reference in New Issue
Block a user