Просмотр исходного кода

consensus: use slot checkpoint coins for leader lottery

aggstam 3 лет назад
Родитель
Сommit
611028d3e6
3 измененных файлов с 34 добавлено и 26 удалено
  1. 18 15
      src/consensus/state.rs
  2. 8 3
      src/consensus/task/proposal.rs
  3. 8 8
      src/consensus/validator.rs

+ 18 - 15
src/consensus/state.rs

@@ -492,12 +492,22 @@ impl ConsensusState {
     /// coin is selected, since the stakeholder can't give more than one proof per block/slot.
     /// * 'sigma1', 'sigma2': slot sigmas
     /// Returns: (check: bool, idx: usize) where idx is the winning coin's index
-    pub fn is_slot_leader(&mut self, sigma1: pallas::Base, sigma2: pallas::Base) -> (bool, usize) {
+    pub fn is_slot_leader(
+        &mut self,
+        sigma1: pallas::Base,
+        sigma2: pallas::Base,
+    ) -> (bool, i64, usize) {
         // Check if node can produce proposals
         if !self.proposing {
-            return (false, 0)
+            return (false, 0, 0)
         }
-        let competing_coins = &self.coins.clone();
+
+        let fork_index = self.longest_chain_index();
+        let competing_coins = if fork_index == -1 {
+            self.coins.clone()
+        } else {
+            self.forks[fork_index as usize].sequence.last().unwrap().coins.clone()
+        };
 
         let mut won = false;
         let mut highest_stake = 0;
@@ -519,32 +529,25 @@ impl ConsensusState {
             }
         }
 
-        (won, highest_stake_idx)
+        (won, fork_index, highest_stake_idx)
     }
 
-    /// Finds the longest blockchain the node holds and
-    /// returns the last block hash and the chain index.
-    pub fn longest_chain_last_hash(&self) -> Result<(blake3::Hash, i64)> {
-        let mut longest: Option<Fork> = None;
+    /// Finds the longest forkchain the node holds and
+    /// returns its index.
+    pub fn longest_chain_index(&self) -> i64 {
         let mut length = 0;
         let mut index = -1;
 
         if !self.forks.is_empty() {
             for (i, chain) in self.forks.iter().enumerate() {
                 if chain.sequence.len() > length {
-                    longest = Some(chain.clone());
                     length = chain.sequence.len();
                     index = i as i64;
                 }
             }
         }
 
-        let hash = match longest {
-            Some(chain) => chain.sequence.last().unwrap().proposal.hash,
-            None => self.blockchain.last()?.1,
-        };
-
-        Ok((hash, index))
+        index
     }
 
     /// Finds the length of longest fork chain the node holds.

+ 8 - 3
src/consensus/task/proposal.rs

@@ -200,8 +200,13 @@ async fn propose_period(consensus_p2p: P2pPtr, state: ValidatorStatePtr) -> bool
 
     // Node checks if it's the slot leader to generate a new proposal
     // for that slot.
-    let (won, idx) = state.write().await.consensus.is_slot_leader(sigma1, sigma2);
-    let result = if won { state.write().await.propose(idx, sigma1, sigma2) } else { Ok(None) };
+    let (won, fork_index, coin_index) =
+        state.write().await.consensus.is_slot_leader(sigma1, sigma2);
+    let result = if won {
+        state.write().await.propose(processing_slot, fork_index, coin_index, sigma1, sigma2)
+    } else {
+        Ok(None)
+    };
     let (proposal, coin) = match result {
         Ok(pair) => {
             if pair.is_none() {
@@ -229,7 +234,7 @@ async fn propose_period(consensus_p2p: P2pPtr, state: ValidatorStatePtr) -> bool
     // Node stores the proposal and broadcast to rest nodes
     info!("consensus: Node is the slot leader: Proposed block: {}", proposal);
     debug!("consensus: Full proposal: {:?}", proposal);
-    match state.write().await.receive_proposal(&proposal, Some((idx, coin))).await {
+    match state.write().await.receive_proposal(&proposal, Some((coin_index, coin))).await {
         Ok(_) => {
             // Here we don't have to check to broadcast, because the flag
             // will always be true, since the node is able to produce proposals

+ 8 - 8
src/consensus/validator.rs

@@ -261,7 +261,9 @@ impl ValidatorState {
     /// chain the node is holding.
     pub fn propose(
         &mut self,
-        idx: usize,
+        slot: u64,
+        fork_index: i64,
+        coin_index: usize,
         sigma1: pallas::Base,
         sigma2: pallas::Base,
     ) -> Result<Option<(BlockProposal, LeadCoin)>> {
@@ -271,10 +273,7 @@ impl ValidatorState {
         }
 
         // Generate proposal
-        let slot = self.consensus.current_slot();
-        let (prev_hash, index) = self.consensus.longest_chain_last_hash().unwrap();
-        let unproposed_txs = self.unproposed_txs(index);
-
+        let unproposed_txs = self.unproposed_txs(fork_index);
         let mut tree = BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(100);
         // The following is pretty weird, so something better should be done.
         for tx in &unproposed_txs {
@@ -285,10 +284,11 @@ impl ValidatorState {
         let root = tree.root(0).unwrap();
 
         // Checking if extending a fork or canonical
-        let coin = if index == -1 {
-            self.consensus.coins[idx]
+        let (prev_hash, coin) = if fork_index == -1 {
+            (self.blockchain.last()?.1, self.consensus.coins[coin_index])
         } else {
-            self.consensus.forks[index as usize].sequence.last().unwrap().coins[idx]
+            let checkpoint = self.consensus.forks[fork_index as usize].sequence.last().unwrap();
+            (checkpoint.proposal.hash, checkpoint.coins[coin_index])
         };
 
         // Generating leader proof