Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
116 changes: 58 additions & 58 deletions Cargo.lock

Large diffs are not rendered by default.

112 changes: 56 additions & 56 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ members = [

[workspace.package]
rust-version = "1.82.0"
version = "0.15.3"
version = "0.15.4"
authors = ["Kaspa developers"]
license = "ISC"
repository = "https://github.com/kaspanet/rusty-kaspa"
Expand All @@ -80,61 +80,61 @@ include = [
]

[workspace.dependencies]
# kaspa-testing-integration = { version = "0.15.3", path = "testing/integration" }
kaspa-addresses = { version = "0.15.3", path = "crypto/addresses" }
kaspa-addressmanager = { version = "0.15.3", path = "components/addressmanager" }
kaspa-bip32 = { version = "0.15.3", path = "wallet/bip32" }
kaspa-cli = { version = "0.15.3", path = "cli" }
kaspa-connectionmanager = { version = "0.15.3", path = "components/connectionmanager" }
kaspa-consensus = { version = "0.15.3", path = "consensus" }
kaspa-consensus-core = { version = "0.15.3", path = "consensus/core" }
kaspa-consensus-client = { version = "0.15.3", path = "consensus/client" }
kaspa-consensus-notify = { version = "0.15.3", path = "consensus/notify" }
kaspa-consensus-wasm = { version = "0.15.3", path = "consensus/wasm" }
kaspa-consensusmanager = { version = "0.15.3", path = "components/consensusmanager" }
kaspa-core = { version = "0.15.3", path = "core" }
kaspa-daemon = { version = "0.15.3", path = "daemon" }
kaspa-database = { version = "0.15.3", path = "database" }
kaspa-grpc-client = { version = "0.15.3", path = "rpc/grpc/client" }
kaspa-grpc-core = { version = "0.15.3", path = "rpc/grpc/core" }
kaspa-grpc-server = { version = "0.15.3", path = "rpc/grpc/server" }
kaspa-hashes = { version = "0.15.3", path = "crypto/hashes" }
kaspa-index-core = { version = "0.15.3", path = "indexes/core" }
kaspa-index-processor = { version = "0.15.3", path = "indexes/processor" }
kaspa-math = { version = "0.15.3", path = "math" }
kaspa-merkle = { version = "0.15.3", path = "crypto/merkle" }
kaspa-metrics-core = { version = "0.15.3", path = "metrics/core" }
kaspa-mining = { version = "0.15.3", path = "mining" }
kaspa-mining-errors = { version = "0.15.3", path = "mining/errors" }
kaspa-muhash = { version = "0.15.3", path = "crypto/muhash" }
kaspa-notify = { version = "0.15.3", path = "notify" }
kaspa-p2p-flows = { version = "0.15.3", path = "protocol/flows" }
kaspa-p2p-lib = { version = "0.15.3", path = "protocol/p2p" }
kaspa-perf-monitor = { version = "0.15.3", path = "metrics/perf_monitor" }
kaspa-pow = { version = "0.15.3", path = "consensus/pow" }
kaspa-rpc-core = { version = "0.15.3", path = "rpc/core" }
kaspa-rpc-macros = { version = "0.15.3", path = "rpc/macros" }
kaspa-rpc-service = { version = "0.15.3", path = "rpc/service" }
kaspa-txscript = { version = "0.15.3", path = "crypto/txscript" }
kaspa-txscript-errors = { version = "0.15.3", path = "crypto/txscript/errors" }
kaspa-utils = { version = "0.15.3", path = "utils" }
kaspa-utils-tower = { version = "0.15.3", path = "utils/tower" }
kaspa-utxoindex = { version = "0.15.3", path = "indexes/utxoindex" }
kaspa-wallet = { version = "0.15.3", path = "wallet/native" }
kaspa-wallet-cli-wasm = { version = "0.15.3", path = "wallet/wasm" }
kaspa-wallet-keys = { version = "0.15.3", path = "wallet/keys" }
kaspa-wallet-pskt = { version = "0.15.3", path = "wallet/pskt" }
kaspa-wallet-core = { version = "0.15.3", path = "wallet/core" }
kaspa-wallet-macros = { version = "0.15.3", path = "wallet/macros" }
kaspa-wasm = { version = "0.15.3", path = "wasm" }
kaspa-wasm-core = { version = "0.15.3", path = "wasm/core" }
kaspa-wrpc-client = { version = "0.15.3", path = "rpc/wrpc/client" }
kaspa-wrpc-proxy = { version = "0.15.3", path = "rpc/wrpc/proxy" }
kaspa-wrpc-server = { version = "0.15.3", path = "rpc/wrpc/server" }
kaspa-wrpc-wasm = { version = "0.15.3", path = "rpc/wrpc/wasm" }
kaspa-wrpc-example-subscriber = { version = "0.15.3", path = "rpc/wrpc/examples/subscriber" }
kaspad = { version = "0.15.3", path = "kaspad" }
kaspa-alloc = { version = "0.15.3", path = "utils/alloc" }
# kaspa-testing-integration = { version = "0.15.4", path = "testing/integration" }
kaspa-addresses = { version = "0.15.4", path = "crypto/addresses" }
kaspa-addressmanager = { version = "0.15.4", path = "components/addressmanager" }
kaspa-bip32 = { version = "0.15.4", path = "wallet/bip32" }
kaspa-cli = { version = "0.15.4", path = "cli" }
kaspa-connectionmanager = { version = "0.15.4", path = "components/connectionmanager" }
kaspa-consensus = { version = "0.15.4", path = "consensus" }
kaspa-consensus-core = { version = "0.15.4", path = "consensus/core" }
kaspa-consensus-client = { version = "0.15.4", path = "consensus/client" }
kaspa-consensus-notify = { version = "0.15.4", path = "consensus/notify" }
kaspa-consensus-wasm = { version = "0.15.4", path = "consensus/wasm" }
kaspa-consensusmanager = { version = "0.15.4", path = "components/consensusmanager" }
kaspa-core = { version = "0.15.4", path = "core" }
kaspa-daemon = { version = "0.15.4", path = "daemon" }
kaspa-database = { version = "0.15.4", path = "database" }
kaspa-grpc-client = { version = "0.15.4", path = "rpc/grpc/client" }
kaspa-grpc-core = { version = "0.15.4", path = "rpc/grpc/core" }
kaspa-grpc-server = { version = "0.15.4", path = "rpc/grpc/server" }
kaspa-hashes = { version = "0.15.4", path = "crypto/hashes" }
kaspa-index-core = { version = "0.15.4", path = "indexes/core" }
kaspa-index-processor = { version = "0.15.4", path = "indexes/processor" }
kaspa-math = { version = "0.15.4", path = "math" }
kaspa-merkle = { version = "0.15.4", path = "crypto/merkle" }
kaspa-metrics-core = { version = "0.15.4", path = "metrics/core" }
kaspa-mining = { version = "0.15.4", path = "mining" }
kaspa-mining-errors = { version = "0.15.4", path = "mining/errors" }
kaspa-muhash = { version = "0.15.4", path = "crypto/muhash" }
kaspa-notify = { version = "0.15.4", path = "notify" }
kaspa-p2p-flows = { version = "0.15.4", path = "protocol/flows" }
kaspa-p2p-lib = { version = "0.15.4", path = "protocol/p2p" }
kaspa-perf-monitor = { version = "0.15.4", path = "metrics/perf_monitor" }
kaspa-pow = { version = "0.15.4", path = "consensus/pow" }
kaspa-rpc-core = { version = "0.15.4", path = "rpc/core" }
kaspa-rpc-macros = { version = "0.15.4", path = "rpc/macros" }
kaspa-rpc-service = { version = "0.15.4", path = "rpc/service" }
kaspa-txscript = { version = "0.15.4", path = "crypto/txscript" }
kaspa-txscript-errors = { version = "0.15.4", path = "crypto/txscript/errors" }
kaspa-utils = { version = "0.15.4", path = "utils" }
kaspa-utils-tower = { version = "0.15.4", path = "utils/tower" }
kaspa-utxoindex = { version = "0.15.4", path = "indexes/utxoindex" }
kaspa-wallet = { version = "0.15.4", path = "wallet/native" }
kaspa-wallet-cli-wasm = { version = "0.15.4", path = "wallet/wasm" }
kaspa-wallet-keys = { version = "0.15.4", path = "wallet/keys" }
kaspa-wallet-pskt = { version = "0.15.4", path = "wallet/pskt" }
kaspa-wallet-core = { version = "0.15.4", path = "wallet/core" }
kaspa-wallet-macros = { version = "0.15.4", path = "wallet/macros" }
kaspa-wasm = { version = "0.15.4", path = "wasm" }
kaspa-wasm-core = { version = "0.15.4", path = "wasm/core" }
kaspa-wrpc-client = { version = "0.15.4", path = "rpc/wrpc/client" }
kaspa-wrpc-proxy = { version = "0.15.4", path = "rpc/wrpc/proxy" }
kaspa-wrpc-server = { version = "0.15.4", path = "rpc/wrpc/server" }
kaspa-wrpc-wasm = { version = "0.15.4", path = "rpc/wrpc/wasm" }
kaspa-wrpc-example-subscriber = { version = "0.15.4", path = "rpc/wrpc/examples/subscriber" }
kaspad = { version = "0.15.4", path = "kaspad" }
kaspa-alloc = { version = "0.15.4", path = "utils/alloc" }

# external
aes = "0.8.3"
Expand Down
2 changes: 1 addition & 1 deletion consensus/core/src/config/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ pub mod perf {

/// The default slack interval used by the reachability
/// algorithm to encounter for blocks out of the selected chain.
pub const DEFAULT_REINDEX_SLACK: u64 = 1 << 12;
pub const DEFAULT_REINDEX_SLACK: u64 = 1 << 14;

const BASELINE_HEADER_DATA_CACHE_SIZE: usize = 10_000;
const BASELINE_BLOCK_DATA_CACHE_SIZE: usize = 200;
Expand Down
6 changes: 3 additions & 3 deletions consensus/core/src/config/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,12 +533,12 @@ pub const TESTNET11_PARAMS: Params = Params {

storage_mass_parameter: STORAGE_MASS_PARAMETER,
storage_mass_activation: ForkActivation::always(),
kip10_activation: ForkActivation::never(),
// Roughly at Dec 3, 2024 1800 UTC
kip10_activation: ForkActivation::new(287238000),
payload_activation: ForkActivation::new(287238000),

skip_proof_of_work: false,
max_block_level: 250,

payload_activation: ForkActivation::never(),
};

pub const SIMNET_PARAMS: Params = Params {
Expand Down
94 changes: 8 additions & 86 deletions consensus/core/src/mass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,6 @@ use crate::{
};
use kaspa_hashes::HASH_SIZE;

/// Temp enum for the transition phases of KIP9
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Kip9Version {
/// Initial KIP9 mass calculation, w/o the relaxed formula and summing storage mass and compute mass
Alpha,

/// Currently proposed KIP9 mass calculation, with the relaxed formula (for the cases `|O| = 1 OR |O| <= |I| <= 2`),
/// and using a maximum operator over storage and compute mass
Beta,
}

// transaction_estimated_serialized_size is the estimated size of a transaction in some
// serialization. This has to be deterministic, but not necessarily accurate, since
// it's only used as the size component in the transaction and block mass limit
Expand Down Expand Up @@ -121,32 +110,18 @@ impl MassCalculator {
/// 2. At least one input (unless coinbase)
///
/// Otherwise this function should never fail.
pub fn calc_tx_storage_mass(&self, tx: &impl VerifiableTransaction, version: Kip9Version) -> Option<u64> {
pub fn calc_tx_storage_mass(&self, tx: &impl VerifiableTransaction) -> Option<u64> {
calc_storage_mass(
tx.is_coinbase(),
tx.populated_inputs().map(|(_, entry)| entry.amount),
tx.outputs().iter().map(|out| out.value),
version,
self.storage_mass_parameter,
)
}

/// Calculates the overall mass of this transaction, combining both compute and storage masses.
/// The combination strategy depends on the version passed.
pub fn calc_tx_overall_mass(
&self,
tx: &impl VerifiableTransaction,
cached_compute_mass: Option<u64>,
version: Kip9Version,
) -> Option<u64> {
match version {
Kip9Version::Alpha => self
.calc_tx_storage_mass(tx, version)
.and_then(|mass| mass.checked_add(cached_compute_mass.unwrap_or_else(|| self.calc_tx_compute_mass(tx.tx())))),
Kip9Version::Beta => self
.calc_tx_storage_mass(tx, version)
.map(|mass| mass.max(cached_compute_mass.unwrap_or_else(|| self.calc_tx_compute_mass(tx.tx())))),
}
pub fn calc_tx_overall_mass(&self, tx: &impl VerifiableTransaction, cached_compute_mass: Option<u64>) -> Option<u64> {
self.calc_tx_storage_mass(tx).map(|mass| mass.max(cached_compute_mass.unwrap_or_else(|| self.calc_tx_compute_mass(tx.tx()))))
}
}

Expand All @@ -160,7 +135,6 @@ pub fn calc_storage_mass(
is_coinbase: bool,
input_values: impl ExactSizeIterator<Item = u64>,
output_values: impl ExactSizeIterator<Item = u64>,
version: Kip9Version,
storage_mass_parameter: u64,
) -> Option<u64> {
if is_coinbase {
Expand Down Expand Up @@ -199,7 +173,7 @@ pub fn calc_storage_mass(
Note: in the case |I| = 1 both formulas are equal, yet the following code (harmonic_ins) is a bit more efficient.
Hence, we transform the condition to |O| = 1 OR |I| = 1 OR |O| = |I| = 2 which is equivalent (and faster).
*/
if version == Kip9Version::Beta && (outs_len == 1 || ins_len == 1 || (outs_len == 2 && ins_len == 2)) {
if outs_len == 1 || ins_len == 1 || (outs_len == 2 && ins_len == 2) {
let harmonic_ins =
input_values.map(|value| storage_mass_parameter / value).fold(0u64, |total, current| total.saturating_add(current)); // C·|I|/H(I)
return Some(harmonic_outs.saturating_sub(harmonic_ins)); // max( 0 , C·( |O|/H(O) - |I|/H(I) ) );
Expand All @@ -219,81 +193,29 @@ pub fn calc_storage_mass(
#[cfg(test)]
mod tests {
use super::*;
use crate::{
constants::{SOMPI_PER_KASPA, STORAGE_MASS_PARAMETER},
subnets::SubnetworkId,
tx::*,
};
use crate::{subnets::SubnetworkId, tx::*};
use std::str::FromStr;

#[test]
fn test_mass_storage() {
// Tx with less outs than ins
let mut tx = generate_tx_from_amounts(&[100, 200, 300], &[300, 300]);
let test_version = Kip9Version::Alpha;

// Assert the formula: max( 0 , C·( |O|/H(O) - |I|/A(I) ) )

let storage_mass =
MassCalculator::new(0, 0, 0, 10u64.pow(12)).calc_tx_storage_mass(&tx.as_verifiable(), test_version).unwrap();
assert_eq!(storage_mass, 0); // Compounds from 3 to 2, with symmetric outputs and no fee, should be zero

// Create asymmetry
tx.tx.outputs[0].value = 50;
tx.tx.outputs[1].value = 550;
let storage_mass_parameter = 10u64.pow(12);
let storage_mass =
MassCalculator::new(0, 0, 0, storage_mass_parameter).calc_tx_storage_mass(&tx.as_verifiable(), test_version).unwrap();
assert_eq!(storage_mass, storage_mass_parameter / 50 + storage_mass_parameter / 550 - 3 * (storage_mass_parameter / 200));

// Create a tx with more outs than ins
let base_value = 10_000 * SOMPI_PER_KASPA;
let mut tx = generate_tx_from_amounts(&[base_value, base_value, base_value * 2], &[base_value; 4]);
let storage_mass_parameter = STORAGE_MASS_PARAMETER;
let storage_mass =
MassCalculator::new(0, 0, 0, storage_mass_parameter).calc_tx_storage_mass(&tx.as_verifiable(), test_version).unwrap();
assert_eq!(storage_mass, 4); // Inputs are above C so they don't contribute negative mass, 4 outputs exactly equal C each charge 1

let mut tx2 = tx.clone();
tx2.tx.outputs[0].value = 10 * SOMPI_PER_KASPA;
let storage_mass =
MassCalculator::new(0, 0, 0, storage_mass_parameter).calc_tx_storage_mass(&tx2.as_verifiable(), test_version).unwrap();
assert_eq!(storage_mass, 1003);

// Increase values over the lim
for out in tx.tx.outputs.iter_mut() {
out.value += 1
}
tx.entries[0].as_mut().unwrap().amount += tx.tx.outputs.len() as u64;
let storage_mass =
MassCalculator::new(0, 0, 0, storage_mass_parameter).calc_tx_storage_mass(&tx.as_verifiable(), test_version).unwrap();
assert_eq!(storage_mass, 0);
}

#[test]
fn test_mass_storage_beta() {
// 2:2 transaction
let mut tx = generate_tx_from_amounts(&[100, 200], &[50, 250]);
let storage_mass_parameter = 10u64.pow(12);
let test_version = Kip9Version::Beta;
// Assert the formula: max( 0 , C·( |O|/H(O) - |I|/O(I) ) )

let storage_mass =
MassCalculator::new(0, 0, 0, storage_mass_parameter).calc_tx_storage_mass(&tx.as_verifiable(), test_version).unwrap();
let storage_mass = MassCalculator::new(0, 0, 0, storage_mass_parameter).calc_tx_storage_mass(&tx.as_verifiable()).unwrap();
assert_eq!(storage_mass, 9000000000);

// Set outputs to be equal to inputs
tx.tx.outputs[0].value = 100;
tx.tx.outputs[1].value = 200;
let storage_mass =
MassCalculator::new(0, 0, 0, storage_mass_parameter).calc_tx_storage_mass(&tx.as_verifiable(), test_version).unwrap();
let storage_mass = MassCalculator::new(0, 0, 0, storage_mass_parameter).calc_tx_storage_mass(&tx.as_verifiable()).unwrap();
assert_eq!(storage_mass, 0);

// Remove an output and make sure the other is small enough to make storage mass greater than zero
tx.tx.outputs.pop();
tx.tx.outputs[0].value = 50;
let storage_mass =
MassCalculator::new(0, 0, 0, storage_mass_parameter).calc_tx_storage_mass(&tx.as_verifiable(), test_version).unwrap();
let storage_mass = MassCalculator::new(0, 0, 0, storage_mass_parameter).calc_tx_storage_mass(&tx.as_verifiable()).unwrap();
assert_eq!(storage_mass, 5000000000);
}

Expand Down
8 changes: 4 additions & 4 deletions consensus/src/consensus/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,12 @@ impl ConsensusStorage {
// Budgets in bytes. All byte budgets overall sum up to ~1GB of memory (which obviously takes more low level alloc space)
let daa_excluded_budget = scaled(30_000_000);
let statuses_budget = scaled(30_000_000);
let reachability_data_budget = scaled(20_000_000);
let reachability_sets_budget = scaled(20_000_000); // x 2 for tree children and future covering set
let reachability_data_budget = scaled(100_000_000);
let reachability_sets_budget = scaled(100_000_000); // x 2 for tree children and future covering set
let ghostdag_compact_budget = scaled(15_000_000);
let headers_compact_budget = scaled(5_000_000);
let parents_budget = scaled(40_000_000); // x 3 for reachability and levels
let children_budget = scaled(5_000_000); // x 3 for reachability and levels
let parents_budget = scaled(80_000_000); // x 3 for reachability and levels
let children_budget = scaled(20_000_000); // x 3 for reachability and levels
let ghostdag_budget = scaled(80_000_000); // x 2 for levels
let headers_budget = scaled(80_000_000);
let transactions_budget = scaled(40_000_000);
Expand Down
8 changes: 4 additions & 4 deletions consensus/src/model/services/reachability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ pub trait ReachabilityService {
/// Note that we use the graph theory convention here which defines that a block is also an ancestor of itself.
fn is_chain_ancestor_of(&self, this: Hash, queried: Hash) -> bool;

/// Result version of [`is_dag_ancestor_of`] (avoids unwrapping internally)
/// Result version of [`Self::is_dag_ancestor_of`] (avoids unwrapping internally)
fn is_dag_ancestor_of_result(&self, this: Hash, queried: Hash) -> Result<bool>;

/// Returns true if `this` is a DAG ancestor of `queried` (i.e., `queried ∈ future(this) ∪ {this}`).
/// Note: this method will return true if `this == queried`.
/// The complexity of this method is `O(log(|future_covering_set(this)|))`
fn is_dag_ancestor_of(&self, this: Hash, queried: Hash) -> bool;

/// Checks if `this` is DAG ancestor of any of the blocks in `queried`. See [`is_dag_ancestor_of`] as well.
/// Checks if `this` is DAG ancestor of any of the blocks in `queried`. See [`Self::is_dag_ancestor_of`] as well.
fn is_dag_ancestor_of_any(&self, this: Hash, queried: &mut impl Iterator<Item = Hash>) -> bool;

/// Checks if any of the blocks in `list` is DAG ancestor of `queried`. See [`is_dag_ancestor_of`] as well.
/// Checks if any of the blocks in `list` is DAG ancestor of `queried`. See [`Self::is_dag_ancestor_of`] as well.
fn is_any_dag_ancestor(&self, list: &mut impl Iterator<Item = Hash>, queried: Hash) -> bool;

/// Result version of [`is_any_dag_ancestor`] (avoids unwrapping internally)
/// Result version of [`Self::is_any_dag_ancestor`] (avoids unwrapping internally)
fn is_any_dag_ancestor_result(&self, list: &mut impl Iterator<Item = Hash>, queried: Hash) -> Result<bool>;

/// Finds the tree child of `ancestor` which is also a chain ancestor of `descendant`.
Expand Down
2 changes: 2 additions & 0 deletions consensus/src/pipeline/virtual_processor/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ pub struct VirtualStateProcessor {

// Storage mass hardfork DAA score
pub(crate) storage_mass_activation: ForkActivation,
pub(crate) kip10_activation: ForkActivation,
}

impl VirtualStateProcessor {
Expand Down Expand Up @@ -230,6 +231,7 @@ impl VirtualStateProcessor {
notification_root,
counters,
storage_mass_activation: params.storage_mass_activation,
kip10_activation: params.kip10_activation,
}
}

Expand Down
Loading
Loading