Explorar el Código

contract/consensus: decoupled GenesisStakeV1 from StakeV1

aggstam hace 2 años
padre
commit
91e2b0b916

+ 1 - 1
doc/src/architecture/consensus/genesis_stake.md

@@ -54,7 +54,7 @@ perform the state transition. We enforce that:
 If these checks pass, we create a state update with the output coin:
 
 ```rust,no_run,no_playground
-{{#include ../../../../src/contract/money/src/model.rs:ConsensusStakeUpdate}}
+{{#include ../../../../src/contract/consensus/src/model.rs:ConsensusGenesisStakeUpdate}}
 ```
 
 ### [`process_update()`](https://github.com/darkrenaissance/darkfi/blob/master/src/contract/consensus/src/entrypoint/stake_v1.rs#L176)

+ 7 - 4
src/contract/consensus/src/entrypoint.rs

@@ -34,12 +34,16 @@ use darkfi_sdk::{
 };
 use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
 
-use crate::{model::ConsensusProposalUpdateV1, ConsensusFunction};
+use crate::{
+    model::{ConsensusGenesisStakeUpdateV1, ConsensusProposalUpdateV1},
+    ConsensusFunction,
+};
 
 /// `Consensus::GenesisStake` functions
 mod genesis_stake_v1;
 use genesis_stake_v1::{
     consensus_genesis_stake_get_metadata_v1, consensus_genesis_stake_process_instruction_v1,
+    consensus_genesis_stake_process_update_v1,
 };
 
 /// `Consensus::Stake` functions
