Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 119 additions & 22 deletions consensus/core/src/config/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub use super::{
use crate::{
BlockLevel, KType,
constants::STORAGE_MASS_PARAMETER,
mass::{BlockLaneLimits, BlockMassLimits},
mass::{BlockLaneLimits, BlockMassLimits, MassCofactors},
network::{NetworkId, NetworkType},
};
use kaspa_addresses::Prefix;
Expand All @@ -17,6 +17,15 @@ use std::{
ops::{Deref, DerefMut},
};

const MEMPOOL_BLOCK_MASS_ACTIVATION_DELAY_SECONDS: u64 = 24 * 60 * 60;
const PRIOR_MAX_SIGNATURE_SCRIPT_LEN: usize = 10_000;
// Increased for stark proofs. This value is effectively covered by the post-Toccata
// transient block mass limit: 1_000_000 transient mass / 4 grams-per-byte = 250_000
// bytes for the entire block, so a larger signature script cannot be accepted anyway.
// TODO(post-toccata): check whether this early signature-script length guard can be
// removed entirely, or whether it remains useful as cheap early protection.
const NEW_MAX_SIGNATURE_SCRIPT_LEN: usize = 250_000;

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct ForkActivation(u64);

Expand Down Expand Up @@ -47,6 +56,13 @@ impl ForkActivation {
current_daa_score >= self.0
}

pub fn delayed_by(self, delay_daa_score: u64) -> Self {
match self.0 {
Self::ALWAYS | Self::NEVER => self,
daa_score => Self(daa_score.saturating_add(delay_daa_score)),
}
}

/// Checks if the fork was "recently" activated, i.e., in the time frame of the provided range.
/// This function returns false for forks that were always active, since they were never activated.
pub fn is_within_range_from_activation(self, current_daa_score: u64, range: u64) -> bool {
Expand Down Expand Up @@ -85,6 +101,10 @@ impl<T: Copy> ForkedParam<T> {
if self.activation.is_active(daa_score) { self.post } else { self.pre }
}

pub fn with_delayed_activation(&self, delay_daa_score: u64) -> Self {
Self::new(self.pre, self.post, self.activation.delayed_by(delay_daa_score))
}

/// Returns the value before activation (=pre unless activation = always)
pub fn before(&self) -> T {
match self.activation.0 {
Expand All @@ -107,6 +127,12 @@ impl<T: Copy> ForkedParam<T> {
}
}

impl<T: Copy> From<T> for ForkedParam<T> {
fn from(value: T) -> Self {
Self::new_const(value)
}
}

impl<T: Copy + Ord> ForkedParam<T> {
/// Returns the min of `pre` and `post` values. Useful for non-consensus initializations
/// which require knowledge of the value bounds.
Expand Down Expand Up @@ -196,12 +222,14 @@ pub struct OverrideParams {

pub max_tx_inputs: Option<usize>,
pub max_tx_outputs: Option<usize>,
pub max_signature_script_len: Option<usize>,
pub prior_max_signature_script_len: Option<usize>,
pub new_max_signature_script_len: Option<usize>,
pub max_script_public_key_len: Option<usize>,
pub mass_per_tx_byte: Option<u64>,
pub mass_per_script_pub_key_byte: Option<u64>,
pub mass_per_sig_op: Option<u64>,
pub block_mass_limits: Option<BlockMassLimits>,
pub prior_block_mass_limits: Option<BlockMassLimits>,
pub new_transient_mass_limit: Option<u64>,
pub block_lane_limits: Option<BlockLaneLimits>,

/// The parameter for scaling inverse KAS value to mass units (KIP-0009)
Expand Down Expand Up @@ -239,12 +267,14 @@ impl From<Params> for OverrideParams {
max_coinbase_payload_len: Some(p.max_coinbase_payload_len),
max_tx_inputs: Some(p.max_tx_inputs),
max_tx_outputs: Some(p.max_tx_outputs),
max_signature_script_len: Some(p.max_signature_script_len),
prior_max_signature_script_len: Some(p.prior_max_signature_script_len),
new_max_signature_script_len: Some(p.new_max_signature_script_len),
max_script_public_key_len: Some(p.max_script_public_key_len),
mass_per_tx_byte: Some(p.mass_per_tx_byte),
mass_per_script_pub_key_byte: Some(p.mass_per_script_pub_key_byte),
mass_per_sig_op: Some(p.mass_per_sig_op),
block_mass_limits: Some(p.block_mass_limits),
prior_block_mass_limits: Some(p.prior_block_mass_limits),
new_transient_mass_limit: Some(p.new_transient_mass_limit),
block_lane_limits: Some(p.block_lane_limits),
storage_mass_parameter: Some(p.storage_mass_parameter),
deflationary_phase_daa_score: Some(p.deflationary_phase_daa_score),
Expand Down Expand Up @@ -291,13 +321,15 @@ pub struct Params {

pub max_tx_inputs: usize,
pub max_tx_outputs: usize,
pub max_signature_script_len: usize,
pub prior_max_signature_script_len: usize,
pub new_max_signature_script_len: usize,
pub max_script_public_key_len: usize,

pub mass_per_tx_byte: u64,
pub mass_per_script_pub_key_byte: u64,
pub mass_per_sig_op: u64,
pub block_mass_limits: BlockMassLimits,
pub prior_block_mass_limits: BlockMassLimits,
pub new_transient_mass_limit: u64,
pub block_lane_limits: BlockLaneLimits,

/// The parameter for scaling inverse KAS value to mass units (KIP-0009)
Expand Down Expand Up @@ -365,6 +397,62 @@ impl Params {
)
}

/// Returns the forked per-dimension block mass limits.
#[inline]
#[must_use]
pub fn block_mass_limits(&self) -> ForkedParam<BlockMassLimits> {
let mut new_block_mass_limits = self.prior_block_mass_limits;
new_block_mass_limits.transient = self.new_transient_mass_limit;
ForkedParam::new(self.prior_block_mass_limits, new_block_mass_limits, self.covenants_activation)
}

/// Returns the forked cofactors for normalizing block mass dimensions.
#[inline]
#[must_use]
pub fn block_mass_cofactors(&self) -> ForkedParam<MassCofactors> {
self.block_mass_limits().map(|limits| limits.cofactors())
}

/// Returns the block mass limits used for mempool policy.
///
/// Mempool policy lags the consensus transient mass relaxation, so transactions
/// near activation are normalized by the stricter pre-activation limits.
#[inline]
#[must_use]
pub fn mempool_block_mass_limits(&self) -> ForkedParam<BlockMassLimits> {
let block_mass_limits = self.block_mass_limits();
let prior_limits = block_mass_limits.before();
let new_limits = block_mass_limits.after();
assert_eq!(
new_limits.compute, prior_limits.compute,
"delaying mempool mass activation assumes the compute mass limit does not change"
);
assert_eq!(
new_limits.storage, prior_limits.storage,
"delaying mempool mass activation assumes the storage mass limit does not change"
);
assert!(
new_limits.transient >= prior_limits.transient,
"delaying mempool mass activation is only safe when the post-activation transient limit is not stricter"
);

block_mass_limits.with_delayed_activation(MEMPOOL_BLOCK_MASS_ACTIVATION_DELAY_SECONDS.saturating_mul(self.bps()))
}

/// Returns the mempool policy cofactors for normalizing block mass dimensions.
#[inline]
#[must_use]
pub fn mempool_block_mass_cofactors(&self) -> ForkedParam<MassCofactors> {
self.mempool_block_mass_limits().map(|limits| limits.cofactors())
}

/// Returns the forked maximum signature script length.
#[inline]
#[must_use]
pub fn max_signature_script_len(&self) -> ForkedParam<usize> {
ForkedParam::new(self.prior_max_signature_script_len, self.new_max_signature_script_len, self.covenants_activation)
}

pub fn ghostdag_k(&self) -> KType {
self.blockrate.ghostdag_k
}
Expand Down Expand Up @@ -462,12 +550,14 @@ impl Params {

max_tx_inputs: overrides.max_tx_inputs.unwrap_or(self.max_tx_inputs),
max_tx_outputs: overrides.max_tx_outputs.unwrap_or(self.max_tx_outputs),
max_signature_script_len: overrides.max_signature_script_len.unwrap_or(self.max_signature_script_len),
prior_max_signature_script_len: overrides.prior_max_signature_script_len.unwrap_or(self.prior_max_signature_script_len),
new_max_signature_script_len: overrides.new_max_signature_script_len.unwrap_or(self.new_max_signature_script_len),
max_script_public_key_len: overrides.max_script_public_key_len.unwrap_or(self.max_script_public_key_len),
mass_per_tx_byte: overrides.mass_per_tx_byte.unwrap_or(self.mass_per_tx_byte),
mass_per_script_pub_key_byte: overrides.mass_per_script_pub_key_byte.unwrap_or(self.mass_per_script_pub_key_byte),
mass_per_sig_op: overrides.mass_per_sig_op.unwrap_or(self.mass_per_sig_op),
block_mass_limits: overrides.block_mass_limits.unwrap_or(self.block_mass_limits),
prior_block_mass_limits: overrides.prior_block_mass_limits.unwrap_or(self.prior_block_mass_limits),
new_transient_mass_limit: overrides.new_transient_mass_limit.unwrap_or(self.new_transient_mass_limit),
block_lane_limits: overrides.block_lane_limits.unwrap_or(self.block_lane_limits),

storage_mass_parameter: overrides.storage_mass_parameter.unwrap_or(self.storage_mass_parameter),
Expand Down Expand Up @@ -573,15 +663,17 @@ pub const MAINNET_PARAMS: Params = Params {
max_tx_inputs: 1000,
max_tx_outputs: 1000,
// Transient mass enforces a limit of 125Kb, however script engine max scripts size is 10Kb so there's no point in surpassing that.
max_signature_script_len: 10_000,
prior_max_signature_script_len: PRIOR_MAX_SIGNATURE_SCRIPT_LEN,
new_max_signature_script_len: NEW_MAX_SIGNATURE_SCRIPT_LEN,
// Compute mass enforces a limit of ~45.5Kb, however script engine max scripts size is 10Kb so there's no point in surpassing that.
// Note that storage mass will kick in and gradually penalize also for lower lengths (generalized KIP-0009, plurality will be high).
max_script_public_key_len: 10_000,

mass_per_tx_byte: 1,
mass_per_script_pub_key_byte: 10,
mass_per_sig_op: 1000,
block_mass_limits: BlockMassLimits::with_shared_limit(500_000),
prior_block_mass_limits: BlockMassLimits::with_shared_limit(500_000),
new_transient_mass_limit: 1_000_000,
block_lane_limits: BlockLaneLimits { lanes_per_block: DEFAULT_LANES_PER_BLOCK_LIMIT, gas_per_lane: DEFAULT_GAS_PER_LANE_LIMIT },

storage_mass_parameter: STORAGE_MASS_PARAMETER,
Expand Down Expand Up @@ -631,15 +723,17 @@ pub const TESTNET_PARAMS: Params = Params {
max_tx_inputs: 1000,
max_tx_outputs: 1000,
// Transient mass enforces a limit of 125Kb, however script engine max scripts size is 10Kb so there's no point in surpassing that.
max_signature_script_len: 10_000,
prior_max_signature_script_len: PRIOR_MAX_SIGNATURE_SCRIPT_LEN,
new_max_signature_script_len: NEW_MAX_SIGNATURE_SCRIPT_LEN,
// Compute mass enforces a limit of ~45.5Kb, however script engine max scripts size is 10Kb so there's no point in surpassing that.
// Note that storage mass will kick in and gradually penalize also for lower lengths (generalized KIP-0009, plurality will be high).
max_script_public_key_len: 10_000,

mass_per_tx_byte: 1,
mass_per_script_pub_key_byte: 10,
mass_per_sig_op: 1000,
block_mass_limits: BlockMassLimits::with_shared_limit(500_000),
prior_block_mass_limits: BlockMassLimits::with_shared_limit(500_000),
new_transient_mass_limit: 1_000_000,
block_lane_limits: BlockLaneLimits { lanes_per_block: DEFAULT_LANES_PER_BLOCK_LIMIT, gas_per_lane: DEFAULT_GAS_PER_LANE_LIMIT },

storage_mass_parameter: STORAGE_MASS_PARAMETER,
Expand Down Expand Up @@ -680,11 +774,12 @@ pub const TESTNET12_PARAMS: Params = Params {
net: NetworkId::with_suffix(NetworkType::Testnet, 12),
genesis: TESTNET12_GENESIS,

// Increased for stark proofs
max_signature_script_len: 300_000,
prior_max_signature_script_len: NEW_MAX_SIGNATURE_SCRIPT_LEN,
new_max_signature_script_len: NEW_MAX_SIGNATURE_SCRIPT_LEN,

// Transient mass is increased for stark proofs
block_mass_limits: BlockMassLimits { compute: 500_000, storage: 500_000, transient: 1_000_000 },
prior_block_mass_limits: BlockMassLimits { compute: 500_000, storage: 500_000, transient: 1_000_000 },
new_transient_mass_limit: 1_000_000,

deflationary_phase_daa_score: TenBps::deflationary_phase_daa_score(),
pre_deflationary_phase_base_subsidy: TenBps::pre_deflationary_phase_base_subsidy(),
Expand Down Expand Up @@ -713,15 +808,16 @@ pub const SIMNET_PARAMS: Params = Params {

max_tx_inputs: 1000,
max_tx_outputs: 1000,
// Increased for stark proofs
max_signature_script_len: 300_000,
prior_max_signature_script_len: NEW_MAX_SIGNATURE_SCRIPT_LEN,
new_max_signature_script_len: NEW_MAX_SIGNATURE_SCRIPT_LEN,
max_script_public_key_len: 10_000,

mass_per_tx_byte: 1,
mass_per_script_pub_key_byte: 10,
mass_per_sig_op: 1000,
// Transient mass is increased for stark proofs
block_mass_limits: BlockMassLimits { compute: 500_000, storage: 500_000, transient: 1_000_000 },
prior_block_mass_limits: BlockMassLimits { compute: 500_000, storage: 500_000, transient: 1_000_000 },
Comment thread
someone235 marked this conversation as resolved.
Outdated
new_transient_mass_limit: 1_000_000,
block_lane_limits: BlockLaneLimits { lanes_per_block: DEFAULT_LANES_PER_BLOCK_LIMIT, gas_per_lane: DEFAULT_GAS_PER_LANE_LIMIT },

storage_mass_parameter: STORAGE_MASS_PARAMETER,
Expand Down Expand Up @@ -754,16 +850,17 @@ pub const DEVNET_PARAMS: Params = Params {

max_tx_inputs: 1000,
max_tx_outputs: 1000,
// Increased for stark proofs
max_signature_script_len: 300_000,
prior_max_signature_script_len: NEW_MAX_SIGNATURE_SCRIPT_LEN,
new_max_signature_script_len: NEW_MAX_SIGNATURE_SCRIPT_LEN,
max_script_public_key_len: 10_000,

mass_per_tx_byte: 1,
mass_per_script_pub_key_byte: 10,
mass_per_sig_op: 1000,

// Transient mass is increased for stark proofs
block_mass_limits: BlockMassLimits { compute: 500_000, storage: 500_000, transient: 1_000_000 },
prior_block_mass_limits: BlockMassLimits { compute: 500_000, storage: 500_000, transient: 1_000_000 },
Comment thread
coderofstuff marked this conversation as resolved.
Outdated
new_transient_mass_limit: 1_000_000,
block_lane_limits: BlockLaneLimits { lanes_per_block: DEFAULT_LANES_PER_BLOCK_LIMIT, gas_per_lane: DEFAULT_GAS_PER_LANE_LIMIT },

storage_mass_parameter: STORAGE_MASS_PARAMETER,
Expand Down
2 changes: 1 addition & 1 deletion consensus/core/src/mass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ mod tests {
for net in NetworkType::iter() {
let params: Params = net.into();
let max_spk_len = (params.max_script_public_key_len as u64)
.min(params.block_mass_limits.compute.div_ceil(params.mass_per_script_pub_key_byte));
.min(params.block_mass_limits().after().compute.div_ceil(params.mass_per_script_pub_key_byte));
let max_plurality = (UTXO_CONST_STORAGE + max_spk_len).div_ceil(UTXO_UNIT_SIZE); // see utxo_plurality
let product = params.storage_mass_parameter.checked_mul(max_plurality).and_then(|x| x.checked_mul(max_plurality));
// verify C·P^2 can never overflow
Expand Down
2 changes: 1 addition & 1 deletion consensus/src/consensus/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ impl ConsensusServices {
let transaction_validator = TransactionValidator::new(
params.max_tx_inputs,
params.max_tx_outputs,
params.max_signature_script_len,
params.max_signature_script_len(),
params.max_script_public_key_len,
params.coinbase_payload_script_public_key_max_len,
params.coinbase_maturity(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ impl BlockBodyProcessor {
}

fn check_block_mass(self: &Arc<Self>, block: &Block) -> BlockProcessResult<Mass> {
let block_mass_limits = self.block_mass_limits.get(block.header.daa_score);
let mut total_compute_mass: u64 = 0;
let mut total_transient_mass: u64 = 0;
let mut total_storage_mass: u64 = 0;
Expand All @@ -84,14 +85,14 @@ impl BlockBodyProcessor {
total_storage_mass = total_storage_mass.saturating_add(storage_mass_commitment);

// Verify each dimension against its own limit
if total_compute_mass > self.block_mass_limits.compute {
return Err(RuleError::ExceedsComputeMassLimit(total_compute_mass, self.block_mass_limits.compute));
if total_compute_mass > block_mass_limits.compute {
return Err(RuleError::ExceedsComputeMassLimit(total_compute_mass, block_mass_limits.compute));
}
if total_transient_mass > self.block_mass_limits.transient {
return Err(RuleError::ExceedsTransientMassLimit(total_transient_mass, self.block_mass_limits.transient));
if total_transient_mass > block_mass_limits.transient {
return Err(RuleError::ExceedsTransientMassLimit(total_transient_mass, block_mass_limits.transient));
}
if total_storage_mass > self.block_mass_limits.storage {
return Err(RuleError::ExceedsStorageMassLimit(total_storage_mass, self.block_mass_limits.storage));
if total_storage_mass > block_mass_limits.storage {
return Err(RuleError::ExceedsStorageMassLimit(total_storage_mass, block_mass_limits.storage));
}

// Pre-Toccata valid blocks contain only native non-coinbase txs with zero gas,
Expand Down
9 changes: 6 additions & 3 deletions consensus/src/pipeline/body_processor/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ use kaspa_consensus_core::{
KType,
block::Block,
blockstatus::BlockStatus::{self, StatusHeaderOnly, StatusInvalid},
config::{genesis::GenesisBlock, params::Params},
config::{
genesis::GenesisBlock,
params::{ForkedParam, Params},
},
mass::{BlockLaneLimits, BlockMassLimits, Mass, MassCalculator},
tx::Transaction,
};
Expand Down Expand Up @@ -55,7 +58,7 @@ pub struct BlockBodyProcessor {
db: Arc<DB>,

// Config
pub(super) block_mass_limits: BlockMassLimits,
pub(super) block_mass_limits: ForkedParam<BlockMassLimits>,
pub(super) block_lane_limits: BlockLaneLimits,
pub(super) genesis: GenesisBlock,
pub(super) _ghostdag_k: KType,
Expand Down Expand Up @@ -108,7 +111,7 @@ impl BlockBodyProcessor {
thread_pool,
db,

block_mass_limits: params.block_mass_limits,
block_mass_limits: params.block_mass_limits(),
block_lane_limits: params.block_lane_limits,
genesis: params.genesis.clone(),
_ghostdag_k: params.ghostdag_k(),
Expand Down
4 changes: 2 additions & 2 deletions consensus/src/pipeline/virtual_processor/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub struct VirtualStateProcessor {
pub(super) max_block_parents: u8,
pub(super) mergeset_size_limit: u64,
pub(super) finality_depth: u64,
pub(super) mass_cofactors: kaspa_consensus_core::mass::MassCofactors,
pub(super) mempool_mass_cofactors: kaspa_consensus_core::config::params::ForkedParam<kaspa_consensus_core::mass::MassCofactors>,

// Stores
pub(super) statuses_store: Arc<RwLock<DbStatusesStore>>,
Expand Down Expand Up @@ -206,7 +206,7 @@ impl VirtualStateProcessor {
genesis: params.genesis.clone(),
max_block_parents: params.max_block_parents(),
mergeset_size_limit: params.mergeset_size_limit(),
mass_cofactors: params.block_mass_limits.cofactors(),
mempool_mass_cofactors: params.mempool_block_mass_cofactors(),

db,
statuses_store: storage.statuses_store.clone(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ impl VirtualStateProcessor {
// At this point we know all UTXO entries are populated, so we can safely pass the tx as verifiable
let mass_and_feerate_threshold = args.feerate_threshold.map(|threshold| {
let mass = kaspa_consensus_core::mass::Mass::new(mutable_tx.calculated_non_contextual_masses.unwrap(), contextual_mass);
(mass.normalized_max(&self.mass_cofactors), threshold)
(mass.normalized_max(&self.mempool_mass_cofactors.get(pov_daa_score)), threshold)
});

let seq_commit_accessor = if self.covenants_activation.is_active(pov_daa_score) {
Expand Down
Loading