Skip to content

feat(consensus): implement kip-15 ( DONT MERGE before refactoring a description .... ) #1

Open
reshmem wants to merge 44 commits intomasterfrom
canonical_tx_order_kip
Open

feat(consensus): implement kip-15 ( DONT MERGE before refactoring a description .... ) #1
reshmem wants to merge 44 commits intomasterfrom
canonical_tx_order_kip

Conversation

@reshmem
Copy link

@reshmem reshmem commented Feb 8, 2025

Accepted-ID-MR = Hash ( SP.Accepted-ID-MR, MR of Accepted-TXs ) as described in https://github.com/svarogg/kips/blob/kip-0015.md/kip-0015.md

Will be happy for a review. 2 things to pay attention to:

  1. I am not 100% about DAA for HF activation. I mean I am not 100% sure I took the right value in both places. Please double check me.

  2. The Hash computation, maybe it worth moving the computation code to some place under new function name ?

let hash_merkle_root = calc_hash_merkle_root(txs.iter(), storage_mass_activated);

let accepted_id_merkle_root = kaspa_merkle::calc_merkle_root(virtual_state.accepted_tx_ids.iter().copied());
let accepted_id_merkle_root = if self.accepted_id_merkle_root.is_active(virtual_state.daa_score) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@svarogg - here DAA_SCORE comes from Virtual-State

// NOTE: when subnetworks will be enabled, the sort should consider them in order to allow grouping under a merkle subtree
ctx.accepted_tx_ids.sort();
// Preserve canonical order of accepted transactions after hard-fork
if !self.accepted_id_merkle_root.is_active(pov_daa_score) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hera POV_DAA_SCORE is equal to header.daa_score of the caller

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@svarogg ...


// Verify header accepted_id_merkle_root
let expected_accepted_id_merkle_root = kaspa_merkle::calc_merkle_root(ctx.accepted_tx_ids.iter().copied());
let expected_accepted_id_merkle_root = if self.accepted_id_merkle_root.is_active(header.daa_score) {
Copy link
Author

@reshmem reshmem Feb 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@svarogg - Here as well, header.daa_score

// Verify header accepted_id_merkle_root
let expected_accepted_id_merkle_root = kaspa_merkle::calc_merkle_root(ctx.accepted_tx_ids.iter().copied());
let expected_accepted_id_merkle_root = if self.accepted_id_merkle_root.is_active(header.daa_score) {
kaspa_merkle::merkle_hash(
Copy link
Author

@reshmem reshmem Feb 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@svarogg - No sure if it better to have new function that computes it....

Copy link

@pycckuu pycckuu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is my 2 cents. 😃

I am not sure If applicable, should we add a task to write boundary tests around the splits:

  1. Boundary block validation to verify that the last pre-activation block enforces sorting, while the first post-activation block uses chained merkle roots

  2. Test chain reorganizations across the activation boundary to prevent invalid blocks

pub runtime_sig_op_counting: ForkActivation,

/// Canonical transaction ordering
pub accepted_id_merkle_root: ForkActivation,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add documentaion referene:

/// KIP-15 activation: When enabled, uses chained merkle roots with canonical tx ordering
pub accepted_id_merkle_root: ForkActivation,

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pycckuu - I am not sure about the name in general - maybe ForkChoice should be kip15_activation or something like this.

let accepted_id_merkle_root = kaspa_merkle::calc_merkle_root(virtual_state.accepted_tx_ids.iter().copied());
let accepted_id_merkle_root = if self.accepted_id_merkle_root.is_active(virtual_state.daa_score) {
kaspa_merkle::merkle_hash(
self.headers_store.get_header(virtual_state.ghostdag_data.selected_parent).unwrap().accepted_id_merkle_root,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed a potential issue in the code where we're using unwrap() on the parent header retrieval. This could cause panics if the header is missing. I suggest replacing it with proper error handling:

let parent_header = self.headers_store.get_header(...)
    .map_err(|_| RuleError::MissingParentHeader(selected_parent))?;

This change adds explicit error handling for header validation and prevents node crashes.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. Good point.... I will check if this situation is possible in general. Looks like from POV of virtual selected-parent should exist. Always. But I will check with core-team, if we should handle this error explicitly ( maybe it is implicitly assumed in this context ). @svarogg ? what do think ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pycckuu - I asked kaspa core-team, and indeed in this context it is safe to call unwrap without error handling. S.P header is there ( specifically in this context )

ctx.accepted_tx_ids.sort();
// Preserve canonical order of accepted transactions after hard-fork
if !self.accepted_id_merkle_root.is_active(pov_daa_score) {
ctx.accepted_tx_ids.sort();
Copy link

@pycckuu pycckuu Feb 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May we sort_unstable() instead?

Suggested change
ctx.accepted_tx_ids.sort();
ctx.accepted_tx_ids.sort_unstable();

It's faster than regular sort, though it won't preserve order of equal elements. It is not important as we shouldn't have duplicates.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was originally sorted this way, so I should preserve past behaviour, otherwise network will split ....

@reshmem reshmem force-pushed the canonical_tx_order_kip branch from 1d90b63 to 58290f7 Compare February 12, 2025 17:00
michaelsutton and others added 25 commits February 17, 2025 21:01
* kip13

* inline tracking per mass unit

* various small fixes

* docs
* implement storage mass plurality

* move plurality calculation to mass module and add a useful trait for accessing it

* utxo cell

* consume outputs iterator only once, fix theoretic overflow

* add sanity check for plurality limits, align comments

* optimize input iterator consumption

* extended comment rewrite

* fix doc build

* inline the relaxed formula conditions

* test_storage_mass_pluralities
kaspanet#642)

* change expected pruning point check from header validity to chain qualification

* adjust `pruning points valid chain` verification to the new rule change
1. Accepted-ID-MR = Hash ( SP.Accepted-ID-MR, MR of Accepted-TXs )
@reshmem reshmem force-pushed the canonical_tx_order_kip branch from 58290f7 to 7909a97 Compare February 26, 2025 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants