Skip to content

Latest commit

 

History

History
160 lines (112 loc) · 14.7 KB

kip-0014.md

File metadata and controls

160 lines (112 loc) · 14.7 KB
KIP: 14
Layer: Consensus (hard fork)
Title: The Crescendo Hardfork
Type: Consensus change (block rate, script engine)
Author: Michael Sutton <[email protected]>
Comments-URI: https://research.kas.pa/t/crescendo-hardfork-discussion-thread/279
created: 2025-01-21
updated: 2025-01-21
Status: Draft

Abstract

This KIP proposes the implementation of the Crescendo Hardfork for the Kaspa network, detailing the consensus changes and transition strategy for various components. The primary change in this KIP is the increase in Blocks Per Second (BPS) from 1 to 10, a significant adjustment with wide-ranging implications for node performance as well as storage and bandwidth requirements. This necessitates updates to many consensus parameters and, in some cases, a rethinking of existing mechanisms to ensure they remain efficient at the increased block rate (e.g., the sparse DAA window introduced in KIP-4).

Additionally, this hardfork includes the activation of other significant improvements to Kaspa. Starting with KIP-9, which introduces a critical mechanism for managing and mitigating state bloat, thereby regulating persistent storage requirements. This is complemented by KIP-13, which regulates transient storage requirements for a node. Another major component activated in this hardfork is KIP-10, which introduces new introspection opcodes to Kaspa's script engine. Through such introspection, these opcodes enable the concept of covenants, allowing for advanced transaction controls, including the design of additive addresses that support microtransactions and complement KIP-9.

This hardfork also marks the closure of KIP-1, the Kaspa Rust Rewrite. The performance improvements enabled by Rusty Kaspa (RK) provide the foundation necessary to support this upgrade, allowing the network to handle the increased demands of 10 BPS and beyond.

Motivation

The Crescendo Hardfork is a proactive upgrade to the Kaspa network, made possible through RK. With TN11—a testnet operating at 10 BPS—running stably for over a year, the network has demonstrated its readiness for this transition. By increasing capacity and speed, this upgrade positions Kaspa to support anticipated demand from emerging technologies, including smart contract layers enabled via the ongoing based ZK bridge design [1].

All of the changes described in this KIP (excluding KIP-13) have already been implemented and tested in TN11, providing valuable insights into their performance and stability. These results ensure that the proposed modifications are ready for deployment on the Kaspa mainnet.

Specification

Consensus changes

1. BPS-related changes

