Skip to content

Commit

Permalink
add an infallible mode to virtual processor build_block_template()
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelsutton committed Sep 21, 2023
1 parent 9a015d1 commit 58e0ed5
Show file tree
Hide file tree
Showing 11 changed files with 49 additions and 17 deletions.
3 changes: 2 additions & 1 deletion consensus/core/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::sync::Arc;

use crate::{
acceptance_data::AcceptanceData,
block::{Block, BlockTemplate, TemplateTransactionSelector},
block::{Block, BlockTemplate, TemplateBuildMode, TemplateTransactionSelector},
block_count::BlockCount,
blockstatus::BlockStatus,
coinbase::MinerData,
Expand All @@ -31,6 +31,7 @@ pub trait ConsensusApi: Send + Sync {
&self,
miner_data: MinerData,
tx_selector: Box<dyn TemplateTransactionSelector>,
build_mode: TemplateBuildMode,
) -> Result<BlockTemplate, RuleError> {
unimplemented!()
}
Expand Down
12 changes: 12 additions & 0 deletions consensus/core/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ pub trait TemplateTransactionSelector {
fn is_successful(&self) -> bool;
}

/// Block template build mode
#[derive(Clone, Copy, Debug)]
pub enum TemplateBuildMode {
/// Block template build can possibly fail if `TemplateTransactionSelector::is_successful` deems the operation unsuccessful.
///
/// In such a case, the build fails with `BlockRuleError::InvalidTransactionsInNewBlock`.
Standard,

/// Block template build always succeeds. The built block contains only the validated transactions.
Infallible,
}

/// A block template for miners.
#[derive(Debug, Clone)]
pub struct BlockTemplate {
Expand Down
5 changes: 3 additions & 2 deletions consensus/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use crate::{
use kaspa_consensus_core::{
acceptance_data::AcceptanceData,
api::{BlockValidationFuture, ConsensusApi},
block::{Block, BlockTemplate, TemplateTransactionSelector},
block::{Block, BlockTemplate, TemplateBuildMode, TemplateTransactionSelector},
block_count::BlockCount,
blockhash::BlockHashExtensions,
blockstatus::BlockStatus,
Expand Down Expand Up @@ -357,8 +357,9 @@ impl ConsensusApi for Consensus {
&self,
miner_data: MinerData,
tx_selector: Box<dyn TemplateTransactionSelector>,
build_mode: TemplateBuildMode,
) -> Result<BlockTemplate, RuleError> {
self.virtual_processor.build_block_template(miner_data, tx_selector)
self.virtual_processor.build_block_template(miner_data, tx_selector, build_mode)
}

fn validate_and_insert_block(&self, block: Block) -> BlockValidationFuture {
Expand Down
8 changes: 5 additions & 3 deletions consensus/src/pipeline/virtual_processor/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use crate::{
};
use kaspa_consensus_core::{
acceptance_data::AcceptanceData,
block::{BlockTemplate, MutableBlock, TemplateTransactionSelector},
block::{BlockTemplate, MutableBlock, TemplateBuildMode, TemplateTransactionSelector},
blockstatus::BlockStatus::{StatusDisqualifiedFromChain, StatusUTXOValid},
coinbase::MinerData,
config::genesis::GenesisBlock,
Expand Down Expand Up @@ -791,6 +791,7 @@ impl VirtualStateProcessor {
&self,
miner_data: MinerData,
mut tx_selector: Box<dyn TemplateTransactionSelector>,
build_mode: TemplateBuildMode,
) -> Result<BlockTemplate, RuleError> {
//
// TODO: tests
Expand Down Expand Up @@ -835,8 +836,9 @@ impl VirtualStateProcessor {
// Check whether this was an overall successful selection episode. We pass this decision
// to the selector implementation which has the broadest picture and can use mempool config
// and context
if !tx_selector.is_successful() {
return Err(RuleError::InvalidTransactionsInNewBlock(invalid_transactions));
match (build_mode, tx_selector.is_successful()) {
(TemplateBuildMode::Standard, false) => return Err(RuleError::InvalidTransactionsInNewBlock(invalid_transactions)),
(TemplateBuildMode::Standard, true) | (TemplateBuildMode::Infallible, _) => {}
}

// At this point we can safely drop the read lock
Expand Down
8 changes: 6 additions & 2 deletions consensus/src/pipeline/virtual_processor/tests.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{consensus::test_consensus::TestConsensus, model::services::reachability::ReachabilityService};
use kaspa_consensus_core::{
api::ConsensusApi,
block::{Block, BlockTemplate, MutableBlock, TemplateTransactionSelector},
block::{Block, BlockTemplate, MutableBlock, TemplateBuildMode, TemplateTransactionSelector},
blockhash,
blockstatus::BlockStatus,
coinbase::MinerData,
Expand Down Expand Up @@ -104,7 +104,11 @@ impl TestContext {
pub fn build_block_template(&self, nonce: u64, timestamp: u64) -> BlockTemplate {
let mut t = self
.consensus
.build_block_template(self.miner_data.clone(), Box::new(OnetimeTxSelector::new(Default::default())))
.build_block_template(
self.miner_data.clone(),
Box::new(OnetimeTxSelector::new(Default::default())),
TemplateBuildMode::Standard,
)
.unwrap();
t.block.header.timestamp = timestamp;
t.block.header.nonce = nonce;
Expand Down
9 changes: 7 additions & 2 deletions mining/src/block_template/builder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use super::{errors::BuilderResult, policy::Policy};
use crate::{block_template::selector::TransactionsSelector, model::candidate_tx::CandidateTransaction};
use kaspa_consensus_core::{
api::ConsensusApi, block::BlockTemplate, coinbase::MinerData, merkle::calc_hash_merkle_root, tx::COINBASE_TRANSACTION_INDEX,
api::ConsensusApi,
block::{BlockTemplate, TemplateBuildMode},
coinbase::MinerData,
merkle::calc_hash_merkle_root,
tx::COINBASE_TRANSACTION_INDEX,
};
use kaspa_core::{
debug,
Expand Down Expand Up @@ -86,11 +90,12 @@ impl BlockTemplateBuilder {
consensus: &dyn ConsensusApi,
miner_data: &MinerData,
transactions: Vec<CandidateTransaction>,
build_mode: TemplateBuildMode,
) -> BuilderResult<BlockTemplate> {
let _sw = Stopwatch::<20>::with_threshold("build_block_template op");
debug!("Considering {} transactions for a new block template", transactions.len());
let selector = Box::new(TransactionsSelector::new(self.policy.clone(), transactions));
Ok(consensus.build_block_template(miner_data.clone(), selector)?)
Ok(consensus.build_block_template(miner_data.clone(), selector, build_mode)?)
}

/// modify_block_template clones an existing block template, modifies it to the requested coinbase data and updates the timestamp
Expand Down
2 changes: 1 addition & 1 deletion mining/src/block_template/selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ impl TemplateTransactionSelector for TransactionsSelector {

fn is_successful(&self) -> bool {
// TODO: comment + constants
self.transactions.is_empty()
self.overall_rejections == 0
|| (self.total_mass as f64) > self.policy.max_block_mass as f64 * 0.8
|| (self.overall_rejections as f64) < self.transactions.len() as f64 * 0.2
}
Expand Down
9 changes: 7 additions & 2 deletions mining/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{
use itertools::Itertools;
use kaspa_consensus_core::{
api::ConsensusApi,
block::BlockTemplate,
block::{BlockTemplate, TemplateBuildMode},
coinbase::MinerData,
errors::{block::RuleError as BlockRuleError, tx::TxRuleError},
tx::{MutableTransaction, Transaction, TransactionId, TransactionOutput},
Expand Down Expand Up @@ -90,7 +90,12 @@ impl MiningManager {

let transactions = self.block_candidate_transactions();
let block_template_builder = BlockTemplateBuilder::new(self.config.maximum_mass_per_block);
match block_template_builder.build_block_template(consensus, miner_data, transactions) {
let build_mode = if attempts < self.config.maximum_build_block_template_attempts {
TemplateBuildMode::Standard
} else {
TemplateBuildMode::Infallible
};
match block_template_builder.build_block_template(consensus, miner_data, transactions, build_mode) {
Ok(block_template) => {
let block_template = cache_lock.set_immutable_cached_template(block_template);
match attempts {
Expand Down
3 changes: 2 additions & 1 deletion mining/src/manager_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod tests {
use kaspa_addresses::{Address, Prefix, Version};
use kaspa_consensus_core::{
api::ConsensusApi,
block::TemplateBuildMode,
coinbase::MinerData,
constants::{MAX_TX_IN_SEQUENCE_NUM, SOMPI_PER_KASPA, TX_VERSION},
errors::tx::{TxResult, TxRuleError},
Expand Down Expand Up @@ -847,7 +848,7 @@ mod tests {

// Build a fresh template for coinbase2 as a reference
let builder = mining_manager.block_template_builder();
let result = builder.build_block_template(consensus, &miner_data_2, transactions);
let result = builder.build_block_template(consensus, &miner_data_2, transactions, TemplateBuildMode::Standard);
assert!(result.is_ok(), "build block template failed for miner data 2");
let expected_template = result.unwrap();

Expand Down
3 changes: 2 additions & 1 deletion mining/src/testutils/consensus_mock.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::coinbase_mock::CoinbaseManagerMock;
use kaspa_consensus_core::{
api::ConsensusApi,
block::{BlockTemplate, MutableBlock, TemplateTransactionSelector},
block::{BlockTemplate, MutableBlock, TemplateBuildMode, TemplateTransactionSelector},
coinbase::MinerData,
constants::BLOCK_VERSION,
errors::{
Expand Down Expand Up @@ -76,6 +76,7 @@ impl ConsensusApi for ConsensusMock {
&self,
miner_data: MinerData,
mut tx_selector: Box<dyn TemplateTransactionSelector>,
_build_mode: TemplateBuildMode,
) -> Result<BlockTemplate, RuleError> {
let mut txs = tx_selector.select_transactions();
let coinbase_manager = CoinbaseManagerMock::new();
Expand Down
4 changes: 2 additions & 2 deletions simpa/src/simulator/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use kaspa_consensus::consensus::Consensus;
use kaspa_consensus::model::stores::virtual_state::VirtualStateStoreReader;
use kaspa_consensus::params::Params;
use kaspa_consensus_core::api::ConsensusApi;
use kaspa_consensus_core::block::{Block, TemplateTransactionSelector};
use kaspa_consensus_core::block::{Block, TemplateBuildMode, TemplateTransactionSelector};
use kaspa_consensus_core::coinbase::MinerData;
use kaspa_consensus_core::sign::sign;
use kaspa_consensus_core::subnets::SUBNETWORK_ID_NATIVE;
Expand Down Expand Up @@ -113,7 +113,7 @@ impl Miner {
let session = self.consensus.acquire_session();
let mut block_template = self
.consensus
.build_block_template(self.miner_data.clone(), Box::new(OnetimeTxSelector::new(txs)))
.build_block_template(self.miner_data.clone(), Box::new(OnetimeTxSelector::new(txs)), TemplateBuildMode::Standard)
.expect("simulation txs are selected in sync with virtual state and are expected to be valid");
drop(session);
block_template.block.header.timestamp = timestamp; // Use simulation time rather than real time
Expand Down

0 comments on commit 58e0ed5

Please sign in to comment.