Skip to content

Commit 4826b38

Browse files
authored
Crescendo Cleanup - Part 2 (#754)
* Get rid of some ghostdag_k.get(..) * Move check_coinbase_outputs_limit back to check_coinbase_in_isolation * Get rid of more ForkedParam.get(..) * Move checks from validate_tx_in_header_context to validate_tx_in_isolation * Remove check_transaction_payload * Get rid of more ForkedParam.get(..) * Remove crescendo activation logic from validate_body_in_isolation * Get rid of some calls to ForkActivation.isActive * Get rid of some pruning constants sanity checks and use of lower_bound() * Get rid of calls to ForkedParam.upper_bound * Remove some uses of ForkActivation * fmt * Address comments
1 parent 2e0fdb9 commit 4826b38

File tree

43 files changed

+146
-467
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+146
-467
lines changed

components/addressmanager/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,11 @@ mod address_store_with_cache {
535535
assert_eq!(iter.count(), 0);
536536
}
537537

538+
// This test is indeterminate, so it is ignored by default.
539+
// Every developer that changes the logic of the address manager should run this test locally before sending a PR.
540+
// TODO: Maybe change statistical parameters to reduce the failure rate?
538541
#[test]
542+
#[ignore]
539543
fn test_network_distribution_weighting() {
540544
kaspa_core::log::try_init_logger("info");
541545

consensus/core/src/config/constants.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ pub mod perf {
166166
impl PerfParams {
167167
pub fn adjust_to_consensus_params(&mut self, consensus_params: &Params) {
168168
// Allow caching up to 10x over the baseline
169-
self.block_data_cache_size *= consensus_params.bps().upper_bound().clamp(1, 10) as usize;
169+
self.block_data_cache_size *= consensus_params.bps().after().clamp(1, 10) as usize;
170170
}
171171
}
172172
}

consensus/core/src/errors/block.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,6 @@ pub enum RuleError {
9797
#[error("coinbase blue score of {0} is not the expected value of {1}")]
9898
BadCoinbasePayloadBlueScore(u64, u64),
9999

100-
#[error("coinbase mass commitment field is not zero")]
101-
CoinbaseNonZeroMassCommitment,
102-
103100
#[error("transaction in isolation validation failed for tx {0}: {1}")]
104101
TxInIsolationValidationFailed(TransactionId, TxRuleError),
105102

consensus/core/src/errors/tx.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ pub enum TxRuleError {
1515
#[error("transaction has non zero gas value")]
1616
TxHasGas,
1717

18-
#[error("a non coinbase transaction has a payload")]
19-
NonCoinbaseTxHasPayload,
20-
2118
#[error("transaction version {0} is unknown")]
2219
UnknownTxVersion(u16),
2320

@@ -45,6 +42,9 @@ pub enum TxRuleError {
4542
#[error("script public key of coinbase output #{0} is too long")]
4643
CoinbaseScriptPublicKeyTooLong(usize),
4744

45+
#[error("coinbase mass commitment field is not zero")]
46+
CoinbaseNonZeroMassCommitment,
47+
4848
#[error(
4949
"transaction input #{0} tried to spend coinbase outpoint {1} with daa score of {2}
5050
while the merging block daa score is {3} and the coinbase maturity period of {4} hasn't passed yet"

consensus/core/src/mass/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ mod tests {
433433
*/
434434
for net in NetworkType::iter() {
435435
let params: Params = net.into();
436-
let max_spk_len = (params.max_script_public_key_len().upper_bound() as u64)
436+
let max_spk_len = (params.max_script_public_key_len().after() as u64)
437437
.min(params.max_block_mass.div_ceil(params.mass_per_script_pub_key_byte));
438438
let max_plurality = (UTXO_CONST_STORAGE + max_spk_len).div_ceil(UTXO_UNIT_SIZE); // see utxo_plurality
439439
let product = params.storage_mass_parameter.checked_mul(max_plurality).and_then(|x| x.checked_mul(max_plurality));

consensus/src/consensus/mod.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,7 @@ impl ConsensusApi for Consensus {
971971
// max_blocks has to be greater than the merge set size limit
972972
fn get_hashes_between(&self, low: Hash, high: Hash, max_blocks: usize) -> ConsensusResult<(Vec<Hash>, Hash)> {
973973
let _guard = self.pruning_lock.blocking_read();
974-
assert!(max_blocks as u64 > self.config.mergeset_size_limit().upper_bound());
974+
assert!(max_blocks as u64 > self.config.mergeset_size_limit().after());
975975
self.validate_block_exists(low)?;
976976
self.validate_block_exists(high)?;
977977

@@ -1187,9 +1187,7 @@ impl ConsensusApi for Consensus {
11871187
return Err(ConsensusError::UnexpectedPruningPoint);
11881188
}
11891189

1190-
// [Crescendo]: get ghostdag k based on the pruning point's DAA score. The off-by-one of not going by selected parent
1191-
// DAA score is not important here as we simply increase K one block earlier which is more conservative (saving/sending more data)
1192-
let ghostdag_k = self.config.ghostdag_k().get(self.headers_store.get_daa_score(pruning_point).unwrap());
1190+
let ghostdag_k = self.config.ghostdag_k().after();
11931191

11941192
// Note: the method `get_ghostdag_chain_k_depth` might return a partial chain if data is missing.
11951193
// Ideally this node when synced would validate it got all of the associated data up to k blocks

consensus/src/consensus/services.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ impl ConsensusServices {
150150
params.max_script_public_key_len(),
151151
params.coinbase_payload_script_public_key_max_len,
152152
params.coinbase_maturity(),
153+
params.ghostdag_k().after(),
153154
tx_script_cache_counters,
154155
mass_calculator.clone(),
155156
params.crescendo_activation,

consensus/src/consensus/storage.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,8 @@ impl ConsensusStorage {
8383
let perf_params = &config.perf;
8484

8585
// Lower and upper bounds
86-
// [Crescendo]: all usages of pruning upper bounds also bound by actual memory bytes, so we can safely use the larger values
87-
let pruning_depth = params.pruning_depth().upper_bound() as usize;
88-
let pruning_size_for_caches = pruning_depth + params.finality_depth().upper_bound() as usize; // Upper bound for any block/header related data
86+
let pruning_depth = params.pruning_depth().after() as usize;
87+
let pruning_size_for_caches = pruning_depth + params.finality_depth().after() as usize; // Upper bound for any block/header related data
8988
let level_lower_bound = 2 * params.pruning_proof_m as usize; // Number of items lower bound for level-related caches
9089

9190
// Budgets in bytes. All byte budgets overall sum up to ~1GB of memory (which obviously takes more low level alloc space)

consensus/src/pipeline/body_processor/body_validation_in_context.rs

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::BlockBodyProcessor;
22
use crate::{
33
errors::{BlockProcessResult, RuleError},
4-
model::stores::{ghostdag::GhostdagStoreReader, headers::HeaderStoreReader, statuses::StatusesStoreReader},
4+
model::stores::statuses::StatusesStoreReader,
55
processes::{
66
transaction_validator::{
77
tx_validation_in_header_context::{LockTimeArg, LockTimeType},
@@ -10,7 +10,7 @@ use crate::{
1010
window::WindowManager,
1111
},
1212
};
13-
use kaspa_consensus_core::{block::Block, errors::tx::TxRuleError};
13+
use kaspa_consensus_core::block::Block;
1414
use kaspa_database::prelude::StoreResultExtensions;
1515
use kaspa_hashes::Hash;
1616
use once_cell::unsync::Lazy;
@@ -19,7 +19,6 @@ use std::sync::Arc;
1919
impl BlockBodyProcessor {
2020
pub fn validate_body_in_context(self: &Arc<Self>, block: &Block) -> BlockProcessResult<()> {
2121
self.check_parent_bodies_exist(block)?;
22-
self.check_coinbase_outputs_limit(block)?;
2322
self.check_coinbase_blue_score_and_subsidy(block)?;
2423
self.check_block_transactions_in_context(block)
2524
}
@@ -35,7 +34,7 @@ impl BlockBodyProcessor {
3534
// We only evaluate the pmt calculation when actually needed
3635
LockTimeType::Time => LockTimeArg::MedianTime((*lazy_pmt_res).clone()?),
3736
};
38-
if let Err(e) = self.transaction_validator.validate_tx_in_header_context(tx, block.header.daa_score, lock_time_arg) {
37+
if let Err(e) = self.transaction_validator.validate_tx_in_header_context(tx, lock_time_arg) {
3938
return Err(RuleError::TxInContextFailed(tx.id(), e));
4039
};
4140
}
@@ -61,32 +60,6 @@ impl BlockBodyProcessor {
6160
Ok(())
6261
}
6362

64-
fn check_coinbase_outputs_limit(&self, block: &Block) -> BlockProcessResult<()> {
65-
// [Crescendo]: coinbase_outputs_limit depends on ghostdag k and thus depends on fork activation
66-
// which makes it header contextual.
67-
//
68-
// TODO (post HF): move this check back to transaction in isolation validation
69-
70-
// [Crescendo]: Ghostdag k activation is decided based on selected parent DAA score
71-
// so we follow the same methodology for coinbase output limit (which is driven from the
72-
// actual bound on the number of blue blocks in the mergeset).
73-
//
74-
// Note that body validation in context is not called for trusted blocks, so we can safely assume
75-
// the selected parent exists and its daa score is accessible
76-
let selected_parent = self.ghostdag_store.get_selected_parent(block.hash()).unwrap();
77-
let selected_parent_daa_score = self.headers_store.get_daa_score(selected_parent).unwrap();
78-
let coinbase_outputs_limit = self.ghostdag_k.get(selected_parent_daa_score) as u64 + 2;
79-
80-
let tx = &block.transactions[0];
81-
if tx.outputs.len() as u64 > coinbase_outputs_limit {
82-
return Err(RuleError::TxInIsolationValidationFailed(
83-
tx.id(),
84-
TxRuleError::CoinbaseTooManyOutputs(tx.outputs.len(), coinbase_outputs_limit),
85-
));
86-
}
87-
Ok(())
88-
}
89-
9063
fn check_coinbase_blue_score_and_subsidy(self: &Arc<Self>, block: &Block) -> BlockProcessResult<()> {
9164
match self.coinbase_manager.deserialize_coinbase_payload(&block.transactions[0].payload) {
9265
Ok(data) => {

consensus/src/pipeline/body_processor/body_validation_in_isolation.rs

Lines changed: 28 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,11 @@ use kaspa_consensus_core::{
1111

1212
impl BlockBodyProcessor {
1313
pub fn validate_body_in_isolation(self: &Arc<Self>, block: &Block) -> BlockProcessResult<Mass> {
14-
let crescendo_activated = self.crescendo_activation.is_active(block.header.daa_score);
15-
1614
Self::check_has_transactions(block)?;
1715
Self::check_hash_merkle_root(block)?;
1816
Self::check_only_one_coinbase(block)?;
1917
self.check_transactions_in_isolation(block)?;
20-
self.check_coinbase_has_zero_mass(block, crescendo_activated)?;
21-
let mass = self.check_block_mass(block, crescendo_activated)?;
18+
let mass = self.check_block_mass(block)?;
2219
self.check_duplicate_transactions(block)?;
2320
self.check_block_double_spends(block)?;
2421
self.check_no_chained_transactions(block)?;
@@ -63,56 +60,36 @@ impl BlockBodyProcessor {
6360
Ok(())
6461
}
6562

66-
fn check_coinbase_has_zero_mass(&self, block: &Block, crescendo_activated: bool) -> BlockProcessResult<()> {
67-
// TODO (post HF): move to check_coinbase_in_isolation
68-
if crescendo_activated && block.transactions[0].mass() > 0 {
69-
return Err(RuleError::CoinbaseNonZeroMassCommitment);
70-
}
71-
Ok(())
72-
}
73-
74-
fn check_block_mass(self: &Arc<Self>, block: &Block, crescendo_activated: bool) -> BlockProcessResult<Mass> {
75-
if crescendo_activated {
76-
let mut total_compute_mass: u64 = 0;
77-
let mut total_transient_mass: u64 = 0;
78-
let mut total_storage_mass: u64 = 0;
79-
for tx in block.transactions.iter() {
80-
// Calculate the non-contextual masses
81-
let NonContextualMasses { compute_mass, transient_mass } = self.mass_calculator.calc_non_contextual_masses(tx);
82-
83-
// Read the storage mass commitment. This value cannot be computed here w/o UTXO context
84-
// so we use the commitment. Later on, when the transaction is verified in context, we use
85-
// the context to calculate the expected storage mass and verify it matches this commitment
86-
let storage_mass_commitment = tx.mass();
87-
88-
// Sum over the various masses separately
89-
total_compute_mass = total_compute_mass.saturating_add(compute_mass);
90-
total_transient_mass = total_transient_mass.saturating_add(transient_mass);
91-
total_storage_mass = total_storage_mass.saturating_add(storage_mass_commitment);
92-
93-
// Verify all limits
94-
if total_compute_mass > self.max_block_mass {
95-
return Err(RuleError::ExceedsComputeMassLimit(total_compute_mass, self.max_block_mass));
96-
}
97-
if total_transient_mass > self.max_block_mass {
98-
return Err(RuleError::ExceedsTransientMassLimit(total_transient_mass, self.max_block_mass));
99-
}
100-
if total_storage_mass > self.max_block_mass {
101-
return Err(RuleError::ExceedsStorageMassLimit(total_storage_mass, self.max_block_mass));
102-
}
63+
fn check_block_mass(self: &Arc<Self>, block: &Block) -> BlockProcessResult<Mass> {
64+
let mut total_compute_mass: u64 = 0;
65+
let mut total_transient_mass: u64 = 0;
66+
let mut total_storage_mass: u64 = 0;
67+
for tx in block.transactions.iter() {
68+
// Calculate the non-contextual masses
69+
let NonContextualMasses { compute_mass, transient_mass } = self.mass_calculator.calc_non_contextual_masses(tx);
70+
71+
// Read the storage mass commitment. This value cannot be computed here w/o UTXO context
72+
// so we use the commitment. Later on, when the transaction is verified in context, we use
73+
// the context to calculate the expected storage mass and verify it matches this commitment
74+
let storage_mass_commitment = tx.mass();
75+
76+
// Sum over the various masses separately
77+
total_compute_mass = total_compute_mass.saturating_add(compute_mass);
78+
total_transient_mass = total_transient_mass.saturating_add(transient_mass);
79+
total_storage_mass = total_storage_mass.saturating_add(storage_mass_commitment);
80+
81+
// Verify all limits
82+
if total_compute_mass > self.max_block_mass {
83+
return Err(RuleError::ExceedsComputeMassLimit(total_compute_mass, self.max_block_mass));
84+
}
85+
if total_transient_mass > self.max_block_mass {
86+
return Err(RuleError::ExceedsTransientMassLimit(total_transient_mass, self.max_block_mass));
10387
}
104-
Ok((NonContextualMasses::new(total_compute_mass, total_transient_mass), ContextualMasses::new(total_storage_mass)))
105-
} else {
106-
let mut total_mass: u64 = 0;
107-
for tx in block.transactions.iter() {
108-
let compute_mass = self.mass_calculator.calc_non_contextual_masses(tx).compute_mass;
109-
total_mass = total_mass.saturating_add(compute_mass);
110-
if total_mass > self.max_block_mass {
111-
return Err(RuleError::ExceedsComputeMassLimit(total_mass, self.max_block_mass));
112-
}
88+
if total_storage_mass > self.max_block_mass {
89+
return Err(RuleError::ExceedsStorageMassLimit(total_storage_mass, self.max_block_mass));
11390
}
114-
Ok((NonContextualMasses::new(total_mass, 0), ContextualMasses::new(0)))
11591
}
92+
Ok((NonContextualMasses::new(total_compute_mass, total_transient_mass), ContextualMasses::new(total_storage_mass)))
11693
}
11794

11895
fn check_block_double_spends(self: &Arc<Self>, block: &Block) -> BlockProcessResult<()> {

0 commit comments

Comments
 (0)