@@ -248,9 +252,8 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
 fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
     match ConsensusFunction::try_from(update_data[0])? {
         ConsensusFunction::GenesisStakeV1 => {
-            // GenesisStake uses the same update as normal Stake
-            let update: ConsensusStakeUpdateV1 = deserialize(&update_data[1..])?;
-            Ok(consensus_stake_process_update_v1(cid, update)?)
+            let update: ConsensusGenesisStakeUpdateV1 = deserialize(&update_data[1..])?;
+            Ok(consensus_genesis_stake_process_update_v1(cid, update)?)
         }
         ConsensusFunction::StakeV1 => {
             let update: ConsensusStakeUpdateV1 = deserialize(&update_data[1..])?;

+ 47 - 13
src/contract/consensus/src/entrypoint/genesis_stake_v1.rs

@@ -17,21 +17,26 @@
  */
 
 use darkfi_money_contract::{
-    error::MoneyError, model::ConsensusStakeUpdateV1, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
-    CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE, CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
+    error::MoneyError, CONSENSUS_CONTRACT_INFO_TREE, CONSENSUS_CONTRACT_STAKED_COINS_TREE,
+    CONSENSUS_CONTRACT_STAKED_COIN_LATEST_COIN_ROOT, CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE,
+    CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE, CONSENSUS_CONTRACT_UNSTAKED_COINS_TREE,
+    CONSENSUS_CONTRACT_ZKAS_MINT_NS_V1,
 };
 use darkfi_sdk::{
-    crypto::{pasta_prelude::*, pedersen_commitment_u64, ContractId, DARK_TOKEN_ID},
-    db::{db_contains_key, db_lookup},
-    error::ContractError,
-    msg,
+    crypto::{pasta_prelude::*, pedersen_commitment_u64, ContractId, MerkleNode, DARK_TOKEN_ID},
+    db::{db_contains_key, db_lookup, db_set},
+    error::{ContractError, ContractResult},
+    merkle_add, msg,
     pasta::pallas,
     util::get_verifying_slot,
     ContractCall,
 };
 use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
 
-use crate::{model::ConsensusGenesisStakeParamsV1, ConsensusFunction};
+use crate::{
+    model::{ConsensusGenesisStakeParamsV1, ConsensusGenesisStakeUpdateV1},
+    ConsensusFunction,
+};
 
 /// `get_metadata` function for `Consensus::GenesisStakeV1`
 ///
@@ -82,13 +87,16 @@ pub(crate) fn consensus_genesis_stake_process_instruction_v1(
     // Verify this contract call is verified on the genesis slot (0).
     let verifying_slot = get_verifying_slot();
     if verifying_slot != 0 {
-        msg!("[GenesisStakeV1] Error: Call is executed for slot {}, not genesis", verifying_slot);
+        msg!(
+            "[ConsensusGenesisStakeV1] Error: Call is executed for slot {}, not genesis",
+            verifying_slot
+        );
         return Err(MoneyError::GenesisCallNonGenesisSlot.into())
     }
 
     // Only DARK_TOKEN_ID can be minted and staked on genesis slot.
     if params.input.token_id != *DARK_TOKEN_ID {
-        msg!("[GenesisStakeV1] Error: Clear input used non-native token");
+        msg!("[ConsensusGenesisStakeV1] Error: Clear input used non-native token");
         return Err(MoneyError::TransferClearInputNonNativeToken.into())
     }
 
@@ -100,13 +108,13 @@ pub(crate) fn consensus_genesis_stake_process_instruction_v1(
     // Check that the coin from the output hasn't existed before.
     let coin = serialize(&params.output.coin);
     if db_contains_key(staked_coins_db, &coin)? {
-        msg!("[GenesisStakeV1] Error: Output coin was already seen in the set of staked coins");
+        msg!("[ConsensusGenesisStakeV1] Error: Output coin was already seen in the set of staked coins");
         return Err(MoneyError::DuplicateCoin.into())
     }
 
     // Check that the coin from the output hasn't existed before in unstake set.
     if db_contains_key(unstaked_coins_db, &coin)? {
-        msg!("[GenesisStakeV1] Error: Output coin was already seen in the set of unstaked coins");
+        msg!("[ConsensusGenesisStakeV1] Error: Output coin was already seen in the set of unstaked coins");
         return Err(MoneyError::DuplicateCoin.into())
     }
 
@@ -115,15 +123,41 @@ pub(crate) fn consensus_genesis_stake_process_instruction_v1(
     if pedersen_commitment_u64(params.input.value, params.input.value_blind) !=
         params.output.value_commit
     {
-        msg!("[GenesisStakeV1] Error: Value commitment mismatch");
+        msg!("[ConsensusGenesisStakeV1] Error: Value commitment mismatch");
         return Err(MoneyError::ValueMismatch.into())
     }
 
     // Create a state update.
-    let update = ConsensusStakeUpdateV1 { coin: params.output.coin };
+    let update = ConsensusGenesisStakeUpdateV1 { coin: params.output.coin };
     let mut update_data = vec![];
     update_data.write_u8(ConsensusFunction::StakeV1 as u8)?;
     update.encode(&mut update_data)?;
 
     Ok(update_data)
 }
+
+/// `process_update` function for `Consensus::GenesisStakeV1`
+pub(crate) fn consensus_genesis_stake_process_update_v1(
+    cid: ContractId,
+    update: ConsensusGenesisStakeUpdateV1,
+) -> ContractResult {
+    // Grab all necessary db handles for where we want to write
+    let info_db = db_lookup(cid, CONSENSUS_CONTRACT_INFO_TREE)?;
+    let staked_coins_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COINS_TREE)?;
+    let staked_coin_roots_db = db_lookup(cid, CONSENSUS_CONTRACT_STAKED_COIN_ROOTS_TREE)?;
+
+    msg!("[ConsensusGenesisStakeV1] Adding new coin to the set");
+    db_set(staked_coins_db, &serialize(&update.coin), &[])?;
+
+    msg!("[ConsensusGenesisStakeV1] Adding new coin to the Merkle tree");
+    let coins: Vec<_> = vec![MerkleNode::from(update.coin.inner())];
+    merkle_add(
+        info_db,
+        staked_coin_roots_db,
+        &serialize(&CONSENSUS_CONTRACT_STAKED_COIN_LATEST_COIN_ROOT),
+        &serialize(&CONSENSUS_CONTRACT_STAKED_COIN_MERKLE_TREE),
+        &coins,
+    )?;
+
+    Ok(())
+}

+ 9 - 0
src/contract/consensus/src/model.rs

@@ -37,6 +37,15 @@ pub struct ConsensusGenesisStakeParamsV1 {
 }
 // ANCHOR_END: ConsensusGenesisStakeParams
 
+/// State update for `Consensus::GenesisStake`
+#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
+// ANCHOR: ConsensusGenesisStakeUpdate
+pub struct ConsensusGenesisStakeUpdateV1 {
+    /// The newly minted coin
+    pub coin: Coin,
+}
+// ANCHOR_END: ConsensusGenesisStakeUpdate
+
 /// Parameters for `Consensus::Proposal`
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 // ANCHOR: ConsensusProposalParams