Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Light History Store for full nodes #2370

Open
wants to merge 5 commits into
base: albatross
Choose a base branch
from

Conversation

viquezclaudio
Copy link
Contributor

@viquezclaudio viquezclaudio commented Apr 15, 2024

Use the light history store for full node clients
Necessary changes to use the history interface
Several changes to the usage of the history store

...

This fixes #1704.

Pull request checklist

  • All tests pass. The project builds and runs.
  • I have resolved any merge conflicts.
  • I have resolved all clippy and rustfmt warnings.

@viquezclaudio viquezclaudio added the WIP This pull request is still work in progress label Apr 15, 2024
@viquezclaudio viquezclaudio force-pushed the viquezcl/history_store branch 2 times, most recently from 98709f7 to 05143af Compare April 15, 2024 15:04
@sisou
Copy link
Member

sisou commented Apr 16, 2024

Does this fix #1704?

@viquezclaudio
Copy link
Contributor Author

Correct, this is the proper fix for 1704.
However this still needs more testing.

@sisou
Copy link
Member

sisou commented Apr 16, 2024

👍 I updated the PR description with that issue number.

@viquezclaudio viquezclaudio force-pushed the viquezcl/history_store branch 3 times, most recently from b27ad62 to 62ad289 Compare April 16, 2024 20:33
Comment on lines 109 to 114
if let Some(txns) = txns_per_block.get_mut(&bn) {
txns.push(txn.clone());
} else {
let new_txns = vec![txn.clone()];
txns_per_block.insert(bn, new_txns);
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if let Some(txns) = txns_per_block.get_mut(&bn) {
txns.push(txn.clone());
} else {
let new_txns = vec![txn.clone()];
txns_per_block.insert(bn, new_txns);
}
txns_per_block.entry(bn).or_default().push(txn.clone());

Comment on lines 118 to 119
for bn in txns_per_block.keys().sorted() {
let hist_txs = txns_per_block.get(bn).unwrap();
Copy link
Member

Choose a reason for hiding this comment

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

Using a BTreeMap, the keys would already be sorted.
Then, this could be simplified to for (bn, hist_txs) in txns_per_block.
Not sure whether it's worth it though.

Also, there's an inconsistency in naming: txs vs txns

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I considered using a BTreeMap, but I wasn't sure if it was worth to add the dependency and use it vs just sorting the keys

Copy link
Contributor

Choose a reason for hiding this comment

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

if it was worth to add the dependency

It's in the standard library, so would be no additional dependency: std::collections::BTreeMap.


for hist_tx in ext_hash_vec {
// If the transaction is inside the validity window, return true.
if hist_tx.block_number >= validity_window_start {
Copy link
Member

Choose a reason for hiding this comment

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

Currently, we only check whether the transaction occurred after the validity window started.
However, it could potentially still fall outside the window if it occurred after it finished.
The second boundary check seems missing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here I'm not doing anything different than what we were doing before, i.e: I just moved this code: https://github.com/nimiq/core-rs-albatross/blob/albatross/blockchain/src/blockchain/wrappers.rs#L196
to the history store file.

Do you suggest that we used to have a bug?
What do you mean by "if it occurred after it finished." ?

Comment on lines 195 to 219
// If size is 0 we need to copy the entries from the previous block number to the new one
if size == 0 {
init_mmr_from_block_number(hist_tree_table, tx, block_number);
}
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand what this is about

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the light history store, what we are using are "peaks-only MMRs"
However, this means that if we have to revert blocks, we don't have enough information to just remove txns and go back to a previous state, as we do with the regular MMR.

So what we are doing is to store "peaks only mmrs" per block, i.e. essentially we have "snapshots" of how the peaks only MMR looked at each block.

However, since history nodes construct a big MMR with all the transactions of the given epoch, and this is the root that we need to verify against, then it means the starting point for block N is the peaks only mmr of block N-1, which is what this line is doing:
when we start pushing transactions for a block that we didn't have before, we first need to start with the peaks only mmr of the previous block and continue from there.

Let me know if this clarifies just question

};

// Deconstruct the key into a block number and a node index.
let (new_block_number, _) = key_to_index(next_key).unwrap();
Copy link
Member

Choose a reason for hiding this comment

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

key_to_index returns an epoch_number instead of a block_number (according to the variable names in the function; so this needs updating)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll update the comment, because we are using the same functions that the regular history store uses (which constructs keys based on {epoch_number, index} , but for the peaks only mmr, we construct keys based on {block_number, index}

@@ -232,6 +241,72 @@ pub fn remove_block_from_store(
}
}

/// Copies the mmr entries of the previous block number
/// This is used to initialize the tree for the given block number, using the previous tree as a baseline
pub fn init_mmr_from_block_number(
Copy link
Member

Choose a reason for hiding this comment

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

What is the advantage of copying the contents over accessing the previous ones when needed?
Less complexity when accessing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See my comment above.

@viquezclaudio viquezclaudio force-pushed the viquezcl/history_store branch 2 times, most recently from 8eda34a to 240da36 Compare April 18, 2024 16:53
@viquezclaudio viquezclaudio force-pushed the viquezcl/history_store branch 2 times, most recently from 3f82095 to 59f9c4b Compare May 13, 2024 20:46
@viquezclaudio viquezclaudio removed the WIP This pull request is still work in progress label May 15, 2024
Use the light history store for full node clients
Necessary changes to use the history interface
Several changes to usage of the history store
Mantain the txns in the validity store in database tables.
The history store range function now uses a database transaction
Added unittest for total_len_at_epoch in the light history store
Add an unittest to exercise the transaction_in_validity_window functionality in the light history store
Fixed typo in range inclusion when pruning the validity store
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.

Full node unable to apply election block
4 participants