Sfoglia il codice sorgente

consensus/state/SlotCheckpoint: renamed eta to previous eta and introduced fork hashes vector

aggstam 3 anni fa
parent
commit
e436e6d069

+ 45 - 15
src/consensus/state.rs

@@ -156,11 +156,16 @@ impl ConsensusState {
     }
 
     /// Generate current slot checkpoint
-    fn generate_slot_checkpoint(&mut self, sigma1: pallas::Base, sigma2: pallas::Base) {
+    fn generate_slot_checkpoint(
+        &mut self,
+        fork_hashes: Vec<blake3::Hash>,
+        sigma1: pallas::Base,
+        sigma2: pallas::Base,
+    ) {
         let slot = self.time_keeper.current_slot();
-        let eta = self.get_eta();
-        info!(target: "consensus::state", "generate_slot_checkpoint: slot: {:?}, eta: {:?}", slot, eta);
-        let checkpoint = SlotCheckpoint { slot, eta, sigma1, sigma2 };
+        let previous_eta = self.get_previous_eta();
+        let checkpoint = SlotCheckpoint { slot, previous_eta, fork_hashes, sigma1, sigma2 };
+        info!(target: "consensus::state", "generate_slot_checkpoint: {:?}", checkpoint);
         self.slot_checkpoints.push(checkpoint);
     }
 
@@ -176,10 +181,11 @@ impl ConsensusState {
     /// Returns flag to signify if epoch has changed.
     pub async fn epoch_changed(
         &mut self,
+        fork_hashes: Vec<blake3::Hash>,
         sigma1: pallas::Base,
         sigma2: pallas::Base,
     ) -> Result<bool> {
-        self.generate_slot_checkpoint(sigma1, sigma2);
+        self.generate_slot_checkpoint(fork_hashes, sigma1, sigma2);
         let epoch = self.time_keeper.current_epoch();
         if epoch <= self.epoch {
             return Ok(false)
@@ -423,7 +429,7 @@ impl ConsensusState {
             let first_winning = coin.is_leader(
                 sigma1,
                 sigma2,
-                self.get_eta(),
+                self.get_previous_eta(),
                 pallas::Base::from(self.time_keeper.current_slot()),
             );
 
@@ -534,7 +540,7 @@ impl ConsensusState {
 
     /// Utility function to extract leader selection lottery randomness(eta),
     /// defined as the hash of the last block, converted to pallas base.
-    pub fn get_eta(&self) -> pallas::Base {
+    pub fn get_previous_eta(&self) -> pallas::Base {
         let (_, hash) = self.blockchain.last().unwrap();
         let mut bytes: [u8; 32] = *hash.as_bytes();
         // Read first 254 bits
@@ -584,6 +590,22 @@ impl ConsensusState {
         }
     }
 
+    /// Retrieve current forks last proposal hashes.
+    /// If node holds no fork, retrieve last canonical hash.
+    pub fn fork_hashes(&self) -> Vec<blake3::Hash> {
+        let mut hashes = vec![];
+        for fork in &self.forks {
+            hashes.push(fork.sequence.last().unwrap().proposal.hash);
+        }
+
+        if hashes.is_empty() {
+            let (_, hash) = self.blockchain.last().unwrap();
+            hashes.push(hash);
+        }
+
+        hashes
+    }
+
     /// Auxiliary structure to reset consensus state for a resync
     pub fn reset(&mut self) {
         self.participating = None;
@@ -668,10 +690,11 @@ impl net::Message for ConsensusSlotCheckpointsResponse {
 pub struct SlotCheckpoint {
     /// Slot UID
     pub slot: u64,
-    /// Slot eta
-    // TODO: this should be renamed to previous_eta,
-    //       corresponding to previous block eta.
-    pub eta: pallas::Base,
+    /// Previous slot eta
+    pub previous_eta: pallas::Base,
+    /// Previous slot forks last proposal/block hashes,
+    /// as observed by the validator
+    pub fork_hashes: Vec<blake3::Hash>,
     /// Slot sigma1
     pub sigma1: pallas::Base,
     /// Slot sigma2
@@ -679,17 +702,24 @@ pub struct SlotCheckpoint {
 }
 
 impl SlotCheckpoint {
-    pub fn new(slot: u64, eta: pallas::Base, sigma1: pallas::Base, sigma2: pallas::Base) -> Self {
-        Self { slot, eta, sigma1, sigma2 }
+    pub fn new(
+        slot: u64,
+        previous_eta: pallas::Base,
+        fork_hashes: Vec<blake3::Hash>,
+        sigma1: pallas::Base,
+        sigma2: pallas::Base,
+    ) -> Self {
+        Self { slot, previous_eta, fork_hashes, sigma1, sigma2 }
     }
 
     /// Generate the genesis slot checkpoint.
     pub fn genesis_slot_checkpoint() -> Self {
-        let eta = pallas::Base::zero();
+        let previous_eta = pallas::Base::zero();
+        let fork_hashes = vec![];
         let sigma1 = pallas::Base::zero();
         let sigma2 = pallas::Base::zero();
 
-        Self::new(0, eta, sigma1, sigma2)
+        Self::new(0, previous_eta, fork_hashes, sigma1, sigma2)
     }
 }
 

+ 5 - 1
src/consensus/task/proposal.rs

@@ -186,10 +186,14 @@ async fn propose_period(consensus_p2p: P2pPtr, state: ValidatorStatePtr) -> bool
     // Keep a record of slot to verify if next slot got skipped during processing
     let processing_slot = state.read().await.consensus.time_keeper.current_slot();
 
+    // Retrieve current forks last hash
+    let fork_hashes = state.read().await.consensus.fork_hashes();
+
     // Retrieve slot sigmas
     let (sigma1, sigma2) = state.write().await.consensus.sigmas();
     // Node checks if epoch has changed and generate slot checkpoint
-    let epoch_changed = state.write().await.consensus.epoch_changed(sigma1, sigma2).await;
+    let epoch_changed =
+        state.write().await.consensus.epoch_changed(fork_hashes, sigma1, sigma2).await;
     match epoch_changed {
         Ok(changed) => {
             if changed {

+ 2 - 2
src/consensus/validator.rs

@@ -362,7 +362,7 @@ impl ValidatorState {
         sigma1: pallas::Base,
         sigma2: pallas::Base,
     ) -> Result<Option<(BlockProposal, LeadCoin, pallas::Scalar)>> {
-        let eta = self.consensus.get_eta();
+        let eta = self.consensus.get_previous_eta();
         // Check if node can produce proposals
         if !self.consensus.proposing {
             return Ok(None)
@@ -576,7 +576,7 @@ impl ValidatorState {
 
             // Validate proposal public value against coin creation slot checkpoint
             let (mu_y, mu_rho) = LeadCoin::election_seeds_u64(
-                self.consensus.get_eta(),
+                self.consensus.get_previous_eta(),
                 self.consensus.time_keeper.current_slot(),
             );
             // y

+ 1 - 3
src/contract/consensus/src/client/proposal_v1.rs

@@ -278,10 +278,8 @@ pub fn create_proposal_proof(
 
     let slot_pallas = pallas::Base::from(slot_checkpoint.slot);
     let seed = poseidon_hash([SEED_PREFIX, input.note.serial]);
-    // NOTE: slot checkpoint eta to be renamed to previous_eta,
-    //       corresponding to previous block eta.
     let mut vrf_input = Vec::with_capacity(32 + 32);
-    vrf_input.extend_from_slice(&slot_checkpoint.eta.to_repr());
+    vrf_input.extend_from_slice(&slot_checkpoint.previous_eta.to_repr());
     vrf_input.extend_from_slice(&slot_pallas.to_repr());
     let vrf_proof = VrfProof::prove(input.secret, &vrf_input, &mut OsRng);
     let mut eta = [0u8; 64];

+ 1 - 3
src/contract/consensus/src/entrypoint/proposal_v1.rs

@@ -97,10 +97,8 @@ pub(crate) fn consensus_proposal_get_metadata_v1(
 
     // Verify eta VRF proof
     let slot_pallas = pallas::Base::from(slot_checkpoint.slot);
-    // NOTE: slot checkpoint eta to be renamed to previous_eta,
-    //       corresponding to previous block eta.
     let mut vrf_input = Vec::with_capacity(32 + 32);
-    vrf_input.extend_from_slice(&slot_checkpoint.eta.to_repr());
+    vrf_input.extend_from_slice(&slot_checkpoint.previous_eta.to_repr());
     vrf_input.extend_from_slice(&slot_pallas.to_repr());
     let vrf_proof = &params.vrf_proof;
     if !vrf_proof.verify(params.input.signature_public, &vrf_input) {

+ 5 - 2
src/contract/consensus/src/model.rs

@@ -113,8 +113,11 @@ pub const HEADSTART: pallas::Base = pallas::Base::from_raw([
 pub struct SlotCheckpoint {
     /// Slot UID
     pub slot: u64,
-    /// Slot eta
-    pub eta: pallas::Base,
+    /// Previous slot eta
+    pub previous_eta: pallas::Base,
+    /// Previous slot forks last proposal/block hashes,
+    /// as observed by the validator
+    pub fork_hashes: Vec<blake3::Hash>,
     /// Slot sigma1
     pub sigma1: pallas::Base,
     /// Slot sigma2

+ 4 - 1
src/contract/consensus/tests/harness.rs

@@ -850,10 +850,13 @@ impl ConsensusTestHarness {
     pub async fn generate_slot_checkpoint(&self, slot: u64) -> Result<SlotCheckpoint> {
         // We grab the genesis slot to generate slot checkpoint
         // using same consensus parameters
+        let faucet = self.holders.get(&Holder::Faucet).unwrap();
+        let fork_hashes = vec![faucet.state.read().await.consensus.genesis_block];
         let genesis_slot = self.get_slot_checkpoint_by_slot(0).await?;
         let slot_checkpoint = SlotCheckpoint {
             slot,
-            eta: genesis_slot.eta,
+            previous_eta: genesis_slot.previous_eta,
+            fork_hashes,
             sigma1: genesis_slot.sigma1,
             sigma2: genesis_slot.sigma2,
         };