The following details the changes solely related to the bps increase.

  1. Increasing BPS from 1 to 10:

    • This change is governed by a consensus parameter named target_time_per_block (milliseconds), which controls the expected time between blocks. To increase bps from 1 to 10, the target_time_per_block will be reduced from 1000 ms to 100 ms.
    • This adjustment will in turn cause the difficulty adjustment algorithm to reduce the difficulty by a factor of 10, thus accelerating block creation tenfold. Further details on this switch are provided below under "Transitioning strategy".
  2. Re-adjusting the Ghostdag K parameter:

    • Reducing block time leads to a higher rate of parallel blocks. Consequently, the Ghostdag K parameter, which is a function of $2 \lambda D$ (where $\lambda$ is the block rate and $D$ is the a priori delay bound), must be recalibrated to maintain network security adhering to the Ghostdag formula (see eq. 1 from section 4.2 of the PHANTOM-GHOSTDAG paper [2]).
    • Setting $D=5, \delta=0.01$, the new Ghostdag K is recalculated to be 124 based on the Poisson tail cutoff therein.
  3. Scaling time-based consensus parameters:

    • Several parameters conceptually defined by time duration but applied via block count must be scaled with the new bps:
      • Finality Depth ($\phi$): Previously defined for a 24-hour duration at 1 bps (86,400 blocks), it will now correspond to a 12-hour duration at 10 bps (432,000 blocks).
      • Merge Depth Bound ($M$): Defined for a 1-hour duration, it will now increase from 3600 blocks at 1 bps to 36,000 blocks at 10 bps.
      • Pruning Depth: Calculated as $\phi + 2M + 4KL + 2K + 2$ [3], where:
        • $\phi$: Finality Depth
        • $M$: Merge Depth Bound
        • $L$: Mergeset Size Limit (see below)
        • $K$: Ghostdag K
        • The pruning depth formula provides a lower bound, yet the actual pruning period can be set longer. Plugging in the scaled parameters, the lower bound is calculated to be 627,258 blocks, representing approximately ~17.4238 hours. We suggest rounding this up to 30 hours for simplicity and practical application. A 30-hour period is closer to the current mainnet pruning period (~51 hours) and aligns closely with the value used and benchmarked throughout TN11 (~31 hours).
      • Coinbase Maturity: Originally defined as 100 seconds or ~100 blocks at 1 bps, this will now correspond to 1000 blocks at 10 bps.
  4. Conservative scaling of performance-impacting parameters:

    • Max Block Parents: Increased from 10 to 16. Based on continuous TN11 data, 16 remains well above the average number of DAG tips, ensuring that all tips are normally merged by subsequent blocks.
    • Mergeset Size Limit ($L$): Increased from 180 to 248 ($2K$) to accommodate the higher bps while maintaining storage efficiency.
  5. Adjustments to the Coinbase reward mechanism:

    • The scheme described below keeps the reward system and the emission schedule precisely intact by conceptually transferring the current reward per block to a reward per second with equal value.
    • Specifically, the reward table will continue to map from months to rewards, but the reward is now considered a per-second reward. To calculate the per-block reward, the per-second reward is divided by the bps.
    • Special care must be taken to correctly calculate the current emission month. Previously, the DAA score (essentially a block count) mapped directly to seconds since blocks were produced at a rate of 1 block per second. Post-hardfork, with 10 bps, the DAA score at activation must be used to maintain accurate second counting.
    • Two key values are used in the subsidy month calculation:
      • deflationary_phase_daa_score: A constant from the current consensus rules that marks the start of the deflationary phase.
      • crescendo_activation_daa_score: The DAA score at the time of the Crescendo activation, which will be set as part of the hardfork's implementation.
    • The following code depicts the required permanent change in subsidy month calculation. The returned subsidy_month value can then be used as before to extract the reward from the subsidy-by-month table.
    // We define a year as 365.25 days and a month as 365.25 / 12 = 30.4375
    // SECONDS_PER_MONTH = 30.4375 * 24 * 60 * 60
    const SECONDS_PER_MONTH: u64 = 2629800;

    fn subsidy_month(daa_score: u64) -> u64 {
        if daa_score < crescendo_activation_daa_score {
            // Pre activation, we simply assume block count represents second units (since block per second = 1)
            return (daa_score - deflationary_phase_daa_score) / SECONDS_PER_MONTH;
        }

        // Else, count seconds differently before and after Crescendo activation
        let seconds_since_deflationary_phase_started = 
            (crescendo_activation_daa_score - deflationary_phase_daa_score) + 
            (daa_score - crescendo_activation_daa_score) / bps;
        return seconds_since_deflationary_phase_started / SECONDS_PER_MONTH;
    }

2. Activation of earlier KIPs

  • Activation of KIP-4: Sparse DAA and Median Time Windows:

    • Transitioning to sparse Difficulty Adjustment Algorithm (DAA) and sparse Median Time (MT) windows while maintaining their previous durations (2641 seconds for DAA; 263 seconds for Median Time).
    • The size of these sparse windows (in blocks) is determined by dividing their durations by chosen sampling intervals. For DAA, we choose a sampling interval of 4 seconds, resulting in a window size of $\lceil 2641/4 \rceil = 661$. For MT, we choose a sampling interval of 10 seconds, resulting in $\lceil 263/10 \rceil = 27$. Notably, these window sizes are now independent of bps.
    • Sampling intervals are scaled by bps to calculate block sample rates:
      • past_median_time_sample_rate = 100 (from MEDIAN_TIME_SAMPLE_INTERVAL=10).
      • difficulty_adjustment_sample_rate = 40 (from DIFFICULTY_WINDOW_SAMPLE_INTERVAL=4).
  • KIP-9 (Storage Mass): Introduces a storage mass formula to mitigate and regulate UTXO set growth in both organic and adversarial conditions.

  • KIP-13 (Transient Storage Mass): Implements transient storage mass to regulate short-term storage usage.

  • KIP-10 (Script Engine Enhancements): Introduces direct introspection within the script engine, enabling covenants and advanced transaction controls.

3. Additional changes

The following details additional minor changes that do not warrant a separate KIP.

Enabling transaction payloads

This hardfork introduces support for arbitrary data in the payload field of native (non-coinbase) transactions. Native transactions, which represent the standard transaction type, now support payloads, while coinbase transactions retain their existing restricted format. Transactions already include a reserved byte array field named payload, which was previously required to remain empty for native transactions. This restriction is now lifted, enabling native transactions to carry arbitrary data.

To ensure proper handling, the sighash mechanism must be adapted to include the payload field, proving authorization over the payload. This is achieved by hashing the payload into a payload_hash and incorporating it into the overall sighash. For backwards compatibility, if the payload is empty, the zero hash is returned as the payload_hash.

The payload field is already included in the transaction hash and id in current Kaspa implementations. However, other clients may have assumed this field is always empty and must verify their implementations to account for it.

This change enables preliminary second-layer smart contract implementations, leveraging Kaspa for sequencing and data availability without settlement functionality yet. Abuse or spam risks are mitigated by the transient storage regulation introduced in KIP-13. This functionality has already been implemented in RK and activated for TN11 (pull request).

Requiring first block parent as Ghostdag selected parent

A new consensus header-validity rule is introduced where the first direct block parent must be the Ghostdag selected parent. This simplifies bringing a witness of the selected chain, particularly for scenarios pre-KIP-6 (which is unplanned for this hardfork).

Transitioning strategy

General activation strategy

In Kaspa, the DAA score of a block typically determines when forking rules are activated. However, certain consensus changes can affect the DAA score of the block itself, resulting in circular logic. One notable example is the activation of KIP-4 (sparse DAA window), which modifies how the DAA score is calculated. To avoid this cycle, we propose using the DAA score of the block's selected parent to determine activation. Another scenario where the selected parent's score must be considered instead is the increase in Ghostdag K, since Ghostdag is computed before the DAA score is known.

To simplify implementation, we suggest extending this method to all header-related changes, which includes bps-related changes (excluding coinbase rewards) and the first-parent rule.

For KIPs 9, 10, and 13, as well as payload activation and coinbase reward changes (all block-body-related), we recommend using the usual, more straightforward approach of relying on the DAA score of the block itself.

Handling difficulty adjustment during the transition

When transitioning to 10 bps, a significant challenge arises because the DAA window post-activation spans both the 1 bps and 10 bps eras. Careful consideration is required to prevent an overly large decrease in difficulty caused by the slower block production rate at the beginning of the window. Furthermore, the adoption of KIP-4 introduces an additional layer of complexity, as we are shifting from a full DAA window to a sparse one.

Proposed solution

To address these challenges, the following approach is proposed:

  • Reset the DAA window: The DAA window should be reset at the activation point and should include only blocks mined post-activation.
  • Difficulty calculation for initial blocks:
    • Empty window: When the window is empty (i.e., the selected parent was mined before activation), increase the difficulty target by a factor of 10, reflecting the new bps. This adjustment reduces the amount of work required to find a block by tenfold, resulting in a tenfold increase in block rate with the same hashrate.
    • Partial window: For blocks where the window contains some post-activation blocks but has not yet reached the minimum required size, use the selected parent's difficulty as is.
  • Minimum window size: The minimum window size should be set to a value in the range of 60–661 blocks, corresponding to approximately 4–44 minutes, to balance stability and responsiveness.

Pruning point adjustment

Upon activation, the pruning depth increases to accommodate the higher bps. However, the pruning point itself should not regress to meet the new depth immediately. Instead, it must transition gradually under the updated rules, remaining fixed at its current location until a point above it accumulates sufficient depth. This ensures pruning point monotonicity.

Rigorous pruning point rules

  1. Denote $B_n$ as the block at depth $n$ on its selected chain. Note that the definition of depth remains unchanged from current rules.
  2. For every block $B$ mined post-activation, let $pre(B)$ denote the pruning point of its last chain ancestor mined pre-activation.
  3. Denote the new pruning depth as $P$.
  4. The pruning point for a post-activation block $B$, denoted $\pi(B)$, is determined by the following rule: $\pi(B) := \max(pre(B), B_P)$.

Acknowledgment

I thank @coderofstuff for helping with the management of the hardfork detailed in this KIP, and all of Kaspa's core developers and researchers for their diligent work toward this massive endeavor.

References