Преглед изворни кода

consensus: proposal eta and sigmas validation against checkpoints impl

aggstam пре 3 година
родитељ
комит
b0bdc6b633
4 измењених фајлова са 92 додато и 62 уклоњено
  1. 19 6
      src/consensus/lead_info.rs
  2. 4 0
      src/consensus/leadcoin.rs
  3. 60 53
      src/consensus/validator.rs
  4. 9 3
      src/error.rs

+ 19 - 6
src/consensus/lead_info.rs

@@ -39,8 +39,10 @@ pub struct LeadInfo {
     pub public_key: PublicKey, // TODO: remove this(to be derived by proof)
     /// Block producer slot competing coins public inputs
     pub public_inputs: Vec<pallas::Base>,
-    /// Response of global random oracle, or it's emulation.
-    pub eta: [u8; 32],
+    /// Leader coin creation slot
+    pub coin_slot: u64,
+    /// Leader coin creation eta
+    pub coin_eta: pallas::Base,
     /// Leader NIZK proof
     pub proof: LeadProof,
     /// Slot offset block producer used
@@ -55,11 +57,21 @@ impl Default for LeadInfo {
         let keypair = Keypair::default();
         let signature = Signature::dummy();
         let public_inputs = vec![];
-        let eta: [u8; 32] = *blake3::hash(b"let there be dark!").as_bytes();
+        let coin_slot = 0;
+        let coin_eta = pallas::Base::zero();
         let proof = LeadProof::default();
         let offset = 0;
         let leaders = 0;
-        Self { signature, public_key: keypair.public, public_inputs, eta, proof, offset, leaders }
+        Self {
+            signature,
+            public_key: keypair.public,
+            public_inputs,
+            coin_slot,
+            coin_eta,
+            proof,
+            offset,
+            leaders,
+        }
     }
 }
 
@@ -68,12 +80,13 @@ impl LeadInfo {
         signature: Signature,
         public_key: PublicKey,
         public_inputs: Vec<pallas::Base>,
-        eta: [u8; 32],
+        coin_slot: u64,
+        coin_eta: pallas::Base,
         proof: LeadProof,
         offset: u64,
         leaders: u64,
     ) -> Self {
-        Self { signature, public_key, public_inputs, eta, proof, offset, leaders }
+        Self { signature, public_key, public_inputs, coin_slot, coin_eta, proof, offset, leaders }
     }
 }
 

+ 4 - 0
src/consensus/leadcoin.rs

@@ -92,6 +92,8 @@ pub struct LeadCoin {
     pub secret_key: SecretKey,
     /// eta
     pub eta: pallas::Base,
+    /// slot
+    pub slot: u64,
 }
 
 impl LeadCoin {
@@ -170,6 +172,7 @@ impl LeadCoin {
             rho_mu,
             secret_key,
             eta,
+            slot: slot_index,
         }
     }
 
@@ -351,6 +354,7 @@ impl LeadCoin {
             rho_mu: self.rho_mu,
             secret_key: self.secret_key,
             eta: self.eta,
+            slot: self.slot,
         }
     }
 

+ 60 - 53
src/consensus/validator.rs

@@ -656,9 +656,9 @@ impl ValidatorState {
         let lead_info = LeadInfo::new(
             signed_proposal,
             public_key,
-            //coin.public_inputs(sigma1, sigma2),
             public_inputs,
-            coin.eta.to_repr(),
+            coin.slot,
+            coin.eta,
             LeadProof::from(proof?),
             self.get_current_offset(slot),
             self.consensus.leaders_history.last().unwrap().clone(),
@@ -751,9 +751,21 @@ impl ValidatorState {
             return Err(Error::ProposalAfterFinalizationError)
         }
 
+        // Proposal validations
         let lf = &proposal.block.lead_info;
         let hdr = &proposal.block.header;
 
+        // Ignore proposal if not for current slot
+        if hdr.slot != current {
+            return Err(Error::ProposalNotForCurrentSlotError)
+        }
+
+        // Check if proposal extends any existing fork chains
+        let index = self.find_extended_chain_index(proposal)?;
+        if index == -2 {
+            return Err(Error::ExtendedChainIndexNotFound)
+        }
+
         // Verify proposal signature is valid based on producer public key
         // TODO: derive public key from proof
         if !lf.public_key.verify(proposal.header.as_bytes(), &lf.signature) {
@@ -798,58 +810,51 @@ impl ValidatorState {
         };
         info!("receive_proposal(): Leader proof verified successfully!");
 
-        let proposed_slot = proposal.block.header.slot;
-        info!("proposed slot: {}", proposed_slot);
-        let block_len = self.blockchain.len() as u64;
-        info!("block length: {}", block_len);
-        let offset = current - block_len;
-        info!("offset: {}", offset);
-        //TODO: subtract eta slot index from empty slots since restarting the network.
-        //let mut slot_eta = self.get_eta_by_slot(proposed_slot.clone()-offset-1);
-
-        /*
-            let slot_eta = self.get_eta();
-            // Verify proposal public values
-            let (mu_y, mu_rho) =
-                LeadCoin::election_seeds_u64(slot_eta, proposed_slot);
-            // y
-            let prop_mu_y = lf.public_inputs[constants::PI_MU_Y_INDEX];
-            if mu_y != prop_mu_y {
-                error!(
-                    "receive_proposal(): Failed to verify mu_y: {:?}, proposed: {:?}",
-                    mu_y, prop_mu_y
-                );
-                return Err(Error::ProposalPublicValuesMismatched)
-            }
-            // rho
-            let prop_mu_rho = lf.public_inputs[constants::PI_MU_RHO_INDEX];
-            if mu_rho != prop_mu_rho {
-                error!(
-                    "receive_proposal(): Failed to verify mu_rho: {:?}, proposed: {:?}",
-                    mu_rho, prop_mu_rho
-                );
-                return Err(Error::ProposalPublicValuesMismatched)
+        // Validate proposal public value against coin creation slot checkpoint
+        let checkpoint = self.get_slot_checkpoint(lf.coin_slot)?;
+        if checkpoint.eta != lf.coin_eta {
+            return Err(Error::ProposalDifferentCoinEtaError)
+        }
+        let (mu_y, mu_rho) = LeadCoin::election_seeds_u64(checkpoint.eta, checkpoint.slot);
+        // y
+        let prop_mu_y = lf.public_inputs[constants::PI_MU_Y_INDEX];
+        if mu_y != prop_mu_y {
+            error!(
+                "receive_proposal(): Failed to verify mu_y: {:?}, proposed: {:?}",
+                mu_y, prop_mu_y
+            );
+            return Err(Error::ProposalPublicValuesMismatched)
+        }
+        // rho
+        let prop_mu_rho = lf.public_inputs[constants::PI_MU_RHO_INDEX];
+        if mu_rho != prop_mu_rho {
+            error!(
+                "receive_proposal(): Failed to verify mu_rho: {:?}, proposed: {:?}",
+                mu_rho, prop_mu_rho
+            );
+            return Err(Error::ProposalPublicValuesMismatched)
         }
-            */
 
+        // Validate proposal coin sigmas against current slot checkpoint
+        let checkpoint = self.get_slot_checkpoint(current)?;
         // sigma1
         let prop_sigma1 = lf.public_inputs[constants::PI_SIGMA1_INDEX];
-        if self.consensus.prev_sigma1 != prop_sigma1 {
+        if checkpoint.sigma1 != prop_sigma1 {
             error!(
                 "receive_proposal(): Failed to verify public value sigma1: {:?}, to proposed: {:?}",
-                self.consensus.prev_sigma1, prop_sigma1
+                checkpoint.sigma1, prop_sigma1
             );
         }
         // sigma2
         let prop_sigma2 = lf.public_inputs[constants::PI_SIGMA2_INDEX];
-        if self.consensus.prev_sigma2 != prop_sigma2 {
+        if checkpoint.sigma2 != prop_sigma2 {
             error!(
                 "receive_proposal(): Failed to verify public value sigma2: {:?}, to proposed: {:?}",
-                self.consensus.prev_sigma2, prop_sigma2
+                checkpoint.sigma2, prop_sigma2
             );
         }
 
-        // sn
+        // TODO: Check if proposal coin nullifiers already exist
         let prop_sn = lf.public_inputs[constants::PI_NULLIFIER_INDEX];
         /*
         for sn in &self.consensus.leaders_nullifiers {
@@ -859,16 +864,18 @@ impl ValidatorState {
             }
         }
         */
-        // cm
 
+        // TODO: Check if proposal coin commitments already spent
         let prop_cm_x: pallas::Base = lf.public_inputs[constants::PI_COMMITMENT_X_INDEX];
         let prop_cm_y: pallas::Base = lf.public_inputs[constants::PI_COMMITMENT_Y_INDEX];
-
-        // Check if proposal extends any existing fork chains
-        let index = self.find_extended_chain_index(proposal)?;
-        if index == -2 {
-            return Err(Error::ExtendedChainIndexNotFound)
+        /*
+        for cm in &self.consensus.leaders_spent_coins {
+            if *cm == (prop_cm_x, prop_cm_y) {
+                error!("receive_proposal(): Proposal coin already spent.");
+                return Err(Error::ProposalIsSpent)
+            }
         }
+        */
 
         // Validate state transition against canonical state
         // TODO: This should be validated against fork state
@@ -1158,7 +1165,13 @@ impl ValidatorState {
     }
 
     /// Auxillary function to retrieve slot checkpoint of provided slot UID.
-    fn get_slot_checkpoin(&self, slot: u64) -> Result<SlotCheckpoint> {
+    fn get_slot_checkpoint(&self, slot: u64) -> Result<SlotCheckpoint> {
+        // Check hot/live slot checkpoints
+        for slot_checkpoint in self.consensus.slot_checkpoints.iter().rev() {
+            if slot_checkpoint.slot == slot {
+                return Ok(slot_checkpoint.clone())
+            }
+        }
         // Check if slot is finalized
         if let Ok(slot_checkpoints) = self.blockchain.get_slot_checkpoints_by_slot(&[slot]) {
             if slot_checkpoints.len() > 0 {
@@ -1167,13 +1180,7 @@ impl ValidatorState {
                 }
             }
         }
-        // Check hot/live slot checkpoints
-        for slot_checkpoint in self.consensus.slot_checkpoints.iter().rev() {
-            if slot_checkpoint.slot == slot {
-                return Ok(slot_checkpoint.clone())
-            }
-        }
-        Err(Error::UnknownSlotCheckpointError)
+        Err(Error::SlotCheckpointNotFound(slot))
     }
 
     // ==========================

+ 9 - 3
src/error.rs

@@ -241,6 +241,9 @@ pub enum Error {
     #[error("Proposal received after finalization sync period")]
     ProposalAfterFinalizationError,
 
+    #[error("Proposal received not for current slot")]
+    ProposalNotForCurrentSlotError,
+
     #[error("Proposal contains missmatched hashes")]
     ProposalHashesMissmatchError,
 
@@ -250,12 +253,12 @@ pub enum Error {
     #[error("Proposal contains different offset")]
     ProposalDifferentOffsetError,
 
+    #[error("Proposal contains different coin creation eta")]
+    ProposalDifferentCoinEtaError,
+
     #[error("proposed coin is spent")]
     ProposalIsSpent,
 
-    #[error("Slot checkpoint doesn't exist")]
-    UnknownSlotCheckpointError,
-
     #[error("unable to verify transfer transaction")]
     TransferTxVerification,
 
@@ -284,6 +287,9 @@ pub enum Error {
     #[error("Block in slot {0} not found in database")]
     SlotNotFound(u64),
 
+    #[error("Slot checkpoint {0} not found in database")]
+    SlotCheckpointNotFound(u64),
+
     #[error("Contract {0} not found in database")]
     ContractNotFound(String),