Explorar el Código

validator/verification: proper genesis block validation

aggstam hace 3 años
padre
commit
5c5a6a2aca
Se han modificado 2 ficheros con 53 adiciones y 21 borrados
  1. 1 1
      src/sdk/src/blockchain.rs
  2. 52 20
      src/validator/verification.rs

+ 1 - 1
src/sdk/src/blockchain.rs

@@ -20,7 +20,7 @@ use darkfi_serial::{SerialDecodable, SerialEncodable};
 use pasta_curves::{group::ff::Field, pallas};
 
 /// Auxiliary structure used to keep track of slot validation parameters.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
+#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)]
 pub struct Slot {
     /// Slot UID
     pub id: u64,

+ 52 - 20
src/validator/verification.rs

@@ -19,6 +19,7 @@
 use std::{collections::HashMap, io::Cursor};
 
 use darkfi_sdk::{
+    blockchain::Slot,
     crypto::{PublicKey, CONSENSUS_CONTRACT_ID},
     pasta::pallas,
 };
@@ -35,6 +36,46 @@ use crate::{
     Error, Result,
 };
 
+/// Validate given genesis [`BlockInfo`], and apply it to the provided overlay
+async fn verify_genesis_block(block: &BlockInfo, block_hash: String) -> Result<()> {
+    // Check genesis slot exist
+    if block.slots.len() != 1 {
+        return Err(Error::BlockIsInvalid(block_hash))
+    }
+
+    // Retrieve genesis slot
+    let genesis_slot = block.slots.last().unwrap();
+
+    // Genesis slot must be the default one
+    if genesis_slot != &Slot::default() {
+        return Err(Error::SlotIsInvalid(genesis_slot.id))
+    }
+
+    // TODO:
+    // Genesis block slot total token must correspond to the total
+    // of all genesis transactions public inputs (genesis distribution).
+    // Retrieve genesis transactions total
+    //let txs_total = genesis_transactions_total(&block.txs);
+
+    // Verify amounts match
+    //if genesis_slot.total_tokens != txs_total {
+    //    return Err(Error::SlotIsInvalid(genesis_slot.id))
+    //}
+
+    // Verify there is not reward
+    if genesis_slot.reward != 0 {
+        return Err(Error::SlotIsInvalid(genesis_slot.id))
+    }
+
+    // Genesis transaction must be the Transaction::default() one (empty)
+    if block.producer.proposal != Transaction::default() {
+        error!(target: "validator", "Genesis proposal transaction is not default one");
+        return Err(TxVerifyFailed::ErroneousTxs(vec![block.producer.proposal.clone()]).into())
+    }
+
+    Ok(())
+}
+
 /// Validate given [`BlockInfo`], and apply it to the provided overlay
 pub async fn verify_block(
     overlay: &BlockchainOverlayPtr,
@@ -49,7 +90,7 @@ pub async fn verify_block(
 
     // Check if block already exists
     if overlay.lock().unwrap().has_block(block)? {
-        return Err(Error::BlockAlreadyExists(block.blockhash().to_string()))
+        return Err(Error::BlockAlreadyExists(block_hash.to_string()))
     }
 
     // Block slot must be the same as the time keeper verifying slot
@@ -57,20 +98,21 @@ pub async fn verify_block(
         return Err(Error::VerifyingSlotMissmatch())
     }
 
-    // TODO: on genesis block, verify slot.total_tokens = txs.total,
-    // thats our genesis distribution, and reward is 0
-
-    // Validate block using its previous, excluding genesis
-    if block.header.slot != 0 {
+    // Validate block
+    if block.header.slot == 0 {
+        // Validate genesis block
+        verify_genesis_block(block, block_hash.to_string()).await?;
+    } else {
+        // Validate normal block, using its previous
         if previous.is_none() {
             return Err(Error::BlockPreviousMissing())
         }
         block.validate(previous.unwrap(), expected_reward)?;
-    }
 
-    // Validate proposal transaction if not in testing mode
-    if !testing_mode {
-        verify_proposal_transaction(overlay, time_keeper, &block.producer.proposal).await?;
+        // Validate proposal transaction if not in testing mode
+        if !testing_mode {
+            verify_proposal_transaction(overlay, time_keeper, &block.producer.proposal).await?;
+        }
     }
 
     // Verify transactions
@@ -93,16 +135,6 @@ pub async fn verify_proposal_transaction(
     let tx_hash = tx.hash();
     debug!(target: "validator", "Validating proposal transaction {}", tx_hash);
 
-    // Genesis transaction must be the Transaction::default() one (empty)
-    if time_keeper.verifying_slot == 0 {
-        if *tx != Transaction::default() {
-            error!(target: "validator", "Genesis proposal transaction is not default one");
-            return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
-        }
-
-        return Ok(())
-    }
-
     // Transaction must contain a single Consensus::Proposal (0x02) call
     if tx.calls.len() != 1 ||
         (tx.calls[0].contract_id != *CONSENSUS_CONTRACT_ID && tx.calls[0].data[0] != 0x02)