Forráskód Böngészése

[ouroboros] support multiple competing coins per slot

mohab metwally 3 éve
szülő
commit
d92ed5f2b8

+ 4 - 0
db/conf

@@ -0,0 +1,4 @@
+segment_size: 524288
+use_compression: false
+version: 0.34
+vQÁ


+ 8 - 9
src/consensus/ouroboros/epoch.rs

@@ -1,8 +1,9 @@
 use crate::{
     consensus::ouroboros::{
         consts::{LOTTERY_HEAD_START, RADIX_BITS},
-        utils::{base2ibig, fbig2ibig},
-        EpochConsensus, Float10,
+        utils::{fbig2ibig},
+        types::{Float10},
+        EpochConsensus,
     },
     crypto::{
         coin::OwnCoin,
@@ -285,9 +286,9 @@ impl Epoch {
     /// only the highest values coin is selected, since the stakeholder can't give more
     /// than a proof per block.
     /// * `sl` - slot relative index
-    /// * `idx` - index of the winning coin
+    /// * `idx` - index of the highest winning coin
     /// returns true if the stakeholder is a leader for the current slot, else otherwise
-    pub fn is_leader(&self, sl: u64, idx: &mut usize) -> bool {
+    pub fn is_leader(&self, sl: u64, idx: &mut usize) -> Vec<bool> {
         let slusize = sl as usize;
         info!("slot: {}, coin len: {}", sl, self.coins.len());
         assert!(slusize < self.coins.len());
@@ -298,9 +299,7 @@ impl Epoch {
         for (winning_idx, coin) in competing_coins.iter().enumerate() {
             let y_exp = [coin.root_sk.unwrap(), coin.nonce.unwrap()];
             let y_exp_hash: pallas::Base =
-                poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<2>, 3, 2>::init(
-                )
-                .hash(y_exp);
+                poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<2>, 3, 2>::init().hash(y_exp);
             let y_coordinates = pedersen_commitment_base(coin.y_mu.unwrap(), mod_r_p(y_exp_hash))
                 .to_affine()
                 .coordinates()
@@ -325,11 +324,11 @@ impl Epoch {
                     highest_stake = coin.value.unwrap();
                     highest_stake_idx = winning_idx;
                 }
-                am_leader.push(iam_leader);
             }
+            am_leader.push(iam_leader);
         }
         *idx = highest_stake_idx;
-        !am_leader.is_empty()
+        am_leader
     }
 
     /// * `sl` - relative slot index (zero based)

+ 22 - 21
src/consensus/ouroboros/stakeholder.rs

@@ -274,7 +274,7 @@ impl Stakeholder {
                     // slot is about to end.
                     // sync, and validate.
                     // no more transactions to be received/send to the end of slot.
-                    if self.workspace.is_leader {
+                    if self.workspace.has_leader() {
                         info!(target: LOG_T, "[leadership won]");
                         //craete block
                         let (block_info, _block_hash) = self.workspace.new_block();
@@ -373,26 +373,27 @@ impl Stakeholder {
         self.workspace.set_e(e);
         self.workspace.set_st(st);
         let mut winning_coin_idx: usize = 0;
-        let won = self.epoch.is_leader(sl, &mut winning_coin_idx);
-        let proof = if won {
-            self.epoch.get_proof(sl, winning_coin_idx, &self.get_leadprovkingkey())
-        } else {
-            Proof::new(vec![])
-        };
-        self.workspace.set_leader(won);
-        self.workspace.set_proof(proof.clone());
-
-        let coin = self.epoch.get_coin(sl as usize, winning_coin_idx as usize);
-        let keypair = coin.keypair.unwrap();
-        let addr = Address::from(keypair.public);
-        let sign = keypair.secret.sign(proof.as_ref());
-        let meta =
-            Metadata::new(sign, addr, self.get_eta().to_repr(), LeadProof::from(proof), vec![]);
-        self.workspace.set_metadata(meta);
-        if won {
-            let owned_coin =
-                self.finalize_coin(&self.epoch.get_coin(sl as usize, winning_coin_idx as usize));
-            self.ownedcoins.push(owned_coin);
+        let won : Vec<bool> = self.epoch.is_leader(sl, &mut winning_coin_idx);
+        for i in 0..won.len() {
+            let proof = if won[i] {
+                self.epoch.get_proof(sl, i, &self.get_leadprovkingkey())
+            } else {
+                Proof::new(vec![])
+            };
+            self.workspace.add_leader(won[i]);
+            self.workspace.set_idx(winning_coin_idx);
+            let coin = self.epoch.get_coin(sl as usize, i);
+            let keypair = coin.keypair.unwrap();
+            let addr = Address::from(keypair.public);
+            let sign = keypair.secret.sign(proof.as_ref());
+            let meta =
+                Metadata::new(sign, addr, self.get_eta().to_repr(), LeadProof::from(proof), vec![]);
+            self.workspace.add_metadata(meta);
+            if won[i] {
+                let owned_coin =
+                    self.finalize_coin(&self.epoch.get_coin(sl as usize, winning_coin_idx as usize));
+                self.ownedcoins.push(owned_coin);
+            }
         }
     }
 

+ 28 - 13
src/consensus/ouroboros/workspace.rs

@@ -16,10 +16,10 @@ pub struct SlotWorkspace {
     pub txs: Vec<Transaction>, // unpublished block transactions
     pub root: MerkleNode,
     /// merkle root of txs
-    pub m: Metadata,
-    pub is_leader: bool,
-    pub proof: Proof,
+    pub m: Vec<Metadata>,
+    pub is_leader: Vec<bool>,
     pub block: BlockInfo,
+    pub idx: usize, // index of the highest winning coin
 }
 
 impl Default for SlotWorkspace {
@@ -30,22 +30,32 @@ impl Default for SlotWorkspace {
             sl: 0,
             txs: vec![],
             root: MerkleNode::from(pallas::Base::zero()),
-            is_leader: false,
-            m: Metadata::default(),
-            proof: Proof::default(),
+            is_leader: vec![],
+            m: vec![],
             block: BlockInfo::default(),
+            idx: 0,
         }
     }
 }
 
 impl SlotWorkspace {
+    /// create new block from the workspace
+    /// if there are multiple winning coins (owned by the same stakeholder)
+    /// then pick the highest winning coin.
+    /// returns tuple of blockinfo, hash of that block
     pub fn new_block(&self) -> (BlockInfo, blake3::Hash) {
         let header = Header::new(self.st, self.e, self.sl, Timestamp::current_time(), self.root);
-        let block = BlockInfo::new(header, self.txs.clone(), self.m.clone());
+        let block = BlockInfo::new(header, self.txs.clone(), self.m[self.idx].clone());
         let hash = block.blockhash();
         (block, hash)
     }
 
+    // each opoch research the worksapce
+    fn reset(&mut self) {
+        self.is_leader = vec![];
+        self.m = vec![];
+    }
+
     pub fn add_tx(&mut self, tx: Transaction) {
         self.txs.push(tx);
     }
@@ -54,12 +64,13 @@ impl SlotWorkspace {
         self.root = root;
     }
 
-    pub fn set_metadata(&mut self, meta: Metadata) {
-        self.m = meta;
+    pub fn add_metadata(&mut self, meta: Metadata) {
+        self.m.push(meta);
     }
 
     pub fn set_sl(&mut self, sl: u64) {
         self.sl = sl;
+        self.reset();
     }
 
     pub fn set_st(&mut self, st: blake3::Hash) {
@@ -70,11 +81,15 @@ impl SlotWorkspace {
         self.e = e;
     }
 
-    pub fn set_proof(&mut self, proof: Proof) {
-        self.proof = proof;
+    pub fn add_leader(&mut self, alead: bool) {
+        self.is_leader.push(alead);
+    }
+
+    pub fn has_leader(&self) -> bool {
+        self.is_leader.iter().any(|&x| x)
     }
 
-    pub fn set_leader(&mut self, alead: bool) {
-        self.is_leader = alead;
+    pub fn set_idx(&mut self, idx: usize) {
+        self.idx = idx;
     }
 }