|
@@ -16,11 +16,7 @@
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-use darkfi_sdk::{
|
|
|
|
|
- blockchain::{expected_reward, PidOutput, PreviousSlot, Slot, POS_START},
|
|
|
|
|
- crypto::SecretKey,
|
|
|
|
|
- pasta::{group::ff::PrimeField, pallas},
|
|
|
|
|
-};
|
|
|
|
|
|
|
+use darkfi_sdk::{crypto::SecretKey, pasta::pallas};
|
|
|
use darkfi_serial::{async_trait, serialize, SerialDecodable, SerialEncodable};
|
|
use darkfi_serial::{async_trait, serialize, SerialDecodable, SerialEncodable};
|
|
|
use log::{debug, error, info};
|
|
use log::{debug, error, info};
|
|
|
use num_bigint::BigUint;
|
|
use num_bigint::BigUint;
|
|
@@ -29,11 +25,10 @@ use smol::lock::RwLock;
|
|
|
use crate::{
|
|
use crate::{
|
|
|
blockchain::{BlockInfo, Blockchain, BlockchainOverlay, BlockchainOverlayPtr, Header},
|
|
blockchain::{BlockInfo, Blockchain, BlockchainOverlay, BlockchainOverlayPtr, Header},
|
|
|
tx::Transaction,
|
|
tx::Transaction,
|
|
|
- util::time::{TimeKeeper, Timestamp},
|
|
|
|
|
|
|
+ util::time::Timestamp,
|
|
|
validator::{
|
|
validator::{
|
|
|
- pid::slot_pid_output,
|
|
|
|
|
pow::PoWModule,
|
|
pow::PoWModule,
|
|
|
- utils::{best_forks_indexes, block_rank, find_extended_fork_index, previous_slot_info},
|
|
|
|
|
|
|
+ utils::{best_forks_indexes, block_rank, find_extended_fork_index},
|
|
|
verify_block, verify_proposal, verify_transactions, TxVerifyFailed,
|
|
verify_block, verify_proposal, verify_transactions, TxVerifyFailed,
|
|
|
},
|
|
},
|
|
|
Error, Result,
|
|
Error, Result,
|
|
@@ -47,131 +42,62 @@ pub const TXS_CAP: usize = 50;
|
|
|
pub struct Consensus {
|
|
pub struct Consensus {
|
|
|
/// Canonical (finalized) blockchain
|
|
/// Canonical (finalized) blockchain
|
|
|
pub blockchain: Blockchain,
|
|
pub blockchain: Blockchain,
|
|
|
- /// Helper structure to calculate time related operations
|
|
|
|
|
- pub time_keeper: TimeKeeper,
|
|
|
|
|
/// Fork size(length) after which it can be finalized
|
|
/// Fork size(length) after which it can be finalized
|
|
|
pub finalization_threshold: usize,
|
|
pub finalization_threshold: usize,
|
|
|
/// Node is participating to consensus
|
|
/// Node is participating to consensus
|
|
|
pub participating: bool,
|
|
pub participating: bool,
|
|
|
- /// Last slot node check for finalization
|
|
|
|
|
- pub checked_finalization: RwLock<u64>,
|
|
|
|
|
/// Fork chains containing block proposals
|
|
/// Fork chains containing block proposals
|
|
|
pub forks: RwLock<Vec<Fork>>,
|
|
pub forks: RwLock<Vec<Fork>>,
|
|
|
/// Canonical blockchain PoW module state
|
|
/// Canonical blockchain PoW module state
|
|
|
pub module: RwLock<PoWModule>,
|
|
pub module: RwLock<PoWModule>,
|
|
|
- /// Flag to enable PoS testing mode
|
|
|
|
|
- pub pos_testing_mode: bool,
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl Consensus {
|
|
impl Consensus {
|
|
|
/// Generate a new Consensus state.
|
|
/// Generate a new Consensus state.
|
|
|
pub fn new(
|
|
pub fn new(
|
|
|
blockchain: Blockchain,
|
|
blockchain: Blockchain,
|
|
|
- time_keeper: TimeKeeper,
|
|
|
|
|
finalization_threshold: usize,
|
|
finalization_threshold: usize,
|
|
|
pow_target: usize,
|
|
pow_target: usize,
|
|
|
pow_fixed_difficulty: Option<BigUint>,
|
|
pow_fixed_difficulty: Option<BigUint>,
|
|
|
- pos_testing_mode: bool,
|
|
|
|
|
) -> Result<Self> {
|
|
) -> Result<Self> {
|
|
|
let module =
|
|
let module =
|
|
|
RwLock::new(PoWModule::new(blockchain.clone(), pow_target, pow_fixed_difficulty)?);
|
|
RwLock::new(PoWModule::new(blockchain.clone(), pow_target, pow_fixed_difficulty)?);
|
|
|
Ok(Self {
|
|
Ok(Self {
|
|
|
blockchain,
|
|
blockchain,
|
|
|
- time_keeper,
|
|
|
|
|
finalization_threshold,
|
|
finalization_threshold,
|
|
|
participating: false,
|
|
participating: false,
|
|
|
- checked_finalization: RwLock::new(0),
|
|
|
|
|
forks: RwLock::new(vec![]),
|
|
forks: RwLock::new(vec![]),
|
|
|
module,
|
|
module,
|
|
|
- pos_testing_mode,
|
|
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Generate next hot/live PoW slot for all current forks.
|
|
|
|
|
- pub async fn generate_pow_slot(&self) -> Result<()> {
|
|
|
|
|
- // Grab a lock over current forks
|
|
|
|
|
- let mut forks = self.forks.write().await;
|
|
|
|
|
-
|
|
|
|
|
- // If no forks exist, create a new one as a basis to extend
|
|
|
|
|
- if forks.is_empty() {
|
|
|
|
|
- forks.push(Fork::new(&self.blockchain, self.module.read().await.clone()).await?);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- for fork in forks.iter_mut() {
|
|
|
|
|
- fork.generate_pow_slot()?;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Drop forks lock
|
|
|
|
|
- drop(forks);
|
|
|
|
|
-
|
|
|
|
|
- Ok(())
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Generate current hot/live PoS slot for all current forks.
|
|
|
|
|
- pub async fn generate_pos_slot(&self) -> Result<()> {
|
|
|
|
|
- // Grab a lock over current forks
|
|
|
|
|
- let mut forks = self.forks.write().await;
|
|
|
|
|
-
|
|
|
|
|
- // Grab current slot id
|
|
|
|
|
- let id = self.time_keeper.current_slot();
|
|
|
|
|
-
|
|
|
|
|
- // If no forks exist, create a new one as a basis to extend
|
|
|
|
|
- if forks.is_empty() {
|
|
|
|
|
- forks.push(Fork::new(&self.blockchain, self.module.read().await.clone()).await?);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Grab previous slot information
|
|
|
|
|
- let (producers, last_hashes, second_to_last_hashes) = previous_slot_info(&forks, id - 1)?;
|
|
|
|
|
-
|
|
|
|
|
- for fork in forks.iter_mut() {
|
|
|
|
|
- fork.generate_pos_slot(id, producers, &last_hashes, &second_to_last_hashes)?;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Drop forks lock
|
|
|
|
|
- drop(forks);
|
|
|
|
|
-
|
|
|
|
|
- Ok(())
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/// Generate an unsigned block for provided fork, containing all
|
|
/// Generate an unsigned block for provided fork, containing all
|
|
|
- /// pending transactions. This should only be called after generating
|
|
|
|
|
- /// next/current slot.
|
|
|
|
|
|
|
+ /// pending transactions.
|
|
|
pub async fn generate_unsigned_block(
|
|
pub async fn generate_unsigned_block(
|
|
|
&self,
|
|
&self,
|
|
|
fork: &Fork,
|
|
fork: &Fork,
|
|
|
producer_tx: Transaction,
|
|
producer_tx: Transaction,
|
|
|
) -> Result<BlockInfo> {
|
|
) -> Result<BlockInfo> {
|
|
|
- // Grab fork's last slot
|
|
|
|
|
- let slot = fork.slots.last().unwrap();
|
|
|
|
|
-
|
|
|
|
|
- // Generate a time keeper for next/current slot
|
|
|
|
|
- let time_keeper = if slot.id < POS_START {
|
|
|
|
|
- let mut t = self.time_keeper.current();
|
|
|
|
|
- t.verifying_block_height = slot.id;
|
|
|
|
|
- t
|
|
|
|
|
- } else {
|
|
|
|
|
- self.time_keeper.current()
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ // Grab forks' next block height
|
|
|
|
|
+ let next_block_height = fork.get_next_block_height()?;
|
|
|
|
|
|
|
|
// Grab forks' unproposed transactions
|
|
// Grab forks' unproposed transactions
|
|
|
- let mut unproposed_txs =
|
|
|
|
|
- fork.unproposed_txs(&self.blockchain, time_keeper.verifying_block_height).await?;
|
|
|
|
|
|
|
+ let mut unproposed_txs = fork.unproposed_txs(&self.blockchain, next_block_height).await?;
|
|
|
unproposed_txs.push(producer_tx);
|
|
unproposed_txs.push(producer_tx);
|
|
|
|
|
|
|
|
// Grab forks' last block proposal(previous)
|
|
// Grab forks' last block proposal(previous)
|
|
|
let previous = fork.last_proposal()?;
|
|
let previous = fork.last_proposal()?;
|
|
|
|
|
|
|
|
// Generate the new header
|
|
// Generate the new header
|
|
|
- // TODO: verify if header timestamp should be blockchain or system timestamp
|
|
|
|
|
let header = Header::new(
|
|
let header = Header::new(
|
|
|
previous.block.hash()?,
|
|
previous.block.hash()?,
|
|
|
- slot.id,
|
|
|
|
|
|
|
+ next_block_height,
|
|
|
Timestamp::current_time(),
|
|
Timestamp::current_time(),
|
|
|
- slot.last_nonce,
|
|
|
|
|
|
|
+ pallas::Base::zero(),
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
// Generate the block
|
|
// Generate the block
|
|
|
- let mut block = BlockInfo::new_empty(header, fork.slots.clone());
|
|
|
|
|
|
|
+ let mut block = BlockInfo::new_empty(header, vec![]);
|
|
|
|
|
|
|
|
// Add transactions to the block
|
|
// Add transactions to the block
|
|
|
block.append_txs(unproposed_txs)?;
|
|
block.append_txs(unproposed_txs)?;
|
|
@@ -180,8 +106,7 @@ impl Consensus {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// Generate a block proposal for provided fork, containing all
|
|
/// Generate a block proposal for provided fork, containing all
|
|
|
- /// pending transactions. This should only be called after generating
|
|
|
|
|
- /// next/current slot. Proposal is signed using provided secret key,
|
|
|
|
|
|
|
+ /// pending transactions. Proposal is signed using provided secret key,
|
|
|
/// which must also have signed the provided proposal transaction.
|
|
/// which must also have signed the provided proposal transaction.
|
|
|
pub async fn generate_signed_proposal(
|
|
pub async fn generate_signed_proposal(
|
|
|
&self,
|
|
&self,
|
|
@@ -200,6 +125,17 @@ impl Consensus {
|
|
|
Ok(proposal)
|
|
Ok(proposal)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /// Generate a new empty fork.
|
|
|
|
|
+ pub async fn generate_empty_fork(&self) -> Result<()> {
|
|
|
|
|
+ debug!(target: "validator::consensus::generate_empty_fork", "Generating new empty fork...");
|
|
|
|
|
+ let mut lock = self.forks.write().await;
|
|
|
|
|
+ let fork = Fork::new(&self.blockchain, self.module.read().await.clone()).await?;
|
|
|
|
|
+ lock.push(fork);
|
|
|
|
|
+ drop(lock);
|
|
|
|
|
+ debug!(target: "validator::consensus::generate_empty_fork", "Fork generated!");
|
|
|
|
|
+ Ok(())
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/// Given a proposal, the node verifys it and finds which fork it extends.
|
|
/// Given a proposal, the node verifys it and finds which fork it extends.
|
|
|
/// If the proposal extends the canonical blockchain, a new fork chain is created.
|
|
/// If the proposal extends the canonical blockchain, a new fork chain is created.
|
|
|
pub async fn append_proposal(&self, proposal: &Proposal) -> Result<()> {
|
|
pub async fn append_proposal(&self, proposal: &Proposal) -> Result<()> {
|
|
@@ -209,22 +145,10 @@ impl Consensus {
|
|
|
let (mut fork, index) = verify_proposal(self, proposal).await?;
|
|
let (mut fork, index) = verify_proposal(self, proposal).await?;
|
|
|
|
|
|
|
|
// Append proposal to the fork
|
|
// Append proposal to the fork
|
|
|
- fork.append_proposal(proposal.hash, self.pos_testing_mode).await?;
|
|
|
|
|
-
|
|
|
|
|
- // Update fork slots based on proposal version
|
|
|
|
|
- match proposal.block.header.version {
|
|
|
|
|
- // PoW proposal
|
|
|
|
|
- 1 => {
|
|
|
|
|
- // Update PoW module
|
|
|
|
|
- fork.module
|
|
|
|
|
- .append(proposal.block.header.timestamp.0, &fork.module.next_difficulty()?);
|
|
|
|
|
- // and generate next PoW slot for this specific fork
|
|
|
|
|
- fork.generate_pow_slot()?;
|
|
|
|
|
- }
|
|
|
|
|
- // PoS proposal
|
|
|
|
|
- 2 => fork.slots = vec![],
|
|
|
|
|
- _ => return Err(Error::BlockVersionIsInvalid(proposal.block.header.version)),
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ fork.append_proposal(proposal.hash).await?;
|
|
|
|
|
+
|
|
|
|
|
+ // Update PoW module
|
|
|
|
|
+ fork.module.append(proposal.block.header.timestamp.0, &fork.module.next_difficulty()?);
|
|
|
|
|
|
|
|
// If a fork index was found, replace forks with the mutated one,
|
|
// If a fork index was found, replace forks with the mutated one,
|
|
|
// otherwise push the new fork.
|
|
// otherwise push the new fork.
|
|
@@ -261,9 +185,9 @@ impl Consensus {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Check if proposal extends canonical
|
|
// Check if proposal extends canonical
|
|
|
- let (last_slot, last_block) = self.blockchain.last()?;
|
|
|
|
|
|
|
+ let (last_height, last_block) = self.blockchain.last()?;
|
|
|
if proposal.block.header.previous != last_block ||
|
|
if proposal.block.header.previous != last_block ||
|
|
|
- proposal.block.header.height <= last_slot
|
|
|
|
|
|
|
+ proposal.block.header.height <= last_height
|
|
|
{
|
|
{
|
|
|
return Err(Error::ExtendedChainIndexNotFound)
|
|
return Err(Error::ExtendedChainIndexNotFound)
|
|
|
}
|
|
}
|
|
@@ -276,16 +200,7 @@ impl Consensus {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Generate a new fork extending canonical
|
|
// Generate a new fork extending canonical
|
|
|
- let mut fork = Fork::new(&self.blockchain, self.module.read().await.clone()).await?;
|
|
|
|
|
- if proposal.block.header.height < POS_START {
|
|
|
|
|
- fork.generate_pow_slot()?;
|
|
|
|
|
- } else {
|
|
|
|
|
- let id = self.time_keeper.current_slot();
|
|
|
|
|
- let (producers, last_hashes, second_to_last_hashes) =
|
|
|
|
|
- previous_slot_info(&forks, id - 1)?;
|
|
|
|
|
- fork.generate_pos_slot(id, producers, &last_hashes, &second_to_last_hashes)?;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ let fork = Fork::new(&self.blockchain, self.module.read().await.clone()).await?;
|
|
|
return Ok((fork, None))
|
|
return Ok((fork, None))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -316,17 +231,12 @@ impl Consensus {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// Update PoW module
|
|
// Update PoW module
|
|
|
- if block.header.version == 1 {
|
|
|
|
|
- fork.module.append(block.header.timestamp.0, &fork.module.next_difficulty()?);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ fork.module.append(block.header.timestamp.0, &fork.module.next_difficulty()?);
|
|
|
|
|
|
|
|
// Use last inserted block as next iteration previous
|
|
// Use last inserted block as next iteration previous
|
|
|
previous = block;
|
|
previous = block;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Rebuilt fork hot/live slots
|
|
|
|
|
- fork.generate_pow_slot()?;
|
|
|
|
|
-
|
|
|
|
|
// Drop forks lock
|
|
// Drop forks lock
|
|
|
drop(forks);
|
|
drop(forks);
|
|
|
|
|
|
|
@@ -340,10 +250,7 @@ impl Consensus {
|
|
|
/// When best fork can be finalized, blocks(proposals) should be appended to canonical, excluding the
|
|
/// When best fork can be finalized, blocks(proposals) should be appended to canonical, excluding the
|
|
|
/// last one, and fork should be rebuilt.
|
|
/// last one, and fork should be rebuilt.
|
|
|
pub async fn finalization(&self) -> Result<Vec<BlockInfo>> {
|
|
pub async fn finalization(&self) -> Result<Vec<BlockInfo>> {
|
|
|
- // Set last slot finalization check occured to current slot
|
|
|
|
|
- let slot = self.time_keeper.current_slot();
|
|
|
|
|
- debug!(target: "validator::consensus::finalization", "Started finalization check for slot: {}", slot);
|
|
|
|
|
- *self.checked_finalization.write().await = slot;
|
|
|
|
|
|
|
+ debug!(target: "validator::consensus::finalization", "Started finalization check");
|
|
|
|
|
|
|
|
// Grab best forks
|
|
// Grab best forks
|
|
|
let forks = self.forks.read().await;
|
|
let forks = self.forks.read().await;
|
|
@@ -408,8 +315,6 @@ pub struct Fork {
|
|
|
pub module: PoWModule,
|
|
pub module: PoWModule,
|
|
|
/// Fork proposal hashes sequence
|
|
/// Fork proposal hashes sequence
|
|
|
pub proposals: Vec<blake3::Hash>,
|
|
pub proposals: Vec<blake3::Hash>,
|
|
|
- /// Hot/live slots
|
|
|
|
|
- pub slots: Vec<Slot>,
|
|
|
|
|
/// Valid pending transaction hashes
|
|
/// Valid pending transaction hashes
|
|
|
pub mempool: Vec<blake3::Hash>,
|
|
pub mempool: Vec<blake3::Hash>,
|
|
|
/// Current fork rank, cached for better performance
|
|
/// Current fork rank, cached for better performance
|
|
@@ -421,17 +326,13 @@ impl Fork {
|
|
|
let mempool =
|
|
let mempool =
|
|
|
blockchain.get_pending_txs()?.iter().map(|tx| blake3::hash(&serialize(tx))).collect();
|
|
blockchain.get_pending_txs()?.iter().map(|tx| blake3::hash(&serialize(tx))).collect();
|
|
|
let overlay = BlockchainOverlay::new(blockchain)?;
|
|
let overlay = BlockchainOverlay::new(blockchain)?;
|
|
|
- Ok(Self { overlay, module, proposals: vec![], slots: vec![], mempool, rank: 0 })
|
|
|
|
|
|
|
+ Ok(Self { overlay, module, proposals: vec![], mempool, rank: 0 })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// Auxiliary function to append a proposal and recalculate current fork rank
|
|
/// Auxiliary function to append a proposal and recalculate current fork rank
|
|
|
- pub async fn append_proposal(
|
|
|
|
|
- &mut self,
|
|
|
|
|
- proposal: blake3::Hash,
|
|
|
|
|
- pos_testing_mode: bool,
|
|
|
|
|
- ) -> Result<()> {
|
|
|
|
|
|
|
+ pub async fn append_proposal(&mut self, proposal: blake3::Hash) -> Result<()> {
|
|
|
self.proposals.push(proposal);
|
|
self.proposals.push(proposal);
|
|
|
- self.rank = self.rank(pos_testing_mode).await?;
|
|
|
|
|
|
|
+ self.rank = self.rank().await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
Ok(())
|
|
|
}
|
|
}
|
|
@@ -448,24 +349,10 @@ impl Fork {
|
|
|
Proposal::new(block)
|
|
Proposal::new(block)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Utility function to extract leader selection lottery randomness(nonce/eta),
|
|
|
|
|
- /// defined as the hash of the last block, converted to pallas base.
|
|
|
|
|
- fn get_last_nonce(&self) -> Result<pallas::Base> {
|
|
|
|
|
- // Retrieve last block(or proposal)
|
|
|
|
|
|
|
+ /// Auxiliary function to compute forks' next block height.
|
|
|
|
|
+ pub fn get_next_block_height(&self) -> Result<u64> {
|
|
|
let proposal = self.last_proposal()?;
|
|
let proposal = self.last_proposal()?;
|
|
|
-
|
|
|
|
|
- match proposal.block.header.version {
|
|
|
|
|
- 1 => Ok(pallas::Base::from(proposal.block.header.nonce)),
|
|
|
|
|
- 2 => {
|
|
|
|
|
- // Read first 240 bits of proposal hash
|
|
|
|
|
- let mut bytes: [u8; 32] = *proposal.hash.as_bytes();
|
|
|
|
|
- bytes[30] = 0;
|
|
|
|
|
- bytes[31] = 0;
|
|
|
|
|
-
|
|
|
|
|
- Ok(pallas::Base::from_repr(bytes).unwrap())
|
|
|
|
|
- }
|
|
|
|
|
- _ => Err(Error::BlockVersionIsInvalid(proposal.block.header.version)),
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Ok(proposal.block.header.height + 1)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// Auxiliary function to retrieve unproposed valid transactions.
|
|
/// Auxiliary function to retrieve unproposed valid transactions.
|
|
@@ -514,79 +401,8 @@ impl Fork {
|
|
|
Ok(unproposed_txs)
|
|
Ok(unproposed_txs)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Generate next hot/live PoW slot
|
|
|
|
|
- pub fn generate_pow_slot(&mut self) -> Result<()> {
|
|
|
|
|
- // Grab last proposal
|
|
|
|
|
- let last = self.last_proposal()?;
|
|
|
|
|
-
|
|
|
|
|
- // Generate the slot
|
|
|
|
|
- let last_slot = last.block.slots.last().unwrap().clone();
|
|
|
|
|
- let id = last_slot.id + 1;
|
|
|
|
|
- let producers = 1;
|
|
|
|
|
- let previous = PreviousSlot::new(
|
|
|
|
|
- producers,
|
|
|
|
|
- vec![last.hash],
|
|
|
|
|
- vec![last.block.header.previous],
|
|
|
|
|
- last_slot.pid.error,
|
|
|
|
|
- );
|
|
|
|
|
- let pid = PidOutput::default();
|
|
|
|
|
- let total_tokens = last_slot.total_tokens + last_slot.reward;
|
|
|
|
|
- let reward = expected_reward(id);
|
|
|
|
|
- let slot = Slot::new(
|
|
|
|
|
- id,
|
|
|
|
|
- previous,
|
|
|
|
|
- pid,
|
|
|
|
|
- pallas::Base::from(last.block.header.nonce),
|
|
|
|
|
- total_tokens,
|
|
|
|
|
- reward,
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // Update fork hot/live slots vector
|
|
|
|
|
- self.slots = vec![slot];
|
|
|
|
|
-
|
|
|
|
|
- Ok(())
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /// Generate current hot/live PoS slot
|
|
|
|
|
- pub fn generate_pos_slot(
|
|
|
|
|
- &mut self,
|
|
|
|
|
- id: u64,
|
|
|
|
|
- producers: u64,
|
|
|
|
|
- last_hashes: &[blake3::Hash],
|
|
|
|
|
- second_to_last_hashes: &[blake3::Hash],
|
|
|
|
|
- ) -> Result<()> {
|
|
|
|
|
- // Grab last known fork slot
|
|
|
|
|
- let previous_slot = if self.slots.is_empty() {
|
|
|
|
|
- self.overlay.lock().unwrap().slots.get_last()?
|
|
|
|
|
- } else {
|
|
|
|
|
- self.slots.last().unwrap().clone()
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // Generate previous slot information
|
|
|
|
|
- let previous = PreviousSlot::new(
|
|
|
|
|
- producers,
|
|
|
|
|
- last_hashes.to_vec(),
|
|
|
|
|
- second_to_last_hashes.to_vec(),
|
|
|
|
|
- previous_slot.pid.error,
|
|
|
|
|
- );
|
|
|
|
|
-
|
|
|
|
|
- // Generate PID controller output
|
|
|
|
|
- let (f, error, sigma1, sigma2) = slot_pid_output(&previous_slot, producers);
|
|
|
|
|
- let pid = PidOutput::new(f, error, sigma1, sigma2);
|
|
|
|
|
-
|
|
|
|
|
- // Each slot starts as an empty slot(not reward) when generated, carrying
|
|
|
|
|
- // last nonce(eta)
|
|
|
|
|
- let last_nonce = self.get_last_nonce()?;
|
|
|
|
|
- let total_tokens = previous_slot.total_tokens + previous_slot.reward;
|
|
|
|
|
- let reward = 0;
|
|
|
|
|
- let slot = Slot::new(id, previous, pid, last_nonce, total_tokens, reward);
|
|
|
|
|
- self.slots.push(slot);
|
|
|
|
|
-
|
|
|
|
|
- Ok(())
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/// Auxiliarry function to compute fork's rank, assuming all proposals are valid.
|
|
/// Auxiliarry function to compute fork's rank, assuming all proposals are valid.
|
|
|
- pub async fn rank(&self, pos_testing_mode: bool) -> Result<u64> {
|
|
|
|
|
|
|
+ pub async fn rank(&self) -> Result<u64> {
|
|
|
// If the fork is empty its rank is 0
|
|
// If the fork is empty its rank is 0
|
|
|
if self.proposals.is_empty() {
|
|
if self.proposals.is_empty() {
|
|
|
return Ok(0)
|
|
return Ok(0)
|
|
@@ -608,7 +424,7 @@ impl Fork {
|
|
|
} else {
|
|
} else {
|
|
|
proposal.clone()
|
|
proposal.clone()
|
|
|
};
|
|
};
|
|
|
- sum += block_rank(proposal, &previous_previous, pos_testing_mode).await?;
|
|
|
|
|
|
|
+ sum += block_rank(proposal, &previous_previous).await?;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Use fork(proposals) length as a multiplier to compute the actual fork rank
|
|
// Use fork(proposals) length as a multiplier to compute the actual fork rank
|
|
@@ -624,10 +440,9 @@ impl Fork {
|
|
|
let overlay = self.overlay.lock().unwrap().full_clone()?;
|
|
let overlay = self.overlay.lock().unwrap().full_clone()?;
|
|
|
let module = self.module.clone();
|
|
let module = self.module.clone();
|
|
|
let proposals = self.proposals.clone();
|
|
let proposals = self.proposals.clone();
|
|
|
- let slots = self.slots.clone();
|
|
|
|
|
let mempool = self.mempool.clone();
|
|
let mempool = self.mempool.clone();
|
|
|
let rank = self.rank;
|
|
let rank = self.rank;
|
|
|
|
|
|
|
|
- Ok(Self { overlay, module, proposals, slots, mempool, rank })
|
|
|
|
|
|
|
+ Ok(Self { overlay, module, proposals, mempool, rank })
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|